You are on page 1of 33

MICROCONTROLADORES PIC PROGRAMAO EM LINGUAGEM C

HANDS ON!

O QUE UM MICROCONTROLADOR?
O microcontrolador PIC um componente eletrnico fabricado pela MICROCHIP, capaz de ser programado para realizar operaes lgicas e aritmticas, interagindo com

perifricos (leds, botes, sensores ou at outro PIC). Deste fato vem o nome PIC (Peripheral Integrated Controller, ou controlador integrado de perifricos). Um microcontrolador (uC), diferentemente de um microprocessador, possue memria voltil (RAM) e no voltil (EEPROM), alm de outros perifricos internos, o que o torna bastante til. Este capaz de operar independente de memrias externas, alm de poder ser programado em linguagem de alto nvel, como a linguagem C.

ESTRUTURA BSICA DO PIC


Nesta apostila sero abordados os modelos PIC16F628A, e PIC16F876A, pois estes esto inclusos em uma boa gama de possveis solues. Apesar da estrutura aqui mencionada tratar destes especficos modelos, esta descreve a grande parte dos microcontroladores. MEMRIA FLASH- a memria em que ser guardado o programa propriamente dito, no formato de linguagem de mquina. Foi desenvolvida na dcada de 80 pela Toshiba e do tipo EEPROM, porm se assemelha com a RAM, permitindo que mltiplos endereos sejam apagados ou escritos em uma s operao. MEMRIA SRAM- Static RAM, significa que no precisa ser periodicamente atualizada como as RAMs comuns, que sem atualizao perdem seus dados. a memria voltil, rapidamente acessada, e que apagada toda vez que a alimentao se ausenta. Local onde so armazenadas as variveis declaradas no programa. MEMRIA EEPROM- a memria no voltil, que mantm os dados escritos independente da alimentao do PIC. acessada quando se deseja armazenar dados por perodos indeterminados, como a senha de um usurio. CPU (Central Processing Unit)- um conjunto composto por: PC: (Program Counter) Seleciona na FLASH o corrente comando a ser executado. WREGs: (Work Registeres) Registradores especias de trabalho. So acessados constantemente e servem para realizar operaes de movimentao e tem acesso direto ULA.

ULA: Unidade Lgica e Aritmtica do uC (microcontrolador), responsvel pelas operaes lgicas e aritimticas dos WREGs. FUSVEIS: Perifricos especiais responsveis pelo pleno funcionamento do sistema. Garantem que o programa no trave e que o uC no opere sob tenses abaixo ou acima do permitido. PERIFRICOS: Circuitos auxiliares que livram o programa de realizar trabalhos especfios. Funcionam de forma paralela ao programa do usurio (na FLASH), ocupando o cdigo apenas para ser configurado ou entregar o resultado de algum servio. Os perifricos abordados nesse documento so: GPIO (General Purpose Input/Output): Usados para entradas digitais, como um boto ou uma chave, e sadas digitais, como um LED ou um motor DC. O programa usurio pode setar uma sada, colocando um pino externo do PIC em nvel lgico 0(0V) ou 1(5V). ADC (Analog to Digital Converter): Usado para recolher sinais analgicos externos e transorm-los em digitais, para ento serem processados pelo programa. USART (Universal Synchronous and Asynchronous Receiver-Transmitter): Perifrico responsvel por enviar e receber dados atravs do protocolo RS-232. TIMERS: Temporizadores de uso geral. Garantem preciso de tempo entre eventos.

Figura 1 Estrutura interna bsica

HARDWARE

Para o pleno funcionamento do uC necessrio que: Ele esteja corretamente alimentado, com seu pino Vdd ligado em 2,2 5,5V e seu pino Vss ligado ao GND. (Os exemplos deste documento usam a tenso de alimentao de 5V). recomendado que um capacitor de 100nF (de cermica com o rtulo 104) seja posto na alimentao, prximo aos terminais do uC, pois este funciona como um filtro contra rudos gerais. O pino MCLR (Masterclear) esteja em 5V. Ao ir para 0V este pino provoca um reset externo do PIC. Os pinos OSC1 e OSC2 estejam ligados no oscilador externo, que nos exemplos ser um cristal de quartzo de 4MHz. Deve-se ressaltar que a frequncia interna (chamada de Fcy) do uC vale da frequncia usada como fonte de relgio ( Fosc). Para uma correta gerao de clock externo, recomendo o uso de dois capacitores de desacoplamento nos terminais do cristal, no valor de 22pF.

O uC PIC16F628A tem o benefco de poder usar um clock interno de 4MHz, alm de no precisar do MCRL. Isso permite que os trs pinos correspondentes sejam usados como GPIO. Esta ser a configurao usada para este uC nos nossos exemplos.

Figura 2 Hardware bsico: PIC16F628A

Figura 3 Hardware bsico: PIC16F876A

SOFTWARE
5

Como ambiente de desenvolvimento, ser usado o compilador PCWH da CCS. Este constitudo de um IDE grfico que pode ser executado em qualquer plataforma Windows. O compilador, como o prprio nome j diz, tem o papel de compilar o cdigo em linguagem C para a linguagem de mquina, a qual est pronta para ser gravada na memria FLASH do uC. Deve-se ressaltar que este compilador case insensitive, ou seja, no diferencia letras mausculas de minsculas. Portanto, se forem declaradas as variveis Temper_Atual e temper_atual, o compilador acusar erro, pois visto como ambiguidade. Os programas embarcados seguem, como os outros tpicos j vistos, uma estrutura bsica. Quando o dispositivo ligado o programa inicia sua execuo numa fase chamada de inicializao. Nessa fase feita toda a configurao do sistema: Quais pinos sero entradas ou sadas. Quais perifricos sero utilizados e como sero utilizados. Declarao das variveis usadas pela funo main. Chamadas de funes (ou comandos) que devem ser executados apenas no incio do processo. Deve ficar claro que o cdigo pertencente a essa fase executado apenas uma vez, sendo executado novamente apenas se o uC for reiniciado. A partir disto o uC est pronto para iniciar sua fase de trabalho propriamente dito. Essa fase recebe o nome de loop infinito, pois onde o programa deve permanecer enquanto o dispositivo estiver energizado. Basicamente, as aes sequencias nesse lao so: Leitura das entradas. Processamento dos dados. Atualizao das sadas.

Figura 4 Fluxo bsico de um programa embarcado

Pode-se adotar como softwares iniciais:


//--Programa Esqueleto-----// #include <16F628A.h> #fuses INTRC_IO, NOMCLR #use delay(clock=4000000) #use fast_io(a) #use fast_io(b) void main(void){ set_tris_a(0b11111111); set_tris_b(0xff); while(true){ } } //-------------------------// } //--Programa Esqueleto-----// #include <16F876A.h> #fuses XT #use delay(clock=4000000) #use fast_io(a) #use fast_io(b) #use fast_io(c) void main(void){ set_tris_a(0b11111111); set_tris_b(0xff); set_tris_c(0xff); while(true){ }

//---------------------//

Explanao:
#include <16FXXXA.h>

Biblioteca que ser utilizada para o compilador gerar o cdigo especfico para o dispositivo utilizado.
#fuses INTRC_IO, NOMCLR, XT

Fusveis configurados. INTRC_IO significa que ser utilizado como fonte de relgio o oscilador interno, que de 4 MHz. NOMLCR habilita o pino 4 do 16F628 para ser usado como GPIO. XT indica que a fonte de relgio um cristal externo de frequncia <= 4MHz. No sero abordados todos os fusveis, porm estes podem ser vistos no CCS em View -> Valid Fuses.
#use delay(clock=4000000)

Comando que fornece a base de tempo para as rotinas de delay usadas no programa, que sero vistas mais adiante.
#use fast_io(a) //(b ou c)

Configura todos os pinos como GPIO (General purpose In/Out). Cada pino do uC pode ser configurado com diferentes propsitos, o que pode ser visto nas Figuras 2 e 3. Por omisso, diremos que todos os pinos sero GPIO. Assim, se quisermos outra funo para algum deles, indicaremos adiante, atualizando o seu propsito. Os canais GPIO no PIC seguem um padro: cada um deve estar associado a um byte e a um bit. Os bytes so nomeados por vogais e so chamados pelo datasheet de PORT, como PORTA, PORTB, PORTC, etc. Os bits so mapeados por nmeros, assim, podemos observar nas Figuras 2 e 3 que o canal A3 (apresentado como RA3) est no pino 2 do 16F628, e no pino 5 do16F876. Como cada PORT um byte, cada um tem 8 canais. Por exemplo, o PORTA vai de A0 at A7, e este ltimo identificado pelo programa do usurio como pin_a7. O PIC16F628 contm as portas A e B, enquanto o PIC16F876 tem as portas A, B e C. Porm, nem todos os canais endereveis em teoria esto disponveis nos pinos externos.
void main(void){

Funo principal de qualquer programa em C. onde realmente comea o programa que ser embarcado. Os comandos mencionados anteriormente so chamados de diretivas do compilador, ou seja, so usados pelo compilador mas no sero executados pelo PIC. O compilador utiliza esses comandos para configurar registradores especiais no momento da gravao. Portanto, se voc escreveu #fuses XT, o registrador responsvel por indicar a fonte de relgio ser configurado no momento do download, e no na inicializao.
set_tris_a(0b11111111);

Primeiro comando do programa (para este exemplo). Essa funo configura os canais GIPO como entrada ou sada. 1 significa IN e 0 OUT, o que facilita a memorizao pela semelhana: 1->In e 0->Out. O prefixo 0b indica que o nmero adiante est representado em binrio. Para representar um nmero em hexadecimal, o prefixo usado 0x, portanto essa funo pode ser escrita: set_tris_a (0xff);. Se um nmero no tiver nenhum prefixo, este ser interpretado pelo compilador como no formato decimal, que nossa forma natural. Podemos dizer ento que essa funo tambm pode ser escrita na forma: set_tris_a (255);, que surtir o mesmo efeito. Convm escrever tal funo em binrio pela melhor visualizao dos canais, que esto dispostos em ordem decrescente. Portanto, se o primeiro pino do 16F628 for usado para acender um LED, deve-se configurar o canal A2 como sada, escrevendo: set_tris_a (0b11111011);. Recomenda-se que todos os canais que no sero utilizados sejam configurados como entrada, pois estaro em alta-impedncia, admitindo qualquer valor. Quanto mais pinos so configurados como sada, maior a probabilidade do usurio acidentalmente toc-los ao manusear o protoboard, e isso pode ocasionar a queima do dispositivo.
while(true){

Equivale a escrever while(1==1){ ou while(1){. Esse o tal loop infinito, onde o programa permanecer indefinidamente. dentro desse while que o programador deve construir a fase de trabalho do uC.

1 EXEMPLO: Hello World!


//-------- Pisca LED -------#include <16F628A.h> #fuses INTRC_IO, NOMCLR #use delay(clock=4000000) } #use fast_io(a) #use fast_io(b) void main(void){ short flag=0; set_tris_a(0b11111110); set_tris_b(0xff); //-------------------------// //-------- Pisca LED -------#include <16F876A.h> #fuses XT #use delay(clock=4000000) while(true){ output_bit(pin_a0,flag); delay_ms(500); flag=!flag; }

#use fast_io(a) #use fast_io(b) #use fast_io(c) void main(void){ set_tris_a(0b11111110); set_tris_b(0xff); set_tris_c(0xff);

while(true){ output_high(pin_a0); delay_ms(500); output_low(pin_a0); delay_ms(500); } } //-------------------------//

Explanao:
short flag=0;

Declarao e inicializao da varivel de 1 bit chamada flag. Tambm pode ser escrito nas formas: boolean flag=0; ou int1 flag=0;
output_high(pin_a0); output_low(pin_a0);

Coloca o pino mencionado em nvel lgico 1 (5V). Coloca o pino mencionado em nvel lgico 0 (0V).
output_bit(pin_a0, flag);

Coloca o pino mencionado no nvel lgico correspondente ao valor corrente da flag.


delay_ms(500);

O programa literalmente pra durante o valor de tempo informado (em milisegundos). O prprio compilador gera o cdigo responsvel por esta ao, atravs de contadores, os quais se baseiam em #use delay(clock=4000000).
flag=!flag;

Realiza o complemento de um da varivel flag. O smbolo ! corresponde operao lgica NOT. Os pinos configurados como entrada drenam uma corrente extremamente pequena, na ordem de picoampres, pois so colocados em alta-impedncia. Assim, podemos consider-la desprezvel. Os pinos definidos como sada no podem receber sinal externo (corrente), pois, como j dito anteriormente, isso certamente causar o falecimento do uC. Estes dois dispositivos abordados podem fornecer at 25mA por pino de sada. Portanto, se a carga utilizada drenar mais do que esse valor, deve ser utilizado um driver, como um transistor.

10

Figura 5 Exemplo 1: hardware 16F876

Figura 6 Exemplo 1: hardware 16F628

Compilao do programa: Inicialmente abra o compilador PICC (PCWHD), clique no smbolo de pastas (primeiro acima), e em seguida
11

Close All. Agora, para criar um novo projeto, clique novamente no smbolo de pastas, e aps isso em New -> Source File. Escolha o diretrio onde ficar salvo este primeiro programa e o nomeie de exemplo1. Digite o cdigo de exemplo para o uC escolhido e em seguida compile o programa em Compile -> Compile, ou atravs da tecla de atalho F9. Neste processo o compilador gera 5 arquivos de sada, porm ser utilizado apenas o exemplo1.hex, que o cdigo que ser transferido para a memria FLASH do uC. Gravao do programa: Coloque o uC escolhido no protoboard e, antes de colocar os outros componentes (capacitor, etc.), insira apenas os jumpers relativos ao ICSP (In Circuit Serial Programming). Plugue agora o cabo do ICSP no protoboard e no gravador PICKit2, e plugue o cabo USB do gravador no PC. Feito isso, abra o software PICKit2. Se o procedimento dito foi feito corretamente, deve aparecer uma mensagem confirmando a deteco do dispositivo. Se isso no ocorreu, confira se houve alguma falha no dito procedimento (ordem dos jumpers, mau contato, etc.), e ento clique em Tools -> Check Communication. No se deve continuar a partir deste ponto at que o uC no tenha sido detectado. Antes de transferir o cdigo, desabilite a funo Tools -> Fast Programming, pois esse modo est bem mais susceptvel a falhas de transferncia, alm de ser pequena diferena em relao ao modo normal. Para verificar se o cdigo foi transferido corretamente, habilite a funo Programmer -> Verify on Write. Feito tudo, clique em File -> Import Hex. Escolha o exemplo1.hex que foi gerado na compilao e, depois de importado o arquivo, clique finalmente em Write para realizar a transferncia do cdigo para o uC. Confirmado o sucesso do download, desconecte o plugue ICSP do protoboard, insira os componentes necessrios e energize o circuito. Se tudo deu certo, o LED piscar a cada 1 segundo. Os componentes no precisam ser retirados para realizar um novo download. Porm, recomendado que sempre se inicie a construo de um hardware pelos jumpers do ICSP, pois na ocorrncia de uma falha (muito

12

comum) deve-se reduzir o hardware para encontrar o defeito. Outra maneira de realizar o download pelo boto no PICKit2 (hardware). Essa funo habilitada em Programmer -> Write on PICkit Button. Quando tal boto pressionado, o arquivo .hex que est sendo apontado no campo Source do PICKit2 (software) transferido para o uC (devidamente conectado). O mesmo efeito obtido pelo boto Write, eliminando a necessidade de toda vez importar o arquivo a ser transferido. Para testar essa funcionalidade, habilite-a primeiro, depois, se o campo Source estiver apontando para o exemplo1.hex, mude o tempo de delay no programa (compilador) para 100ms e o recompile. V agora para o PICKit2 (software) e, observando a tela, pressione o boto no PICKit2 (hardware). O programa percebe que houve uma alterao e realiza um reloading. Os exemplos seguintes abordaro apenas o PIC16f876A, por questes de total semelhana. Sempre que for escrever um novo programa que possa se basear no atual, copie o texto deste, clique em Close All, depois em New -> Source File. Cole o texto copiado.

2 EXEMPLO: Push-button
/----------------------- push-button ------------------------#include <16F876A.h> #fuses XT #use delay(clock=4000000) #use fast_io(a) #use fast_io(b) #use fast_io(c) void main(void){ set_tris_a(0b11111110); set_tris_b(0xff); set_tris_c(0xff); while(true){ if(input(pin_c4)) output_high(pin_a0); else output_low(pin_a0); }

/---------------------------------------------------------------

Explanao:
input(pin_c4);

13

Realiza a leitura externa do nvel lgico no pino mencionado e a retorna para o programa.

Figura 7 Exemplo 2: hardware 16F876

Em uma entrada utilizada para ler um boto, deve-se usar um resistor ligado ao terra. Sem o resistor (chamado de pull-down), se o boto no estiver pressionado, o nivel lgico na entrada no ser 0, pois este estar alta impedncia. Esse estado pode ser denominado floating (flutuando), onde o sinal no tem um valor fixo, fica variando aleatoriamente em funo de rudos locais. Ateno ao ligar um push-button de 4 terminais no protoboard. Dois de seus terminais esto conectados aos outros dois. Portanto, se um dos terminais foi ligado 5V, o outro terminal conectado esse tambm estar em 5V, inviabilizando o uso do seu ramo no protoboard.

3 EXEMPLO: INTERRUO EXTERNA


Podemos engatilhar uma rotina especfica dentro do nosso microcontrolador a partir de sinais externos ou mesmo eventos internos do microcontrolador. Neste exemplo trabalheremos com interrupes externas, que em resumo a execuo de determinada rotina quando houver uma mudana de estado em um pino pr-determinado, sendo esta uma forma mais eficiente de controlar as atividades do microcontrolador por eventos externos, j que desta forma
14

no h perda de tempo ao se realizar a leitura do estado do pino a cada ciclo de trabalho . O hardware que utilizaremos a seguir o mesmo do exemplo anterior ( push-button), exceto pelo fato que o boto deve estar conectado ao pino responsvel por chamar interrupes externas , no caso do PIC16F876A o pino rb0.
//--------INTERRUPO EXTERNA---------------------------------------#include <16F628A.h> #fuses INTRC_IO, NOMCLR #use delay(clock=4000000) #use fast_io(a) #use fast_io(b) short int cont = 0; void main(void){ cont=0; set_tris_a(0xff); set_tris_b(0b11111011); ext_int_edge(L_TO_H); enable_interrupts(GLOBAL); enable_interrupts(INT_RB); while(true){ sleep(); }} #INT_RB Void piscaled_int_ext(void) { if(input(pin_b0)) { delay_ms(20); if(input(pin_b0)) { output_bit(pin_a0,cont); if(cont==0) cont=1; else cont=0; }}}

//--------INTERRUPO EXTERNA----------------------------------------

Explanao:
ext_int_edge(L_TO_H);

Esta funo define que o microcontrolador entrar em interrupo quando o pino de interrupo externa em questo passar do estado 0 para 1( low to high).
enable_interrupts(GLOBAL);

Funo responsvel por habilitar qualquer tipo de interrupo que microcontrolador tenha, deve ser usada antes de habilitar qualquer interrupo especificamente.
enable_interrupts(INT_RB);

Especifica a interrupo que ser usada, no caso interrupo externa por alterao de estado nos pinos RB que so responsveis pelas interrupes externas.

4 EXEMPLO: Display LCD 2x16


//----------------------------- LCD ------------------------------------#include <16F876A.h> #fuses XT #use delay(clock=4000000)

15

#use fast_io(a) #use fast_io(b) #use fast_io(c) #include <lcdt.c> #define lig output_high #define des output_low #define seta output_bit #define esp delay_ms #define led pin_a0 #define bot pin_c4 #define bl pin_c7 void main(void){ unsigned int i; set_tris_a(0b11111110); set_tris_c(0b01111111); lcd_init(); printf(lcd_putc,"\fCurso de uC PIC "); printf(lcd_putc,"\nPET-EngElet.Ufes);

lig(bl); des(led); for(i=0;i<6;i++){ seta(led,!input(led)); esp(400); } while(true){ if(input(bot)){ printf(lcd_putc,"\f Feliz"); printf(lcd_putc,"\n :)"); lig(led); lig(bl); }else{ printf(lcd_putc,"\f Triste"); printf(lcd_putc,"\n :("); des(led); des(bl); } esp(200); }

//------------------------------------------------------------//

Explanao:
#include <lcdt.c>

Incluso da biblioteca do LCD. Esse arquivo deve estar na mesma pasta onde ser salvo o programa que a utiliza.
#define lig output_high

Amarrao entre duas entidades. Serve para aumentar a legibilidade do cdigo. O compilador substitui a parte esquerda pela direita no momento da compilao do programa.
unsigned int i;

Declarao da varivel de 8 bits e sem sinal (0 255) chamada i.


lcd_init();

Inicializao da biblioteca do LCD. Essa funo configura os pinos da porta B (menos o B0, que pode ser configurado na main()), e prepara o LCD para iniciar sua operao.
printf(lcd_putc,"\fCurso de uC PIC ");

Funo de impresso no LCD. Existem comandos especiais: \f -> Limpa a tela toda e pe o cursor na primeira posio (1,1). \n -> Pe o cursor no incio da segunda linha. \b -> Retorna o cursor uma posio. Os caracteres so impressos sempre na posio corrente do cursor, que pode ser alterada pela funo
16

lcd_gotoxy(x,y);. A funo lcd_getc(x,y); retorna o atual caractere que ocupa a posio informada. Como os canais B6 e B7 so utilizados para gravao e comunicao com o LCD, deve-ser usar dois resistores para aumentar a impedncia de entrada dos terminais PGD e PGC do PICKit2. Sem tais resistores, o LCD e o PIC drenam, juntos, muita corrente do gravador, resultando numa distoro do sinal de gravao. O pino 3 do display o sinal V0, que determina o contraste entre a parte escrita e o plano de fundo da tela. O potencimetro deve ser regulado para obter-se uma boa visualizao.

Figura 8 Hardware Display LCD

5 EXEMPLO: Converso A/D


No instante em que o programa usurio requisita ao mdulo um processo de converso A/D, o corrente valor de tenso na entrada especificada convertido em um valor digital, para ento ser manipulado pelo programa. Neste exemplo o uC ser configurado para uma converso de 8 bits, e o range de tenso a ser convertida ser o padro, ou seja, a prpria alimentao do PIC (05V). Portanto, essa faixa ser dividida em 256 partes iguais, e o resultado de uma converso ser o byte correspondente a parte em que se encontra a tenso convertida.

17

Figura 9 Funo de transferncia da converso A/D desse exemplo //------------------------ Voltmetro ----------------------------------#include <16F876A.h> #device adc=8 #fuses XT #use delay(clock=4000000) #use fast_io(a) #use fast_io(b) #use fast_io(c) #include <lcdt.c> #define esp delay_ms void main(void){ unsigned int digital; float tensao; set_tris_a(0b11111111); set_tris_c(0b01111111); setup_adc_ports(ALL_ANALOG); setup_adc(ADC_CLOCK_INTERN AL); set_adc_channel(0);

lcd_init(); printf(lcd_putc,"\f Voltimetro "); printf(lcd_putc,"\nPETEngElet.Ufes"); esp(2000); output_high(pin_c7); while(true){ digital=read_adc(); tensao= 5.0*(float)digital/255.0; printf(lcd_putc,"\fT: %1.2f",tensao); printf(lcd_putc,"\nD: %3u",digital); esp(500); } }

//---------------------------------------------------------------------//

Explanao: O PIC16F628A no tem conversor A/D.


#device adc=8

Configura a resoluo da converso. Pode ser observado na Figura 9 que a variao mnima que essa converso pode reconhecer de aproximadamente 20mV. Isso significa que
18

um sinal de 10mV e outro de 15mV sero convertidos para o mesmo valor (0). Isso pode ser ruim para determinadas aplicaes. Por exemplo, o sensor de temperatura LM35 fornece em sua sada 10mV/C. Uma converso de 8 bits no capaz de perceber a diferena entre 0 e 1 C. Porm, pode-se melhorar a resoluo, utilizando 10 bits. Isso torna o sistema capaz de perceber uma diferena mnima de 5mV (0,5C). No se deve esquecer de utilizar uma varivel do tipo unsigned long int (16 bits), cuja impresso feita pela sintaxe %4lu. Outra forma de melhorar a resoluo diminuir o range do valor a ser convertido. Para isso, so utilizados sinais externos como V REFH e/ou VREFL, os quais podem ser configurados na prxima funo.
setup_adc_ports(ALL_ANALOG);

Configura todas as portas possveis como analgicas. Neste caso, nenhuma delas poder ser utilizada como GPIO. Para ver as possveis configuraes do perifrico ADC, no IDE CCS, clique com o boto direito em #include <16F876A.h> -> Open File at Cursor, e v linha 220. Por omisso (default), sero adotados como VREFH e VREFL os sinais de alimentao, VDD e VSS, respectivamente.
setup_adc(ADC_CLOCK_INTERNAL);

Configura a frequncia de operao (fonte de relgio) do hardware.


setup_adc_channel(0);

Este PIC tem vrios canais analgicos, porm apenas um mdulo de converso. Essa funo indica o canal que ser ligado ao mdulo para o prximo processo. Como este exemplo utiliza apenas um canal, este foi configurado na inicializao e no sofrer alterao. Em uma aplicao que utiliza mltiplos canais, esta funo deve estar no loop infinito, pois ser dinmica. O compilador recomenda que entre a configurao de um canal e a leitura do mesmo deve haver um intervalo de 10s. V no Help do compilador (F1), na aba Index, e digite: setup_adc_channel. Veja o tpico Examples. digital=read_adc(); Realiza a converso A/D do ltimo canal configurado e atribui o resultado do processo varivel digital. Note que no programa deste exemplo o backlight do display ligado aps o comando esp(2000);. Isso implica que, em algumas vezes, o backlight estar aceso durante a apresentao, e nas outras ele estar apagado. Isso se d ao fato de que um canal configurado como sada, se no for
19

atualizado, assumir valores imprevisveis. Essa uma comum fonte de erros, pois sadas podem iniciar-se indevidamente acionadas e provocar prejuzos. Recomenda-se que, logo aps configurar as entras/sadas, se desative todas as sadas.

Figura 10 Hardware ADC

6 EXEMPLO: UART

A UART definida como um perifrico de comunicao utilizado para troca de informaes entre dispositivos digitais. Este mdulo se baseia no protocolo RS-232, o mais popular padro de comunicao assncrona, ou seja, entre dispositivos com fontes de relgio distintas. Por isso, a grande maioria dos uCs possuem este hardware integrado. Apesar de seguirem o mesmo protocolo, um uC e uma porta serial de um PC no podem ser diretamente ligados, pois a representao eltrica dos smbolos (bits 0 e 1) no a mesma. Os uCs utilizam o padro TTL, ou seja, o bit 0 representado como 0V e o bit 1 como 5V (ou a alimentao, caso seja diferente). Uma porta serial, bem como aparelhos industriais, reconhecem o sinal lgico 1 um valor entre -25V e -3V, e o sinal lgico 0 um valor entre 3 e 25V (geralmente usa-se 12V). Essa escolha se d ao fato de aumentar a relao sinal/rudo, permitindo uma maior taxa de transmisso, maior distncia do cabo que conecta os dispositivos, alm de diminuir a TEB (taxa de erro de bit).
20

Para que um uC e um PC possam trocar informaes existe o MAX232, que um conversor de padro eltrico para o RS-232. Este mdulo tambm pode ser nomeado como USART, que significa Universal Synchronous and Asynchronous Receiver-Transmitter. Nessa configurao, alm dos sinais RX e TX, transmitido tambm um sinal de relgio, fornecido por apenas um dos ns envolvidos. Uma comunicao sncrona permite uma taxa de transmisso mais elevada, pois o instante da leitura do sinal bem definido devido referncia do relgio. O exemplo demonstrado aqui abordar a comunicao assncrona. Em um sistema de comunicao RS-232, todos os elementos envolvidos devem ser configuradados com os mesmos parmentros, pois s assim o sucesso da transmisso garantido. Como se os ns da rede falassem a mesma lngua. Os parmetros desse protocolo so: Baud rate: Define a taxa de transmisso e consequentemente o tempo de bit (tbit), que o inverso desse nmero. O valor mais comum 9600 bps, e outros bastante usados so 2400, 4800, 19200 e 115200 bps (bits por segundo). Start bit: um parmetro imutvel, unitrio, tem valor lgico zero e dura 1 tbit, como todos os outros bits transmitidos. Payload: Tamb chamado de carga til, o dado transmitido. Pode assumir de 5 a 9 bits, e seu valor padro 8 bits (1 byte). Parity bit: Bit de paridade. Tem o papel de identificar erros na transmisso e, se presente, fica entre o payload e o stop bit. Pode ser configurado de trs formas: paridade par, paridade mpar ou ausente. Na paridade par, ele inserido de forma a tornar o nmero de 1s no payload+parity bit um valor par. Analogamente funciona a paridade mpar. Dessa forma, se for enviado o caractere a (01100001) e os dispositivos envolvidos foram configurados com paridade par, o bit de paridade assumir valor 1, totalizando quatro nmeros 1s. Se qualquer um dos bits for lido erroneamente (devido rudo), o bit de paridade (que no caso 1) acusar o erro na transmisso, e o dado recebido ser descartado.
21

Existe, no entanto, a probabilidade (mesmo que nfima) de dois bits serem alterados numa mesma transmisso, e assim o mecanismo de paridade no detectar o erro. Stop bit: Pode ser unitrio ou duplo, e tem valor lgico um. No PIC, um canal serial pode ser implementado por hardware, ou seja, a UART, ou por software. Nessa ltima, o programa embarcado integralmente responsvel pela transmisso/recepo dos dados, tornando a CPU indisponvel para realizar qualquer outra tarefa durante esse ato. As duas implementaes surtem o mesmo efeito (externo) e o receptor segue o mesmo algortmo para capturar o dado:

Figura 11 Transmisso de um caractere a (0x61 0b01100001). Oito bits de payload, sem bit de paridade e um stopbit

A O canal constantemente observado. Espera-se o startbit. B A transio negativa indica o incio do startbit. Aguarda-se ento tbit. C O startbit verificado, pois a transio pode ter sido causada por rudo. Se verdadeiro, aguarda-se 1 tbit e o processo continua. Se no, o processo volta ao estado A. D Inicia-se o processo de aquisio. O bit menos significativo (LSB) capturado e aguarda-se 1 tbit para a aquisio do prximo bit. Todos os outros bits do payload so capturados desta mesma forma. E verificado o stopbit, pois existe a chance de rudos terem validado as etapas B e C. Se verdadeiro, o dado recebido finalmente entregue

22

ao programa usurio. Se falso, o dado descartado. Retorna-se ao estado A.

//------------------------------- TX -------------------------------------#include <16F628A.h> #fuses INTRC_IO, NOMCLR #use delay(clock=4000000) #use fast_io(a) #use fast_io(b) #use rs232(baud=9600, rcv=pin_b1, xmit=pin_b2, parity=N) char dado=a; void main(void){ set_tris_a(0xff); set_tris_b(0b11111011); } #INT_EXT void trata_int_ext(void){ putc(dado++); if(dado==f) dado=a; delay_ms(200); } enable_interrupts(GLOBAL); enable_interrupts(INT_EXT); while(true){ sleep(); }

ext_int_edge(L_TO_H); //-----------------------------------------------------------------------// //------------------------------ RX --------------------------------------#include <16f876A.h> #fuses XT #use delay(clock=4000000) #use fast_io(a) #use fast_io(b) #use fast_io(c) #include <lcdt.c> #use rs232(baud=9600, rcv=pin_c7, xmit=pin_c6, parity=N) short flag=1; char dado=k; #INT_RDA void trata_int_rx(void){ 23 dado=getc(); flag=1; } void main(void){ set_tris_a(0xff); set_tris_c(0b10111111); lcd_init(); enable_interrupts(GLOBAL| INT_RDA); printf(lcd_putc,"\fDado: "); while(true){ if(flag){ printf(lcd_putc,"\n %c",dado); flag=0; }

} } //--------------------------------------------------------------------//

Explanao:

#use rs232(baud=9600, rcv=pin_b1, xmit=pin_b2, parity=N)

Definio dos parmetros do canal serial criado. Se os pinos mencionados so RX e TX (UART), o canal implementado por hardware. Porm, pode-se usar quaisquer outros pinos de I/O para se criar um canal. Nesse caso, a implementao feita por software, e o prprio compilador o responsvel por esta tarefa.
char dado=k;

Declarao e inicializao da varivel global do tipo char (8 bits) chamada dado. dita global porque no foi declarada dentro de uma funo, e, portanto, pode ser acessada por qualquer uma do programa.
ext_int_edge(L_TO_H);

Configurao da interrupo externa, realizada pelo pino RB0/INT. O parmetro L_TO_H indica que, se habilitada, a interrupo ocorrer na transio low to high, ou seja, na borda de subida do sinal externo. Portanto, deve-se usar no pino RB0/INT um push-button com um resistor de pulldown, assim como descrito no segundo exemplo.
enable_interrupts(GLOBAL);

Para que qualquer interrupo seja acionada, necessrio habilitar a chave interna chamada GLOBAL. Esse mecanismo foi criado para que se possa desabilitar todas as fontes de interrupo (que foram previamente habilitadas) atravs de um nico comando. Assim, se o programa entra em uma regio crtica, onde no pode ser interrompido, no se faz necessrio desabilitar as interrupes uma a uma. Funciona como um disjuntor geral das interrupes.
enable_interrupts(INT_EXT);

Habilita a interrupo externa.


enable_interrupts(INT_RDA); sleep();

Habilita a interrupo por recepo de dado na UART. Coloca o dispositivo em modo sleep. Nesse estado o ncleo pra de trabalhar e alguns perifricos so desabilitados, diminuindo drasticamente o consumo de corrente. O sistema despertado com a ocorrncia de uma
24

interrupo, que nesse caso a externa. Nem todas as fontes de interrupo podem acordar o processador, como, por exemplo, o Timer0.
#INT_EXT

Diretiva que indica ao compilador que a prxima funo a rotina de tratamento para a interrupo externa. No instante em que a interrupo ocorre, o programa principal (main()) pra onde estiver e a funo void trata_int_ext(void) executada. Aps o seu trmino, o programa principal volta a ser executado a partir de onde parou.
#INT_RDA

Indica ao compilador que a prxima funo a rotina de tratamento para a interrupo gerada pela recepo de um dado.
putc(dado++);

Comando para enviar um caractere atravs do canal serial criado. Se este canal usa o pino TX como sada, a varivel dado simplesmente transferida para o TXREG (registrador de transmisso), pois a UART se encarregar de gerar o sinal correspondente. Para o programa, esta tarefa consome poucos ciclos de relgio, bem como instrues. Porm, se o canal serial utiliza outro pino como sada, o programa o responsvel por gerar o sinal adequado. Neste caso, o compilador insere no cdigo (no momento da compilao) uma funo responsvel por realizar tal tarefa. Deve ficar claro que, durante a execuo dessa funo, o processador no pode realizar outra tarefa ou ser interrompido, pois o sinal de transmisso pode ser comprometido.
dado=getc();

Transferncia do dado recebido por um canal para uma regio na memria RAM (varivel dado). Esta funo deve estar no incio da ISR (Interrupt Service Routine) referente ao #INT_RDA, ou aps a validao do teste da flag kbhit(), pois quando um novo dado estar disponvel. Esta flag foi criada para indicar o instante em que um dado recebido, caso no se queira usar a interrupo #INT_RDA, ou caso tenha-se escolhido um canal por software (o qual no pode gerar tal interrupo). Se o canal por hardware (UART), essa flag levantada no instante em que o stopbit confirmado, indicando que o dado est disponvel no RXREG. No entanto, se a implementao por software, essa flag setada assim que se identifica o incio do
25

startbit. A partir da a funo getc() invoca a sub-rotina (criada pelo compilador) responsvel por receber o frame. Em ambos os casos, a execuo da funo getc() faz com que a flag kbhit() seja zerada de forma automtica, preparando o sistema para uma nova recepo.

7 EXEMPLO: Timer 0
Os Timers so perifricos responsveis pela contagem de tempo, mas que tambm podem ser usados para contar pulsos de um sinal externo. So muito teis quando se deseja um intervalo de tempo preciso entre eventos, pois podem ser configurados pelo programa usurio para contar uma certa quantidade de tempo (manipulada como nmero de clocks). Podem realizar o papel da funo delay_ms(X);, mas o uso de um timer permite que o programa trabalhe em outras atividades enquanto o tempo est sendo contado. Esse exemplo aborda apenas o Timer0, que um contador crescente e de oito bits (assume valores de 0 a 255). Porm, os outros timers presentes nesses dois PICs funcionam a partir do mesmo mecanismo, com outras poucas particularidades. Para utilizar o Timer0 o programador deve inicialmente configurar a fonte de contagem, a qual est associada a uma freqncia. Para preparar o Timer0 para contar uma certa quantidade de tempo deve-se obter, com uma simples regra de trs, quantos pulsos da fonte de contagem corresponde ao intervalo de tempo desejado. Como a contagem crescente, retira-se de 256 o nmero de pulsos obtido, e o resultado carregado para o Timer0. A partir disto, o programa habilita a contagem e fica livre para realizar outras atividades, pois o Timer0 estar sendo incrementado na freqncia da fonte de contagem. Quando se atinge o numero 255, o prximo incremento faz com que a contagem assuma o valor zero. Nesse instante o Timer0 acusa o estouro (overflow) ao programa, indicando que se passou o tempo desejado. O programador pode ainda habilitar a ocorrncia de uma interrupo no momento do estouro, fazendo com que seja executada uma funo especfica nesse instante. Por fim, o programa usurio pode tambm ler o valor atual do Timer0 para saber quanto tempo se passou desde o incio da contagem.
26

Por exemplo, se a fonte de contagem tem freqncia de 1MHz e se deseja agendar um estouro para daqui a 150s, deve-se carregar no Timer0 o nmero 106 (=256150), pois ser contado de 106 at 256 (que corresponde ao zero devido ao overflow). No entanto, se necessrio que os estouros ocorram periodicamente com intervalos de 150s, deve-se carregar o Timer0 a cada estouro. Seno, aps o primeiro estouro ser contado de 0 a 256, totalizando 256s. Normalmente usa-se a fonte de relgio interna para contagem, pois no necessita de hardware adicional. E para que se possa trabalhar com vrias faixas de freqncias existe o mecanismo de prescale. O valor atribudo a esse parmetro ser usado como divisor do clock interno. Portanto, se desejado que o Timer0 seja incrementado com a metade da freqncia interna, o prescale deve configurado com o nmero 2. Pode-se usar os valores 2, 4, 8, 16, 32, 64, 128 ou 256. Eis outro exemplo para esclarecer o funcionamento: deseja-se obter eventos com intervalos de 2048s. Sabe-se que nos exemplos abordados neste documento usa-se freqncia de 4MHz (Fosc), e que a freqncia interna desses PICs (Fcy) so da Fosc, ou seja, 1MHz (vide pgina 3). Portanto, a partir de Fcy, s possvel contar at 256s. Para atingir o intervalo desejado pode-se utilizar um contador para saber quantos estouros se passaram, ou ajustar o prescale, o que bem mais simples. Se esse for configurado com o valor 8, o Timer0 ser incrementado a cada 8s (Fcy/8), e, portanto, sua contagem pode ser de
27

Figura 12 Interface entre o programa usurio e Timer0

at 2048s, que o intervalo desejado. Para este caso no necessrio carregar nenhum valor ao Timer0, pois este deve contar de 0 at 256 (que o zero da prxima contagem).

Figura 13 Comportamento temporal do Timer0 para este subexemplo

O primeiro exemplo deste documento (Pisca LED) pode ser implementado com o uso do Timer0, sem a necessidade do programa ter que trabalhar contando o tempo, e com maior preciso. Isso ocorre no prximo cdigo, que faz um LED piscar a 0,5Hz.

//-------------------------- Pisca LED ---------------------------------#include <16F876A.h> #fuses XT #use delay(clock=4000000) #use fast_io(a) #use fast_io(b) #use fast_io(c) short led; unsigned int cont; #INT_TIMER0 void trata_tmr0(void){ set_timer0(131+get_timer0()); if(++cont==125){ } void main(void){ set_tris_a(0b11111110); set_tris_b(0b11111111); set_tris_c(0b11111111); setup_timer_0(RTCC_INTERNAL| RTCC_DIV_64); set_timer0(131); 28 cont=0; led=!led; output_bit(pin_a0,led); }

enable_interrupts(GLOBAL| INT_TIMER0); while(true){

} }

//---------------------------------------------------------------------//

Explanao: Nesse programa o Timer0 incrementado a cada 64s e o perodo entre estouros corresponde a 125 incrementos, ou seja, 8ms. Um contador usado para indicar que se passaram 125 (coincidncia) estouros desde a ltima alterao da sada ligada ao LED. Detectada essa ocorrncia, a sada tem seu nvel lgico alterado e o contador zerado para recomear uma nova contagem. Portanto, o estado do LED muda a cada 64s x 125 x 125 = 1 segundo.
#INT_TIMER0

Indica ao compilador que a prxima funo a rotina de tratamento para a interrupo gerada pelo estouro do Timer0.
set_timer0(131+get_timer0());

A cada estouro o programa carrega o Timer0 com o valor 131. Faz a contagem correspondente ao perodo de estouro ser de 131 a 256, ou seja, 125. A funo get_timer0() serve para aumentar a preciso da contagem, pois a funo set_timer0(131+get_timer0()); no executada exatamente no momento do estouro. Existe um pequeno intervalo de tempo entre o estouro e a execuo da rotina de tratamento, denominado tempo de latncia da interrupo. Supe-se que esse pequeno intervalo corresponde a 4 incrementos do Timer0. Se no houvesse a funo get_timer0(), o Timer0 seria carregado com o valor 131, porm nesse instante j haveria se passado 4 incrementos desde o ltimo estouro. Isso faria com que o os estouros ocorressem a cada 129 incrementos, o que destoa do clculo realizado. O uso de get_timer0() implica que o valor carregado seja 135 e a contagem at o prximo estouro seja de 121 incrementos. Esse intervalo mais o tempo de latncia ocasionam 125 incrementos entre estouros.
if(++cont==125){ 29

Teste que indica se passaram 125 incrementos da varivel conta desde a ltima alterao da sada.
setup_timer_0(RTCC_INTERNAL|RTCC_DIV_64);

Configura o clock interno como fonte de contagem e o prescaler com 64, alm de habilitar o funcionamento do Timer0. Entretanto, a interrupo s ocorrer se for habilitada, o que feito na prxima funo.
enable_interrupts(GLOBAL|INT_TIMER0);

Habilita a interrupo referente ao estouro do Timer0.

Figura 14 Comportamento temporal do Timer0 e cont para esse exemplo

30

Apndice:
Tabela ASCII: Quando se utiliza a comunicao serial os caracteres enviados entre dispositivos so codificados de acordo com a tabela ASCII, enviando-se o valor binrio correspondente ao caractere desejado.

Figura 15 Tabela de smbolos ASCII e seus respectivos valores em decimal, octal e hexadecimal Pinagem PIC 16f628 e 16f876a Podemos extrair inmeras informaes do dispositivo olhando somente para a configurao de pinos. VDD/VSS Pinos utilizados para a alimentao do dispositivo, sendo VDD a alimentao positiva e VSS a alimentao negativa. Deve ser verificado sempre a tenso a ser utilizada. Normamlemte essa pode ser de 2.2 V a 5.5 V, porm alguns modelos no podem ultrapassar um valor mximo de 3.6 V. VPP/MCLR Pino ativao do chip. Este s estar ligado se a tenso nesse pino for VDD. 31

Ry#: Exemplo : y: Port ao qual o pino est ligado. Para os dispositivos abordados nesse material vemos os ports A, B e C #: "Posio" do pino no port. Comumente vemos nmeros de 0 a 7, formando os ports de 8 bits (0 a 7). Os pinos com essa nomenclatura so utilizados como entradas e/ou sadas digitais. Deve-se consultar quais destes podem ser utilizados como entrada ou sada. Como exemplo o pino RA5 do PIC 16f628 pode ser utilizado somente como entrada. RX/TX: Pinos ligados comunicao serial (RS232), diretamente ligados ao perifrico UART ou USART, que tira a carga da comunicao da rotina principal. O pino RX utilizado para o recebimento de dados e o pino TX utilizado para enviar dados. AN#: Pinos com essa nomeclatura so utilizados como canais de converso A/D, sendo # o nmero do canal. VREF+/VREFEstes pinos so utilizados para definir limeites superiores e inferiores converso A/D, respectivamente. Se fizermos V REF+ = 3V e VREF-=1V, somente valores analgicos entre 1 e 3 V sero considerados, e toda a resoluco ser concentrada nesse intervalo, de modo que para uma converso de 8 bits, uma leitura de 0 representar 1V e uma leitura de 255 representar 3V T#CKI/ T#OSO/ T#OSI: Os pinos T#CKI e T#OSI so utilizados como base de clock para o timer # do microcontrolador, sendo que para um mesmo timer somente um deve ser utilizado. O T#OS0 utilizado para externar a base de clock do timer #. OSC1/OSC2 Pinos de entrada para o oscilador quando se utiliza um cristal. CLKIN/CLKOUT Quando se utiliza um oscilador capacitivo ou uma onda quadrada como base de tempo do PIC, deve-se conectar esse sinal ao pino CLKIN. Este pode ser externado pelo pino CLKOUT. CMP#/CCP# Pinos diretamente ligados ao perifrico captura/comparao/PWM, sendo sua funo configurada por software para gerar um sinal de frequncia fixa e tempo alto/baixo variveis(PWM), guardar o valor de contagem do timer associado com um estmulo externo(captura) e controlar o pino associado quando o contador chegar ao valor desejado(comparao). SS/SCK/SDI/SDO Pinos associados comunicao SPI, sendo SS (slave select) o pino de seleo do dispositivo a transmitir, SCL o pino de clock

32

compartilhado, SDI e SDO os canais de recebimento e transimsso, respectivamente. SDA/SCL

Pinos associados comunicao I2C, sendo SCL o pino de clock compartilhado e SDA o pino de comunicao bidirecional. CK/DT Os pinos CK e DT so utilizados para comunicar-se pela USART de forma sncrona, sendo CK o clock e DT o canal de dados. PGC/PGD/PGM Pinos associados gravao do chip. Em PGC deve ser fornecido o clock, em PGD os dados a serem programados e PGM utilizado somente para gravao de baixa tenso.

INT Pino utilizado para a interrupo externa. Se houver uma variao nesse pino a rotina de interrupo engatilhada.

FIN.

33

You might also like