Prévia do material em texto
UNIALFA – Prof. Eduardo J. Nogueira
1
UNIALFA – Prof. Eduardo J. Nogueira
2
CONVERSOR AD INTERNO DOS MICROCONTROLADORES
PIC
Introdução
Os conversores A/D padrão dos microcontroladores PIC têm uma resolu-
ção máxima de 10 bits, sendo que o clock pode ser selecionado pelo usuário e
utilizam a técnica de aproximação sucessiva para a conversão.
Nesta apostila vamos utilizar como exemplo o PIC 16F877A, mas as in-
formações fornecidas se aplicam a qualquer microcontrolador das linhas 12 ou
16 que possuam conversor AD interno.
O microcontrolador PIC 16F877A tem um total de 8 entradas para conver-
são de um sinal analógico para digital e estas podem ser configurados conforme
a tabela abaixo através do registrador ADCON1.
UNIALFA – Prof. Eduardo J. Nogueira
3
Verificamos na tabela também as tensões de referência (VREF+ e VREF-).
Nesta configuração, a tensão nos pinos configurados será comparada com as
tensões de referência, sendo que se a tensão aplicada for igual à tensão de re-
ferência VREF+, o resultado da conversão será o máximo (1024) e quando a
tensão de entrada for igual a VREF-, o resultado será 0.
As referências podem ser internas (VDD e VSS) ou externas que são co-
nectadas aos pinos RA2 (VREF-) e RA3 (VREF+).
Temos abaixo uma tabela com os limites elétricos das tensões de referên-
cia. Estes valores precisam ser respeitados:
Processo de conversão
Os microcontroladores PIC utilizam internamente um processo de conver-
são conhecido com Sample and Hold (S/H) para evitar problemas de ruído e
variações na entrada analógica. Este processo consiste na amostra do sinal e o
congelamento do seu valor.
No PIC, internamente, existe um capacitor (120pF) ligado ao canal analó-
gico que fica carregado com a tensão existente no canal em uso (amostra) e
quando o processo de conversão é iniciado, este capacitor é desligado automa-
ticamente do canal analógico e o valor carregado é mantido (congelado) e a ten-
são utilizada no processo de conversão é a tensão existente no capacitor e não
mais a tensão existente no canal analógico. Este processo faz com que a tensão
seja mantida durante a conversão mesmo que a tensão externa (no canal ana-
lógico) varie.
Configuração
SETUP_ADC () // configura o conversor AD interno.
UNIALFA – Prof. Eduardo J. Nogueira
4
Sintaxe:
SETUP_ADC(opções); // opções é uma variável ou constante inteira de 8 bits.
Exemplo:
SETUP_ADC(ADC_OFF);
As opções podem variar de acordo com o microcontrolador utilizado. Para
sabermos mais detalhes vamos verificar o arquivo header para o microcontrola-
dor PIC16F877A. Podemos encontrá-lo, geralmente, em ‘C:\Arquivos de Progra-
mas\PICC\Devices\16F877A.h’, dependendo da pasta onde foi instalado o PCW.
Vamos analisar somente a parte que configura o conversor AD....essa
parte se encontra na linha 232 do arquivo 16F877A.h.
Podemos verificar que as opções disponíveis para o PIC 16F877A são:
SETUP_ADC_PORTS() //Configura as entradas analógicas do conversor AD
//interno.
Sintaxe:
UNIALFA – Prof. Eduardo J. Nogueira
5
SETUP_ADC_PORTS(opções); //opções é uma variável ou constante inteira
//de 8 bits.
Essas opções também podem ser encontradas no arquivo header de cada
microcontrolador. Aqui exemplificamos para o PIC 16F877A.
Temos abaixo uma tabela com as opções válidas:
SET_ADC_CHANNEL() //Seleciona um canal de entrada para o módulo AD.
Sintaxe:
SET_ADC_CHANNEL(canal); //Onde: canal é uma variável inteira de 8 bits.
Exemplo:
SET_ADC_CHANNEL(0); //Configura o canal 0 como analógico.
READ_ADC() //Inicia a conversão AD e somente retorna o valor após o ciclo
//de conversão.
Sintaxe:
ad = READ_ADC(); //Guarda o valor lido na variável ad.
Onde: ad é uma variável inteira de 8 ou 16 bits.
UNIALFA – Prof. Eduardo J. Nogueira
6
Podemos utilizar também a diretiva #device ADC = x para especificar o
número (x) de bits que a função READ_ADC() retornará.
Vamos fazer um exemplo onde o valor de uma conversão será mostrado
no display LCD. Para isso nosso programa fará a leitura do canal analógico 0
onde está conectado um trimpot (para variação da tensão a ser convertida, assim
a tensão na entrada do canal 0 poderá variar de o a +5V.
Circuito utilizado para o programa de conversão A/D
Definições do Projeto:
Nome do Projeto: ADC
Arquivo principal: ADC.c
RA0/AN0
2
RA1/AN1
3
RA2/AN2/VREF-/CVREF
4
RA4/T0CKI/C1OUT
6
RA5/AN4/SS/C2OUT
7
RE0/AN5/RD
8
RE1/AN6/WR
9
RE2/AN7/CS
10
OSC1/CLKIN
13
OSC2/CLKOUT
14
RC1/T1OSI/CCP2
16
RC2/CCP1
17
RC3/SCK/SCL
18
RD0/PSP0
19
RD1/PSP1
20
RB7/PGD
40
RB6/PGC
39
RB5
38
RB4
37
RB3/PGM
36
RB2
35
RB1
34
RB0/INT
33
RD7/PSP7
30
RD6/PSP6
29
RD5/PSP5
28
RD4/PSP4
27
RD3/PSP3
22
RD2/PSP2
21
RC7/RX/DT
26
RC6/TX/CK
25
RC5/SDO
24
RC4/SDI/SDA
23
RA3/AN3/VREF+
5
RC0/T1OSO/T1CKI
15
MCLR/Vpp/THV
1
U1
PIC16F877A
D
7
1
4
D
6
1
3
D
5
1
2
D
4
1
1
D
3
1
0
D
2
9
D
1
8
D
0
7
E
6
R
W
5
R
S
4
V
S
S
1
V
D
D
2
V
E
E
3
LCD1
LM016L
R1
4k7
5
2
%
1
2
3
RV1
10k
5
0
%
1
2
3
RV2
10k
Volts
+2.50
UNIALFA – Prof. Eduardo J. Nogueira
7
Código fonte do programa ADC.c escrito no PCW.
Neste programa também utilizamos a biblioteca criada pela ACEPIC para
acesso ao LCD, note a inclusão na linha 9.
#include "LCD8B.c" //Diretiva de inclusão do arquivo LCD8B.c ao projeto
Veja o código escrito no PCW na próxima página.
Bem, como fizemos a inclusão, então é interessante que este arquivo
(LCD8B.c) esteja também na mesma pasta em que criamos nosso projeto. Caso
contrário, precisaríamos dar o caminho completo na diretiva #include.
Ex:
#include "C:\PROJETOS\LCD_PRO\LCD8B.c" //Diretiva de inclusão do
//arquivo LCD8B.c ao projeto
8
UNIALFA – Prof. Eduardo J. Nogueira
8
UNIALFA – Prof. Eduardo J. Nogueira
9
Código do LCD8B.c na janela de edição do PCW.
Função printf
Neste exemplo a função printf foi utilizada com uma formatação diferente
da que utilizamos na comunicação serial, neste caso especificamos que o con-
teúdo da variável ad deve ser impresso no formato inteiro longo (long int).
Ex: Linha 26 do código ADC1.c.
printf(lcd_escreve,"\fADC = %lu",ad); //Mostra a mensagem 'ADC =' + o valor //da
conversão.
Temos a seguir uma tabela com algumas apresentações de valores e
seus tipos para a formatação da saída. Esta formatação serve para toda vez que
a função printf for utilizada, para escrever no LCD ou para comunicação serial
ou em outra circunstância qualquer.
UNIALFA – Prof. Eduardo J. Nogueira
10
Utilização de mais de um conversor AD
Neste próximo exemplo, faremos a leitura dos canais analógicos 0, 1 e 3,
sendo que o canal 3 está conectado ao sensor de temperatura LM35. A ventoi-
nha deverá ser ligada logo no início do programa e ao verificar o valor da con-
versão AD no canal 3 menor ou igual a 55, deveremos acionar o aquecimento e
desligar a ventoinha e quando o valor da conversão AD no canal 3 for maior ou
igual a 80, desligaremos o aquecimento e ligaremos a ventoinha.
A ventoinha é acionada através do pino RC2 e o aquecedor através do
pino RC1, conforme esquema abaixo:
Definições do projeto
Nome do Projeto: ADC_Aq
Arquivo : ADC_Aq.c
RA0/AN0
2
RA1/AN1
3
RA2/AN2/VREF-/CVREF
4
RA4/T0CKI/C1OUT
6
RA5/AN4/SS/C2OUT
7
RE0/AN5/RD
8
RE1/AN6/WR
9
RE2/AN7/CS
10
OSC1/CLKIN
13
OSC2/CLKOUT
14
RC1/T1OSI/CCP2
16
RC2/CCP1
17
RC3/SCK/SCL
18
RD0/PSP0
19
RD1/PSP1
20
RB7/PGD
40
RB6/PGC
39
RB5
38
RB4
37
RB3/PGM
36
RB2
35
RB1
34
RB0/INT
33
RD7/PSP7
30
RD6/PSP6
29
RD5/PSP5
28
RD4/PSP4
27
RD3/PSP3
22
RD2/PSP2
21
RC7/RX/DT
26
RC6/TX/CK
25
RC5/SDO
24
RC4/SDI/SDA23
RA3/AN3/VREF+
5
RC0/T1OSO/T1CKI
15
MCLR/Vpp/THV
1
U1
PIC16F877A
D
7
1
4
D
6
1
3
D
5
1
2
D
4
1
1
D
3
1
0
D
2
9
D
1
8
D
0
7
E
6
R
W
5
R
S
4
V
S
S
1
V
D
D
2
V
E
E
3
LCD1
LM016L
R1
4k7
5
0
%
1
2
3
RV2
10k
23.0
3
1
VOUT
2
U2
LM35
+
1
2
V
R2
2k2
+
1
2
V
R3
56R
R4
2k2
5
2
%
1
2
3
RV1
10k
Q2
NPN
Q1
NPN
D1
UNIALFA – Prof. Eduardo J. Nogueira
11
Código escrito na janela de edição do PCW.
Videoaula sobre o conteúdo desta apostila:
https://youtu.be/gIr1LTXB39Y
https://youtu.be/gIr1LTXB39Y
UNIALFA – Prof. Eduardo J. Nogueira
12
Referências:
ACEPIC – Apostila de linguagem C, padrão CCS para PIC
LUZ, Carlos E. S. – Curso Linguagem C para microcontroladores PIC – Edição
do autor.
PEREIRA, Fábio - Microcontroladores PIC: Programação em C - Érica
UNIALFA – Prof. Eduardo J. Nogueira
13
Anexo 1
ADC_1.c
#include<16F877A.h> //Aqui é incluso o header (*.h) para o microcontrolador
//utilizado.
#device ADC = 10 //Define 10 bits para o resultado da conversão AD
#use delay (clock=8000000) //Aqui definimos a frequência do cristal para cálculo
//dos delays
#fuses HS, NOWDT, PUT, BROWNOUT, NOLVP //Configuração dos fusíveis
#include "LCD8B.c" //Diretiva de inclusão do arquivo LCD8B.c ao projeto
long int ad; //Variável para armazenamento da conversão
void main() //Função principal
{
lcd_ini(); /*Chamada à função lcd_ini()... Esta função é para a inicialização
do LCD e está no arquivo LCD8B.c*/
SETUP_ADC_PORTS(RA0_ANALOG); //Configurada a entrada analógica, so-
mente a
//entrada RA0
SETUP_ADC(ADC_CLOCK_INTERNAL); //Configurado o conversor AD in-
terno
SET_ADC_CHANNEL(0); //Configurado o canal de leitura 0
printf(lcd_escreve,"\f"); //Limpa lcd
printf(lcd_escreve,"\Microcontr."); //Escreve na primeira linha
printf(lcd_escreve,"\n UNIALFA "); //Escreve na segunda linha
delay_ms(1500); //Atraso de 1,5s
while(true) //Loop principal
{
ad = READ_ADC(); //Faz a conversão AD e a salva na variável ad
printf(lcd_escreve,"\fADC = %lu",ad); //Mostra a mensagem 'ADC =' + o
//valor da conversão
delay_ms(1000); //Atraso de 1s para mostrar a leitura
}
}
UNIALFA – Prof. Eduardo J. Nogueira
14
Anexo 2
ADC_2.c
#include<16F877A.h> //Aqui é incluso o header (*.h) para o microcontrolador
//utilizado.
#device ADC = 10 //Define 10 bits para o resultado da conversão AD
#use delay (clock=8000000) //Aqui definimos a frequência do cristal para
//cálculo dos delays
#fuses HS, NOWDT, PUT, BROWNOUT, NOLVP //Configuração dos fusíveis
#include "LCD8B.c" //Diretiva de inclusão do arquivo LCD8B.c ao projeto
long int ad0,ad1,ad3; //Variáves para armazenamento da conversão
void main() //Função principal
{
lcd_ini(); //Chama a função para inicialização do LCD
SETUP_ADC_PORTS(RA0_RA1_RA3_ANALOG); //Configura as entradas
analógicas
//RA0,RA1,RA3
SETUP_ADC(ADC_CLOCK_INTERNAL); //Configura o conversor AD interno
Output_High(PIN_C2); //Liga ventoinha
while(true) //Loop principal
{
SET_ADC_CHANNEL(0); //Configura o canal de leitura 0
delay_us(100); //Tempo de ajuste do canal (necessário)
ad0 = READ_ADC(); //Faz a conversão AD e a salva na variável ad0
printf(lcd_escreve,"\fS0=%lu",ad0); //Mostra valor da conversão do canal 0
SET_ADC_CHANNEL(1); //Configura o canal de leitura 1
delay_us(100); //Tempo de ajuste do canal (necessário)
ad1 = READ_ADC(); //Faz a conversão AD e a salva na variável ad1
SET_ADC_CHANNEL(3); //Configura o canal de leitura 3
delay_us(100); //Tempo de ajuste do canal (necessário)
ad3 = READ_ADC(); //Faz a conversão AD e a salva na variável ad3
//Mostra valor da conversão dos canais 1 e 3
printf(lcd_escreve,"\nS1=%lu - S3=%lu",ad1,ad3);
if (ad3>=80) //Sendo ad3 >= 80...
{
Output_High(PIN_C2); //Liga ventoinha
Output_low(PIN_C1); //Desliga aquecimento
}
if (ad3<=55) //Sendo <= 55...
{
Output_High(PIN_C1); //liga aquecimento
Output_low(PIN_C2); //Desliga ventoinha
}
delay_ms(1000); //Atraso de 1 segundo
}
}
UNIALFA – Prof. Eduardo J. Nogueira
15
Anexo 3
LCD8B.c
//////////////////// LCD8B.c ///////////////////////////////////////////////////
//Programa para controle do display LCD por 8 vias do Port D //
//Este programa foi feito pela ACEPIC, fabricante da maior parte dos kits de //
//microcontroladores usados em nossos laboratórios no UNIALFA e foi adaptado
//
//pelo Professor Eduardo J. Nogueira. //
////////////////////////////////////////////////////////////////////////////////
#define EN PIN_E1 //Definimos o pino 1 da porta E como EN
#define RS PIN_E0 //Definimos o pino 0 da porta E como RS
#define DATA OUTPUT_D //Definimos a saída para a porta D como DATA
void lcd_cmd(byte cmd) //Função para envio de comandos para o LCD
{
DATA(cmd); //Coloca o conteúdo da variável cmd na porta D
OUTPUT_HIGH(EN); //Pulso alto (1) no pino EN (Pino 1 da porta E)
OUTPUT_LOW(EN); //Retorna a nível baixo (0) em EN
}
void lcd_envia_byte(boolean nivel,byte dado) //Função para envio de dados ou
//escrita para o LCD
{
OUTPUT_LOW(RS); //Coloca em nível baixo o pino RS (Pino 0 da porta E)
OUTPUT_BIT(RS,nivel); //Coloca o pino RS no nível da variável nivel
delay_us(100); //Atraso de 100 us
OUTPUT_LOW(EN); //Coloca em nível baixo o pino EN
lcd_cmd(dado); //Chama a função lcd_cmd já com os dados a serem
//enviados para a porta D
}
void lcd_pos_xy(byte x, byte y) //Função de posicionamento do cursor
{
byte endereco; //Variável de informação para o endereço do cursor
if (y!=1) //Se o valor de y for 2
endereco = 0xC0; //então endereco vai ser igual a 0xC0 (endereço da
//segunda linha)
else //Senão
endereco = 0x80; //endereço vai ser igual a 0x80 (endereço da primeira
// linha)
endereco += x-1; //Aqui decrementa o valor da variável x e o resultado é
//somado com a variável endereço...
lcd_envia_byte(0,endereco); //Chama a função lcd_envia_byte, com o valor 0,
//informando para o LCD que será enviado um dado e o
//dado está contido na variável endereço...
}
void lcd_escreve(char c) //Função para envio dos caracteres e/ou dados para o
// LCD
{
UNIALFA – Prof. Eduardo J. Nogueira
16
switch(c) //comando switch com a variável c
{
case '\f' : lcd_envia_byte(0,1); //Caso c seja ‘\f’, o dado 1 será enviado
//ao LCD para limpar todo o seu conteúdo.
delay_ms(2); //Atraso de 2 ms
break; //Comando break, terminou o processo acima, já
//não testa
//nenhum outro caso...
case '\n' : //Caso c seja ‘\n’
case '\r' : lcd_pos_xy(1,2); //ou ‘\r’, muda o cursor para a segunda linha
//do LCD
break; //Comando break
case '\b' : lcd_envia_byte(0,0x10); //Caso c seja ‘\b’ então desloca o
//cursor para a esquerda
break; //Comando break
default : lcd_envia_byte(1,c); //caso seja um caractere qualquer, então
//este será escrito no LCD pela função lcd_envia_byte…
break; //Comando break
}
}
void lcd_ini() //Função de inicialização do LCD
{
byte conta; //Variável de contagem
DATA(0x00); //Coloca na porta D o valor 0x00
OUTPUT_LOW(RS); //Coloca em nível baixo o pino RS
OUTPUT_LOW(EN); //Coloca em nível baixo o pino EN
delay_ms(15); //Atraso de 15ms
for (conta=1;conta<=3;conta++) //Executará 3 vezes os comandos abaixo
{
lcd_cmd(0x30); //Envia o comando 0x30 para o LCD
delay_ms(5); //Atraso de 5ms
}
lcd_cmd(0x38); //Escreve comando para interface de 8 vias de dados
lcd_cmd(0x01); //Escreve comando para limpar todo o display
delay_ms(1); //Atraso de 1mslcd_cmd(0x0C); //Escreve comando para ligar o display sem cursor
lcd_cmd(0x06); //Escreve comando para incrementar automaticamente à di-
reita
}
OBS: Todos os códigos dos anexos pode ser copiado da apostila e colados na
janela de edição do PCW.