Hmm schrieb:
> Ich bin der Ansicht, dass der Einsatz des Sleep-Modes hier unangebracht
> ist.
>
> Magst Du das Programm mal bitte kommentieren, vielleicht erstmal in
> Hinblick auf den Sleep-Mode? Was soll mit dessen Verwendung errreicht
> werden und in welcher Weise`?
Der Sleep-Mode soll einfach weniger Saft ziehen wie eine IDLE-Loop
z.B.:
1 | while (ADCSRA & (1 << ADSC))
|
2 | ;
|
Ich will warten, bis die CPU fertig ist, dann den ADC wert auslesen, und
weiter geht's im Programm.
Die while-schleife ist da, da der timer ständig Interrupts abfeuert (und
die werden auch gebraucht!).
Ich habe aber festgestellt, dass nach jedem 2. Mess-versuch von VBG der
darauf folgende Messwert auch grottenfalsch ist (viel zu niedrig, eher
das, was ich für VBG erwartet hätte).
Ich habe das Problem aber jetzt gelöst:
1 | uint16_t get_adc_val(uint8_t chan) {
|
2 | int16_t adc_val;
|
3 |
|
4 | if (oldchan != chan) {
|
5 | ADMUX = (1 << REFS0) | (chan & 31);
|
6 | oldchan = chan;
|
7 | /* we disable and re-enable the ADC to avoid shitty readings */
|
8 | ADCSRA &= ~(1 << ADEN);
|
9 | ADCSRA |= (1 << ADEN);
|
10 |
|
11 | /* then we do a dummy reading (NB: old_chan is already changed here), and then we sleep for 100ms */
|
12 | get_adc_val(chan);
|
13 | _delay_ms(1.0);
|
14 |
|
15 | }
|
16 |
|
17 | set_sleep_mode(SLEEP_MODE_IDLE);
|
18 | sleep_enable();
|
19 | sei();
|
20 |
|
21 | ADCSRA |= (1 << ADSC); /* start cvonversion */
|
22 |
|
23 | while (ADCSRA & (1 << ADSC))
|
24 | sleep_cpu();
|
25 |
|
26 | sleep_disable();
|
27 | adc_val = ADC;
|
28 |
|
29 | return adc_val;
|
30 | }
|
Also, beim Kanal wechseln, einen vollen Reset des adc, dummy-messung, 1
ms warten, messen.
Hier habe ich die Busy-loop, weil ich normalerweise den Kanal nicht so
oft wechsle. Jetzt gib't auch sinnvolle Messwerte.