• Welcome to LusoRobótica - Robótica em Português.
 

leitura de voltagens com o analogRead(A0)

Started by vasco, 23 de August de 2018, 00:43

Previous topic - Next topic

0 Members and 1 Guest are viewing this topic.

vasco

Já li tantas vezes a parte do ADC da datasheet que acho que vou imprimir e mandar encadernar... :-)

Acho que não perceberam o que eu estava a perguntar.

Essa função, que é usada para ler o Vcc do arduino usa a ref.interna de 1.1v.  ->  ADMUX = _BV(REFS0) | _BV(MUX3) | _BV(MUX2) | _BV(MUX1);

Logo, como é possível que:

a) Leia corretamente valores acima de 1.1 V, já testei com USB e dá 4.7 V e com 5V diretos ao pino +5V dá 5.1V

b) Como é que, depois de terminar, não deixa o arduino configurado na ref. de 1.1V ?
Stupid men are often capable of things the clever wouldn't dare to contemplate.

jm_araujo

Pelo que entendi, acho que percebeste mal essa leitura.
O que faz é ler os 1.1V com a referência do Vcc. Faz a operação invertida ao  que dizes. Por isso quando acaba deixa a referência como Vcc e não como 1.1V

Agora estou no telemóvel e é difícil fazer explicações mais longas, mas se não fui claro diz qq coisa que logo tento desenvolver (se não aparecer ninguém primeiro)

Njay

Tu é que ainda não percebeste, Vasco :)
A função usa a alimentação do AVR como Vref (REFS[1:0] = 01b = "AVCC with external capacitor at AREF pin", tabela 28-3 da datasheet), e está a medir e Vref interna de 1.1V, pois uma das entradas do MUX (MUX[3:0] = 1110b = "1.1V (VBG)"*, tabela 28-4) está ligada a ela e permite lê-la. Ou seja, o ADC tem uma Vref de 5V (estás a alimentar o AVR a 5V, acho) e está a ler um valor que anda em torno de 1.1V, portanto não há problema nenhum.

QuoteADMUX = _BV(REFS0) | _BV(MUX3) | _BV(MUX2) | _BV(MUX1);

Isto faz REFS[1:0] = 01b e MUX[3:0] = 1110b


*VBG = Vbandgap

vasco

#48
Daaaaa...



Vou continuar a ler... eventualmente chego lá.... jezzzzzusss...

Stupid men are often capable of things the clever wouldn't dare to contemplate.

Njay


vasco

Realmente estava a ver a coisa ao contrário, achei que estavam a usar a ref de 1.1V para ler o AVcc. É escarafunchoso fazer a coisa desta maneira. Mas, obviamente é uma solução válida.

Entretanto tentei criar a minha própria referência para poder compensar as diferenças entre diferentes arduinos Nano. Usei uma referência LT-1004-2.5 e duas resistências de 100K em paralelo (porque raio não fazem resistências de 50 K ????) e nas várias situações que testei tenho sempre o mesmo valor.
No entanto, o facto é que não sei como usar esta referência para calibração.
Tentei simplesmente ler o seu valor, que numa situação ideal deveria retornar 512 e usar o valor lido para obter um offset que depois seria adicionado a todas as medições. Mas não vejo quaisquer melhoras relativamente à exatidão dos valores que estou a obter.

E faz sentido colocar um condensador de 10nF entre o AREF e o GND ?
O valor do condensador não vem na datasheet, mas encontrei varias threads sobre isso no AVRfreaks. Mas parece-me evidente que estão a falar de coisas muito mais hardcore do que aquilo que eu estou a fazer.
Stupid men are often capable of things the clever wouldn't dare to contemplate.

Njay

Não sei se escarafunchoso é a palavra certa, mas não é uma forma nada precisa, por causa da variação da precisão da Vref interna de 1V1, a não ser que se meça essa Vref (chip a chip) e se use o valor "exacto" nas contas.

A melhor estratégia é sempre a de calibrar o sistema como um todo, como indiquei naquele post da interpolação linear. Mas se quiseres mesmo fazer contas com a Vref interna, um DMM tem muito melhor precisão que ela, por isso podes usá-lo para fazer uma "calibração manual". Configuras o ADC para usar a "Vref interna com um cap no pino AREF", e depois medes a tensão no AREF - essa é a tensão da Vref interna. Usas o valor no teu código. Esta calibração é válida para o chip que usaste (qualquer calibração, baseada na Vref interna, o é).

Em alternativa podes automatizar um pouco mais a calibração, usando uma tensão de referência externa de maior precisão, como esse LT1004-2.5 (espero que seja muito barato, pois 20mV de erro não é nada de especial). Aí ligas essa referência a um pino entrada de ADC e fazes a leitura com a Vref interna. Sabendo tu a tensão que estás a medir, resolves a equação em ordem à Vref interna, que então usas nas contas (eu costumo fazer um programa para calibrar, que guarda o valor da Vref na EEPROM, e depois o"programa principal" lê-o de lá).

Njay

#52
Ah, em relação ao condensador no AREF, eu costumo meter 100nF, mas acho que 10nF tb deve servir.

O condensador serve para ajudar a estabilizar ainda mais a Vref, isto é importante para reduzir os erros na conversão. A Vref dos ADC deve ser "rock solid", ou seja, ter um valor o mais estável possível.

Agora, se o deves fazer ou não, depende. Há um detalhe. Quanto maior for a capacitância, maior é o tempo que demora a mudar a Vref do ADC (por exemplo de AVcc para Vref interna ou vice-versa). Se usas sempre a mesma Vref no teu programa isto não é um problema, mas se tens que trocar de Vref então tens que ter isso em conta.

vasco

10nF ou 100nF não me faz diferença, embora num estágio mais avançado possa pensar mudar para a refª de 1.1 quando tiver que medir uma voltagem abaixo de 1 V (como faz o Transistor Tester) para esta aplicação não tenho qualquer problema em esperar que a referência estabilize.
Um LT-1004-2.5 custa cerca de 1.5€, provavelmente haveria maneiras mais baratas mas eu já tenho confusão que chegue dentro da cabeça.
Gostaria de conseguir automatizar a calibração o mais possível, para a coisa poder funcionar com qualquer Nano, entre dois que tenho por aqui que são claramente de fornadas diferentes até o valor do Vcc (quando ligados por USB na mesma porta e com o mesmo cabo) muda significativamente.
Stupid men are often capable of things the clever wouldn't dare to contemplate.

senso

Eu utilizava uma ferrite e um condensador de 1uF , está na datasheet algures.
Avr fanboy

vasco

Encontro na figura 28-9 "ADC Power connections" que o pino AVCC teria um condensador de 100nF ao GND e ligação ao VCC via uma bobine de 10uH... Será isto a que te referes ?
Stupid men are often capable of things the clever wouldn't dare to contemplate.

Njay

#56
Trabalhas em Lx Vasco? Posso emprestar-te por uns tempos uma cena para calibrares os teus aparelhos/chips, é de 1.8V -/+1mV. Contacta-me por MP se interessado.

Não me lembro da ferrite nem cap de 1u na datasheet. Isso que o Vasco fala é relacionado com o ADC mas não é do que o senso está a falar.

senso

Oh, estão a falar do AREF e não do AVCC.

1uF X7r no AREF, 1uF+100nF+BLM31PG121SN1L ou 81-BLM15BB221SN1D, funciona que nem ginjas quando tinha as atxmega/atmegaRFA/RFR pendurados em reguladores comutados, e melhor ainda com LDO's.

Se bem que depois apanhei o hábito de utilizar LM4040 de 2.048 em sistemas 3.3v ou de 4.096v em sistemas 5v, é baratissimo comparado com a limpeza que dá em arredondamentos.
Avr fanboy

vasco

#58
Quote from: Njay on 29 de October de 2018, 15:31
Em alternativa podes automatizar um pouco mais a calibração, usando uma tensão de referência externa de maior precisão, como esse LT1004-2.5 (espero que seja muito barato, pois 20mV de erro não é nada de especial). Aí ligas essa referência a um pino entrada de ADC e fazes a leitura com a Vref interna. Sabendo tu a tensão que estás a medir, resolves a equação em ordem à Vref interna, que então usas nas contas (eu costumo fazer um programa para calibrar, que guarda o valor da Vref na EEPROM, e depois o"programa principal" lê-o de lá).

Era essa a minha ideia e foi assim que liguei o lt1004.

Tentei calcular o Vcc com base na ref de 2.485V no pino A1, mas falhei miseravelmente... :-(
Dá-me 7.657V de Vcc
Julgo que   ADMUX = _BV(REFS0) | (A1 & 7); quer dizer para ler o pino A1 usando Vcc como referência, certo ?


long readVcc_25() {
  long result;
  // Read 2.485V reference in pin A1 against AVcc
  ADMUX = _BV(REFS0) | (A1 & 7);
  delay(2); // Wait for Vref to settle
  ADCSRA |= _BV(ADSC); // Convert
  while (bit_is_set(ADCSRA,ADSC));
  result = ADCL;
  result |= ADCH<<8;
  result = (2.485*1023*1000) / result; // Back-calculate AVcc in mV    <===== WRONG !!!!!
  return(result);
}


Nota: o 1023 em vez de 1024 vem da função original onde 1125300 = 1.1*1023*1000
Nota2: Grande referência para o ADC - http://www.gammon.com.au/adc
Stupid men are often capable of things the clever wouldn't dare to contemplate.

Njay

#59
Quote from: vasco on 30 de October de 2018, 00:25
Tentei calcular o Vcc com base na ref de 2.485V no pino A1, mas falhei miseravelmente... :-(
Dá-me 7.657V de Vcc
Julgo que   ADMUX = _BV(REFS0) | (A1 & 7); quer dizer para ler o pino A1 usando Vcc como referência, certo ?

A1? Onde foste buscar isso? Estás a misturar coisas de Arduino, parece-me... Os nomes dos bits para selecionar a entrada do multiplexer analógico no registo ADMUX são MUX0 a MUX3 (datasheet... e é o que está a ser usado no código original e é o que temos estado a usar), e tens que converter o número do bit (é o que as macros de nomes de bits num registo são) numa bitmask, com a _BV (Bit Value) por exemplo.

Depois tens que ADCcounts = Vpin * 2ADCbits / Vref daí que Vref = Vpin * 2ADCbits / ADCcounts .
Em mV é multiplicar o resultado por 1000, ou melhor, multiplicar antes de dividir pelo ADCcounts e somar ADCcounts/2 também antes de dividir para melhorar a precisão. Como vês, Vpin * 2ADCbits * 1000, na tua aplicação é uma constante.