SlideShare uma empresa Scribd logo
1 de 33
Baixar para ler offline
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-----//

//--Programa Esqueleto-----//

#include <16F628A.h>
#fuses INTRC_IO, NOMCLR
#use delay(clock=4000000)

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

#use fast_io(a)
#use fast_io(b)

#use fast_io(a)
#use fast_io(b)
#use fast_io(c)

void main(void){
set_tris_a(0b11111111);
set_tris_b(0xff);

void main(void){
set_tris_a(0b11111111);
set_tris_b(0xff);
set_tris_c(0xff);

while(true){
}

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)

Configura todos 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 --------

while(true){
output_bit(pin_a0,flag);
delay_ms(500);
flag=!flag;
}

#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)

9
#use fast_io(a)
#use fast_io(b)
#use fast_io(c)

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

void main(void){
set_tris_a(0b11111110);
set_tris_b(0xff);
set_tris_c(0xff);

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

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 picoampé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-se reduzir 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)

set_tris_b(0xff);
set_tris_c(0xff);
while(true){
if(input(pin_c4))
output_high(pin_a0);
else
output_low(pin_a0);
}

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

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

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)

}}
#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;
}}}

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();

//--------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);

}

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);
}

lcd_init();
printf(lcd_putc,"fCurso de uC PIC ");
printf(lcd_putc,"nPET-EngElet.Ufes”);

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

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)

lcd_init();
printf(lcd_putc,"f Voltimetro
");
printf(lcd_putc,"nPETEngElet.Ufes");
esp(2000);
output_high(pin_c7);

#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;

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);
}
}

set_tris_a(0b11111111);
set_tris_c(0b01111111);
setup_adc_ports(ALL_ANALOG);
setup_adc(ADC_CLOCK_INTERN
AL);
set_adc_channel(0);

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

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 V REFH 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);

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);
}

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)

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: ");

short flag=1;
char dado=‘k’;

while(true){
if(flag){
printf(lcd_putc,"n %c",dado);
flag=0;
}

#INT_RDA
void trata_int_rx(void){
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 pulldown, 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. Quando
se 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 (=256150), 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 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 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+/VREFEstes pinos são utilizados para definir limeites superiores e
inferiores à conversão A/D, respectivamente. Se fizermos V REF+
= 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

Mais conteúdo relacionado

Mais procurados

Apresentação pic
Apresentação picApresentação pic
Apresentação picSaddam Lande
 
Microcontroladores pic
Microcontroladores picMicrocontroladores pic
Microcontroladores picCesar Prim
 
Aula 1 - Assembly - 8051
Aula 1 - Assembly - 8051Aula 1 - Assembly - 8051
Aula 1 - Assembly - 8051Thiago Oliveira
 
Material Auxiliar Para Curso BáSico Msp430 1 A 54
Material Auxiliar Para Curso BáSico Msp430   1 A 54Material Auxiliar Para Curso BáSico Msp430   1 A 54
Material Auxiliar Para Curso BáSico Msp430 1 A 54Texas Instruments
 
Resumo linguagem c para microcontroladores PIC usando MikroC
Resumo linguagem c para microcontroladores PIC usando MikroCResumo linguagem c para microcontroladores PIC usando MikroC
Resumo linguagem c para microcontroladores PIC usando MikroCFabio Souza
 
Material Auxiliar Para Curso BáSico Msp430 55 A 98
Material Auxiliar Para Curso BáSico Msp430   55 A 98Material Auxiliar Para Curso BáSico Msp430   55 A 98
Material Auxiliar Para Curso BáSico Msp430 55 A 98Texas Instruments
 
Clp varios modelos
Clp varios modelosClp varios modelos
Clp varios modelosdetectfelix
 
8085 Introducao
8085 Introducao8085 Introducao
8085 Introducaoedgluc2001
 
15507933 apostila-de-cl ps-ladder
15507933 apostila-de-cl ps-ladder15507933 apostila-de-cl ps-ladder
15507933 apostila-de-cl ps-ladderelkbongg
 
38698469 slides-arduino
38698469 slides-arduino38698469 slides-arduino
38698469 slides-arduinoRui Alves
 
2ª SATEC - SENAI - Arduino + CLP + Maquina de estados
2ª SATEC - SENAI - Arduino + CLP + Maquina de estados2ª SATEC - SENAI - Arduino + CLP + Maquina de estados
2ª SATEC - SENAI - Arduino + CLP + Maquina de estadosHamilton Sena
 

Mais procurados (20)

Apresentação pic
Apresentação picApresentação pic
Apresentação pic
 
Microcontroladores pic
Microcontroladores picMicrocontroladores pic
Microcontroladores pic
 
Aula 1 - Assembly - 8051
Aula 1 - Assembly - 8051Aula 1 - Assembly - 8051
Aula 1 - Assembly - 8051
 
Programando microcontroladores pic março
Programando microcontroladores pic marçoProgramando microcontroladores pic março
Programando microcontroladores pic março
 
Roteiro exp9
Roteiro exp9Roteiro exp9
Roteiro exp9
 
HC11
HC11HC11
HC11
 
Pic aula1
Pic   aula1Pic   aula1
Pic aula1
 
Seminario pic
Seminario picSeminario pic
Seminario pic
 
Curso clp siemens
Curso clp siemensCurso clp siemens
Curso clp siemens
 
Material Auxiliar Para Curso BáSico Msp430 1 A 54
Material Auxiliar Para Curso BáSico Msp430   1 A 54Material Auxiliar Para Curso BáSico Msp430   1 A 54
Material Auxiliar Para Curso BáSico Msp430 1 A 54
 
Resumo linguagem c para microcontroladores PIC usando MikroC
Resumo linguagem c para microcontroladores PIC usando MikroCResumo linguagem c para microcontroladores PIC usando MikroC
Resumo linguagem c para microcontroladores PIC usando MikroC
 
Resumo x86
Resumo x86Resumo x86
Resumo x86
 
Material Auxiliar Para Curso BáSico Msp430 55 A 98
Material Auxiliar Para Curso BáSico Msp430   55 A 98Material Auxiliar Para Curso BáSico Msp430   55 A 98
Material Auxiliar Para Curso BáSico Msp430 55 A 98
 
Clp varios modelos
Clp varios modelosClp varios modelos
Clp varios modelos
 
8085 Introducao
8085 Introducao8085 Introducao
8085 Introducao
 
15507933 apostila-de-cl ps-ladder
15507933 apostila-de-cl ps-ladder15507933 apostila-de-cl ps-ladder
15507933 apostila-de-cl ps-ladder
 
38698469 slides-arduino
38698469 slides-arduino38698469 slides-arduino
38698469 slides-arduino
 
8085 3
8085 38085 3
8085 3
 
2ª SATEC - SENAI - Arduino + CLP + Maquina de estados
2ª SATEC - SENAI - Arduino + CLP + Maquina de estados2ª SATEC - SENAI - Arduino + CLP + Maquina de estados
2ª SATEC - SENAI - Arduino + CLP + Maquina de estados
 
Clp
ClpClp
Clp
 

Semelhante a Pic apostila

Clp completa
Clp completaClp completa
Clp completapanelada
 
Pcs2031 projeto01 introducao_pic_v4
Pcs2031 projeto01 introducao_pic_v4Pcs2031 projeto01 introducao_pic_v4
Pcs2031 projeto01 introducao_pic_v4Flávia Martins
 
Microcontroladores pic lingc unicamp-150206140414-conversion-gate02
Microcontroladores pic lingc unicamp-150206140414-conversion-gate02Microcontroladores pic lingc unicamp-150206140414-conversion-gate02
Microcontroladores pic lingc unicamp-150206140414-conversion-gate02Cláudio Alves
 
1 história e características dos microcontroladores pic
1 história e características dos microcontroladores pic1 história e características dos microcontroladores pic
1 história e características dos microcontroladores picAnderson Inácio Morais
 
Microcontroladores PIC.pptx
Microcontroladores PIC.pptxMicrocontroladores PIC.pptx
Microcontroladores PIC.pptxfmtpereira
 
Apostila controladores ladder (1)
Apostila controladores ladder (1)Apostila controladores ladder (1)
Apostila controladores ladder (1)Duilho Silva
 
Apostila controladores ladder
Apostila controladores ladderApostila controladores ladder
Apostila controladores ladderCarlos Melo
 
Apostila controladores ladder
Apostila controladores ladderApostila controladores ladder
Apostila controladores ladderMaycon Vinicius
 
Introdução ao Arduino
Introdução ao ArduinoIntrodução ao Arduino
Introdução ao Arduinoelliando dias
 
Apostila - Tutorial Arduino (Básico).PDF
Apostila - Tutorial Arduino (Básico).PDFApostila - Tutorial Arduino (Básico).PDF
Apostila - Tutorial Arduino (Básico).PDFengelrfs
 
201728 22259 manual_picgenios
201728 22259 manual_picgenios201728 22259 manual_picgenios
201728 22259 manual_picgeniosBárbara Gama
 
Curso microcontroladores pic no mp lab 8
Curso microcontroladores pic no mp lab 8Curso microcontroladores pic no mp lab 8
Curso microcontroladores pic no mp lab 8RogerMasters
 
Curso clp siemens
Curso clp siemensCurso clp siemens
Curso clp siemensSENAI SP
 
Aula 004 noções de hardware
Aula 004   noções de hardwareAula 004   noções de hardware
Aula 004 noções de hardwareFlávio Freitas
 

Semelhante a Pic apostila (20)

Clp completa
Clp completaClp completa
Clp completa
 
Pcs2031 projeto01 introducao_pic_v4
Pcs2031 projeto01 introducao_pic_v4Pcs2031 projeto01 introducao_pic_v4
Pcs2031 projeto01 introducao_pic_v4
 
Microcontroladores pic lingc unicamp-150206140414-conversion-gate02
Microcontroladores pic lingc unicamp-150206140414-conversion-gate02Microcontroladores pic lingc unicamp-150206140414-conversion-gate02
Microcontroladores pic lingc unicamp-150206140414-conversion-gate02
 
Introducao clp
Introducao clpIntroducao clp
Introducao clp
 
Introducao clp
Introducao clpIntroducao clp
Introducao clp
 
1 história e características dos microcontroladores pic
1 história e características dos microcontroladores pic1 história e características dos microcontroladores pic
1 história e características dos microcontroladores pic
 
Microcontroladores PIC.pptx
Microcontroladores PIC.pptxMicrocontroladores PIC.pptx
Microcontroladores PIC.pptx
 
ApresPP.pptx
ApresPP.pptxApresPP.pptx
ApresPP.pptx
 
Apostila controladores ladder (1)
Apostila controladores ladder (1)Apostila controladores ladder (1)
Apostila controladores ladder (1)
 
Apostila controladores ladder
Apostila controladores ladderApostila controladores ladder
Apostila controladores ladder
 
Apostila controladores ladder
Apostila controladores ladderApostila controladores ladder
Apostila controladores ladder
 
Introdução ao Arduino
Introdução ao ArduinoIntrodução ao Arduino
Introdução ao Arduino
 
Apostila - Tutorial Arduino (Básico).PDF
Apostila - Tutorial Arduino (Básico).PDFApostila - Tutorial Arduino (Básico).PDF
Apostila - Tutorial Arduino (Básico).PDF
 
Corpo relatorio
Corpo relatorioCorpo relatorio
Corpo relatorio
 
201728 22259 manual_picgenios
201728 22259 manual_picgenios201728 22259 manual_picgenios
201728 22259 manual_picgenios
 
Curso microcontroladores pic no mp lab 8
Curso microcontroladores pic no mp lab 8Curso microcontroladores pic no mp lab 8
Curso microcontroladores pic no mp lab 8
 
Clp
ClpClp
Clp
 
Curso clp siemens
Curso clp siemensCurso clp siemens
Curso clp siemens
 
Basico sobre clp
Basico sobre clpBasico sobre clp
Basico sobre clp
 
Aula 004 noções de hardware
Aula 004   noções de hardwareAula 004   noções de hardware
Aula 004 noções de hardware
 

Último

ABRIL VERDE.pptx Slide sobre abril ver 2024
ABRIL VERDE.pptx Slide sobre abril ver 2024ABRIL VERDE.pptx Slide sobre abril ver 2024
ABRIL VERDE.pptx Slide sobre abril ver 2024Jeanoliveira597523
 
CRÔNICAS DE UMA TURMA - TURMA DE 9ºANO - EASB
CRÔNICAS DE UMA TURMA - TURMA DE 9ºANO - EASBCRÔNICAS DE UMA TURMA - TURMA DE 9ºANO - EASB
CRÔNICAS DE UMA TURMA - TURMA DE 9ºANO - EASBAline Santana
 
Pedologia- Geografia - Geologia - aula_01.pptx
Pedologia- Geografia - Geologia - aula_01.pptxPedologia- Geografia - Geologia - aula_01.pptx
Pedologia- Geografia - Geologia - aula_01.pptxleandropereira983288
 
Nova BNCC Atualizada para novas pesquisas
Nova BNCC Atualizada para novas pesquisasNova BNCC Atualizada para novas pesquisas
Nova BNCC Atualizada para novas pesquisasraveccavp
 
RedacoesComentadasModeloAnalisarFazer.pdf
RedacoesComentadasModeloAnalisarFazer.pdfRedacoesComentadasModeloAnalisarFazer.pdf
RedacoesComentadasModeloAnalisarFazer.pdfAlissonMiranda22
 
UFCD_10392_Intervenção em populações de risco_índice .pdf
UFCD_10392_Intervenção em populações de risco_índice .pdfUFCD_10392_Intervenção em populações de risco_índice .pdf
UFCD_10392_Intervenção em populações de risco_índice .pdfManuais Formação
 
GÊNERO TEXTUAL - TIRINHAS - Charges - Cartum
GÊNERO TEXTUAL - TIRINHAS - Charges - CartumGÊNERO TEXTUAL - TIRINHAS - Charges - Cartum
GÊNERO TEXTUAL - TIRINHAS - Charges - CartumAugusto Costa
 
E agora?! Já não avalio as atitudes e valores?
E agora?! Já não avalio as atitudes e valores?E agora?! Já não avalio as atitudes e valores?
E agora?! Já não avalio as atitudes e valores?Rosalina Simão Nunes
 
“Sobrou pra mim” - Conto de Ruth Rocha.pptx
“Sobrou pra mim” - Conto de Ruth Rocha.pptx“Sobrou pra mim” - Conto de Ruth Rocha.pptx
“Sobrou pra mim” - Conto de Ruth Rocha.pptxthaisamaral9365923
 
Modelos de Desenvolvimento Motor - Gallahue, Newell e Tani
Modelos de Desenvolvimento Motor - Gallahue, Newell e TaniModelos de Desenvolvimento Motor - Gallahue, Newell e Tani
Modelos de Desenvolvimento Motor - Gallahue, Newell e TaniCassio Meira Jr.
 
AD2 DIDÁTICA.KARINEROZA.SHAYANNE.BINC.ROBERTA.pptx
AD2 DIDÁTICA.KARINEROZA.SHAYANNE.BINC.ROBERTA.pptxAD2 DIDÁTICA.KARINEROZA.SHAYANNE.BINC.ROBERTA.pptx
AD2 DIDÁTICA.KARINEROZA.SHAYANNE.BINC.ROBERTA.pptxkarinedarozabatista
 
Manual da CPSA_1_Agir com Autonomia para envio
Manual da CPSA_1_Agir com Autonomia para envioManual da CPSA_1_Agir com Autonomia para envio
Manual da CPSA_1_Agir com Autonomia para envioManuais Formação
 
ATIVIDADE AVALIATIVA VOZES VERBAIS 7º ano.pptx
ATIVIDADE AVALIATIVA VOZES VERBAIS 7º ano.pptxATIVIDADE AVALIATIVA VOZES VERBAIS 7º ano.pptx
ATIVIDADE AVALIATIVA VOZES VERBAIS 7º ano.pptxOsnilReis1
 
Música Meu Abrigo - Texto e atividade
Música   Meu   Abrigo  -   Texto e atividadeMúsica   Meu   Abrigo  -   Texto e atividade
Música Meu Abrigo - Texto e atividadeMary Alvarenga
 
Programa de Intervenção com Habilidades Motoras
Programa de Intervenção com Habilidades MotorasPrograma de Intervenção com Habilidades Motoras
Programa de Intervenção com Habilidades MotorasCassio Meira Jr.
 
A horta do Senhor Lobo que protege a sua horta.
A horta do Senhor Lobo que protege a sua horta.A horta do Senhor Lobo que protege a sua horta.
A horta do Senhor Lobo que protege a sua horta.silves15
 
COMPETÊNCIA 1 DA REDAÇÃO DO ENEM - REDAÇÃO ENEM
COMPETÊNCIA 1 DA REDAÇÃO DO ENEM - REDAÇÃO ENEMCOMPETÊNCIA 1 DA REDAÇÃO DO ENEM - REDAÇÃO ENEM
COMPETÊNCIA 1 DA REDAÇÃO DO ENEM - REDAÇÃO ENEMVanessaCavalcante37
 
Gerenciando a Aprendizagem Organizacional
Gerenciando a Aprendizagem OrganizacionalGerenciando a Aprendizagem Organizacional
Gerenciando a Aprendizagem OrganizacionalJacqueline Cerqueira
 

Último (20)

ABRIL VERDE.pptx Slide sobre abril ver 2024
ABRIL VERDE.pptx Slide sobre abril ver 2024ABRIL VERDE.pptx Slide sobre abril ver 2024
ABRIL VERDE.pptx Slide sobre abril ver 2024
 
CRÔNICAS DE UMA TURMA - TURMA DE 9ºANO - EASB
CRÔNICAS DE UMA TURMA - TURMA DE 9ºANO - EASBCRÔNICAS DE UMA TURMA - TURMA DE 9ºANO - EASB
CRÔNICAS DE UMA TURMA - TURMA DE 9ºANO - EASB
 
XI OLIMPÍADAS DA LÍNGUA PORTUGUESA -
XI OLIMPÍADAS DA LÍNGUA PORTUGUESA      -XI OLIMPÍADAS DA LÍNGUA PORTUGUESA      -
XI OLIMPÍADAS DA LÍNGUA PORTUGUESA -
 
Pedologia- Geografia - Geologia - aula_01.pptx
Pedologia- Geografia - Geologia - aula_01.pptxPedologia- Geografia - Geologia - aula_01.pptx
Pedologia- Geografia - Geologia - aula_01.pptx
 
Nova BNCC Atualizada para novas pesquisas
Nova BNCC Atualizada para novas pesquisasNova BNCC Atualizada para novas pesquisas
Nova BNCC Atualizada para novas pesquisas
 
RedacoesComentadasModeloAnalisarFazer.pdf
RedacoesComentadasModeloAnalisarFazer.pdfRedacoesComentadasModeloAnalisarFazer.pdf
RedacoesComentadasModeloAnalisarFazer.pdf
 
UFCD_10392_Intervenção em populações de risco_índice .pdf
UFCD_10392_Intervenção em populações de risco_índice .pdfUFCD_10392_Intervenção em populações de risco_índice .pdf
UFCD_10392_Intervenção em populações de risco_índice .pdf
 
GÊNERO TEXTUAL - TIRINHAS - Charges - Cartum
GÊNERO TEXTUAL - TIRINHAS - Charges - CartumGÊNERO TEXTUAL - TIRINHAS - Charges - Cartum
GÊNERO TEXTUAL - TIRINHAS - Charges - Cartum
 
E agora?! Já não avalio as atitudes e valores?
E agora?! Já não avalio as atitudes e valores?E agora?! Já não avalio as atitudes e valores?
E agora?! Já não avalio as atitudes e valores?
 
“Sobrou pra mim” - Conto de Ruth Rocha.pptx
“Sobrou pra mim” - Conto de Ruth Rocha.pptx“Sobrou pra mim” - Conto de Ruth Rocha.pptx
“Sobrou pra mim” - Conto de Ruth Rocha.pptx
 
Em tempo de Quaresma .
Em tempo de Quaresma                            .Em tempo de Quaresma                            .
Em tempo de Quaresma .
 
Modelos de Desenvolvimento Motor - Gallahue, Newell e Tani
Modelos de Desenvolvimento Motor - Gallahue, Newell e TaniModelos de Desenvolvimento Motor - Gallahue, Newell e Tani
Modelos de Desenvolvimento Motor - Gallahue, Newell e Tani
 
AD2 DIDÁTICA.KARINEROZA.SHAYANNE.BINC.ROBERTA.pptx
AD2 DIDÁTICA.KARINEROZA.SHAYANNE.BINC.ROBERTA.pptxAD2 DIDÁTICA.KARINEROZA.SHAYANNE.BINC.ROBERTA.pptx
AD2 DIDÁTICA.KARINEROZA.SHAYANNE.BINC.ROBERTA.pptx
 
Manual da CPSA_1_Agir com Autonomia para envio
Manual da CPSA_1_Agir com Autonomia para envioManual da CPSA_1_Agir com Autonomia para envio
Manual da CPSA_1_Agir com Autonomia para envio
 
ATIVIDADE AVALIATIVA VOZES VERBAIS 7º ano.pptx
ATIVIDADE AVALIATIVA VOZES VERBAIS 7º ano.pptxATIVIDADE AVALIATIVA VOZES VERBAIS 7º ano.pptx
ATIVIDADE AVALIATIVA VOZES VERBAIS 7º ano.pptx
 
Música Meu Abrigo - Texto e atividade
Música   Meu   Abrigo  -   Texto e atividadeMúsica   Meu   Abrigo  -   Texto e atividade
Música Meu Abrigo - Texto e atividade
 
Programa de Intervenção com Habilidades Motoras
Programa de Intervenção com Habilidades MotorasPrograma de Intervenção com Habilidades Motoras
Programa de Intervenção com Habilidades Motoras
 
A horta do Senhor Lobo que protege a sua horta.
A horta do Senhor Lobo que protege a sua horta.A horta do Senhor Lobo que protege a sua horta.
A horta do Senhor Lobo que protege a sua horta.
 
COMPETÊNCIA 1 DA REDAÇÃO DO ENEM - REDAÇÃO ENEM
COMPETÊNCIA 1 DA REDAÇÃO DO ENEM - REDAÇÃO ENEMCOMPETÊNCIA 1 DA REDAÇÃO DO ENEM - REDAÇÃO ENEM
COMPETÊNCIA 1 DA REDAÇÃO DO ENEM - REDAÇÃO ENEM
 
Gerenciando a Aprendizagem Organizacional
Gerenciando a Aprendizagem OrganizacionalGerenciando a Aprendizagem Organizacional
Gerenciando a Aprendizagem Organizacional
 

Pic apostila

  • 1. 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
  • 2. 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
  • 3. 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
  • 4. 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
  • 5. 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
  • 6. 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
  • 7. Figura 4 – Fluxo básico de um programa embarcado Pode-se adotar como softwares iniciais: //--Programa Esqueleto-----// //--Programa Esqueleto-----// #include <16F628A.h> #fuses INTRC_IO, NOMCLR #use delay(clock=4000000) #include <16F876A.h> #fuses XT #use delay(clock=4000000) #use fast_io(a) #use fast_io(b) #use fast_io(a) #use fast_io(b) #use fast_io(c) void main(void){ set_tris_a(0b11111111); set_tris_b(0xff); void main(void){ set_tris_a(0b11111111); set_tris_b(0xff); set_tris_c(0xff); while(true){ } 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
  • 8. 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) Configura todos 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
  • 9. 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 -------- while(true){ output_bit(pin_a0,flag); delay_ms(500); flag=!flag; } #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) 9
  • 10. #use fast_io(a) #use fast_io(b) #use fast_io(c) while(true){ output_high(pin_a0); delay_ms(500); output_low(pin_a0); delay_ms(500); } void main(void){ set_tris_a(0b11111110); set_tris_b(0xff); set_tris_c(0xff); } //-------------------------// 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 picoampé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
  • 11. 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
  • 12. “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
  • 13. comum) deve-se reduzir 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) set_tris_b(0xff); set_tris_c(0xff); while(true){ if(input(pin_c4)) output_high(pin_a0); else output_low(pin_a0); } #use fast_io(a) #use fast_io(b) #use fast_io(c) void main(void){ set_tris_a(0b11111110); /--------------------------------------------------------------- Explanação: input(pin_c4); 13
  • 14. 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
  • 15. 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) }} #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; }}} 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(); //--------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
  • 16. #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); } 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); } lcd_init(); printf(lcd_putc,"fCurso de uC PIC "); printf(lcd_putc,"nPET-EngElet.Ufes”); //------------------------------------------------------------// 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
  • 17. “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
  • 18. 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) lcd_init(); printf(lcd_putc,"f Voltimetro "); printf(lcd_putc,"nPETEngElet.Ufes"); esp(2000); output_high(pin_c7); #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; 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); } } set_tris_a(0b11111111); set_tris_c(0b01111111); setup_adc_ports(ALL_ANALOG); setup_adc(ADC_CLOCK_INTERN AL); set_adc_channel(0); //---------------------------------------------------------------------// 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
  • 19. 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 V REFH 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
  • 20. 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
  • 21. 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
  • 22. 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
  • 23. 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); 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); } 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) 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: "); short flag=1; char dado=‘k’; while(true){ if(flag){ printf(lcd_putc,"n %c",dado); flag=0; } #INT_RDA void trata_int_rx(void){ 23
  • 24. } } //--------------------------------------------------------------------// 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 pulldown, 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
  • 25. 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
  • 26. 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. Quando se 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
  • 27. 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 (=256150), 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
  • 28. 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 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 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
  • 29. 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
  • 30. 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
  • 31. 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
  • 32.          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+/VREFEstes pinos são utilizados para definir limeites superiores e inferiores à conversão A/D, respectivamente. Se fizermos V REF+ = 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
  • 33.    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