Forum: Mikrocontroller und Digitale Elektronik ATTiny85 ACD


von Z.B. Max (darter)


Lesenswert?

Hi,
Sollte mir folgender Code nicht bei einer Spannung kleiner 3.3V an Pin 
PB4 die LED blinken lassen? Leider blinkt die LED unabhängig von der 
anliegenden Spannung an PB4.
Sieht jemand meinen Fehler?
1
#include <Arduino.h>
2
3
#define BAT_EMPTY_PIN PB2
4
5
int getBattV()
6
{       
7
    DDRB &= ~_BV(PB4); // PB4 as input
8
    PORTB &= ~_BV(PB4); // no pullup on PB4 
9
10
    ADMUX = _BV(MUX1) | _BV(REFS1); //ADC2/PB4  and 1.1V as ref
11
12
    delay(5); // wait for Vref to settle
13
14
    ADCSRA |= _BV(ADSC); // reading ADC
15
    while (bit_is_set(ADCSRA, ADSC)); //ADSC will be set to 0 wen conversion is finished
16
17
    uint8_t low = ADCL;
18
    unsigned int adcVal = (ADCH << 8) | low;
19
20
    // discard previous result ("The first ADC conversion result after switching voltage reference source maybe inaccurate, and the user is advised to discard this result.")
21
    ADCSRA |= _BV(ADSC); // Convert
22
    while (bit_is_set(ADCSRA, ADSC));
23
    low = ADCL;
24
    adcVal = (ADCH << 8) | low;
25
26
    return ((long)1024 * 1100) / adcVal;
27
}
28
29
void setup()
30
{
31
    DDRB |= _BV(BAT_EMPTY_PIN); //debug led
32
}     
33
    
34
void loop(){
35
    if((getBattV()/1000.0) < 3.3){
36
        PORTB |= _BV(BAT_EMPTY_PIN); //high
37
        delay(10);
38
        PORTB &= ~_BV(BAT_EMPTY_PIN); //low
39
        delay(90);
40
    }
41
}

: Bearbeitet durch User
von Sebastian W. (wangnick)


Lesenswert?

Erstens liefert bei AREF 1.1V jeder Messwert >1.1V als ADC-Ergebnis 
1023.

Zweitens ist diese Zeile komisch:
1
    return ((long)1024 * 1100) / adcVal;

LG, Sebastian

von Georg M. (g_m)


Lesenswert?

Sebastian W. schrieb:
> Zweitens ist diese Zeile komisch

Offensichtlich unüberlegt abgeschrieben: so wird die Spannung am VDD-Pin 
gemessen.

von Z.B. Max (darter)


Lesenswert?

Sebastian W. schrieb:
> Erstens liefert bei AREF 1.1V jeder Messwert >1.1V als ADC-Ergebnis
> 1023.

Ist das so? Ist mir so aus dem Datenblatt nicht klar geworden, wo steht 
das?

Dann müsste ja das funktionieren? Geht aber leider auch nciht
1
    ADMUX = _BV(MUX1); //ADC2/PB4  and Vdd als Ref(4,8V)
2
    ..
3
    ..
4
    return ((long)1024 * 4800) / adcVal;

Georg M. schrieb:
> Sebastian W. schrieb:
>> Zweitens ist diese Zeile komisch
>
> Offensichtlich unüberlegt abgeschrieben: so wird die Spannung am VDD-Pin
> gemessen.
1
return ((long)1024 * 1100) / adcVal;

Sicher nicht unüberlegt.
Ich dachte die Zeile setzt das Ergebnis vom ADC ins Verhältnis zur 
Referenzspannung.(1,1V ->1100)
1
ADMUX = _BV(MUX3) | _BV(MUX2);
Gibt mir tatsächlich die Spannung am VDD.
Warum sollte dann
1
ADMUX = _BV(MUX1)
,was laut Datenblatt den Input für den ACD auf ADC2 setzt, nicht 
funktionieren?

: Bearbeitet durch User
von Georg M. (g_m)


Lesenswert?

Die VDD-Spannung ist höher als VREF, deswegen ist die Gleichung 
umgestellt.
Deswegen je kleiner der ADC-Wert ist, desto größer ist die gemessene 
Versorgungsspannung.

von Sebastian W. (wangnick)


Lesenswert?

Z.B. Max schrieb:
> return ((long)1024 * 1100) / adcVal;
>
> Sicher nicht unüberlegt.
> Ich dachte die Zeile setzt das Ergebnis vom ADC ins Verhältnis zur
> Referenzspannung.(1,1V ->1100)

Das Ergebnis wird aber größer wenn der Messwert kleiner wird ...

LG, Sebastian

von Sebastian W. (wangnick)


Lesenswert?

Z.B. Max schrieb:
> ADMUX = _BV(MUX3) | _BV(MUX2);
>
> Gibt mir tatsächlich die Spannung am VDD.
> Warum sollte dann
>
> ADMUX = _BV(MUX1)
>
> ,was laut Datenblatt den Input für den ACD auf ADC2 setzt, nicht
> funktionieren?

Ok. Wenn MUX auf 0b1100 gestellt wird, und REFS auf 0b000, dann passiert 
folgendes: Der ADC misst seine interne (stabile) Bandgap-Spannung im 
Verhältnis zu VCC. Wenn also VCC 4.4V ist, dann wird die 1.1V 
Bandgap-Spannung als 256 gemessen. Wenn VCC 3.3V ist, dann misst man 
341. Dann stimmt deine Rechenmethode, um VCC auszurechnen.

Aber wenn du eine veränderliche Spannung an einem der ADC-Eingangspins 
messen willst, brauchst du a) eine stabile Referenzspannung, b) darf die 
Eingangsspannung nicht größer als die Referenzspannung werden (sonst 
kommt als Messwert immer 1023 raus), und c) musst du deine 
Berechnungsformel umstellen.

HTH.

LG, Sebastian

: Bearbeitet durch User
von Z.B. Max (darter)


Lesenswert?

Sebastian W. schrieb:
> Z.B. Max schrieb:
>> ADMUX = _BV(MUX3) | _BV(MUX2);
>>
>> Gibt mir tatsächlich die Spannung am VDD.
>> Warum sollte dann
>>
>> ADMUX = _BV(MUX1)
>>
>> ,was laut Datenblatt den Input für den ACD auf ADC2 setzt, nicht
>> funktionieren?
>
> Ok. Wenn MUX auf 0b1100 gestellt wird, und REFS auf 0b000, dann passiert
> folgendes: Der ADC misst seine interne (stabile) Bandgap-Spannung im
> Verhältnis zu VCC. Wenn also VCC 4.4V ist, dann wird die 1.1V
> Bandgap-Spannung als 256 gemessen. Wenn VCC 3.3V ist, dann misst man
> 341. Dann stimmt deine Rechenmethode, um VCC auszurechnen.
>
> Aber wenn du eine veränderliche Spannung an einem der ADC-Eingangspins
> messen willst, brauchst du a) eine stabile Referenzspannung, b) darf die
> Eingangsspannung nicht größer als die Referenzspannung werden (sonst
> kommt als Messwert immer 1023 raus), und c) musst du deine
> Berechnungsformel umstellen.
>
> HTH.
>
> LG, Sebastian

Hi danke für die Antwort.

Ist mir gerade nach langem Googeln auch klar geworden.
Habe fäschlicherweise gedacht Vbg == Vcc
und Somit die Funktionsweise von GetVcc() total falsch verstanden.

Jetzt ist`s klar.
Ich setzte also REFS1 und REFS0 auf 0 für Vcc als Ref und MUX auf 0b0010 
für ACD2.
Dann müsste mir Aref(Vcc) / 1024 * ResultACD die Spannung am Pin ACD2 
geben.

Ist es eigentlich notwendig den Pin als Input ohne Pullup zu setzen oder 
reicht es das Digital Input Disable Register zu setzen?

: Bearbeitet durch User
von Arduino F. (Firma: Gast) (arduinof)


Lesenswert?

Z.B. Max schrieb:
> Jetzt ist`s klar.
> Ich setzte also REFS1 und REFS0 auf 0 für Vcc als Ref und MUX auf 0b0010
> für ACD2.
> Dann müsste mir Aref(Vcc) / 1024 * ResultACD die Spannung am Pin ACD2
> geben.

Du bist verwirrt, wie mir scheint...

Wenn du die Betriebsspannung des µC messen willst, was hat das dann mit 
Pin 2 zu tun?
Und wenn du die Spannung an Pin 2 messen willst, dann doch nicht 
ratiometrisch gegen Vcc.
Oder?

Du merkst:
Ich habe noch nicht verstanden was du willst!
Weißt du was du willst?

von Sebastian W. (wangnick)


Lesenswert?

Z.B. Max schrieb:
> Jetzt ist`s klar.
> Ich setzte also REFS1 und REFS0 auf 0 für Vcc als Ref und MUX auf 0b0010
> für ACD2.
> Dann müsste mir Aref(Vcc) / 1024 * ResultACD die Spannung am Pin ACD2
> geben.

Ja. Setzt natürlich voraus dass du VCC kennst ...

LG, Sebastian

von Z.B. Max (darter)


Lesenswert?

Arduino F. schrieb:
> Z.B. Max schrieb:
>> Jetzt ist`s klar.
>> Ich setzte also REFS1 und REFS0 auf 0 für Vcc als Ref und MUX auf 0b0010
>> für ACD2.
>> Dann müsste mir Aref(Vcc) / 1024 * ResultACD die Spannung am Pin ACD2
>> geben.
>
> Du bist verwirrt, wie mir scheint...
>
> Wenn du die Betriebsspannung des µC messen willst, was hat das dann mit
> Pin 2 zu tun?
> Und wenn du die Spannung an Pin 2 messen willst, dann doch nicht
> ratiometrisch gegen Vcc.
> Oder?
>
> Du merkst:
> Ich habe noch nicht verstanden was du willst!
> Weißt du was du willst?

Hi, ich möchte nicht die Vcc messen sondern die Batteriespannung. Der 
ATTiny wird über eine 9V Batterie über einen Linerregler mit 5V 
betrieben. Nun möchte ich herausfinden wann die 9V Batterie leer ist.
Also über einen 50/50 Spannungsteiler an ACD2 angelegt.


Hab das ganze jetzt mal an einem 328 getestet damit ich die Werte über 
den seriellen Port anzeigen lassen kann.

Vin laut Multimeter 4,8V
Über ein Netzteil gebe ich nun auf ACD2 0 - 4,8V

Nun erwarte ich dass das Ergebnis vom ADC bei 4,8V am Pin ACD2 1023, 
jedoch bekomme ich schon bei 4,2V 1023 als Ergebnis. Warum?
1
#include <Arduino.h>
2
int getBattV()
3
{       
4
    DDRB &= ~_BV(PC2); // PB4 as input
5
    PORTB &= ~_BV(PC2); // no pullup on PB4 
6
7
    DIDR0 &= ~_BV(ADC2D); //disable digital input for ADC2
8
9
    ADMUX = _BV(MUX1)| _BV(REFS0);  //ADC2/PB4  and Vdd als Ref(4,8V)
10
11
    delay(5); // wait for Vref to settle
12
13
    ADCSRA |= _BV(ADSC); // reading ADC
14
    while (bit_is_set(ADCSRA, ADSC)); //ADSC will be set to 0 wen conversion is finished
15
16
    uint8_t low = ADCL;
17
    unsigned int adcVal = (ADCH << 8) | low;
18
19
    // discard previous result ("The first ADC conversion result after switching voltage reference source maybe inaccurate, and the user is advised to discard this result.")
20
    ADCSRA |= _BV(ADSC); // Convert
21
    while (bit_is_set(ADCSRA, ADSC));
22
    low = ADCL;
23
    adcVal = (ADCH << 8) | low;
24
25
    return adcVal;
26
}
27
void setup() {
28
  Serial.begin(9600);
29
  while(!Serial){
30
31
  }
32
33
}
34
35
void loop() {
36
  Serial.println(getBattV());
37
}

von Sebastian W. (wangnick)


Lesenswert?

Bei einem Arduino ist VIN nicht VCC ...

LG, Sebastian

von Z.B. Max (darter)


Lesenswert?

Sebastian W. schrieb:
> Bei einem Arduino ist VIN nicht VCC ...
>
> LG, Sebastian

Sorry meine natürlich VCC nicht VIN ich benutze nur den 328 auf nem 
breadboard.
Aber hab meinen Fehler grad gefunden VCC !=AVCC
Brücke ich VCC und AVCC bekomm ich das erwartete Ergebnis.

von Sebastian W. (wangnick)


Lesenswert?

Z.B. Max schrieb:
> Brücke ich VCC und AVCC

AVCC ist die Versorgung für den Analogteil. Wenn man die weglässt, dann 
wird der Analogteil aus VCC parasitär versorgt, also über Pfade und 
Dioden die für Ströme nicht ausgelegt sind. Auf diesen Pfaden fallen 
dann schnell einige Zehntel Volt ab. Soll man nicht machen ...

LG, Sebastian

von Z.B. Max (darter)


Lesenswert?

Sebastian W. schrieb:
> Z.B. Max schrieb:
>> Brücke ich VCC und AVCC
>
> AVCC ist die Versorgung für den Analogteil. Wenn man die weglässt, dann
> wird der Analogteil aus VCC parasitär versorgt, also über Pfade und
> Dioden die für Ströme nicht ausgelegt sind. Auf diesen Pfaden fallen
> dann schnell einige Zehntel Volt ab. Soll man nicht machen ...
>
> LG, Sebastian

Bin grad erst am Anfang mit den Microcontrollern, da hab ich übersehen 
dass der 328 im Gegensatz zum t85 ne extra Spannungsversorgung für den 
Analogteil hat.

Danke für deine Hilfe, hat mir sehr geholfen.

Bitte melde dich an um einen Beitrag zu schreiben. Anmeldung ist kostenlos und dauert nur eine Minute.
Bestehender Account
Schon ein Account bei Google/GoogleMail? Keine Anmeldung erforderlich!
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.