Forum: Mikrocontroller und Digitale Elektronik atmega88p ADC sleep Problem


von Marco P. (Firma: keine) (marcopolo)


Lesenswert?

Irgendwie versteh ich das mit dem ADC und dem Sleep noch nicht ganz. Ich 
möchte zyklisch aufwachen und die Versorgungsspannung (mit der Bandgap 
Referenz), da Batteriebetrieben, messen. Ohne den Sleep Modus geht es 
wunderbar, mit Sleep bekomme ich komische Werte als Spannung.

Ich mache Folgendes:

//einmalig
void ADC_Init()
{
    ADMUX |= ((1 << MUX3) | (1 << MUX2) | (1 << MUX1)); /* 1.1V (VBG) */
    ADCSRA |= ( (1 << ADEN) | (1 << ADSC)); /* hit it */
}

//zyklisch
//Aufwachen
void ADC_GetVccVoltage()
{
  ADCSRA |= (1 << ADEN) ;
  ADCSRA |= ( (1 << ADSC));  /* enable ADC to get VCC */
  while ((ADCSRA & (1<<ADSC)))
  {}

  u16_voltage = (ADC >> 2);
  if(u16_voltage != 0)
  {
    u16_voltage = (uint16_t) ((((11 * 2550)) / (u16_voltage)));
  }
  ADCSRA &= (~(1 << ADEN));  /* disable ADC to save power */
}

//gehe nach sleep -> SLEEP_MODE_PWR_SAVE

Ich hab auch schon überall _delays_ms() eingebaut, ohne Erfolg, da ja 
das enable auch einige Zeit dauern soll.

Habt Ihr noch einen Tip für mich? Vielen Dank und Grüße!!!

: Bearbeitet durch User
von Sebastian H. (sebastian_h54)


Lesenswert?

Habe gelesen, dass beim Atmega8(8) nach aktivieren des ADC eine 
Probemessung gemacht werden muss, um den ADC zu initialisieren.

Bei der 2. Messung sollte also alles ok sein.

von Marco P. (Firma: keine) (marcopolo)


Lesenswert?

Habe ich auch schon probiert, und die Messung mehrmals im zyklischen 
Task gemacht.

Also so:
//wakeup
//enable ADC
...
  ADCSRA |= ( (1 << ADSC));  /* enable ADC to get VCC */
  while ((ADCSRA & (1<<ADSC)))
  {}
  (void)ADC; /* read value to get the next updated */
  ADCSRA |= ( (1 << ADSC));  /* enable ADC to get VCC */
  while ((ADCSRA & (1<<ADSC)))
  {}
...
//disable ADC
//sleep


Hat aber nix gebracht, ich bekomme immer falsche Messwerte. Es müssten 
für 5V 500 rauskommen und für 4.5V 450.

Aktuell ist der erste messwert 500 und alle nachfolgenden 230-250. Mein 
Gefühl ist, das ich irgendwo noch etwas auf den ADC warten muss, aber 
hab schon fast alle Stellen durchprobiert. Kruzifix ;-)

von Steffen (Gast)


Lesenswert?

Sebastian H. schrieb:
> Habe gelesen, dass beim Atmega8(8) nach aktivieren des ADC eine
> Probemessung gemacht werden muss, um den ADC zu initialisieren.
>
> Bei der 2. Messung sollte also alles ok sein.

genau. zum einen nach dem aktivieren eine Messung machen und verwerfen, 
zum andren warten bis BG gestartet ist.

Bandgap reference start-up time max.70µ

von Steffen (Gast)


Lesenswert?

ach ja, es kann auch an der gesamten startroutine liegen. warum machst 
das nicht wie im tutorial?

http://www.mikrocontroller.net/articles/AVR-GCC-Tutorial/Analoge_Ein-_und_Ausgabe

das klappt auf alle fälle.

von Marco P. (Firma: keine) (marcopolo)


Lesenswert?

Ich habs mal folgendermassen modifieziert aber ich kann keine 
Verbesserung bemerken.

//einmalig
void ADC_Init()
{
    ADMUX |= ((1 << MUX3) | (1 << MUX2) | (1 << MUX1)); /* 1.1V (VBG) */
    ADCSRA |= ( (1 << ADEN) | (1 << ADSC)); /* hit it */
}

//zyklisch
//Aufwachen
void ADC_GetVccVoltage()
{
  ADCSRA |= (1 << ADEN) ;
  _delay_us(70);
  ADCSRA |= ( (1 << ADSC));  /* enable ADC to get VCC */
  while ((ADCSRA & (1<<ADSC)))
  {}
  (void)ADC; /* read value to get the next updated */
  ADCSRA |= ( (1 << ADSC));  /* enable ADC to get VCC */
  while ((ADCSRA & (1<<ADSC)))
  {}

  u16_voltage = (ADC >> 2);
  if(u16_voltage != 0)
  {
    u16_voltage = (uint16_t) ((((11 * 2550)) / (u16_voltage)));
  }
  ADCSRA &= (~(1 << ADEN));  /* disable ADC to save power */
}

von Marco P. (Firma: keine) (marcopolo)


Lesenswert?

Steffen schrieb:
> ach ja, es kann auch an der gesamten startroutine liegen. warum machst
> das nicht wie im tutorial?
>
> 
http://www.mikrocontroller.net/articles/AVR-GCC-Tutorial/Analoge_Ein-_und_Ausgabe
>
> das klappt auf alle fälle.

Weil das Tutorial nicht zu meiner Anwendung passt. Ich hab das schon 
gelesen, und so ähnlich mach ich das ja auch. Ich hab einen Externen 
Quarz welcher den atmega weckt und ab und zu genau diesen Task ausführt. 
Die Init wird nach Reset aufgerufen. Ander Aufgaben hat der ADC bis 
jetzt nicht.

: Bearbeitet durch User
von Steffen (Gast)


Lesenswert?

das dachte  ich schon... nur irgendwie ist das komisch:

u16_voltage = (ADC >> 2);

hier ist ne klammer zu viel ;-)
u16_voltage = (uint16_t) ((((11 * 2550)) / (u16_voltage)));

von Marco P. (Firma: keine) (marcopolo)


Lesenswert?

Hehe, die Klammer...
Ich hab das
   ADCSRA |= ( (1 << ADSC));  /* enable ADC to get VCC */
   while ((ADCSRA & (1<<ADSC))){}
   (void) ADC;

nun 5mal nacheinander drin. Damit gehts. Aber ich versteh nicht warum!??

: Bearbeitet durch User
von Steffen (Gast)


Angehängte Dateien:

Lesenswert?

ja die klammern ;-)

while (ADCSRA & (1<<ADSC)) {}

das reicht auch ;-)
hab dir mal eine main.c von mir angehangen, da mess ich die spannung und 
sende die per rfm12 raus. das geht 100%. der uc ist im sleep und wird 
durch den wdog aufgeweckt.

von Marco P. (Firma: keine) (marcopolo)


Lesenswert?

Vielen Dank dir!

Ich habs gerad auch empirisch ermittelt. Scheinbar muss der ADC Wert 
gelesen werden, und danach passiert noch was anderes bevor der start 
conversion wieder durchstartet. Mit 70us funktioniert es nicht, aber mit 
längeren Wartezeiten...

//zyklisch
//Aufwachen
void ADC_GetVccVoltage()
{
  ADCSRA |= (1 << ADEN) ;

  ADCSRA |= ( (1 << ADSC));  /* enable ADC to get VCC */
  while ((ADCSRA & (1<<ADSC)))
  {}
  (void)ADC; /* read value to get the next updated */

  _delay_us(500);

  ADCSRA |= ( (1 << ADSC));  /* enable ADC to get VCC */
  while ((ADCSRA & (1<<ADSC)))
  {}

  u16_voltage = (ADC >> 2);
  if(u16_voltage != 0)
  {
    u16_voltage = (uint16_t) (((11 * 2550) / (u16_voltage)));
  }
  ADCSRA &= (~(1 << ADEN));  /* disable ADC to save power */
}

Dann kann ich ja nun beruhigt ins Bette gehen. Danke Dir Steffen!

: Bearbeitet durch User
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.