Buscar

PIC APOSTILA BOA

Faça como milhares de estudantes: teste grátis o Passei Direto

Esse e outros conteúdos desbloqueados

16 milhões de materiais de várias disciplinas

Impressão de materiais

Agora você pode testar o

Passei Direto grátis

Você também pode ser Premium ajudando estudantes

Faça como milhares de estudantes: teste grátis o Passei Direto

Esse e outros conteúdos desbloqueados

16 milhões de materiais de várias disciplinas

Impressão de materiais

Agora você pode testar o

Passei Direto grátis

Você também pode ser Premium ajudando estudantes

Faça como milhares de estudantes: teste grátis o Passei Direto

Esse e outros conteúdos desbloqueados

16 milhões de materiais de várias disciplinas

Impressão de materiais

Agora você pode testar o

Passei Direto grátis

Você também pode ser Premium ajudando estudantes
Você viu 3, do total de 33 páginas

Faça como milhares de estudantes: teste grátis o Passei Direto

Esse e outros conteúdos desbloqueados

16 milhões de materiais de várias disciplinas

Impressão de materiais

Agora você pode testar o

Passei Direto grátis

Você também pode ser Premium ajudando estudantes

Faça como milhares de estudantes: teste grátis o Passei Direto

Esse e outros conteúdos desbloqueados

16 milhões de materiais de várias disciplinas

Impressão de materiais

Agora você pode testar o

Passei Direto grátis

Você também pode ser Premium ajudando estudantes

Faça como milhares de estudantes: teste grátis o Passei Direto

Esse e outros conteúdos desbloqueados

16 milhões de materiais de várias disciplinas

Impressão de materiais

Agora você pode testar o

Passei Direto grátis

Você também pode ser Premium ajudando estudantes
Você viu 6, do total de 33 páginas

Faça como milhares de estudantes: teste grátis o Passei Direto

Esse e outros conteúdos desbloqueados

16 milhões de materiais de várias disciplinas

Impressão de materiais

Agora você pode testar o

Passei Direto grátis

Você também pode ser Premium ajudando estudantes

Faça como milhares de estudantes: teste grátis o Passei Direto

Esse e outros conteúdos desbloqueados

16 milhões de materiais de várias disciplinas

Impressão de materiais

Agora você pode testar o

Passei Direto grátis

Você também pode ser Premium ajudando estudantes

Faça como milhares de estudantes: teste grátis o Passei Direto

Esse e outros conteúdos desbloqueados

16 milhões de materiais de várias disciplinas

Impressão de materiais

Agora você pode testar o

Passei Direto grátis

Você também pode ser Premium ajudando estudantes
Você viu 9, do total de 33 páginas

Faça como milhares de estudantes: teste grátis o Passei Direto

Esse e outros conteúdos desbloqueados

16 milhões de materiais de várias disciplinas

Impressão de materiais

Agora você pode testar o

Passei Direto grátis

Você também pode ser Premium ajudando estudantes

Prévia do material em texto

MICROCONTROLADORES PIC
PROGRAMAÇÃO EM 
LINGUAGEM C
HANDS 
ON!
O QUE É UM MICROCONTROLADOR?
O microcontrolador PIC é um componente eletrônico 
fabricado pela MICROCHIP, capaz de ser programado para 
realizar operações lógicas e aritméticas, interagindo com 
periféricos (leds, botões, sensores ou até outro PIC). Deste 
fato vem o nome PIC (Peripheral Integrated Controller, ou 
controlador integrado de periféricos). Um microcontrolador 
(uC), diferentemente de um microprocessador, possue 
memória volátil (RAM) e não volátil (EEPROM), além de 
outros periféricos internos, o que o torna bastante útil. Este 
é capaz de operar independente de memórias externas, 
além de poder ser programado em linguagem de alto nível, 
como a linguagem C. 
ESTRUTURA BÁSICA DO PIC
Nesta apostila serão abordados os modelos 
PIC16F628A, e PIC16F876A, pois estes estão inclusos em 
uma boa gama de possíveis soluções. Apesar da estrutura 
aqui mencionada tratar destes específicos modelos, esta 
descreve a grande parte dos microcontroladores. 
MEMÓRIA FLASH- É a memória em que será guardado 
o programa propriamente dito, no formato de “linguagem 
de máquina”. Foi desenvolvida na década de 80 pela 
Toshiba e é do tipo EEPROM, porém se assemelha com a 
RAM, permitindo que múltiplos endereços sejam apagados 
ou escritos em uma só operação.
MEMÓRIA SRAM- Static RAM, significa que não precisa 
ser periodicamente atualizada como as RAMs comuns, que 
sem atualização perdem seus dados. É a memória volátil, 
rapidamente acessada, e que é apagada toda vez que a 
alimentação se ausenta. Local onde são armazenadas as 
variáveis declaradas no programa.
MEMÓRIA EEPROM- É a memória não volátil, que 
mantém os dados escritos independente da alimentação do 
PIC. É acessada quando se deseja armazenar dados por 
períodos indeterminados, como a senha de um usuário.
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. São acessados constantemente e servem 
para realizar operações de movimentação e tem 
acesso direto à ULA.
 
2
• ULA: Unidade Lógica e Aritmética do uC 
(microcontrolador), responsável pelas operações 
lógicas e aritiméticas dos WREGs. 
FUSÍVEIS: Periféricos especiais responsáveis pelo pleno 
funcionamento do sistema. Garantem que o programa não 
“trave” e que o uC não opere sob tensões abaixo ou acima 
do permitido.
PERIFÉRICOS: Circuitos auxiliares que livram o 
programa de realizar trabalhos específios. Funcionam de 
forma paralela ao programa do usuário (na FLASH), 
ocupando o código apenas para ser configurado ou entregar 
o resultado de algum serviço. Os periféricos abordados 
nesse documento são:
• GPIO (General Purpose Input/Output): Usados para 
entradas digitais, como um botão ou uma chave, e 
saídas digitais, como um LED ou um motor DC. O 
programa usuário pode setar uma saída, colocando um 
pino externo do PIC em nível lógico ‘0’(0V) ou ‘1’(5V).
• ADC (Analog to Digital Converter): Usado para 
recolher sinais analógicos externos e transormá-los em 
digitais, para então serem processados pelo programa.
• USART (Universal Synchronous and Asynchronous 
Receiver-Transmitter): Periférico responsável por 
enviar e receber dados através do protocolo RS-232.
• TIMERS: Temporizadores de uso geral. Garantem 
precisão de tempo entre eventos.
 
3
Figura 1 – Estrutura interna básica
HARDWARE 
Para o pleno funcionamento do uC é necessário 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 tensão 
de alimentação de 5V). É recomendado que um 
capacitor de 100nF (de cerâmica com o rótulo 104) 
seja posto na alimentação, próximo aos terminais do 
uC, pois este funciona como um filtro contra ruídos 
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 
frequência interna (chamada de Fcy) do uC vale ¼ 
da frequência usada como fonte de relógio (Fosc). 
Para uma correta geração de clock externo, é 
recomendo o uso de dois capacitores de 
desacoplamento nos terminais do cristal, no valor 
de 22pF.
 
4
O uC PIC16F628A tem o benefíco de poder usar um 
clock interno de 4MHz, além de não precisar do MCRL. 
Isso permite que os três pinos correspondentes sejam 
usados como GPIO. Esta será a configuração usada para 
este uC nos nossos exemplos. 
Figura 2 – Hardware básico: PIC16F628A
Figura 3 – Hardware básico: PIC16F876A 
SOFTWARE
 
5
Como ambiente de desenvolvimento, será usado o 
compilador PCWH da CCS. Este é constituído de um IDE 
gráfico que pode ser executado em qualquer plataforma 
Windows. O compilador, como o próprio nome já diz, tem o 
papel de compilar o código em linguagem C para a 
linguagem de máquina, a qual está pronta para ser gravada 
na memória FLASH do uC. Deve-se ressaltar que este 
compilador é case insensitive, ou seja, não diferencia letras 
maíusculas de minúsculas. Portanto, se forem declaradas as 
variáveis “Temper_Atual” e “temper_atual”, o compilador 
acusará erro, pois é visto como ambiguidade.
Os programas embarcados seguem, como os outros 
tópicos já vistos, uma estrutura básica. Quando o 
dispositivo é ligado o programa inicia sua execução numa 
fase chamada de “inicialização”. Nessa fase é feita toda a 
configuração do sistema: 
• Quais pinos serão entradas ou saídas.
• Quais periféricos serão utilizados e como serão 
utilizados.
• Declaração das variáveis usadas pela função main.
• Chamadas de funções (ou comandos) que devem ser 
executados apenas no início do processo.
Deve ficar claro que o código 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 ações sequencias nesse laço 
são:
• Leitura das entradas.
• Processamento dos dados.
• Atualização das saídas.
 
6
Figura 4 – Fluxo básico 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){
}
}
//---------------------//
Explanação:
#include <16FXXXA.h> 
Biblioteca que será utilizada para o compilador gerar o 
código específico para o dispositivo utilizado.
#fuses INTRC_IO, NOMCLR, XT 
 
7
Fusíveis configurados. INTRC_IO significa que será utilizado 
como fonte de relógio 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 relógio é um cristal externo 
de frequência <= 4MHz. Não serão abordados todos os 
fusíveis, porém 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 serão vistas mais adiante.
#use fast_io(a) //(b ou c)
Configuratodos os pinos como GPIO (General purpose 
In/Out). Cada pino do uC pode ser configurado com 
diferentes propósitos, o que pode ser visto nas Figuras 2 e 
3. Por omissão, diremos que todos os pinos serão GPIO. 
Assim, se quisermos outra função para algum deles, 
indicaremos adiante, atualizando o seu propósito. Os canais 
GPIO no PIC seguem um padrão: cada um deve estar 
associado a um byte e a um bit. Os bytes são nomeados por 
vogais e são chamados pelo datasheet de PORT, como 
PORTA, PORTB, PORTC, etc. Os bits são mapeados por 
números, 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 usuário 
como “pin_a7”. O PIC16F628 contém as portas A e B, 
enquanto o PIC16F876 tem as portas A, B e C. Porém, nem 
todos os canais endereçáveis em teoria estão disponíveis 
nos pinos externos.
void main(void){
Função principal de qualquer programa em C. É onde 
realmente começa o programa que será embarcado. Os 
comandos mencionados anteriormente são chamados de 
“diretivas do compilador”, ou seja, são usados pelo 
compilador mas não serão executados pelo PIC. O 
compilador utiliza esses comandos para configurar 
registradores especiais no momento da gravação. Portanto, 
se você escreveu “#fuses XT”, o registrador responsável por 
indicar a fonte de relógio será configurado no momento do 
download, e não na inicialização.
set_tris_a(0b11111111); 
 
8
Primeiro comando do programa (para este exemplo). Essa 
função configura os canais GIPO como entrada ou saída. ‘1’ 
significa “IN” e ‘0’ “OUT”, o que facilita a memorização pela 
semelhança: 1->In e 0->Out. O prefixo “0b” indica que o 
número adiante está representado em binário. Para 
representar um número em hexadecimal, o prefixo usado é 
“0x”, portanto essa função pode ser escrita: “set_tris_a 
(0xff);”. Se um número não tiver nenhum prefixo, este será 
interpretado pelo compilador como no formato decimal, que 
é nossa forma natural. Podemos dizer então que essa 
função também pode ser escrita na forma: “set_tris_a (255);”, 
que surtirá o mesmo efeito. Convém escrever tal função em 
binário pela melhor visualização dos canais, que estão 
dispostos em ordem decrescente. Portanto, se o primeiro 
pino do 16F628 for usado para acender um LED, deve-se 
configurar o canal A2 como saída, escrevendo: “set_tris_a 
(0b11111011);”. Recomenda-se que todos os canais que não 
serão utilizados sejam configurados como entrada, pois 
estarão em alta-impedância, admitindo qualquer valor. 
Quanto mais pinos são configurados como saída, maior é a 
probabilidade do usuário 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);
while(true){
output_bit(pin_a0,flag);
delay_ms(500);
flag=!flag;
}
}
//-------------------------//
//-------- Pisca LED --------
#include <16F876A.h> 
#fuses XT
#use delay(clock=4000000) 
 
9
#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);
}
}
//-------------------------//
Explanação:
short flag=0; 
Declaração e inicialização da variável de 1 bit chamada 
“flag”. Também pode ser escrito nas formas: “boolean 
flag=0;” ou “int1 flag=0;”
output_high(pin_a0); 
Coloca o pino mencionado em nível lógico 1 (5V).
output_low(pin_a0); 
Coloca o pino mencionado em nível lógico 0 (0V).
output_bit(pin_a0, flag); 
Coloca o pino mencionado no nível lógico correspondente 
ao valor corrente da “flag”.
delay_ms(500); 
O programa literalmente pára durante o valor de tempo 
informado (em milisegundos). O próprio compilador gera o 
código responsável por esta ação, através de contadores, 
os quais se baseiam em “#use delay(clock=4000000)”.
flag=!flag; 
Realiza o “complemento de um” da variável “flag”. O 
símbolo “!” corresponde à operação lógica NOT.
Os pinos configurados como entrada drenam uma 
corrente extremamente pequena, na ordem de pico-
ampéres, pois são colocados em alta-impedância. Assim, 
podemos considerá-la desprezível.
Os pinos definidos como saída não 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 saída. 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
Compilação do programa:
Inicialmente abra o compilador PICC (PCWHD), clique 
no símbolo de “pastas” (primeiro acima), e em seguida 
 
11
“Close All”. Agora, para criar um novo projeto, clique 
novamente no símbolo de “pastas”, e após isso em “New” 
-> “Source File”. Escolha o diretório onde ficará salvo este 
primeiro programa e o nomeie de “exemplo1”. Digite o 
código de exemplo para o uC escolhido e em seguida 
compile o programa em “Compile” -> “Compile”, ou através 
da tecla de atalho “F9”. Neste processo o compilador gera 5 
arquivos de saída, porém será utilizado apenas o 
“exemplo1.hex”, que é o código que será transferido para a 
memória FLASH do uC.
Gravação 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 detecção do dispositivo. Se isso não ocorreu, 
confira se houve alguma falha no dito procedimento (ordem 
dos jumpers, mau contato, etc.), e então clique em “Tools” 
-> “Check Communication”. Não se deve continuar a partir 
deste ponto até que o uC não tenha sido detectado. 
Antes de transferir o código, desabilite a função 
“Tools” -> “Fast Programming”, pois esse modo está bem 
mais susceptível a falhas de transferência, além de ser 
pequena diferença em relação ao modo normal. Para 
verificar se o código foi transferido corretamente, habilite a 
função “Programmer” -> “Verify on Write”.
Feito tudo, clique em “File” -> “Import Hex”. Escolha o 
“exemplo1.hex” que foi gerado na compilação e, depois de 
importado o arquivo, clique finalmente em “Write” para 
realizar a transferência do código para o uC. Confirmado o 
sucesso do download, desconecte o plugue ICSP do 
protoboard, insira os componentes necessários e energize o 
circuito. Se tudo deu certo, o LED piscará a cada 1 segundo. 
Os componentes não precisam ser retirados para 
realizar um novo download. Porém, é recomendado que 
sempre se inicie a construção de um hardware pelos 
jumpers do ICSP, pois na ocorrência de uma falha (muito 
 
12
comum) deve-sereduzir o hardware para encontrar o 
defeito.
Outra maneira de realizar o download é pelo botão no 
PICKit2 (hardware). Essa função é habilitada em 
“Programmer” -> “Write on PICkit Button”. Quando tal 
botão é 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 botão “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 botão no PICKit2 (hardware). O programa 
percebe que houve uma alteração e realiza um “reloading”.
Os exemplos seguintes abordarão apenas o 
PIC16f876A, por questões de total semelhança. 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);
 }
/---------------------------------------------------------------
Explanação:
input(pin_c4); 
 
13
Realiza a leitura externa do nível lógico no pino mencionado 
e a retorna para o programa.
Figura 7 – Exemplo 2: hardware 16F876
Em uma entrada utilizada para ler um botão, deve-se 
usar um resistor ligado ao terra. Sem o resistor (chamado 
de pull-down), se o botão não estiver pressionado, o nivel 
lógico na entrada não será 0, pois este estará alta 
impedância. Esse estado pode ser denominado floating 
(flutuando), onde o sinal não tem um valor fixo, fica 
variando aleatoriamente em função de ruídos locais. 
Atenção ao ligar um push-button de 4 terminais no 
protoboard. Dois de seus terminais estão conectados aos 
outros dois. Portanto, se um dos terminais foi ligado à 5V, o 
outro terminal conectado à esse também estará em 5V, 
inviabilizando o uso do seu ramo no protoboard.
3º EXEMPLO: INTERRUÇÃO EXTERNA
Podemos engatilhar uma rotina específica dentro do nosso 
microcontrolador a partir de sinais externos ou mesmo 
eventos internos do microcontrolador. Neste exemplo 
trabalheremos com interrupções externas, que em resumo 
é a execução de determinada rotina quando houver uma 
mudança 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
não 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 botão deve estar conectado ao pino 
responsável por chamar interrupções externas , no caso do 
PIC16F876A é o pino rb0.
//--------INTERRUPÇÃO 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;
}}}
//--------INTERRUPÇÃO EXTERNA----------------------------------------
Explanação:
ext_int_edge(L_TO_H); 
Esta função define que o microcontrolador entrará em interrupção 
quando o pino de interrupção externa em questão passar do estado 0 
para 1( low to high).
enable_interrupts(GLOBAL);
Função responsável por habilitar qualquer tipo de interrupção que 
microcontrolador tenha, deve ser usada antes de habilitar qualquer 
interrupção especificamente.
enable_interrupts(INT_RB);
Especifica a interrupção que será usada, no caso interrupção externa 
por alteração de estado nos pinos RB que são responsáveis pelas 
interrupções 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);
}
}
//------------------------------------------------------------//
Explanação:
#include <lcdt.c> 
Inclusão da biblioteca do LCD. Esse arquivo deve estar na 
mesma pasta onde será salvo o programa que a utiliza. 
#define lig output_high 
Amarração entre duas entidades. Serve para aumentar a 
legibilidade do código. O compilador substitui a parte 
esquerda pela direita no momento da compilação do 
programa.
unsigned int i; 
Declaração da variável de 8 bits e sem sinal (0 – 255) 
chamada “i”.
lcd_init(); 
Inicialização da biblioteca do LCD. Essa função configura os 
pinos da porta B (menos o B0, que pode ser configurado na 
“main()”), e prepara o LCD para iniciar sua operação.
printf(lcd_putc,"\fCurso de uC PIC "); 
Função de impressão no LCD. Existem comandos especiais:
• \f -> Limpa a tela toda e põe o cursor na primeira 
posição (1,1).
• \n -> Põe o cursor no início da segunda linha.
• \b -> Retorna o cursor uma posição.
Os caracteres são impressos sempre na posição 
corrente do cursor, que pode ser alterada pela função 
 
16
“lcd_gotoxy(x,y);”. A função “lcd_getc(x,y);” retorna o atual 
caractere que ocupa a posição informada.
Como os canais B6 e B7 são utilizados para gravação e 
comunicação com o LCD, deve-ser usar dois resistores para 
aumentar a impedância 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 
distorção do sinal de gravação.
O pino 3 do display é o sinal “V0”, que determina o 
contraste entre a parte escrita e o plano de fundo da tela. O 
potenciômetro deve ser regulado para obter-se uma boa 
visualização.
Figura 8 – Hardware Display LCD
5º EXEMPLO: Conversão A/D
No instante em que o programa usuário requisita ao 
módulo um processo de conversão A/D, o corrente valor de 
tensão na entrada especificada é convertido em um valor 
digital, para então ser manipulado pelo programa. Neste 
exemplo o uC será configurado para uma conversão de 8 
bits, e o range de tensão a ser convertida será o padrão, ou 
seja, a própria alimentação do PIC (0–5V). Portanto, essa 
faixa será dividida em 256 partes iguais, e o resultado de 
uma conversão será o byte correspondente a parte em que 
se encontra a tensão convertida.
 
17
Figura 9 – Função de transferência da conversão A/D desse exemplo
//------------------------ Voltímetro -----------------------------------#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,"\nPET-
EngElet.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);
}
}
//---------------------------------------------------------------------//
Explanação:
O PIC16F628A não tem conversor A/D.
#device adc=8
Configura a resolução da conversão. Pode ser observado na 
Figura 9 que a variação mínima que essa conversão pode 
reconhecer é de aproximadamente 20mV. Isso significa que 
 
18
um sinal de 10mV e outro de 15mV serão convertidos para 
o mesmo valor (0). Isso pode ser ruim para determinadas 
aplicações. Por exemplo, o sensor de temperatura LM35 
fornece em sua saída 10mV/°C. Uma conversão de 8 bits 
não é capaz de perceber a diferença entre 0 e 1°C. Porém, 
pode-se melhorar a resolução, utilizando 10 bits. Isso torna 
o sistema capaz de perceber uma diferença mínima de 5mV 
(0,5°C). Não se deve esquecer de utilizar uma variável do 
tipo “unsigned long int” (16 bits), cuja impressão é feita pela 
sintaxe “%4lu”. Outra forma de melhorar a resolução é 
diminuir o range do valor a ser convertido. Para isso, são 
utilizados sinais externos como VREFH e/ou VREFL, os quais 
podem ser configurados na próxima função.
setup_adc_ports(ALL_ANALOG); 
Configura todas as portas possíveis como analógicas. Neste 
caso, nenhuma delas poderá ser utilizada como GPIO. Para 
ver as possíveis configurações do periférico ADC, no IDE 
CCS, clique com o botão direito em #include <16F876A.h> -> 
“Open File at Cursor”, e vá à linha 220. Por omissão 
(default), serão adotados como VREFH e VREFL os sinais de 
alimentação, VDD e VSS, respectivamente.
setup_adc(ADC_CLOCK_INTERNAL); 
Configura a frequência de operação (fonte de relógio) do 
hardware.
setup_adc_channel(0); 
Este PIC tem vários canais analógicos, porém apenas um módulo 
de conversão. Essa função indica o canal que será ligado ao 
módulo para o próximo processo. Como este exemplo utiliza 
apenas um canal, este foi configurado na “inicialização” e não 
sofrerá alteração. Em uma aplicação que utiliza múltiplos canais, 
esta função deve estar no “loop infinito”, pois será dinâmica. O 
compilador recomenda que entre a configuração de um canal e 
a leitura do mesmo deve haver um intervalo de 10μs. Vá no 
“Help” do compilador (F1), na aba “Index”, e digite: 
“setup_adc_channel”. Veja o tópico “Examples”.
digital=read_adc(); 
Realiza a conversão A/D do último canal configurado e atribui o 
resultado do processo à variável “digital”.
Note que no programa deste exemplo o backlight do 
display é ligado após o comando “esp(2000);”. Isso implica que, 
em algumas vezes, o backlight estará aceso durante a 
apresentação, e nas outras ele estará apagado. Isso se dá ao 
fato de que um canal configurado como saída, se não for 
 
19
atualizado, assumirá valores imprevisíveis. Essa é uma comum 
fonte de erros, pois saídas podem iniciar-se indevidamente 
acionadas e provocar prejuízos. Recomenda-se que, logo após 
configurar as entras/saídas, se desative todas as saídas.
 
Figura 10 – Hardware ADC
6º EXEMPLO: UART
A UART é definida como um periférico de comunicação 
utilizado para troca de informações entre dispositivos 
digitais. Este módulo se baseia no protocolo RS-232, o mais 
popular padrão de comunicação assíncrona, ou seja, entre 
dispositivos com fontes de relógio 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 não podem ser diretamente ligados, pois a 
representação elétrica dos símbolos (bits 0 e 1) não é a 
mesma. Os uCs utilizam o padrão TTL, ou seja, o bit 0 é 
representado como 0V e o bit 1 como 5V (ou a alimentação, 
caso seja diferente). Uma porta serial, bem como aparelhos 
industriais, reconhecem o sinal lógico 1 um valor entre -25V 
e -3V, e o sinal lógico 0 um valor entre 3 e 25V (geralmente 
usa-se ±12V). Essa escolha se dá ao fato de aumentar a 
relação sinal/ruído, permitindo uma maior taxa de 
transmissão, maior distância do cabo que conecta os 
dispositivos, além de diminuir a TEB (taxa de erro de bit). 
 
20
Para que um uC e um PC possam trocar informações existe 
o MAX232, que é um conversor de padrão elétrico para o 
RS-232.
Este módulo também pode ser nomeado como USART, 
que significa “Universal Synchronous and Asynchronous 
Receiver-Transmitter”. Nessa configuração, além dos sinais 
RX e TX, é transmitido também um sinal de relógio, 
fornecido por apenas um dos nós envolvidos. Uma 
comunicação síncrona permite uma taxa de transmissão 
mais elevada, pois o instante da leitura do sinal é bem 
definido devido à referência do relógio. O exemplo 
demonstrado aqui abordará a comunicação assíncrona.
Em um sistema de comunicação RS-232, todos os 
elementos envolvidos devem ser configuradados com os 
mesmos parâmentros, pois só assim o sucesso da 
transmissão é garantido. Como se os nós da rede “falassem 
a mesma língua”. Os parâmetros desse protocolo são:
• Baud rate: Define a taxa de transmissão e 
consequentemente o tempo de bit (tbit), que é o 
inverso desse número. O valor mais comum é 9600 
bps, e outros bastante usados são 2400, 4800, 19200 
e 115200 bps (bits por segundo).
• Start bit: É um parâmetro imutável, unitário, tem 
valor lógico 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 
padrão é 8 bits (1 byte).
• Parity bit: Bit de paridade. Tem o papel de identificar 
erros na transmissão e, se presente, fica entre o 
payload e o stop bit. Pode ser configurado de três 
formas: paridade par, paridade ímpar ou ausente. Na 
paridade par, ele é inserido de forma a tornar o 
número 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 números ‘1s’. Se qualquer um dos 
bits for lido erroneamente (devido à ruído), o bit de 
paridade (que no caso é ‘1’) acusará o erro na 
transmissão, e o dado recebido será descartado. 
 
21
Existe, no entanto, a probabilidade (mesmo que 
ínfima) de dois bits serem alterados numa mesma 
transmissão, e assim o mecanismo de paridade não 
detectará o erro. 
• Stop bit: Pode ser unitário ou duplo, e tem valor 
lógico um.
No PIC, um canal serial pode ser implementado por 
hardware, ou seja, a UART, ou por software. Nessa última, o 
programa embarcado é integralmente responsável pela 
transmissão/recepção dos dados, tornando a CPU 
indisponível para realizar qualquer outra tarefa durante 
esse ato. As duas implementações surtem o mesmo efeito 
(externo) e o receptor segue o mesmo algorítmo para 
capturar o dado:
Figura 11 – Transmissão 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 transição negativa indica o início do startbit. 
Aguarda-se então½ tbit.
• C – O startbit é verificado, pois a transição pode ter 
sido causada por ruído. Se verdadeiro, aguarda-se 1 
tbit e o processo continua. Se não, o processo volta 
ao estado A.
• D – Inicia-se o processo de aquisição. O bit menos 
significativo (LSB) é capturado e aguarda-se 1 tbit 
para a aquisição do próximo bit. Todos os outros bits 
do payload são capturados desta mesma forma.
• E – É verificado o stopbit, pois existe a chance de 
ruídos terem validado as etapas B e C. Se 
verdadeiro, o dado recebido é finalmente entregue 
 
22
ao programa usuário. 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);
 
ext_int_edge(L_TO_H);
 enable_interrupts(GLOBAL);
 enable_interrupts(INT_EXT);
 while(true){
 sleep();
 }
}
#INT_EXT
void trata_int_ext(void){
 putc(dado++);
 if(dado==‘f’) dado=‘a’;
 delay_ms(200);
}
//-----------------------------------------------------------------------//
//------------------------------ 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){
 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;
 }
 
23
 }
}
//--------------------------------------------------------------------//
 
Explanação:
#use rs232(baud=9600, rcv=pin_b1, xmit=pin_b2, parity=N) 
Definição dos parâmetros do canal serial criado. Se os pinos 
mencionados são RX e TX (UART), o canal é implementado 
por hardware. Porém, pode-se usar quaisquer outros pinos 
de I/O para se criar um canal. Nesse caso, a implementação 
é feita por software, e o próprio compilador é o responsável 
por esta tarefa. 
char dado=‘k’; 
Declaração e inicialização da variável global do tipo “char” 
(8 bits) chamada “dado”. É dita global porque não foi 
declarada dentro de uma função, e, portanto, pode ser 
acessada por qualquer uma do programa. 
ext_int_edge(L_TO_H); 
Configuração da interrupção externa, realizada pelo pino 
RB0/INT. O parâmetro “L_TO_H” indica que, se habilitada, a 
interrupção ocorrerá na transição 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 pull-
down, assim como descrito no segundo exemplo. 
enable_interrupts(GLOBAL); 
Para que qualquer interrupção seja acionada, é necessário 
habilitar a chave interna chamada GLOBAL. Esse 
mecanismo foi criado para que se possa desabilitar todas as 
fontes de interrupção (que foram previamente habilitadas) 
através de um único comando. Assim, se o programa entra 
em uma região crítica, onde não pode ser interrompido, não 
se faz necessário desabilitar as interrupções uma a uma. 
Funciona como um “disjuntor geral” das interrupções.
enable_interrupts(INT_EXT); 
Habilita a interrupção externa.
enable_interrupts(INT_RDA); 
Habilita a interrupção por recepção de dado na UART.
sleep(); 
Coloca o dispositivo em modo sleep. Nesse estado o núcleo 
pára de trabalhar e alguns periféricos são desabilitados, 
diminuindo drasticamente o consumo de corrente. O 
sistema é “despertado” com a ocorrência de uma 
 
24
interrupção, que nesse caso é a externa. Nem todas as 
fontes de interrupção podem acordar o processador, como, 
por exemplo, o Timer0.
#INT_EXT 
Diretiva que indica ao compilador que a próxima função é a 
rotina de tratamento para a interrupção externa. No 
instante em que a interrupção ocorre, o programa principal 
(main()) pára onde estiver e a função “void trata_int_ext(void)” 
é executada. Após o seu término, o programa principal volta 
a ser executado a partir de onde parou.
#INT_RDA 
Indica ao compilador que a próxima função é a rotina de 
tratamento para a interrupção gerada pela recepção de um 
dado.
putc(dado++); 
Comando para enviar um caractere através do canal serial 
criado. Se este canal usa o pino TX como saída, a variável 
“dado” é simplesmente transferida para o TXREG 
(registrador de transmissão), pois a UART se encarregará de 
gerar o sinal correspondente. Para o programa, esta tarefa 
consome poucos ciclos de relógio, bem como instruções. 
Porém, se o canal serial utiliza outro pino como saída, o 
programa é o responsável por gerar o sinal adequado. 
Neste caso, o compilador insere no código (no momento da 
compilação) uma função responsável por realizar tal tarefa. 
Deve ficar claro que, durante a execução dessa função, o 
processador não pode realizar outra tarefa ou ser 
interrompido, pois o sinal de transmissão pode ser 
comprometido. 
dado=getc(); 
Transferência do dado recebido por um canal para uma 
região na memória RAM (variável “dado”). Esta função deve 
estar no início da ISR (Interrupt Service Routine) referente 
ao “#INT_RDA”, ou após a validação do teste da flag “kbhit()”, 
pois é quando um novo dado estará disponível. Esta flag foi 
criada para indicar o instante em que um dado é recebido, 
caso não se queira usar a interrupção “#INT_RDA”, ou caso 
tenha-se escolhido um canal por software (o qual não pode 
gerar tal interrupção). Se o canal é por hardware (UART), 
essa flag é “levantada” no instante em que o stopbit é 
confirmado, indicando que o dado está disponível no 
RXREG. No entanto, se a implementação é por software, 
essa flag é setada assim que se identifica o início do 
 
25
startbit. A partir daí a função “getc()” invoca a sub-rotina 
(criada pelo compilador) responsável por receber o frame. 
Em ambos os casos, a execução da função “getc()” faz com 
que a flag “kbhit()” seja zerada de forma automática, 
preparando o sistema para uma nova recepção.
7º EXEMPLO: Timer 0
Os Timers são periféricos responsáveis pela contagem 
de tempo, mas que também podem ser usados para contar 
pulsos de um sinal externo. São muito úteis quando se 
deseja um intervalo de tempo preciso entre eventos, pois 
podem ser configurados pelo programa usuário para contar 
uma certa quantidade de tempo (manipulada como número 
de clocks). Podem realizar o papel da função “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). Porém, 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 freqüência. Para 
preparar o Timer0 para contar uma certa quantidade de 
tempo deve-se obter, com uma simples “regra de três”, 
quantos pulsos da fonte de contagem corresponde ao 
intervalo de tempo desejado. Como a contagem é 
crescente, retira-se de 256 o número 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 freqüência da fonte de contagem. Quandose atinge o numero 255, o próximo 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 ocorrência de uma interrupção no momento do 
estouro, fazendo com que seja executada uma função 
específica nesse instante. Por fim, o programa usuário pode 
também ler o valor atual do Timer0 para saber quanto 
tempo se passou desde o início da contagem.
 
26
Figura 12 – Interface entre o programa usuário e Timer0
Por exemplo, se a fonte de contagem tem freqüência 
de 1MHz e se deseja “agendar” um estouro para daqui a 
150μs, deve-se carregar no Timer0 o número 106 (=256-
150), pois será contado de 106 até 256 (que corresponde 
ao zero devido ao overflow). No entanto, se é necessário 
que os estouros ocorram periodicamente com intervalos de 
150μs, deve-se carregar o Timer0 a cada estouro. Senão, 
após o primeiro estouro será contado de 0 a 256, 
totalizando 256μs.
Normalmente usa-se a fonte de relógio interna para 
contagem, pois não necessita de hardware adicional. E para 
que se possa trabalhar com várias faixas de freqüências 
existe o mecanismo de “prescale”. O valor atribuído a esse 
parâmetro será usado como divisor do clock interno. 
Portanto, se é desejado que o Timer0 seja incrementado 
com a metade da freqüência interna, o “prescale” deve 
configurado com o número 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 2048μs. Sabe-se 
que nos exemplos abordados neste documento usa-se 
freqüência de 4MHz (Fosc), e que a freqüência interna 
desses PICs (Fcy) são ¼ da Fosc, ou seja, 1MHz (vide 
página 3). Portanto, a partir de Fcy, só é possível contar até 
256μs. 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 8μs (Fcy/8), e, portanto, sua contagem pode ser de 
 
27
até 2048μs, que é o intervalo desejado. Para este caso não 
é necessário carregar nenhum valor ao Timer0, pois este 
deve contar de 0 até 256 (que é o zero da próxima 
contagem).
Figura 13 – Comportamento temporal do Timer0 para este sub-
exemplo
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 precisão. Isso ocorre no próximo 
código, 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){
 cont=0;
 led=!led;
 output_bit(pin_a0,led);
 }
}
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
enable_interrupts(GLOBAL|
INT_TIMER0);
while(true){
}
}
//---------------------------------------------------------------------//
Explanação:
Nesse programa o Timer0 é incrementado a cada 64μs e o 
período entre estouros corresponde a 125 incrementos, ou 
seja, 8ms. Um contador é usado para indicar que se 
passaram 125 (coincidência) estouros desde a última 
alteração da saída ligada ao LED. Detectada essa 
ocorrência, a saída tem seu nível lógico alterado e o 
contador é zerado para recomeçar uma nova contagem. 
Portanto, o estado do LED muda a cada 64μs x 125 x 125 = 
1 segundo. 
#INT_TIMER0 
Indica ao compilador que a próxima função é a rotina de 
tratamento para a interrupção 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 período de estouro 
ser de 131 a 256, ou seja, 125. A função “get_timer0()” serve 
para aumentar a precisão da contagem, pois a função 
“set_timer0(131+get_timer0());” não é executada exatamente 
no momento do estouro. Existe um pequeno intervalo de 
tempo entre o estouro e a execução da rotina de 
tratamento, denominado “tempo de latência da 
interrupção”. Supõe-se que esse pequeno intervalo 
corresponde a 4 incrementos do Timer0. Se não houvesse 
a função “get_timer0()”, o Timer0 seria carregado com o 
valor 131, porém 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 cálculo realizado. O uso de “get_timer0()” implica que o 
valor carregado seja 135 e a contagem até o próximo 
estouro seja de 121 incrementos. Esse intervalo mais o 
tempo de latência ocasionam 125 incrementos entre 
estouros. 
if(++cont==125){ 
 
29
Teste que indica se passaram 125 incrementos da variável 
“conta” desde a última alteração da saída. 
setup_timer_0(RTCC_INTERNAL|RTCC_DIV_64); 
Configura o clock interno como fonte de contagem e o 
prescaler com 64, além de habilitar o funcionamento do 
Timer0. Entretanto, a interrupção só ocorrerá se for 
habilitada, o que é feito na próxima função.
enable_interrupts(GLOBAL|INT_TIMER0); 
Habilita a interrupção referente ao estouro do Timer0.
Figura 14 – Comportamento temporal do Timer0 e cont para esse 
exemplo
 
30
Apêndice:
• Tabela ASCII:
Quando se utiliza a comunicação serial os caracteres 
enviados entre dispositivos são codificados de acordo com a 
tabela ASCII, enviando-se o valor binário correspondente ao 
caractere desejado.
Figura 15 – Tabela de símbolos ASCII e seus respectivos valores em 
decimal, octal e hexadecimal
• Pinagem PIC 16f628 e 16f876a
Podemos extrair inúmeras informações do dispositivo olhando 
somente para a configuração de pinos.
 VDD/VSS
Pinos utilizados para a alimentação do dispositivo, sendo 
VDD a alimentação positiva e VSS a alimentação negativa. Deve 
ser verificado sempre a tensão a ser utilizada. Normamlemte 
essa pode ser de 2.2 V a 5.5 V, porém alguns modelos não 
podem ultrapassar um valor máximo de 3.6 V. 
 VPP/MCLR
Pino ativação do chip. Este só estará ligado se a tensão 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
#: "Posição" do pino no port. Comumente vemos números de 0 
a 7, formando os ports de 8 bits (0 a 7).
Os pinos com essa nomenclatura são utilizados como entradas 
e/ou saídas digitais. Deve-se consultar quais destes podem ser 
utilizados como entrada ou saída. Como exemplo o pino RA5 do 
PIC 16f628 pode ser utilizado somente como entrada.
 RX/TX:
Pinos ligados à comunicação serial (RS232), diretamente ligados 
ao periférico UART ou USART, que tira a carga da comunicação 
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 são utilizados como canais de 
conversão A/D, sendo # o número do canal.
 VREF+/VREF-
Estes pinos são utilizados para definir limeites superiores e 
inferiores à conversão A/D, respectivamente. Se fizermos VREF+ 
= 3V e VREF-=1V, somente valores analógicos entre 1 e 3 V 
serão considerados, e toda a resolucão será concentrada nesse 
intervalo, de modo que para uma conversão 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 são 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 periférico 
captura/comparação/PWM, sendo sua função configurada por 
software para gerar um sinal de frequência fixa e tempo 
alto/baixo variáveis(PWM), guardar o valor de contagem do 
timer associado com um estímulo externo(captura) e controlar o 
pino associado quando o contador chegar ao valor 
desejado(comparação).
 SS/SCK/SDI/SDO
Pinos associados à comunicação SPI, sendo SS (slave select) o 
pino de seleção do dispositivo a transmitir, SCL o pino de clock 
 
32
compartilhado, SDI e SDO os canais de recebimento e 
transimssão, respectivamente.
 SDA/SCL
Pinos associados à comunicação I2C, sendo SCL o pino de clock 
compartilhado e SDA o pino de comunicação bidirecional.
 CK/DT
Os pinos CK e DT são utilizados para comunicar-se pela USART 
de forma síncrona, sendo CK o clock e DT o canal de dados.
 PGC/PGD/PGM
Pinos associados à gravação do chip. Em PGC deve ser 
fornecido o clock, em PGD os dados a serem programados e 
PGM é utilizado somente para gravação de baixa tensão.
 INT
Pino utilizado para a interrupção externa. Se houver uma variação 
nesse pino a rotina de interrupção é engatilhada.
FIN.
 
33

Continue navegando