Você está na página 1de 16

1

UNIALFA – Prof. Eduardo J. Nogueira


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.

2
UNIALFA – Prof. Eduardo J. Nogueira
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.

3
UNIALFA – Prof. Eduardo J. Nogueira
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:

4
UNIALFA – Prof. Eduardo J. Nogueira
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.

5
UNIALFA – Prof. Eduardo J. Nogueira
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

LCD1
LM016L

U1
RV2 13 33
OSC1/CLKIN RB0/INT
2

14 34
OSC2/CLKOUT RB1
35

VDD
VSS

VEE
RB2

RW
RS

D0
D1
D2
D3
D4
D5
D6
D7
2 36

E
50%

RA0/AN0 RB3/PGM
3 3 37
RA1/AN1 RB4
4 38
RA2/AN2/VREF-/CVREF RB5

1
2
3

4
5
6

7
8
9
10
11
12
13
14
5 39
RA3/AN3/VREF+ RB6/PGC
RV1
1

10k 6 40
RA4/T0CKI/C1OUT RB7/PGD
7
2

RA5/AN4/SS/C2OUT
15
RC0/T1OSO/T1CKI
8 16
RE0/AN5/RD RC1/T1OSI/CCP2
52%

9 17
RE1/AN6/WR RC2/CCP1 3
10 18
RE2/AN7/CS RC3/SCK/SCL
23
RC4/SDI/SDA
1 24
MCLR/Vpp/THV RC5/SDO
1

10k
+2.50 25
RC6/TX/CK
26
Volts RC7/RX/DT
19
RD0/PSP0
20
R1 RD1/PSP1
21
4k7 RD2/PSP2
22
RD3/PSP3
27
RD4/PSP4
28
RD5/PSP5
29
RD6/PSP6
30
RD7/PSP7
PIC16F877A

Definições do Projeto:

Nome do Projeto: ADC

Arquivo principal: ADC.c

6
UNIALFA – Prof. Eduardo J. Nogueira
8

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

7
UNIALFA – Prof. Eduardo J. Nogueira
8
UNIALFA – Prof. Eduardo J. Nogueira
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.

9
UNIALFA – Prof. Eduardo J. Nogueira
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:

R3

+12V
+12V

56R

R4 Q2
NPN D1
2k2

RV1 LCD1
2

LM016L
52%

RV2 U1
Q1
1

10k 13 33
2

OSC1/CLKIN RB0/INT NPN


14 34
OSC2/CLKOUT RB1
35
VDD
VSS

VEE
RB2

RW
RS

D0
D1
D2
D3
D4
D5
D6
D7
50%

2 36

E
3 RA0/AN0 RB3/PGM
3 37
RA1/AN1 RB4
4 38
RA2/AN2/VREF-/CVREF RB5 R2
1
2
3

4
5
6

7
8
9
10
11
12
13
14
5 39
RA3/AN3/VREF+ RB6/PGC
1

10k 2k2
6 40
RA4/T0CKI/C1OUT RB7/PGD
7
RA5/AN4/SS/C2OUT
15
RC0/T1OSO/T1CKI
8 16
RE0/AN5/RD RC1/T1OSI/CCP2
9 17
RE1/AN6/WR RC2/CCP1
10 18
RE2/AN7/CS RC3/SCK/SCL
23
RC4/SDI/SDA
1 U2 1
MCLR/Vpp/THV RC5/SDO
24
25
RC6/TX/CK
26
RC7/RX/DT
23.0 19
RD0/PSP0
20
R1 RD1/PSP1
21
2 4k7 RD2/PSP2
VOUT 22
RD3/PSP3
27
RD4/PSP4
28
RD5/PSP5
29
3 LM35 RD6/PSP6
30
RD7/PSP7
PIC16F877A

Definições do projeto

Nome do Projeto: ADC_Aq

Arquivo : ADC_Aq.c

10
UNIALFA – Prof. Eduardo J. Nogueira
Código escrito na janela de edição do PCW.

Videoaula sobre o conteúdo desta apostila:

https://youtu.be/gIr1LTXB39Y

11
UNIALFA – Prof. Eduardo J. Nogueira
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

12
UNIALFA – Prof. Eduardo J. Nogueira
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
}
}

13
UNIALFA – Prof. Eduardo J. Nogueira
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
}
}

14
UNIALFA – Prof. Eduardo J. Nogueira
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
{

15
UNIALFA – Prof. Eduardo J. Nogueira
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 1ms
lcd_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.

16
UNIALFA – Prof. Eduardo J. Nogueira

Você também pode gostar