Ir ao conteúdo
  • Cadastre-se

Tensão de referência em pino do PIC 16F886


Posts recomendados

Olá a todos.

Estou montando um termômetro, que é parte de um projeto maior. Estou usando o LM35 como elemento sensor, ligado a uma porta analógica do PIC. Os testes foram bem com VREF configurado como VDD. Entretanto, para maior resolução, fixei no pino VREF+ uma tensão de 3,9V. Então, o range vai de 3,9V a 5V, me dando o range de 1,1V. A ideia é aumentar a precisão. Veja se estou certo: sendo o range de 1,1V e, considerando a resolução do conversor AD 10 bits, terei 1,1V / 1023 = 0,0010752688172, ou seja, terei, arredondando, 1mV para cada degrau da conversão. Como estou usando apenas dezena e unidade para ver a medição (o projeto só precisa disso, mas é necessária a boa precisão para outras razões do mesmo projeto) e usando dois displays comuns de catodo comum, estou usando a seguinte fórmula para conversão: temp_ADC_scaling = (temp_ADC_scaling * 100) / 1023

Para ver os valores nos displays, uso:

varUni = temp_ADC_scaling % 10

varDez = temp_ADC_scaling / 10

varUni e varDez são as variáveis globais que recebem os dados para exibição nos displays.

Enfim, o problema: depois que eu fixei VREF no pino VREF+ (pino 5) em 3,9V, não consigo obter o valor nos displays. Na simulação, 30ºC promovem uma leitura de 7 nos displays. Ressalto que, voltando tudo ao estado anterior com VREF em VDD, o circuito funciona (com precisão reduzida).

Estou usando o PIC 16F886, programando em C-CCS.

A minha configuração está assim:


setup_comparator(NC_NC_NC_NC);
set_adc_channel(0);
setup_adc_ports(sAN0, VREF_VDD);
setup_vref(VREF_HIGH); //não entendi bem - é para definir q o pino VREF+ está em uso?
setup_adc(ADC_CLOCK_INTERNAL);

O arquivo de cabeçalho está assim:


// Constants used in setup_vref() are:
//
#define VREF_LOW 0xa0
#define VREF_HIGH 0x80
// Or (with |) the above with a number 0-15

// Constants used for SETUP_ADC() are:
#define ADC_OFF 0 // ADC Off
#define ADC_CLOCK_DIV_2 0x100
#define ADC_CLOCK_DIV_8 0x40
#define ADC_CLOCK_DIV_32 0x80
#define ADC_CLOCK_INTERNAL 0xc0 // Internal 2-6us

// Constants used in SETUP_ADC_PORTS() are:
// First argument:
// OR together desired pins
#define sAN0 1 //| A0
#define sAN1 2 //| A1
#define sAN2 4 //| A2
#define sAN3 8 //| A3
#define sAN4 16 //| A5
#define sAN5 32 //| E0
#define sAN6 64 //| E1
#define sAN7 128 //| E2
#define sAN8 0x10000 //| B2
#define sAN9 0x20000 //| B3
#define sAN10 0x40000 //| B1
#define sAN11 0x80000 //| B4
#define sAN12 0x100000 //| B0
#define sAN13 0x200000 //| B5
#define NO_ANALOGS 0 // None
#define ALL_ANALOG 0x1F00FF // A0 A1 A2 A3 A5 E0 E1 E2 B0 B1 B2 B3 B4 B5

// Optional Second argument:
#define VSS_VDD 0x0000 //| Range 0-Vdd
#define VSS_VREF 0x1000 //| Range 0-Vref
#define VREF_VREF 0x3000 //| Range Vref-Vref
#define VREF_VDD 0x2000 //| Range Vref-Vdd

A minha função de leitura e conversão está assim:


void le_temp_converte(void){
unsigned int16 temp_ADC_scaling;
temp_ADC_scaling = read_adc();
temp_ADC_scaling = (temp_ADC_scaling * 100) / 1023;
varUni = temp_ADC_scaling % 10;
varDez = temp_ADC_scaling / 10;
}

Antecipo meus agradecimentos.

Bons trabalhos.

Link para o comentário
Compartilhar em outros sites

Colega, não li o código todo pois fez uma pequena confusão no inicio.

Se você colocou 3.9V no pino VREF+, seu AD ficará com um range de 0 a 3.9 e não como você disse.

O problema provavelmente está ai.

O VREF+ é a referencia superior e o VREF- é o limite inferior.

Não se esqueça que o datasheet informa um range de no minimo 2V.

Falou

  • Curtir 1
Link para o comentário
Compartilhar em outros sites

Entendi.

Fiz da maneira citada, porque o arquivo de cabeçalho do compilador informa:


#define VREF_VDD 0x2000 //| Range Vref-Vdd

Então, pensei que o range seria do Vref (no caso, os 3,9V que citei) ao VDD, que é de 5V.

Mas, já vou alterar aqui seguindo sua dica.

Também havia me esquecido do range mínimo de 2V.

Muito obrigado, Matheus.

Farei as alterações e volto.

Bons trabalhos.

Link para o comentário
Compartilhar em outros sites

advtec, pelo seu último post, tive uma curiosidade maior e consigo compreender sua confusão. Aproveito para completar meu post anterior, pois o mesmo ficou vago.

Antes não coloquei mais detalhes pois estava digitando pelo celular e dá preguiça de escrever muito por lá. Vim para o PC para ilustrar melhor.

Quando não indicamos que referência usar, o CCS entende que será a padrão, de VSS a VDD, ou seja 0 e 5V, sendo 0V a referencia inferior e 5V sendo a superior. Considerando que você alimenta o PIC com esses valores.

Como você mesmo postou anteriormente, temos as seguintes opções nesse PIC:

[COLOR="Red"][B]1 - [/B][/COLOR]#define VSS_VDD              0x0000        //| Range 0-Vdd
[COLOR="Red"][B]2 - [/B][/COLOR]#define VSS_VREF 0x1000 //| Range 0-Vref
[COLOR="Red"][B]3 - [/B][/COLOR]#define VREF_VREF 0x3000 //| Range Vref-Vref
[COLOR="Red"][B]4 -[/B][/COLOR]#define VREF_VDD 0x2000 //| Range Vref-Vdd

Na opção número 1 é a padrão e além disso, opcional. Caso não especifique nenhuma, o compilador irá configurar como essa. 0 e 5V.

A nº 2, seria de 0V até Vref. Entenda que nesse caso, seria a referencia superior (PINO 5, RA3)

A nº 3 seria no caso de você ter duas referencias, uma em cada pino (PINO 4 sendo Vref inferior e PINO 5 a superior).

A nº 4 sendo de Vref inferior até VDD (5V).

O seu raciocínio inicial não está errado DESDE que você tenha colocado os 3.9V no pino 4 que é o RA2 ou, seja a referencia inferior. Aí sim, nesse caso, teríamos 1.1V de range.

Lembrando novamente que os datasheets que já vi indicam 2V como mínimo. Confirme nesse PIC.

Falou

  • Curtir 2
Link para o comentário
Compartilhar em outros sites

Matheus, novamente, muito obrigado.

Coloquei a tensão de 2,8V em Vref- o que, portanto, resulta num range de 2,2V.

A configuração está assim:


setup_adc_ports(sAN0, VREF_VDD);

No Proteus, ao simular, houve o retorno da seguinte mensagem:

Voltage references for ADC conversion yield a 0V range (V+=0, V-=0).

Mesmo assim, no Protoboard a leitura resultante é 00.

Inverti, no Proteus, a ligação dos 2,8V para o Vref+. O resultado foi a medição do valor corretamente. Digo, entretanto, corretamente, configurando a fórmula de conversão para os 2,8V, porque para os 2,2V (5 - 2,8) não dá resultado correto (passa longe). No protoboard, entretanto, a leitura é também 00. No protoboard só funciona se eu usar o Vref padrão.

A tensão de 2,8V estou conseguindo com um diodo zener.

Aproveito para perguntar: posso assumir que o Proteus está simulando o PIC trabalhar com 5V (presumo que sim, porque a fórmula de conversão usando VDD de 5V resulta em medição correta).

Abaixo, o meu código inteiro da parte do termômetro (separei do restante do projeto e vou trabalhar somente nele até conseguir dominar esse assunto de Vref e conversões):


#include <16F886.h>
#device adc=10
#use delay(clock=20000000)
#use fast_io(a)
#use fast_io(
#use fast_io(c)

#fuses HS,NOWDT,NOMCLR,PUT,NOPROTECT,NOBROWNOUT,NOLVP

#define disp1 pin_c0 //pino de acionamento do display 1 (dezena)
#define disp2 pin_c1 //pino de acionamento do display 2 (unidade)

void le_temp_converte(void);
void trata_timer1(void);

unsigned char varDez = 0, varUni = 0;
byte const display[] = { //"mascara" de dados apresentados nos displays
0b01111110, //0
0b00001100, //1
0b10110110, //2
0b10011110, //3
0b11001100, //4
0b11011010, //5
0b11111010, //6
0b00001110, //7
0b11111110, //8
0b11011110, //9
0b11110010, //E
0b10100000, //r
0b00001100, //I
0b10101000, //n
0b11100010, //F
0b00100000, //i
0b10000000, //- (16)
};

void le_temp_converte(void){
unsigned int16 temp1 = 0, temp2 = 0, temp_ADC_scaling = 0;
unsigned char i;
for(i=0; i<30; i++) {
delay_us(30);
temp1 = read_adc();
temp2 = temp2 + temp1;
}
temp2 = temp2/30;
temp_ADC_scaling = (temp2 * 500) / 1023;//p/ Vref = VDD 5V.
varUni = temp_ADC_scaling % 10;
varDez = temp_ADC_scaling / 10;
}

#int_timer0
void trata_timer0(void) {
}

#int_timer1
void trata_timer1(void) {
boolean displays;
displays = !displays;
if(displays) {
output_low(disp2);
output_b((display[varDez]));
output_high(disp1);
}
else {
output_low(disp1);
output_b((display[varUni]));
output_high(disp2);
}
set_timer1(63660);
}

void main() {
setup_comparator(NC_NC_NC_NC);
set_adc_channel(0); //canal 0 como analogico
setup_adc_ports(sAN0, VREF_VDD);
setup_adc(ADC_CLOCK_INTERNAL);
set_pwm1_duty(false);
setup_ccp1(ccp_off);

output_a(0b00000000);
output_b(0b00000000);
output_c(0b00000000);
delay_ms(100);

set_tris_a(0b11011111);
set_tris_b(0b00000001);
set_tris_c(0b00000000);

SETUP_TIMER_0 (RTCC_INTERNAL|RTCC_DIV_256);
SETUP_TIMER_1(T1_INTERNAL | T1_DIV_BY_8);
SETUP_TIMER_2(T2_DIV_BY_16,195,16);

enable_interrupts(GLOBAL);
enable_interrupts(int_timer0);
enable_interrupts(int_timer1);
disable_interrupts(int_timer2);
disable_interrupts(INT_EXT);
ext_int_edge(H_TO_L);

set_timer0(1);
set_timer1(63660);
set_timer2(195);

disable_interrupts(periph);
disable_interrupts(int_ccp1);
disable_interrupts(int_rb);

while(true) {
le_temp_converte();
delay_ms(50);
}
}

Abaixo, o circuito no Proteus:

termometro-teste.html

Parece estar faltando alguma configuração ainda. Mais alguma ideia? Novamente, muito obrigado e bons trabalhos.

Edição:

Após várias consultas e configurações, sem resultado, configurei assim:


setup_adc_ports(sAN0, VREF_VREF);

Então, neste caso, o range vai do pino VREF- ao pino VREF+. Como VREF+ já estava com 2,8V (fixada com um zener), coloquei o pino VREF- em 0V. Ajustei a fórmula e a leitura ficou correta (e estará até mesmo mais correto, porque não corro o risco de diferenças no VDD afetarem as medições, porque de 0V a 2,8V - ou outra tensão que eu fixar - não haverá flutuações). Embora esteja funcionando, ainda assim gostaria de saber porque isto está ocorrendo, ou seja: por que se eu configuro o range a partir de VREF até VDD não funciona? Lembro que tentei fazer as ligações em VREF- e em VREF+ também. Alguma ideia?

Link para o comentário
Compartilhar em outros sites

  • 1 ano depois...

Alguma ideia?

Boa tarde. ressuscitando este tópico. haha

 

conseguisse algum exito ?

estou usando o PIC 18f4550, e gostaria de fazer o mesmo que voce. porém não tem jeito de eu conseguir que ele use a referencia do pino an3, 

e quando eu coloco essa sua ultima função ai.

 

ele da erro, primeiro não reconhece o "sano", depois fica empombando com os parenteses...

se puder da uma força ai. 

 

desde ja agradeço.

Link para o comentário
Compartilhar em outros sites

Alexandre, boa tarde!

Não pode usar a referência no pino an3 por razões de seu projeto, ou em razão de erros?

Não estou conseguindo ver a sua função. Poste-a novamente. Lembre-se de postar partes essenciais do código, incluindo o que colocou em main no que concerne à configuração das portas analógicas.

Pode postar também o circuito?

 

Bons trabalhos.

Link para o comentário
Compartilhar em outros sites

boa tarde. Obrigado por responder.

 

Eu não consegui usar por motivos de programação mesmo. 

O pino AN3 esta disponível sim, porém eu alimento eles com a tesão menor, mas ele não a usa como referencia. 

eu tentei colocar essa parte do seu código, mas da erro. 

 

gostaria de saber se você obteve exito em seu projeto. att


Alexandre, boa tarde!

Não pode usar a referência no pino an3 por razões de seu projeto, ou em razão de erros?

Não estou conseguindo ver a sua função. Poste-a novamente. Lembre-se de postar partes essenciais do código, incluindo o que colocou em main no que concerne à configuração das portas analógicas.

Pode postar também o circuito?

 

Bons trabalhos.

boa tarde. Obrigado por responder.

 

Eu não consegui usar por motivos de programação mesmo. 

O pino AN3 esta disponível sim, porém eu alimento eles com a tesão menor, mas ele não a usa como referencia. 

eu tentei colocar essa parte do seu código, mas da erro. 

 

gostaria de saber se você obteve exito em seu projeto. att

Link para o comentário
Compartilhar em outros sites

Boa tarde, Alexandre.

Sim, eu tive êxito. Mas tive êxito fazendo o que comentei na edição ao post nº 5, acima. Funcionou perfeitamente, com excelente precisão.

Veja que, no caso, o range ficou um pouco maior do que 2V - uma recomendação bem observada pelo MatheusLPS (a observância do range mínimo de 2V para modelos de PICs). Vamos olhar no datasheet de seu PIC se há a mesma "regra".

Não estou conseguindo ver sua citação de código. Tente usar os recursos do forum para tanto. Poste também o seu código para que eu possa tentar ajuda-lo melhor.

 

Bons trabalhos.

Link para o comentário
Compartilhar em outros sites

Boa tarde, Alexandre.

Sim, eu tive êxito. Mas tive êxito fazendo o que comentei na edição ao post nº 5, acima. Funcionou perfeitamente, com excelente precisão.

Veja que, no caso, o range ficou um pouco maior do que 2V - uma recomendação bem observada pelo MatheusLPS (a observância do range mínimo de 2V para modelos de PICs). Vamos olhar no datasheet de seu PIC se há a mesma "regra".

Não estou conseguindo ver sua citação de código. Tente usar os recursos do forum para tanto. Poste também o seu código para que eu possa tentar ajuda-lo melhor.

 

Bons trabalhos.

desculpe-me pela demora. 

 

Bom na verdade eu não tenho um código muito bem escrito e pronto, eu fiz um simples para tentar fazer funcionar o lm35,

estou usando o pic 18f4550, e esse seu código não funcionou neste pic. sabe me dizer por que ?

 

Eu uso uma placa teste comprada para este PIC então hardware não acredito que seja. 

que como voce postar o codigo que deu certo?

Link para o comentário
Compartilhar em outros sites

Alexandre, o código que está funcionano é o mesmo que está no post nº 5, acima. A diferença é que, no lugar de

setup_adc_ports(sAN0, VREF_VDD);

na função main, a configuração atual é

setup_adc_ports(sAN0, VREF_VREF);

Se não funcionar aí com você, poste o seu código para que eu possa tentar ajudar a encontrar o que está errado.

 

Lembre-se que, neste caso, no circuito eletrônico tenho o range vai do pino VREF- ao pino VREF+, ou seja, o pino VREF- está ligado no GND e o VREF+ está referenciado com uma tensão de 2,8V.

 

Bons trabalhos.

Link para o comentário
Compartilhar em outros sites

Visitante
Este tópico está impedido de receber novas respostas.

Sobre o Clube do Hardware

No ar desde 1996, o Clube do Hardware é uma das maiores, mais antigas e mais respeitadas comunidades sobre tecnologia do Brasil. Leia mais

Direitos autorais

Não permitimos a cópia ou reprodução do conteúdo do nosso site, fórum, newsletters e redes sociais, mesmo citando-se a fonte. Leia mais

×
×
  • Criar novo...