Ir ao conteúdo
  • Cadastre-se

Bibliotecas para HI-TECH C para PIC10/12/16/18


edu.

Posts recomendados

Boa noite a todos os companheiros do fórum!

O que me trouxe aqui hoje foi a vontade de criar um tópico comum de livre acesso com material disponível para os amantes desse ótimo compilador da microchip. Em primeiro lugar gostaria de ressaltar que já utilizei o CCS e o ganho em liberdade e eficiência se comparado aos compiladores da microchip é imenso. A maioria dos iniciantes prefere esse compilador pela facilidade que as bibliotecas prontas oferecem, e na intenção de quebrar esse paradigma que inicio esse tópico.

Ao longo do ano passado eu sesenvolvi por conta alguns "drivers" que usava para fazer a maioria dos meus programas. Para quando precisar da serial simplesmente usar "UARTInit(2400)", e pronto. Agora estou revisando eles em busca de erros e tentando torná-los mais eficientes, além de aplicar alguns conceitos de "boa programação" para tornar o código legível e facilmente adaptável para as mais diversas aplicações.

--SUMÁRIO

Teclado matricial - edu.

UART - edu.

LCD de caracteres - edu.

Shift Register - ricardospimentel

O primeiro arquivo que converti foi o driver para teclados matriciais digitais, fazendo a leitura por varredura. Antigamente eu utilizava delays e aguardava o pressionamento do botão para retornar valor. Agora procuro sempre que possível utilizar o loop principal do programa ininterrupto, de modo que seja executado rapidamente sem ficar preso por nada, assim pode-se adicionar um WatchDog dando mais segurança ao aplicativo sem que haja erros e resets indesejados durante delays e pressionamento de botões. Além disso implementei um buffer FIFO para as teclas lidas, assim, se por algum motivo o processamento dos digitos teclados for lento os mesmos serão armazenados para evitar perdas. Como disse acima, o buffer tem o tamanho definido pelo usuário para ser adaptável.

Para finalizar antes de postar o código, eu escrevi os comentários e o código todo em inglês. Como quase todo material disponível por ai é na língua materna dos µC optei por utilizar também. Não sou nativo e provavelmente haverá erros nos comentários, me avisem para que possa arrumar.

E é claro, fiquem livres para postar seus códigos e facilitar a vida de todos que utilizam o compilador.


* *
* *
* KEYPAD DRIVER INCLUDE *
* BY: EDUARDO T. LOURENÇO *
* *
* Code for PIC16 HI-TECH C compiler. *
* *
* *
************************************************************************/
#ifndef _KEYPAD_C_
#define _KEYPAD_C_


/************************************************
* *
* PINOUT DEFINITION *
* *
* Columns input with pull-up. *
* Lines push-pull output. *
* *
************************************************/
#define PAD_C1 RC0
#define PAD_C2 RC1
#define PAD_C3 RC2
#define PAD_L1 RC3
#define PAD_L2 RC4
#define PAD_L3 RC5
#define PAD_L4 RC6


/************************************************
* *
* SYSTEM DEFINITIONS *
* *
* PAD_BUFFER_SIZE, defines the size of *
* the input buffer. *
* PAD_LIMIT_FLAG, defines the number of *
* bytes necessary to set the buffer flag. *
* PAD_DEBOUNCE_LOOPS, defines the number *
* of loops to debounce the pads. *
* PAD_BUFFER_EMPTY, defines the error *
* code when a getc is called with an empty *
* buffer. *
* PAD_DATA_INVALID, defines the value *
* when an error occure while reading the *
* keypad. *
* *
************************************************/
#define PAD_BUFFER_SIZE 2
#define PAD_LIMIT_FLAG 1
#define PAD_DEBOUNCE_LOOPS 500
#define PAD_BUFFER_EMPTY 0
#define PAD_DATA_INVALID 0


/************************************************
* *
* RETURN DEFINITIONS *
* *
* Return must be diffrent from *
* PAD_BUFFER_EMPTY and PAD_DATA_INVALID. *
* *
************************************************/
#define PAD_L1C1 '1'
#define PAD_L1C2 '2'
#define PAD_L1C3 '3'
#define PAD_L2C1 '4'
#define PAD_L2C2 '5'
#define PAD_L2C3 '6'
#define PAD_L3C1 '7'
#define PAD_L3C2 '8'
#define PAD_L3C3 '9'
#define PAD_L4C1 '*'
#define PAD_L4C2 '0'
#define PAD_L4C3 '#'


/************************************************
* *
* GLOBAL VARIABLES *
* *
************************************************/
unsigned int PADdebounce=0;
char PADbuffer[PAD_BUFFER_SIZE],PADbufferCont=0;
bit PADtaskStep=0;


/************************************************
* *
* PAD_TASKS *
* *
* Input: void. *
* Return: void. *
* Description: This function must be *
* called periodicaly to keep the buffer *
* updated. *
* *
************************************************/
void PADTasks(void)
{
if( !PADtaskStep )
{//run step 0
PAD_L1=0;
PAD_L2=0;
PAD_L3=0;
PAD_L4=0;
__delay_us(1);
if( !( PAD_C1 && PAD_C2 && PAD_C3 ) )
{//if pad is pressed
if( PADdebounce > PAD_DEBOUNCE_LOOPS )
{//if debounce is done
PADdebounce=0;
if( PADbufferCont < PAD_BUFFER_SIZE )
{//if there is space in the buffer
//check line 1
PAD_L2=1;
PAD_L3=1;
PAD_L4=1;
__delay_us(1);
if( !PAD_C1 )
PADbuffer[PADbufferCont] = PAD_L1C1;
else if( !PAD_C2 )
PADbuffer[PADbufferCont] = PAD_L1C2;
else if( !PAD_C3 )
PADbuffer[PADbufferCont] = PAD_L1C3;
else
{//check line 2
PAD_L1=1;
PAD_L2=0;
__delay_us(1);
if( !PAD_C1 )
PADbuffer[PADbufferCont] = PAD_L2C1;
else if( !PAD_C2 )
PADbuffer[PADbufferCont] = PAD_L2C2;
else if( !PAD_C3 )
PADbuffer[PADbufferCont] = PAD_L2C3;
else
{//check line 3
PAD_L2=1;
PAD_L3=0;
__delay_us(1);
if( !PAD_C1 )
PADbuffer[PADbufferCont] = PAD_L3C1;
else if( !PAD_C2 )
PADbuffer[PADbufferCont] = PAD_L3C2;
else if( !PAD_C3 )
PADbuffer[PADbufferCont] = PAD_L3C3;
else
{//check line 4
PAD_L3=1;
PAD_L4=0;
__delay_us(1);
if( !PAD_C1 )
PADbuffer[PADbufferCont] = PAD_L4C1;
else if( !PAD_C2 )
PADbuffer[PADbufferCont] = PAD_L4C2;
else if( !PAD_C3 )
PADbuffer[PADbufferCont] = PAD_L4C3;
else
PADbuffer[PADbufferCont] = PAD_DATA_INVALID;
}
}
}
if( PADbuffer[PADbufferCont] != PAD_DATA_INVALID )
{//if data is valid
PADbufferCont++;
}
}
//goto step 1
PADtaskStep=1;
}
else//if debounce not done
PADdebounce++;
}
else//if pad not pressed
PADdebounce=0;
}
else
{//run step 1
PAD_L1=0;
PAD_L2=0;
PAD_L3=0;
PAD_L4=0;
__delay_us(1);
if( PAD_C1 && PAD_C2 && PAD_C3 )
{//if pad keep pressed
if( PADdebounce > PAD_DEBOUNCE_LOOPS )
{//if debounce is done
PADdebounce=0;
//back to step 0
PADtaskStep=0;
}
else//if debounce not done
PADdebounce++;
}
else//if pad not pressed
PADdebounce=0;
}
//end pad_tasks
}


/************************************************
* *
* PAD_KBHIT *
* *
* Input: void. *
* Return: bit indicating if the buffer *
* reach the defined number of chars or not. *
* Description: Indicate the buffer *
* status. *
* *
************************************************/
bit PADKbhit(void)
{
if( PADbufferCont >= PAD_LIMIT_FLAG )
return 1;
else
return 0;
}


/************************************************
* *
* PAD_GETC *
* *
* Input: void. *
* Return: the oldest char in the buffer. *
* Description: Read data from buffer. *
* *
************************************************/
char PADGetc(void)
{
char PADGaux,PADGret;
if( PADbufferCont )
{
PADGret = PADbuffer[0];
for( PADGaux=0; PADGaux<PADbufferCont; PADGaux++ )
PADbuffer[PADGaux] = PADbuffer[PADGaux+1];
PADbufferCont--;
return PADGret;
}
else
return PAD_BUFFER_EMPTY;
}


/************************************************
* *
* PAD_CLR *
* *
* Input: void. *
* Return: void. *
* Description: Clears the buffer. *
* *
************************************************/
#define PADClear() PADbufferCont=0


/************************************************
* *
* PAD_GET_NEXT_CHAR *
* *
* Input: void. *
* Return: the next char pressed. *
* Description: Clears the buffer, and *
* gets the next char. *
* *
************************************************/
char PADGetNextChar(void)
{
PADClear();
while( !PADbufferCont )
PADTasks();
PADClear();
return PADbuffer[0];
}


#endif
/************************************************************************
* *
* *
* KEYPAD DRIVER END *
* *
* *
************************************************************************/
/************************************************************************

EDIT: Segue um dos códigos que utilizei para fazer os testes e ajustes no driver. É bem simples e utiliza a UART na mão porque ainda não concluí a revisão dessa biblioteca (2400bps).


#define _XTAL_FREQ 4000000

#include "keypad_3x4_digital.c"

__CONFIG( FOSC_INTRCIO & WDTE_OFF & PWRTE_ON & MCLRE_OFF );

char aux;

void main(void)
{
ANSEL = 0;
ANSELH = 0;
TRISA = 0;
TRISB = 0;
TRISC = 0x07; //RC0 to RC2 input
PORTA = 0;
PORTB = 0;
PORTC = 0;

TXSTA = 0x20;
RCSTA = 0x90;
BAUDCTL = 0;
SPBRG = 25;
SPBRGH = 0;

while(1)
{
PADTasks();
// if( PADKbhit() )
// RA0=1;
// else
// RA0=0;
// if( PADbufferCont == 2 )
// RA1=1;
// else
// RA1=0;
// if( PADbufferCont > 2 )
// RA2=1;
// else
// RA2=0;
if( PADKbhit() )
{
TXREG = PADGetc();
// aux = PADGetc();
// if( aux=='1' )
// PORTA ^= 0x01;
// else if( aux=='2' )
// PORTA ^= 0x02;
// else if( aux=='3' )
// PORTA ^= 0x04;
// else if( aux=='4' )
// PORTA ^= 0x10;
// else if( aux=='5' )
// PORTA ^= 0x20;
// else if( aux=='6' )
// PORTB ^= 0x10;
// else if( aux=='7' )
// PORTB ^= 0x20;
// else if( aux=='8' )
// PORTB ^= 0x40;
// else if( aux=='9' )
// PORTB ^= 0x80;
}
}
}
#include <htc.h>

  • Curtir 1
Link para o comentário
Compartilhar em outros sites

Olá Edu,

Parabens pela iniciativa, com certeza vai ser útil para muita gente.

Eu não entendo nada de C, então instalei o MikroC e postei algumas perguntas aqui no fórum, recebi várias críticas falando que o Hi Tech é muito melhor.

Então decidi instalar o Hi Tech PIC10/12/16, mas não achei nenhuma literatura que me ajudasse a entender a linguagem C e o compilador Hi Tech.

O manual deste compilador é para profissional, não entendi nada.

Desisti por enquanto do Hi Tech e do MikroC e comprei o livro PIC C do Fábio Pereira para o Compilador CCS - 7º edição, pelo menos é em Portugês e estou aprendendo algum coisa.

Agora com relação ao CCS que você elogiou, tenho lido muitas críticas a respeito do mesmo e até agora não entendi o por que das reclamações.

Depois que eu aprender o suficiente com o CCS vou tentar novamente o Hi Tech e/ou MikroC.

Abraços e boa sorte,

Renato

Link para o comentário
Compartilhar em outros sites

O problema é que no CCS você perde o controle do hardware, não sabe o que vai ser gerado a cada linha e nao tem acesso a todos os registradores do MCU. Para se utilizar ele quase sempre é necessário mapear algum registrador que precise, além de que, quando os bugs aparecem, tem que esquentar muito a cabeça para procurar as falahas pois tudo é feito por bibliotecas prontas e não se sabe o que ta rolando no hardware.

Programação em C é bastante simples, você ja programou em assembly? É recomendado que se começe por ai para ter noção do que acontece por trás das linhas. Quando se entende o funcionamento do hardware o C é mais poderoso e oferece recursos muito além do ASM. Uma das vantagens é que o HI-TECH é compatível com ANSI-C, que é uma norma que define como as coisas devem ser, funçoes, macros, tipos de dados. Sendo assim, é bem mais fácil migrar do HI-TECH para outros compiladores, e inclusive para outros MCU uma vez que a norma é a mesma para todos. CCS é um pseudo ANSI, nao é compativel na maioria das coisas e tudo que você faz é indireto através de funçoes.

Para iniciar, é bom utilizar LEDs e fazer piscas e leitura de estados de botões. Basicamente você precisa incluir o cabeçalho padrão <htc.c> que busca nas definições do projeto qual MCU estás utilizando e inclui o cabeçalho adequado. Quando se deseja utilizar delays defina a frequência do sistema _XTAL_FREQ. E antes de qualuqer código sete os bits de configuração com a função __CONFIG. As opções de configuração assim como o mapeamento de toda a memória do MCU estão no headrer .h do pic correspondente. Procure na pasta include pelo cabeçalho de seu MCU. Depois adicione o main e só botar pra rodar. O manual é mais uma fonte de consulta para que você possa ver os tipos de dados, os macros e funções que ele disponibiliza, não tem um bom "getting started".

Espero que não desista e siga tentando com o HI-TECH, é um ótimo compilador e lhe trará os frutos do seu esforço em performace e economia. Sem falar que é free, do fabricante do MCU e com suporte de demais usuários e dos staffs no fórum da microchip (apesar de eu achar as respostas muito lentas e o apoio muito fraco).

Link para o comentário
Compartilhar em outros sites

Valeu pela explanação Edu, eu não sabia destes detalhes do CCS.

Não sou expert em assembly, mas aprendi um pouco e já percebi que conhecendo o hardware do PIC ajuda muito no aprendizado de programação em C.

Eu gosto do assembly e não penso em desisitir desta linguagem de programação, mas aprender a linguagem C também é importante.

Como eu não tenho um "getting started" do Hi Tech eu vou continuar lendo o livro do Fabio Pereira que alias estou gostando muito, afinal de contas eu nem sabia por onde começar o aprendizado de programação em C.

Depois que eu tiver alguma noção de programação em CCS C vou tentar o HT mais uma vez, espero não estar indo na contra-mão.

Eu tenho lido sobre bibliotecas abertas e/ou fechadas nos diversos compiladores C, porém eu não sei o nome destas bibliotecas para eu mesmo verificar se são abertas ou fechadas.

Um exemplo: um forista de um outro fórum comentou que ele não usa as bibliotecas nativas do MikroC, ele pega do C18 que são abertas e faz as alterações necessárias para o uso dele.

Por acaso as bibliotecas do Hi Tech PIC10/12/16 são abertas e do CCS são fechadas?

Abs,

Renato

Link para o comentário
Compartilhar em outros sites

Hmm...

Nunca fui atras das bibliotecas do CCS, alguns drivers eu sei que sao abertos, mas as funções nativas não. No HI-TECH eu encontrei vários cabeçalhos onde ele descreve e declara a função, mas o código em si não encontrei. Também n fui muito atras. Como mostrei acima prefico criar meus proprios drivers. O negócio do HI-TECH são os exemplos mais para frente, as application notes e todo o duporte do fabricante. Além de como disse, ter o hardware todo declarado e aberto para manipular.

Link para o comentário
Compartilhar em outros sites

Parabéns edu, sugiro a fixação do tópico.

Posso dar uma sugestão? Afim de orgarnizar melhor seus códigos e facilitar a vida do compilador na hora de linkar os arquivos, sempre que criares uma biblioteca gere sempre os dois arquivos o .c e o .h

No caso de sua UART separe o que é função do que é protótipo isso ajuda na portabilidade de código e na sua compreensão:

veja só:

no .C coloque:

- Todos os includes, inclusive o do seu driver, por exemplo no seu UART.c voce deve incluir o UART.h e depois criar ele

- Variaveis globais sim elas ficam no .C

-As funções sem os prototipos;

ja no .H inclua:

- o #ifndef e define que voce fez certinho;

- os defines e constantes;

- structs e unions;

- apenas os prototipos das funções

- possíveis externs

ao criar os dois arquivos crie uma pastinha so para eles dois e compile a pasta toda, com isso voce ja ativa a função do #ifndef e evita a recompilação desnecessária da biblioteca.

dúvidas posta ai, vou acompanhar de perto o tópico, e quanto ao CCS o pessoal que ja viu meus tópicos conhece bem minha opinião sobre ele e porque penso isso.

Abs.

Link para o comentário
Compartilhar em outros sites

edu,

inclusive no arquivo main.c deve ser feito um main.h onde o proprio void main é um prototipo de função, estranho né? Mas é assim mesmo.

No main.c você inclui sempre o .h também, o header file nada mais é do que o cabeçalho do teu arquivo .c contendo o prototipo das funções e constantes, porém é ele que será usado pelo linker para conectar os diversos modulos do programa.

Em todo caso pode-se generalizar:

- .C é o código em si e o que ele faz.

- .H é o cabeçalho que contem os prototipos e constantes, também usado para proteção do código escondendo assim o .C, outro ponto de vista o .h é para você explicar a um terceiro como é usado o módulo que você escreveu sem ter de mostrar como funciona o algoritmo.

Quando digo para compilar a pasta, me refiro a voce antes de dar um build all no seu projeto compile por diretorios, por exemplo no seu driver UART vai ter uma pastinha no seu projeto so dela, ai na IDE voce vai la e compila o .h da UART tendeu?

duvidas manda bala.

Abs.

  • Curtir 1
Link para o comentário
Compartilhar em outros sites

Opa, voltando ae para mais uma contribuição.

Felipe, eu fiz como você disse para organizar o código mas o resultado final foi mais desordem do que ordem. Enfim, é muita coisa para cada arquivo criar um .h e depois criar sub-folders para os arquivos. Eu prefiro fazer um projeto simples, com o main na lista de arquivos e no topo do código adicionar os demais .c. Com o arquivo bem organizado e as descrições das funções claras é possível tornar o código bem legível.

Enfim, pulando essa parte de organização do código e etc que é bastante pessoal de cada um, o real motivo que me trouxe aqui foi uma nova biblioteca bastante simples porém extremamente útil para lidar com a UART. Eu fiz as funções básicas para lidar com o hardware já pronto do MCU, inicialização e envio e recebimento de dados. Tentei por mais de uma vez implementar uma fifo de entrada e saída mais eficiente porém me perdi em erros e não consegui completar, cheguei a concluão que talvez não fosse tão útil para um driver genérico e que estivesse perdendo tempo.

O driver tem ao final dois tipos de função, com e sem o controle de erros. Para aplicações bem simples (que são a maioria) e que a conversa é simples e não se precisa de demasiado controle fiz as funções de sempre Putc, Puts e Getc. Funcionam bem e quebram grande parte dos galhos. Porém quando é preciso tratar error e enviar dados com mais eficiência eu criei as funções PutByte e GetByte, que retornam erros para fazer o controle da porta, além de não ficarem trancadas aguardando a liberação do buffer.

Penso eu que a interrupção é uma característica bem peculiar de cada código e que varia muito, logo não seriam realmente úteis funções para lidar com as ints. Por fim, na inicialização da porta eu fiz o cálculo do baud rate com contador de 16bits e high speed, pois oferece o maior 'range' de velocidades com maior resolução (precisão).


* *
* *
* UART DRIVER INCLUDE *
* BY: EDUARDO T. LOURENÇO *
* *
* Code for PIC16 HI-TECH C compiler. *
* *
* *
************************************************************************/
#ifndef _UART_C_
#define _UART_C_


/************************************************
* *
* UART ERROR DEFINITION *
* *
* UART_SUCCESSFUL, no error has occured. *
* UART_ERROR, an error has occured. *
* UART_FRAMIN_ERROR, stop bit not recived. *
* UART_OVERRUN_ERROR, byte recived without *
* space in the buffer. *
* UART_NO_DATA_AVAILABLE, there is no data *
* on the recive buffer. *
* *
************************************************/
#define UART_SUCCESSFUL 0
#define UART_ERROR 1
#define UART_FRAMING_ERROR 0x03
#define UART_OVERRUN_ERROR 0x05
#define UART_NO_DATA_AVAILABLE 0x09


/************************************************
* *
* UART_INIT *
* *
* Input: Baud rate (24bits). *
* Return: Error report. *
* Description: Initializate the UART *
* port in asynchronous mode for 8bits. *
* *
************************************************/
bit UARTInit(unsigned short long UARTIbaud)
{
UARTIbaud = _XTAL_FREQ/(4*UARTIbaud);
if( (UARTIbaud>1) && (UARTIbaud<65536) )
{
BAUDCTL = 0x08;
UARTIbaud --;
SPBRG = UARTIbaud;
SPBRGH = UARTIbaud >> 8;
TXSTA = 0x24;
RCSTA = 0x90;
return UART_SUCCESSFUL;
}
else
return UART_ERROR;
}


/************************************************
* *
* UART_CLOSE *
* *
* Input: void. *
* Return: void. *
* Description: Close the UART port and *
* reset the default values in registers. *
* *
************************************************/
#define UARTClose() { RCSTA=0; TXSTA=0; BAUDCTL=0; SPBRG=0; SPBRGH=0; }


/************************************************
* *
* UART_RX_BUFFER *
* *
* Input: void. *
* Return: 1 if there is a char in the *
* recive buffer, else 0. *
* Description: Reads the recive buffer *
* status. *
* *
************************************************/
#define UARTRxBuffer() ( RCIF )


/************************************************
* *
* UART_TX_BUFFER *
* *
* Input: void. *
* Return: 1 if there is a space in the *
* transmit buffer, else 0. *
* Description: Reads the transmit buffer *
* status. *
* *
************************************************/
#define UARTTxBuffer() ( TXIF )


/************************************************
* *
* UART_GET_BYTE *
* *
* Input: Pointer to data storage. *
* Return: Error report. *
* Description: Gets the byte in the *
* recive buffer (RXREG). *
* *
************************************************/
char UARTGetByte(char *UARTGBdata)
{
char UARTGBreturn=UART_SUCCESSFUL;
if( UARTRxBuffer() )
{
if( FERR || OERR )
{
if( FERR )
{
UARTGBreturn = RCREG;
UARTGBreturn = UART_FRAMING_ERROR;
}
if( OERR )
{
CREN=0;
CREN=1;
UARTGBreturn |= UART_OVERRUN_ERROR;
}
}
else
*UARTGBdata = RCREG;

}
else
UARTGBreturn = UART_NO_DATA_AVAILABLE;
return UARTGBreturn;
}


/************************************************
* *
* UART_PUT_BYTE *
* *
* Input: Byte to be send. *
* Return: Error report. *
* Description: Sends the desired byte *
* to UART port. *
* *
************************************************/
bit UARTPutByte(char UARTPBdata)
{
if( UARTTxBuffer() )
{
TXREG = UARTPBdata;
return UART_SUCCESSFUL;
}
else
return UART_ERROR;
}


/************************************************
* *
* UART_GETC *
* *
* Input: void. *
* Return: Character in buffer. *
* Description: Gets a character. *
* *
************************************************/
char UARTGetc(void)
{
char UARTGchar;
if( !UARTGetByte(&UARTGchar) )
return UARTGchar;
else
return 0;
}


/************************************************
* *
* UART_PUTC *
* *
* Input: Character to be send. *
* Return: void. *
* Description: Sends a character. *
* *
************************************************/
void UARTPutc(char UARTPchar)
{
while( UARTPutByte(UARTPchar) );
}


/************************************************
* *
* UART_PUTS *
* *
* Input: Pointer to string. *
* Return: void. *
* Description: Sends a string. *
* *
************************************************/
void UARTPuts(const char *UARTPpointer)
{
while( *UARTPpointer )
{
UARTPutc(*UARTPpointer);
UARTPpointer++;
}
}


#endif
/************************************************************************
* *
* *
* UART DRIVER END *
* *
* *
************************************************************************/
/************************************************************************

Novamente segue um exemplo bem simples da utilização do driver.


#define _XTAL_FREQ 4000000


#include "uart_asynchronous_8bits.c"


__CONFIG( FOSC_INTRCIO & WDTE_OFF & PWRTE_ON & MCLRE_OFF );


void interrupt code(void)
{
UARTPutc(UARTGetc());
}


void main(void)
{
ANSEL=0;
ANSELH=0;

UARTInit(9600);
RCIE=1;
PEIE=1;
GIE=1;

UARTPuts("Init OK!");

while(1)
{
NOP();
}
}
#include <htc.h>

Link para o comentário
Compartilhar em outros sites

  • mês depois...

Ja faz um tempinho que eu estou tentando concluir mais um pequeno código para contribuir ai, mas a pascoa me deu alguma folginha e consegui concluir. É uma biblioteca para rodar LCDs alfanuméricos, aqui em casa eu só tenho 16x2 e foi com o que testei, no proteus coloquei vários outros de diversos tamanhos e deu tudo certo também. O único porém é que com mais de duas linhas dai tem que fazer alguma adaptações e acertar os endereços iniciais das linhas no LCDGotoxy().

Sem mais delongas, o código eu fiz bastante simples com e sem opção de leitura baseando-me no datasheet do controlador HD44780U da HITACHI. Além do comum eu criei uma função para criar caracteres novos na CGRAM, e algumas funções definidas que facilitam no trabalho com cursor, shift de display e outros comandos básicos.


* *
* *
* LCD DRIVER INCLUDE *
* BY: EDUARDO T. LOURENÇO *
* *
* Code for PIC16 HI-TECH C compiler. *
* v1.0.00 *
* *
* *
************************************************************************/
#ifndef _LCD_C_
#define _LCD_C_


/************************************************************************
* *
* USEFUL DEFINITIONS *
* *
************************************************************************/
#ifndef TRUE
#define TRUE 1
#endif

#ifndef FALSE
#define FALSE 0
#endif

#ifndef _XTAL_FREQ
#error "_XTAL_FREQ not defined."
#endif


/************************************************************************
* *
* SYSTEM DEFINITIONS *
* *
* LCD_ENABLE_READS: *
* TRUE *
* Enable read operations in the display, RW pin should *
* be connected and TRIS definition associated to data pins. *
* FALSE *
* Disable read operations in the display, RW pin should *
* be connect to the ground. *
* LCD_LINE1: *
* Address number of the first line of the screen. *
* LCD_LINE2: *
* Address number of the second line of the screen. *
* *
************************************************************************/
#define LCD_ENABLE_READS TRUE
#define LCD_LINE1 0x80
#define LCD_LINE2 0xC0


/************************************************************************
* *
* PIN DEFINITIONS *
* *
* In case of using RW pin, be sure that TRIS definition are *
* matching the right IO pin. *
* *
************************************************************************/
#define LCD_DB7 RC0
#define LCD_DB6 RC1
#define LCD_DB5 RC2
#define LCD_DB4 RC3
#define LCD_E RC4
#define LCD_RS RC5
#if LCD_ENABLE_READS == TRUE
#define LCD_RW RC6
#define TRIS_DB7 TRISC0
#define TRIS_DB6 TRISC1
#define TRIS_DB5 TRISC2
#define TRIS_DB4 TRISC3
#endif


/************************************************************************
* *
* FUNCTION PROTOTYPES *
* *
************************************************************************/
#if LCD_ENABLE_READS == TRUE
char LCDReadNibble(void);
#endif
void LCDWriteNibble( char LCDWNnib );
#if LCD_ENABLE_READS == TRUE
char LCDBusyAc(void);
char LCDGetc(void);
#endif
void LCDWrite( char LCDWrs ,char LCDWdata );
void LCDPutc( char LCDPchar );
void LCDInit(void);
void LCDPuts( const char * LCDPstr );
void LCDGotoxy( char LCDGx, char LCDGy );
void LCDMakeChar( char LCDMCaddr, const char *LCDMCdata );


/************************************************************************
* *
* LCD_TRIS_READ *
* *
* Input: *
* Void *
* Return: *
* Void *
* Description: *
* Setup data pins as inputs for read operations. *
* *
************************************************************************/
#if LCD_ENABLE_READS == TRUE
#define LCDTrisRead() { TRIS_DB7=1; TRIS_DB6=1; TRIS_DB5=1; TRIS_DB4=1; }
#endif


/************************************************************************
* *
* LCD_TRIS_WRITE *
* *
* Input: *
* Void *
* Return: *
* Void *
* Description: *
* Setup data pins as outputs for write operations. *
* *
************************************************************************/
#if LCD_ENABLE_READS == TRUE
#define LCDTrisWrite() { TRIS_DB7=0; TRIS_DB6=0; TRIS_DB5=0; TRIS_DB4=0; }
#endif


/************************************************************************
* *
* LCD_READ_NIBBLE *
* *
* Input: *
* Void *
* Return: *
* Char *
* The nibble read from LCD in the 4 high order bits, *
* the 4 low order bits are always 0. *
* Description: *
* Read a nibble from LCD. *
* *
************************************************************************/
#if LCD_ENABLE_READS == TRUE
char LCDReadNibble(void)
{
char LCDRNnib=0;
LCD_E = 1;
__delay_us(1);
if( LCD_DB7 ) LCDRNnib |= 0x80;
if( LCD_DB6 ) LCDRNnib |= 0x40;
if( LCD_DB5 ) LCDRNnib |= 0x20;
if( LCD_DB4 ) LCDRNnib |= 0x10;
LCD_E = 0;
__delay_us(1);
return LCDRNnib;
}
#endif


/************************************************************************
* *
* LCD_WRITE_NIBBLE *
* *
* Input: *
* LCDWNnib *
* The nibble to be send, just the 4 high order bits are *
* going to be send. *
* Return: *
* Void *
* Description: *
* Write a nibble in the LCD. *
* *
************************************************************************/
void LCDWriteNibble( char LCDWNnib )
{
LCD_E = 1;
__delay_us(1);
if( LCDWNnib&0x80 ) LCD_DB7 = 1;
else LCD_DB7 = 0;
if( LCDWNnib&0x40 ) LCD_DB6 = 1;
else LCD_DB6 = 0;
if( LCDWNnib&0x20 ) LCD_DB5 = 1;
else LCD_DB5 = 0;
if( LCDWNnib&0x10 ) LCD_DB4 = 1;
else LCD_DB4 = 0;
__delay_us(1);
LCD_E = 0;
}


/************************************************************************
* *
* LCD_BUSY_AC *
* *
* Input: *
* Void *
* Return: *
* Char *
* AC *
* Address counter in the 7 low order bits. *
* BUSY *
* Busy flag in the MSB. *
* Description: *
* Read address counter and busy flag status. *
* *
************************************************************************/
#if LCD_ENABLE_READS == TRUE
char LCDBusyAc(void)
{
char LCDBAbusy;
LCDTrisRead();
LCD_RS = 0;
LCD_RW = 1;
__delay_us(1);
LCDBAbusy = LCDReadNibble();
LCDBAbusy |= LCDReadNibble()>>4;
return LCDBAbusy;
}
#endif


/************************************************************************
* *
* LCD_GETC *
* *
* Input: *
* Void *
* Return: *
* Char *
* Character read from the LCD. *
* Description: *
* Reads a character from LCD DDRAM. *
* *
************************************************************************/
#if LCD_ENABLE_READS == TRUE
char LCDGetc(void)
{
char LCDGchar;
LCDTrisRead();
LCD_RS = 1;
LCD_RW = 1;
__delay_us(1);
LCDGchar = LCDReadNibble();
LCDGchar |= LCDReadNibble()>>4;
while( LCDBusyAc()&0x80 );
return LCDGchar;
}
#endif


/************************************************************************
* *
* LCD_WRITE *
* *
* Input: *
* LCDWrs *
* TRUE *
* A data is going to be write. *
* FALSE *
* A command is going to be write. *
* LCDWdata *
* Data or command that is going to be send. *
* Return: *
* Void *
* Description: *
* Write a data or command to the LCD. *
* *
************************************************************************/
void LCDWrite( char LCDWrs ,char LCDWdata )
{
if( LCDWrs )
LCD_RS = 1;
else
LCD_RS = 0;
#if LCD_ENABLE_READS == TRUE
LCD_RW = 0;
LCDTrisWrite();
#endif
__delay_us(1);
LCDWriteNibble( LCDWdata );
LCDWriteNibble( LCDWdata<<4 );
#if LCD_ENABLE_READS == TRUE
while( LCDBusyAc()&0x80 );
#else
if( LCDWdata == 1 )
__delay_ms(2);
else
__delay_us(50);
#endif
}


/************************************************************************
* *
* LCD_COMMAND *
* *
* Input: *
* LCDCcom *
* Command to be send. *
* Return: *
* Void *
* Description: *
* Write a command to the LCD. *
* *
************************************************************************/
#define LCDCommand(LCDCcom) LCDWrite(FALSE,LCDCcom)


/************************************************************************
* *
* LCD_PUTC *
* *
* Input: *
* LCDPchar *
* Character to be write on the LCD. *
* Return: *
* Void *
* Description: *
* Write a character to LCD DDRAM. *
* *
************************************************************************/
void LCDPutc( char LCDPchar )
{
if( LCDPchar == '\f' )
//form feed (FF) = 0x0C = '\f'
LCDCommand( 0x01 );
else
LCDWrite(TRUE,LCDPchar);
}


/************************************************************************
* *
* LCD_INIT *
* *
* Input: *
* Void *
* Return: *
* Void *
* Description: *
* Initialize the LCD. *
* *
************************************************************************/
void LCDInit(void)
{
LCD_E = 0;
LCD_RS = 0;
#if LCD_ENABLE_READS == TRUE
LCD_RW=0;
#endif
__delay_ms(50);
LCDWriteNibble( 0x30 );
__delay_ms(5);
LCDWriteNibble( 0x30 );
__delay_us(150);
LCDWriteNibble( 0x30 );
LCDWriteNibble( 0x20 );
__delay_us(50);
LCDCommand( 0x28 );
LCDCommand( 0x0F );
LCDCommand( 0x01 );
LCDCommand( 0x06 );
}


/************************************************************************
* *
* LCD_PUTS *
* *
* Input: *
* LCDPstr *
* Pointer to a string to be write. *
* Return: *
* Void *
* Description: *
* Puts a string on the LCD DDRAM, the string must ends with *
* /0 (0x00); *
* *
************************************************************************/
void LCDPuts( const char * LCDPstr )
{
while( *LCDPstr )
{
LCDPutc( *LCDPstr );
LCDPstr++;
}
}


/************************************************************************
* *
* LCD_GOTOXY *
* *
* Input: *
* LCDGx *
* X position (column). *
* LCDGy *
* Y position (line). *
* Return: *
* Void *
* Description: *
* Changes the cursor position to X, Y (starting at 0,0). *
* *
************************************************************************/
void LCDGotoxy( char LCDGx, char LCDGy )
{
if( LCDGy == 0 )
LCDGy = LCD_LINE1;
else if( LCDGy==1 )
LCDGy = LCD_LINE2;
LCDCommand( LCDGy + LCDGx );
}


/************************************************************************
* *
* LCD_MAKE_CHAR *
* *
* Input: *
* LCDMCaddr *
* DDRAM address of the new character (0 to 7). *
* LCDMCdata *
* Pointer to 8byte data string of the new character. *
* Return: *
* Void *
* Description: *
* Creates a new character at CGRAM. *
* *
************************************************************************/
void LCDMakeChar( char LCDMCaddr, const char *LCDMCdata )
{
char LCDMCaux;
LCDCommand( 0x40 | ((LCDMCaddr&0x07)<<3) );
for( LCDMCaux=0; LCDMCaux<8; LCDMCaux++ )
LCDWrite( 1, LCDMCdata[LCDMCaux] );
LCDCommand( 0x80 );
}


/************************************************************************
* *
* USEFUL FUNCTIONS *
* *
************************************************************************/
#define LCDClear() LCDCommand(0x01)
#define LCDHome() LCDCommand(0x02)
#define LCDDisplay(LCD_D) LCDCommand(0x08|LCD_D)
#define DISPLAY_OFF 0x00
#define CURSOR_OFF 0x04
#define CURSOR_ON 0x06
#define CURSOR_BLINK 0x07
#define LCDShift(LCD_S) LCDCommand(0x10|LCD_S)
#define MOVE_LEFT 0x00
#define MOVE_RIGHT 0x04
#define SHIFT_LEFT 0x08
#define SHIFT_RIGHT 0x0C


#endif
/************************************************************************
* *
* *
* LCD DRIVER END *
* *
* *
************************************************************************/
/************************************************************************

Junto aqui o pequeno aplicativo que rodei para os testes.


#define _XTAL_FREQ 4000000
__CONFIG( WDTE_OFF & MCLRE_OFF & FOSC_INTRCIO & PWRTE_ON );


#include "lcd_character.c"


char aux;
const char data[8][8]={ {0x12,0x09,0x04,0x12,0x09,0x04,0x12,0x09},
{0x04,0x04,0x04,0x1F,0x04,0x04,0x04,0x00},
{0x09,0x09,0x09,0x09,0x09,0x09,0x09,0x09},
{0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04},
{0x1F,0x00,0x1F,0x00,0x1F,0x00,0x1F,0x00},
{0x1F,0x11,0x11,0x11,0x11,0x11,0x11,0x1F},
{0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01},
{0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11}
};


void main(void)
{
ANSEL = 0;
ANSELH = 0;
TRISA = 0;
TRISB = 0;
TRISC = 0;
PORTA = 0;
PORTB = 0;
PORTC = 0;

LCDInit();

LCDMakeChar( 0, data[0] );
LCDMakeChar( 1, data[1] );
LCDMakeChar( 2, data[2] );
LCDMakeChar( 3, data[3] );
LCDMakeChar( 4, data[4] );
LCDMakeChar( 5, data[5] );
LCDMakeChar( 6, data[6] );
LCDMakeChar( 7, data[7] );

LCDGotoxy(0,0);

LCDPutc(0);
LCDPutc(1);
LCDPutc(2);
LCDPutc(3);
LCDPutc(4);
LCDPutc(5);
LCDPutc(6);
LCDPutc(7);

LCDGotoxy(2,1);

LCDPuts("Hello World");

LCDGotoxy(6,1);

aux = LCDGetc();

LCDGotoxy(15,1);

LCDPutc(aux);




while(1);
}
#include <htc.h>

---------------------------------------------------------------------------------------------------------

Agora gostaria de saber um pouco do felipe_eletronic, nao entendi direito a organização que tu tinha proposto com as pastas e .c e .h, tirei uma SS do meu workspace para que possas entender como eu trabalho. Tentei adicionar o código no Source Files e deu erro.

exemplo_workspace.png

Link para o comentário
Compartilhar em outros sites

  • 2 meses depois...

Oi edu. Parabéns à iniciativa.

Eu estou ainda inicando na mundo dos uCs da Microchip e decidi por usar a dupla Mplab X + SDCC e também estou construindo os meus drivers. Atualmente estou criando o do lcd e vou me base basear no seu código.

Uma grande dúvida eu tenho quanto ao uso do pino "RW" de um lcd, já que ainda não precisei dele.

Se eu decidir por utilizar o pino "RW" junto a um teclado PS2, eu poderia realizar operações tipicas de um editor de textos, bem como selecionar o texto do lcd e dar um "CTRL+ C" e "CTRL+ V", ler esses dados do lcd e só então enviar esses dados para a EEPROM? Ou seria mesmo melhor realizar tal ato apenas usando as variáveis de memória?

Desde já lhe agradeço.

Link para o comentário
Compartilhar em outros sites

  • 2 semanas depois...

Passei a utilizar o XC8 (Me parece que é a evolução do Hi-Tech ou C18 com suporte à família Mid-Range da Microchip) em vez do SDCC por ter uma documentação mais clara e prática de utilização e estou utilizando o "Driver-fonte" disposto por Edu e o estou modificando para o meu próprio uso, mas sempre sendo grato ao seu autor, claro.

Futuramente retornarei ao SDCC para comparações, visto que muitos usuários dizem que ele produz resultados mais enxutos e otimizados, além de esperar uma maior maturidade da SDCC-Toolchain que ainda está cheia de mini-bugues, bem como não permitir o uso de PICS que contenham um "a" como sufixo (Se bem que eu mesmo achei tal problema e vi como resolvê-lo, mas não essa sua unica falha).

Ainda tenho dúvidas quanto às funções postas ao final do código do LCD e acharia também interessante que o Edu dispusesse de um código com alguns exemplos de uso, como exemplo realizar um scroll.

A minha dúvida acima era mesmo quanto ao uso com um teclado PS2, pois quero criar uma biblioteca para utilização do teclado PS2 junto ao PIC e LCD que funcione como num computador, implementando assim, funções como Control+C, V e X, o uso do teclado numérico da direita do teclado, pois já vi rotinas que não permitiam isso.

Link para o comentário
Compartilhar em outros sites

O uso do teclado PS2 requer estudo do protocolo PS2.

Sua dúvida está relacionada ao protocolo.

Se eu decidir por utilizar o pino "RW" junto a um teclado PS2, eu poderia realizar operações tipicas de um editor de textos, bem como selecionar o texto do lcd e dar um "CTRL+ C" e "CTRL+ V", ler esses dados do lcd e só então enviar esses dados para a EEPROM? Ou seria mesmo melhor realizar tal ato apenas usando as variáveis de memória

Essa opção de 'copiar/colar',é implementada pela OS(Windows,Linux etc),não tem qualquer ligação com o mundo dos microcontroladores.

voce tem que implementar(programar) essas rotinas que não dependem de bibliotecas.

Link para o comentário
Compartilhar em outros sites

Sim, já estou estudando o protocolo dele. Sei que o clock é controlado pelo próprio teclado e que são 11 bits neste protocolo sendo o 1º bit de ativação seguido de 1 byte de dados, 1 bit de paridade terminando com 1 bit de stop.

Baseado nisto, estou a desenvolver esta biblioteca e vou utilizá-la num projeto meu com lcd e gravação na EEPROM.

Link para o comentário
Compartilhar em outros sites

A parte que citou,é a parte 'elétrica',mas me refiro ao protocolo.

No protocolo existem bytes de comando e controle que seguem um padrão de inicialização.

voce deve estar planejando conectar um teclado PS2 a um Pic para enviar comandos ou letras quaiquer para serem mostrada num lCD,é isso?

Link para o comentário
Compartilhar em outros sites

A minha intenção, primariamente, será a de rotular 8 ou 16 entradas de um PIC e guardar essas informações numa eeprom além de usar o teclado para outras coisas também.

Sei sim que deverei implementar cada função que eu necessitar, como as funções de selecionar o texto, alterar o estado do cursor no LCD, copiar para a ram do microcontrolador e fazer o que eu quiser com esse dado depositado na ram. Isso tudo é trabalho para o programador fazer, pois o teclado só me enviará a informação das teclas que estão sendo apertadas.

Quanto ao protocolo, estou estudando alguns documentos tratando disso e já elaborando algo no MPlabX e em breve ou retorno ou crio um tópico tratando de tal assunto. Desde já, agradeço à atenção.

Adicionado em 2012/06/26

Quanto à biblioteca ps/2-Keyboard, estarei, em breve, abrindo um novo tópico a respeito afim de não bagunçar o tópico criado por nosso querido camarada.

Link para o comentário
Compartilhar em outros sites

  • 2 semanas depois...

Boa tarde hamdam.

Tanto o Hitech-C quanto o XC8, que são da Microchip, têm suas versões Free que nada mais são que um compilador completo, mas que na versão Free não possuem otimizações.

Podes usar a vontade tanto o Hitech-C quanto o XC8 que são, sim, Free, mas sem otimizações.

Link para o comentário
Compartilhar em outros sites

se eu quiser programar outro tipo de uC, qual o compilador que posso usar?

Pelo que entendi o hi-tech é a autentica linguagem C certo? o que eu uso aqui é meio estranho, nao é case sensitive tem algum que segue o padrão c de programação de pc?

Link para o comentário
Compartilhar em outros sites

Oi hamdan, sobre o caso do case sensitive, em algumas IDES pode-se optar por usar ou não isso, como é o caso do MPLABX & XC8.

Para outros µCs, outras IDEs & Compiladores deverão ser utilizadas, pois a Microchip® só produz suas IDEs para os seus próprios produtos, assim como é o caso dos 8051, AVRs & CIA, da NXP, Motorola, Phillips, e etc. O melhor local para se procurar pelos programas adequados ao seu µC é no próprio site do fabricante e conforme sua experiência com aquele µC vai aumentando, vai também conhecendo outros compiladores adequados ao su uso.

Diferenças entre IDE & Compilador:

IDE: Integrated Development Environment o que significa que é a Interface de desenvolvimento que reúne numa só interface todas as ferramentas que necessitas para se trabalhar com o programa que estais desenvolvendo, como estamos tratando de uma IDE para µCs, então esta IDE é capaz de gerar programas para µCs na linguagem que escolheres. É ele quem controla se queres o uso de "case sensitive" ou não.

Linguagem: É a sua comunicação com o compilador que se comunica com o µC. Na verdade, um microcontrolador da Microchip recebe a sua programação em números binários num arquivo ".hex". A maioria absoluta é assim.

Compilador: É ele quem irá gerar o programa para o seu µC e gerar o arquivo .hex.

Então: Você usa uma IDE para gerar um Programa na Linguagem do seu Compilador que gerará seu precioso Hex.

Link para o comentário
Compartilhar em outros sites

Bom dia, não havia reparado que havia respostas neste tópico, desculpem.

Com relação ao caso do ricardo, o pino RW seleciona se a operação a ser realizada será de leitura ou escrita, como na maioria dos casos não é necessário ler o que está escrito no LCD esse pino é ligado ao GND de modo que sempre sejam feitas operações de escrita. Se você deseja ler e escrever o conteúdo do LCD deve controlar esse pino para ter ambas as operações liberadas.

As funções de copiar e colar são implementações do sistema operacional, que combinam o uso do teclado, mouse e monitor (que são a interface do computador) para interagir com o operador. Caso você deseje utilizar funções semelhantes deve desenvolver a própria interface utilizando o teclado referido e o LCD.

Link para o comentário
Compartilhar em outros sites

Oi Edu, tá tudo certo, depois você nos paga uma bebida, refigerante pra mim, de preferência.

A função deste pino RW não é muito usada e muitos preferem usar delays em vez do aviso dessas portas, assim se economiza mais um pininho do µC, aliás, também acho mais interessante que em vez de se ler os pinos de dados só pra ver qual é o caractere sob o cursor, que se faça isso usando a própria RAM do µC.

Vai aí uma contribuiçãozinha de um código para expansão das portas do PIC usando-se um Shift-Register 74595.


/*
* File: main.c
* Author: Ricardo da Silva Pimentel
*
* Created on 28 de Junho de 2012
* Este é o desenvolvimento do driver para se trabalhar com Shift-Refisters
* tanto de entrada como de saída.
*
* Como um shift-register funciona:
*
* Basicamente, há quatro tipos de Shift-Register:
* •SIPO: Serial Input / Parallel Output. Possui entrada serial e saída paralela
* •PISO: Parallel Input / Serial Output. Possui entrada paralela e saída serial
* •SISO: Serial Input / Serial OUtput. Possui entrada serial e saída serial
* •PIPO: Parallel Input / Parallel Output. Poussui entrada Paralela e saída paralela
*
* No caso deste código, construirei um driver para uso de Shift-Registers tipo
* SIPO para saída, pois converte dados seriais para a saída paralela e PISO para
* entrada, pois converte dados em paralelo em sua entrada para uma saída serial.
*
* O funcionamento desses dois tipos é bastante similar e primeiro tratarei do
* funcionamento de um 74595, que é um SIPO.
*
* Um S.R. trabalha na base do empurrãozinho assim houver um pulso de clock.
* Assim que ele recebe o primeiro bit 1, a cada pulso que o clock der esse
* bit 1 passará por cada uma das portas de saída até que não haja mais pulsos
* de clock e ainda se nao houver mais portas disponíveis para o uso desse
* bit 1, então ele sairá pela porta Saída Serial e irá ao próximo S.R..
*
* Há a possibilidade de duas formas de se enviar dados à sua saída paralela
* sendo uma destrutiva e a outra não destrutiva.
*
* A destrutiva consiste em passar esse bit 1 por todas as portas e alterando
* o estado da porta pela qual ele passará até que não haja mais pulsos, já a
* Não Destrutiva desloca esse bit por trás das portas até que o byte esteja
* completo e então, assim que o pino RW é então posto em estado HIGH, esse
* byte é passado para as saídas alterando assim seus estados.
*
* Resumo: O byte entra pela porta "Serial-In" e a cada pulsar no pino "Clock"
* do estado baixo para o alto, um bit desse byte entra no S.R., e assim que o
* byte estiver completo, passamos então o pino RW para o estado alto e então
* esse byte aparecerá em sua saída paralela.
*
* A pinagem do 74HCT595:
* Q1 - 1 - Saída 1 de dados em paralelo.
* ... ... ...
* Q7 - 7 - Saída 2 de dados em paralelo.
* GND - 8 - Negativo, grade, 0 V.
* Q7S - 9 - Saída serial de dados. Envia o restante dos dados para
* o próx. Shift Register.
* MR - 10- Master Reset. Manter em estado alto, se colocado em estado alto
* reiniciará, então, o estado de todas as portas de saída.
* SHCP - 11- Shift Register, entrada de Clock.
* Cada pulso, do baixo para alto, incrementa 1 bit, 0 ou 1.
* STCP - 12- Armazenamento dos bits, Latch. Os dados entrantes pelo pino
* "DS" e incrementados pelo pino Clock (SHCP) ficarão guardados
* na memória até que este pino seja posto em estado alto.
* OE - 13- Ativar saídas. Sua função é a de ativar ou desativar as saídas,
* o que o diferencia da função latch é que ele desliga as saídas
* Q0 a Q7 como uma chave liga desliga, mas não perde os dados nas
* saídas nem as altera ou ativa.
* DS - 14- Entra de dados serial. Por aqui é que os bits e bytes entram,
* enquanto esta porta estiver alta, conforme houver pulsos
* de clock, bits '1' esta´rão entrando e se "DS" estiver em
* estado baixo, entrarão bits '0'.
* Q0 - 15- Saída 0 de dados em paralelo.
* VCC - 16- Positivo da alimentação. Até 7 V.
*
* Um exemplo prático e direto do funcionamento do 74HC595, basta por no
* 'main' e setar 1 ou 0 em SR_Dados e cada saída correspondente.
*
* //Saída Q7
* SR_Dados =0; SR_Clock =0; SR_Clock =1;
*
* //Saída Q6
* SR_Dados =0; SR_Clock =0; SR_Clock =1;
*
* //Saída Q5
* SR_Dados =0; SR_Clock =0; SR_Clock =1;
*
* //Saída Q4
* SR_Dados =0; SR_Clock =0; SR_Clock =1;
*
* //Saída Q3
* SR_Dados =0; SR_Clock =0; SR_Clock =1;
*
* //Saída Q2
* SR_Dados =0; SR_Clock =0; SR_Clock =1;
*
* //Saída Q1
* SR_Dados =0; SR_Clock =0; SR_Clock =1;
*
* //Saída Q0
* SR_Dados =1; SR_Clock =0; SR_Clock =1;
*
* //Ativa o byte enviado às saídas
* SR_Latch =1; SR_Latch =0;
*/
/** Configurações ─────────────────────────────────── */
__CONFIG (FOSC_INTOSCIO & //•Habilita oscilador interno com liberação das portas A6 e A7 para I/O.
WDTE_OFF & //•Desabilita WATCH-TIMER-DOG;
// PWRTE_OFF & //•Desabilita RESET interno. Usar com RESET externo;
PWRTE_ON & //•Habilita RESET interno. O PIC se ativará 72 ms após alimentação positiva no pino MCLR.
MCLRE_ON & //•Liga o RESET externo;
BOREN_OFF & //•Desativa a função de RESET se alimentação cair por mais de 100 µS.
LVP_OFF & //•RB4/PGM pin has digital I/O function, HV on MCLR must be used for programming;
CPD_OFF & //•Data memory code protection off;
CP_OFF //•Desliga a proteção da região "0000h a 0FFFh" do código;
);

#define _XTAL_FREQ 4000000

#define SR_Clock PORTBbits.RB2
#define SR_Latch PORTBbits.RB0
#define SR_Dados PORTBbits.RB1
#define Tempo 500

void Inicializacao (void) ;
void SR_Saida (unsigned char Byte);

void Inicializacao (void) {
/* Info sobre PORTs e TRISs */
/*TRIS 76543210
* 0b00000000 - Saída
* 0b11111111 - Entrada
*PORT 76543210
* 0b00000000 - Desligado
* 0b11111111 - Ligado */

TRISA = 0b00100000; //
TRISB = 0b00001000; //TRIS → Configura as portas como saídas ou entradas
PORTA = 0; //PORT → Define o estado inicial das portas
PORTB = 0; //PORT → Define o estado inicial das portas

CMCON = 0x07; //desabilita os comparadores internos
}

void SR_Saida (unsigned char Byte) {
/* Relação de Saídas X Byte
* Saídas |Q7|Q6|Q5|Q4|Q3|Q2|Q1|Q0|
* Byte ↓ ↓ ↓ ↓ ↓ ↓ ↓ ↓
* 0b 0 0 0 0 0 0 0 0
* || || ||
* LSB MSB
*/
SR_Dados = 0; //Garante que o pino DS esteja em nível baixo.
SR_Latch = 0; //Garante que o pino Latch esteja em nível baixo.
SR_Clock = 0; //Garante que o pino Clock esteja em alta.
unsigned char v = 0;
for (signed char i = 7; i >= 0; i --) {
v = Byte >> i;
if (v & 1)
SR_Dados = 1;
else
SR_Dados = 0;
NOP (); SR_Clock = 1;
NOP (); SR_Clock = 0;
}//For(ii, fim.
NOP (); SR_Latch = 1; //Dá o Latch nas saídas do SR e ativa o byte enviado.
}//ShiftRegister(), fim.

void main (void) {
Inicializacao ();
while (1) {

char k = 0x80;//0x80=0b00000001
SR_Saida (k);
__delay_ms (Tempo);
char k = 0x1;//0x1=0b10000000
SR_Saida (k);
__delay_ms (Tempo);

}//Fim while(1)
}//Fim void main


Link para o comentário
Compartilhar em outros sites

  • 4 semanas depois...

Ola Edu, talvez este nao seja o lugar ideal para postar, mas estou iniciando neste forum e na programação de PIC (Começando com o 12F629). Meu problema é achar um manual compativel(correto) para o compilador Hi-tech V9.83.

Vi sua brilhante colaboração de bibliotecas e vi que se não fosse alguns comandos que estavam la como __CONFIG, eu não tinha conseguido fazer o LED piscar. Isto tudo porque o manual do compilador que vem junto com a instalacao do compilador baixado do site da microship nao condiz com a programação, ou seja os comandos, instruções sao um pouco diferente tipo com exemplo:

__CONFIG(WDTDIS) //não funciona e é o que o manual diz para fazer.

__CONFIG(WDTE_OFF) //funciona e é o que peguei do seu exemplo.

Gostaria que voce me enviasse o link ou o manual que voce está utilizando.

Link para o comentário
Compartilhar em outros sites

Visitante
Este tópico está impedido de receber novas respostas.

Sobre o Clube do Hardware

No ar desde 1996, o Clube do Hardware é uma das maiores, mais antigas e mais respeitadas comunidades sobre tecnologia do Brasil. Leia mais

Direitos autorais

Não permitimos a cópia ou reprodução do conteúdo do nosso site, fórum, newsletters e redes sociais, mesmo citando-se a fonte. Leia mais

×
×
  • Criar novo...

Ebook grátis: Aprenda a ler resistores e capacitores!

EBOOK GRÁTIS!

CLIQUE AQUI E BAIXE AGORA MESMO!