Takteinstellung ATtiny84A

Gast #3319295
Lesenswert?

Hallo!

Ich verwende den ATtiny84A für eine LED-Ansteuerung mit PWM, auch der 
ADC und Timer werden benutzt.

Datenblatt:
http://www.atmel.com/Images/doc8183.pdf

Ein interner Oszillator hat 8MHZ für den Takt, ist defaultmäig 
aktiviert. Auch die Fuse CKDIV8 ist defaultmäßig gesetzt, der µC läuft 
also mit 1 MHZ Takt. Ich habe die ganzen Prescaler für PWM, Timer, ADC 
Takt auf diesen Takt bezogen (z.B. beim Timer: Prescaler 8 ergibt dann 
einen Takt von 125kHz). So weit so gut...

Nun besitzt der µC auch einen internen Oszillator mit 128kHz, welchen 
ich gerne aus Energiespargründen verwenden würde.
Meine Fragen dazu:
1.) Kann ich das nur beim Programmiervorgang über die Fuse umstellen 
oder geht das auch, indem ich softwaremäßig in CKSEL Register was 
reinschreib?

2.) Werden die ganzen Takte für PWM, Timer, ADC nun auf diesen Takt 
bezogen? Muss ich also die Prescaler dementsprechend anpassen?!

3.) Wie ist das dann mit dieser CKDIV8-Fuse, muss ich diese auch 
deaktivieren damit der Takt bei 128 kHz bleibt?

Vielen Dank!
#3319316
Lesenswert?

Seite 32 des Datasheet:
das DIV8 Fuse verursacht, dass der Clock Prescaler mit 8 initialisiert 
wird, d.h. das gilt auch für den 128k Oszillator.
Dementsprechend gilt das für alles, was von der System Clock abhängt.
Wenn Du es also nicht haben willst, musst Du die Fuse rausnehmen beim 
Programmieren.

Die 128k Modus setzt Du über Fuse, kannst Du nicht im Code "von innen" 
machen.
Du kannst aber den Prescaler im laufenden Betrieb rausnehmen und von 
128/8 auf 128k kommen nachdem Dein Progrämmchen gestartet hat.
D.h. DIV8 ist gesetzt, AVR startet mit 128k/k Hz, dann Prescaler setzen, 
Du hast 128k Hz.
Gast #3319344
Lesenswert?

Ok danke für die Antwort...

Ich programmiere üpber DWenable. Bevor ich die Fuses setze, habe ich 
während des Debuggens "Disable DebugWire and Close" ausgewählt 
(Debug-Menü), damit die DWEN-Fuse wieder gelöscht wird und ich auf die 
Fuses zugreifen kann.

Dann habe ich unter Tools->Device Programming -> Fuses die CKDIV8 Fuse 
gelöscht und bei SUT_CKSEL 128kHz internen Oszillator ausgewählt. Dann 
bin ich auf "Programm" und seit dem kann ich die Fuses nicht mehr 
lesen?!

Ich kann jedoch weiterhin im DebugWireEnable Modus programmieren. Was 
habe ich falsch gemacht?

Danke
#3319380
Lesenswert?

Hans Peter schrieb:
> Ok danke für die Antwort...
>
> Ich programmiere üpber DWenable. Bevor ich die Fuses setze, habe ich
> während des Debuggens "Disable DebugWire and Close" ausgewählt
> (Debug-Menü), damit die DWEN-Fuse wieder gelöscht wird und ich auf die
> Fuses zugreifen kann.
>
> Dann habe ich unter Tools->Device Programming -> Fuses die CKDIV8 Fuse
> gelöscht und bei SUT_CKSEL 128kHz internen Oszillator ausgewählt. Dann
> bin ich auf "Programm" und seit dem kann ich die Fuses nicht mehr
> lesen?!
>
> Ich kann jedoch weiterhin im DebugWireEnable Modus programmieren. Was
> habe ich falsch gemacht?
>
> Danke

Wenn ich das jetzt richtig sortiert habe, kannst du im ISP-Mode nicht 
mehr zugreifen, weil dein ISP-Takt mit 125KHz zu hoch ist. Der ISP muss 
<=1/4 CPU-Takt sein.

Aber zu deinem Hauptanliegen:
Du willst doch keine 2-mA-Leds dimmen. Den Löwenanteil des Stromes 
ziehen deine Leds aus der Batterie. Das, was der Controller 
währenddessen braucht, sind doch Peanuts. Und das bleiben auch bei 8MHz 
noch Peanuts.

Lass dieses Taktgefriemel. Schalte das Teil aus, wenn die Leds nicht 
leuchten oder setzt den Controller in den Powerdown-Seepmode. Und gut 
ist.

Und wenn das Ganze an einem Netzteil hängt, lohnt es sich nicht, auch 
nur eine Sekunde über Stromsparmodi nachzudenken.

mfg.
#3319416
Lesenswert?

Hans Peter schrieb:
> Ok, jetzt ist mir wieder einiges klarer...
>
> Wohl, ich will 2 mA LEDs dimmen. Insgeamt fließen um die 5 mA, zahlt es
> sich in diesem Fall auch nicht aus, den Takt runterzustellen?
>
> Dankesehr :)

Guck mal ins Datenblatt:
21.2.1 Current Consumption in Active Mode

Bei 2,7V und das reicht für deine Leds dicke aus, beträgt der 
Unterschied zwischen 128KHz und 1MHz ca. 0,2 mA. Also in deinem Fall 
etwa 5,1 zu 5,3. Der Preis dafür ist, daß du aus deinem Controller eine 
total lahme Gurke machst.

mfg.
Gast #3324145
Lesenswert?

Hallo!

Ich habe nun doch versucht und es geschafft, die Taktfrequenz auf 128 
kHz umzustellen. Ich verwende eine Batterie mit 1,5V, die mit einem 
Step-Up auf 5V für die µC Versorgung gebracht wird... Dieser 
funktioniert bis 0,7V und in diesem Bereich werden die Ströme am Eingang 
höher um die 5V zu halten (um die 40mA). Am Ausgang des µC habe ich 4 
LEDs (2 Parallelstränge mit jeweils 2 LEDs und einen Rv) udn einen 
zusätzliche LED. Durch all diese LEDs fließe ca 2 mA, also insgesamt ca. 
6mA. Zusätzlich hängen am Ausgang des Step-UP(5V) nur noch der µC selbst 
und externe Beschaltungen (Externe Referenz für ADC,...).

Da es in diesem Bereich, in dem die Batteriespannung immer kleiner wird, 
größere Unterscheide im Strom gibt (zwischen 1MHz Takt und 128kHz Takt, 
ca 10mA), würde ich es mit den 128kHz trotzdem gerne versuchen.

Die beiden Timer habe ich ohne Prescaler initialisert (laufen also mit 
128kHz) den ADC Takt habe ich mit einen Teiler von 2 auf 64kHz 
eingestellt (sollte laut Datenblatt in dem Bereich liegen). Die CKDIV8 
Fuse habe ich ebenfalls rausgenommen, um bei den 128kHz zu bleiben.

Timer und ADC funktionieren soweit richtig, aber der Programmablauf ist 
sehr langsam. Alein die Initialisierungsphase:
1
  DDRA |= (1 << PA7) | (1 << PA3);  // output
2
  DDRB |= (1 << PB2);           // output
3
  
4
  PORTA &= ~(1 << PA3);  // low  
5
  //PORTB |= (1 << PB1);  // high 
6
  
7
  // Timer0 -> PWM (8 Bit)
8
  TCCR0A |= (1 << COM0A1) | (1 << COM0B1) | (1 << WGM00);
9
  TCCR0B |= (1 << CS00);  // prescaler 1 -> 128kHz
10
  TCNT0 = 0;                            
11
  OCR0A = 0    // compare value 0 -> duty cycle 0
12
  OCR0B = 0;
13
  
14
  // Timer1 -> general purpose timer (16 Bit)
15
  TCCR1B |= (1 << CS10);  // prescaler 1 -> 128 kHz
16
  TIMSK1 |= (1 << TOIE1);    // enable interrupt for timer overflow
17
  TCNT1 = 0;    // timer value initialization
18
  
19

20
  // ADC
21
  PRR &= ~(1 << PRADC);     //disable Power Reduction for ADC
22
  ADMUX |= (1 << REFS0) | (1 << MUX1);  //extern reference, activate ADC channel 2 (PA2)
23
  _delay_ms(1);
24
  ADCSRA |= (1 << ADEN) | (1 << ADATE) | (1 << ADIE);  // activate ADC, free running mode, ADC interrupt enable (conversion complete), prescaler 2 -> 64 kHz
25
  _delay_ms(1);
26
  ADCSRA |= (1 << ADSC);  // start ADC
27
  _delay_ms(1);
28

29
  sei();  // global interrupt enable
30
  
31
  _delay_ms(100);

dauert sehr lange (ca 10 Sek.) Auch auf Tastendrücke währned des 
Betriebes reagiert der µC erst nach ca 2 Sek...

Nun meine Frage: Ist das die "lahme Ente" von der Du (Thomas) gesprochen 
hast? Ist das prinzipiell wegen der niedrigen Taktfrequenz von 128 kHz 
oder liegts am Code?

Danke, lG
Gast #3324232
Lesenswert?

OK, danke...

Die delay-Befehle scheinen viel zu lange zu dauern. Aber auch der oben 
angeführte Code bis zum ersten delayms(1) dauert ca 2 Sek... Ist das OK?

Ich habe nun am Beginn #define F_CPU 128000 eingefügt, das ändert aber 
nichts :(
#3324254
Lesenswert?

Hans Peter schrieb:
> OK, danke...
>
> Die delay-Befehle scheinen viel zu lange zu dauern. Aber auch der oben
> angeführte Code bis zum ersten delayms(1) dauert ca 2 Sek... Ist das OK?
>
> Ich habe nun am Beginn #define F_CPU 128000 eingefügt, das ändert aber
> nichts :(

Mach halt mal einen Test
1
#define F_CPU 128000
2

3
#include <avr/io.h>
4
#include <util/delay.h>
5

6

7
int main()
8
{
9
  // *******************************
10

11
  DDRB |= (1 << PB2);          // so schnell wie möglich eine LED einschalten
12
  PORTB &= ~( 1 << PB2 );
13

14
  // *******************************
15

16
  DDRA |= (1 << PA7) | (1 << PA3);  // output
17
  DDRB |= (1 << PB2);           // output
18
  
19
  PORTA &= ~(1 << PA3);  // low  
20
  //PORTB |= (1 << PB1);  // high 
21
  
22
  // Timer0 -> PWM (8 Bit)
23
  TCCR0A |= (1 << COM0A1) | (1 << COM0B1) | (1 << WGM00);
24
  TCCR0B |= (1 << CS00);  // prescaler 1 -> 128kHz
25
  TCNT0 = 0;                            
26
  OCR0A = 0    // compare value 0 -> duty cycle 0
27
  OCR0B = 0;
28
  
29
  // Timer1 -> general purpose timer (16 Bit)
30
  TCCR1B |= (1 << CS10);  // prescaler 1 -> 128 kHz
31
  TIMSK1 |= (1 << TOIE1);    // enable interrupt for timer overflow
32
  TCNT1 = 0;    // timer value initialization
33
  
34

35
  // ADC
36
  PRR &= ~(1 << PRADC);     //disable Power Reduction for ADC
37
  ADMUX |= (1 << REFS0) | (1 << MUX1);  //extern reference, activate ADC channel 2 (PA2)
38
  ADCSRA |= (1 << ADEN) | (1 << ADATE) | (1 << ADIE);  // activate ADC, free running mode, ADC interrupt enable (conversion complete), prescaler 2 -> 64 kHz
39
  ADCSRA |= (1 << ADSC);  // start ADC
40

41
  // *******************************
42
  // Kontrollled wieder ausschalten
43
  PORTB |= ( 1 << PB2 );
44

45
  while( 1 ) {
46
    _delay_ms( 500 );
47
    PORTB &= ~( 1 << PB2 );
48
    _delay_ms( 500 );
49
    PORTB |= ( 1 << PB2 );
50
  }
51
}

Ich hab angenommen, dass an PORTB, Pin 2 eine LED sitzt. Wenn das bei 
dir anders ist, dann tausch das eben aus.

Die Zeit nach dem Einschalten, bis die LED ganz am Anfang von main() 
eingeschaltet wird, kann man zwar noch verkürzen, aber ansonsten ist die 
mehr oder weniger vorgegeben. Denn das C-Runtime System hat auch einiges 
zu tun, bis es die Kontrolle an main() abgibt

Vor der Hauptschleife wird die LED dann noch mal umgeschaltet, die Zeit 
dazwischen, das ist die Zeit, die für deine Initialisierungen gebraucht 
wird. Ich würde mal erwarten, dass das nicht allzulang ist. Denn auch 
bei 128kHz werden die 20 oder 30 Operationen in weniger als 1 
Millisekunde abgearbeitet.
Und dann ist da noch die Hauptschleife, in der es darum geht, ob 
_delay_ms mit 128kHz überhaupt korrekte Ergebnisse liefert.

Ganz abgesehen von der Fragestellung, wozu man _delay_ms überhaupt 
braucht (*). Delays sind in einem Programm selten die Lösung. Sie sind 
aber oft das Problem.

(*) mit der Ausnahme von delays im µs Bereich, die man für Protokolle 
schon mal braucht, bzw. delays am Programmanfang um die 
Selbstinitialisierung externer Komponenten, wie zb LCD, abzuwarten.
Gast #3324362
Lesenswert?

Mit deinem Testprogramm funktioniert alles wie es soll... Die 
Initialisierungsphase ist sehr kurz und danach blinkts im 2Hz-Takt...

Aber wenn ich mein Programm dann wieder starte hab ich wieder das 
gleiche Problem... Kann das Problem eventuell daran liegen, dass der ADC 
im FreeRunningModus läuft (mit 64kHz). Der Haupttakt liegt ja nun bei 
128kHz, kann das sein, dass nun nach jedem zweiten Befehl eine ADC 
Wandlung durchgeführt wird?

Danke!!
Gast #3324372
Lesenswert?

Hi

>Kann das Problem eventuell daran liegen, dass der ADC
>im FreeRunningModus läuft (mit 64kHz).

Da alle 26 Controllertakte ein Interrupt ausgelöst wird, durchaus 
möglich. Wie sieht deine ISR aus?

MfG Spess
Gast #3324412
Lesenswert?

Hi

Interessant wäre das Assembler Listing. Aber wenn das grob geschätzt 20 
Takte braucht, dann bleiben nur 6 Takte für das restliche Programm. Das 
merkt man schon.

An deiner Stelle würde ich statt Free Running den ADC mit dem 
Timer0-Overflow triggern. Kannst du mit den ADTS-Bits von ADCSRB 
einstellen.

MfG Spess
Gast #3324426
Lesenswert?

Hmm, danke vielmals für den Hinweis, werde ich mal versuchen!

Im Zuge des Debuggens ist mir nun auch aufgefallen, dass IF-Abfragen 
relativ lange (ca 1s!!) dauern, was auch sehr stark zu verzögerungen 
beiträgt.. Wie kann das sein?

lG
Moderator Persönliche Seite #3324434
Lesenswert?

Conny G. schrieb:
> Die 128k Modus setzt Du über Fuse, kannst Du nicht im Code "von innen"
> machen.

Man kann aber den normalen 8-MHz-Oszillator nehmen und den mit dem
Prescaler herunterteilen.  Auf diese Weise kommt man bis zu 32 kHz
hinab.

Dürfte deutlich handlicher sein als das Gefummel mit den Fuses.

Eigentlich ist es aber nicht sinnvoll, so langsam zu takten.  Besser
ist es, stattdessen die CPU während der Wachphase schneller laufen
zu lassen und dann schlafen zu legen.

_delay_ms benutzt eine Loop, die mit 4 Takten pro Zyklus arbeitet.
Bei 128 kHz ergibt das eine Granularität von 31 µs.  Eigentlich sollte
sich damit ein Delay von 1 ms brauchbar genug einrichten lassen.

Dumme Frage: die Compiler-Optimierung hast du aber aktiviert, ja?
#3324504
Lesenswert?

Hans Peter schrieb:

> relativ lange (ca 1s!!) dauern, was auch sehr stark zu verzögerungen
> beiträgt.. Wie kann das sein?


An deinem Code!
(So wie immer. Und auch so wie immer, zeigst du den nur in 
homöopathischen Dosen, erwartest aber, dass wir dir ganz genau sagen wo 
die Probleme liegen)


Wenn bei meinem Code die _delay_ms korrekt arbeiten, in deinem Code aber 
nicht, dann könnte das an der Reihenfolge liegen

Falsch
1
#include <util/delay.h>
2

3
#define F_CPU 128000

Richtig
1
#define F_CPU 128000
2

3
#include <util/delay.h>
Gast #3324546
Lesenswert?

Das define F_CPU ist vor dem include<delay...> definiert, das mit den 
delays funktioniert nun auch korrekt...

Wenn ich den ganzen Code rein stelle, wird es wohl sehr 
unübersichtlich... Es liegt wahrscheinlich wirklich daran, dass der ADC 
im FreeRunningModus läuft... wenn ich in der ISR vom ADC einen 
breakpoint setze, komm ich gar nicht mehr raus...

Ich bin gerade dabei, den ADC auf den Timer0(8bit) zu triggern. das 
erreiche ich, wenn ich das ADTS2 Bit im ADCSRB register setze. Den Timer 
0 hab ich aber für PWM initialisiert, kann ich trotzdem einen Timer0 
overflow interrupt aktivieren? Das würde ich mit TIMSK |= (1<<TOIE0) 
machen. Muss ich dann in der ISR des Timer0 noch was machen oder wandelt 
der danns chon jedes mal, wenn Timer0 überläuft? (das ADSC bit im ADSCRA 
ist gesetzt)...

Vielen Dank!
Gast #3324565
Lesenswert?

Hi

>Den Timer
>0 hab ich aber für PWM initialisiert, kann ich trotzdem einen Timer0
>overflow interrupt aktivieren?

Ja, das beeinflußt die PWN nicht.

>Muss ich dann in der ISR des Timer0 noch was machen

Nein.

>oder wandelt der danns chon jedes mal, wenn Timer0 überläuft?

Ja.

>(das ADSC bit im ADSCRA ist gesetzt)...

Brauchst du nicht setzen. Das wird bei Free Running nur zum Starten 
gebraucht.

MfG Spess
Gast #3324665
Lesenswert?

Schön langsam bin ich am verzweifeln:

in der ersten Zeile in der main rufe ich eine funktion init auf, in der 
ich alles initialisiere:
1
#define F_CPU 128000
2

3
#include "init.h"
4
#include <avr/io.h>
5
#include <util/delay.h>
6
#include <avr/interrupt.h>
7

8
void init()
9
{
10
  sei();  // global interrupt enable
11
  // general port definitions
12
  DDRA |= (1 << PA7) | (1 << PA3);  
13
  DDRB |= (1 << PB2);  // output
14
  
15
  PORTA &= ~(1 << PA3);  // low  
16

17
  // Timer0 -> PWM (8 Bit)
18
  TCCR0A |= (1 << COM0A1) | (1 << COM0B1) | (1<<WGM00); //  clear when up, set when down counting, WGM00: PWM phase correct
19
  TCCR0B |= (1 << CS00);  // prescaler 1 -> 128kHz
20
  
21
         //TIMSK0 |= (1 << TOIE0);  // overflow interrupt enable -> triggering ADC
22
  
23
          TCNT0 = 0;   // timer value initialization
24
  
25
  OCR0A = 0;    // compare value 0 -> duty cycle 0
26
  OCR0B = 0;
27
  
28
  // Timer1 -> general purpose timer (16 Bit)
29
  TCCR1B |= (1 << CS10);  // prescaler 1 -> 128 kHz
30
  TIMSK1 |= (1 << TOIE1);    // enable interrupt for timer overflow
31
  TCNT1 = 0;  // timer value initialization
32
  
33

34
  // ADC
35
  PRR &= ~(1 << PRADC); //disable Power Reduction for ADC
36
  ADMUX |= (1 << REFS0) | (1 << MUX1);            //extern reference, activate ADC channel 2 (PA2)
37
  _delay_ms(1);
38
  ADCSRA |= (1 << ADEN) | (1 << ADATE) | (1 << ADIE);    // activate ADC, free running mode, ADC interrupt enable conversion complete), prescaler 2 -> 64 kHz
39
  _delay_ms(1);
40
  ADCSRB |= (1 << ADTS2);  // Trigger on TIMER0 Overflow
41
  //ADCSRA |= (1 << ADSC);   // start ADC
42
  _delay_ms(1);
43

44
  
45
  
46
  _delay_ms(100);
47
  battery_test();    
48
}

Folgendes Problem:
sobald ich die Zeile //TIMSK0 |= (1 << TOIE0); auskommentiere, komm ich 
nicht mehr aus der init funktion raus (zurück in die main). Ich muss den 
Interrupt des Timer0 aber aktivieren, damit der ADC getriggert wird. 
Wenn ich den Kommentar drin lasse, funktioniert der Ablauf ganz normal, 
aber der ADC interrupt wird (verständlicherweise) nie ausgelöst! Ich 
nehme an, dass er bei diesem Befehl TIMSK0 |= (1 << TOIE0); immer 
irgendwie neu startet und aus der main wieder in die init hüpft...

Ich habe das nun so verstanden, dass ich den ADC nicht explizit starten 
muss, wenn er auf eine Timeroverflow getriggert ist. Was mache ich 
falsch?

Danke!!!
#3324676
Lesenswert?

Hans Peter schrieb:

> sobald ich die Zeile //TIMSK0 |= (1 << TOIE0); auskommentiere, komm ich
> nicht mehr aus der init funktion raus (zurück in die main).

Und. Hast du auch eine ISR für alle Interrupts die du frei gibst.

> Ich muss den
> Interrupt des Timer0 aber aktivieren, damit der ADC getriggert wird.

Ganz ehrlich.
Lass doch den ganzen Autotrigger Autotrigger sein.

Was ist denn falsch daran, wenn du in der Hauptschleife den ADC 
anstösst, der wandelt, du wartest auf das Ergebnis und wenn es fertig 
ist holst du es dir ab.

Einfach, simpel und funktioniert.
Gast #3324688
Lesenswert?

Muss ich für jeden Interrupt, den ich freigebe, auch eien ISR 
implementieren??? Das hab ich für den Timer0Overflow nicht gemacht, ich 
habe ihn nur aktiviert. Wenn das so ist, dann implementier ich dis ISR 
für TimeroOverflow als leere Funktion... und wenn er dann überläuft wird 
der ADC getriggert.

Was meinst du mit deiner zweiten Aussage? meinst du damit den 
FreeRunning mode oder einfach dass ich immer nach eienr gewissen zeit 
eine wandlung manuell starte?

Danke, lG
Gast #3324689
Lesenswert?

Hi

C ist nicht meine bevorzugte Programmiersprache.

Das sei() am Anfang der Initialisierung ist nicht sehr sinnvoll. Mach es 
ans Ende.

Hast du eine ISR für den Timer0 Overflow und bist du sicher, das die 
nicht wegoptimiert (Weiss nicht, ob das möglich ist) wird, wenn leer?

MfG Spess
Moderator Persönliche Seite #3324720
Lesenswert?

Hans Peter schrieb:
> Muss ich für jeden Interrupt, den ich freigebe, auch eien ISR
> implementieren?

Selbstverfreilich.  Wofür soll denn sonst der Interrupt gut sein?

> ??

Deine Fragezeichentaste klemmt. ;-)

> Das hab ich für den Timer0Overflow nicht gemacht, ich
> habe ihn nur aktiviert.

Dann bekommst du beim ersten Overflow einen Sprung auf die Adresse 0,
denn das ist als default-ISR hinterlegt.

> Wenn das so ist, dann implementier ich dis ISR
> für TimeroOverflow als leere Funktion...

Dafür gäbe es den Makro EMPTY_ISR(). (*)

> und wenn er dann überläuft wird
> der ADC getriggert.

Dafür brauchst du aber keinen Interrupt.  Der Überlauf selbst ist der
entsprechende Triggerpunkt für den auto-trigger-Modus.  Der Überlauf
selbst erfolgt (sofern der Timer läuft) ganz und gar auch dann, wenn
man dafür keinen Interrupt aktiviert.  Was sollte auch sonst mit dem
Timer in dem Moment passieren, wo die Zählweite erreicht ist und der
nächste Taktimpuls ankommt? ;-)

(*) Es kann manchmal Sinn haben, eine leere ISR zu haben für einen
Interrupt, der zwar freigeschaltet ist, aber sonst nicht behandelt
werden muss.  Das ist beispielsweise dann der Fall, wenn der
Interrupt dazu genutzt wird, den Controller aus dem Schlaf aufzuwecken,
aber sonst keine weitere Aktion in dem Moment nötig ist.
Gast #3324737
Lesenswert?

Hi

>Dafür brauchst du aber keinen Interrupt. Der Überlauf selbst ist der
>entsprechende Triggerpunkt für den auto-trigger-Modus.

Nein. Das Overflow-IR-Flag triggert den ADC. Man kann das natürlich auch 
im ADC-Interrupt manuell zurück setzen.

MfG Spess
#3324750
Lesenswert?

Hans Peter schrieb:

> Was meinst du mit deiner zweiten Aussage? meinst du damit den
> FreeRunning mode

Ich meine genau den Free Running Mode.

Auf der einen Seite bremst du deinen µC her, dass es nicht mehr 
feierlich ist, auf der anderen Seite bist du erpicht darauf, den ADC 
freilaufend (also möglichst schnell laufend) zu haben. Mit allen 
Problemen die sich daraus ergeben, wie zb das du nicht weißt wie alt das 
letzte Andlungsergebnis ist, dass du beim Zugriff auf das 
Wandlungsergebnis eine Sicherung für den atomaren Zugriff brauchst.
Gast #3324754
Lesenswert?

Weltklasse, jetzt funktionierts!

DANKE Euch vielmals!

Jetz ist mir das mit der ISR und dem Overflow auch klar. Was mir 
allerdings nicht klar ist, ist der Fehler, warum es nicht funktioniert 
hat:

Es ist die fehlende ISR des Timer0Overflow.

Mir ist klar, dass der ADC nun auf eienn Overflow getriggert ist, aber 
es funktioniert nicht, wenn ich
1
TIMSK1 |= (1 << TOIE1);// enable interrupt for timer overflow
und die ISR weglasse.

Wenn der Interrupt aktiviert und die ISR vorhanden ist (kann auch leer 
sein) funktioniert alles perfekt! Anscheinend ist das doch nicht auf 
eienn Overflow, sondern auf den interrupt getriggert?!

Wie auch immer, es funktioniert jetz und ich versteh nun auch, warum er 
ohne die ISR immer zum Anfang zurückgesprungen ist!

DANKE!
#3324759
Lesenswert?

Hans Peter schrieb:

> es funktioniert nicht, wenn ich
>
1
> TIMSK1 |= (1 << TOIE1);// enable interrupt for timer overflow
2
>
> und die ISR weglasse.
>

Weil das Ereignis ein Interrupt Flag setzt.
Aufgrund dieses gesetzten Interrupt Flags werden dann die weiteren 
Aktionen eingeleitet:
Ist es gesetzt, dann wird die ISR angesprungen
Wenn du genau liest, dann ist es der Vorgang des Setzens, der den ADC 
triggert.

D.h. wenn das Flag erst mal gesetzt ist, dann muss es auch gelöscht 
werden.
Entweder du machst das von Hand oder aber der µC macht das. Wie macht 
der µC das automatisch? Indem er in die ISR springt. Durch den Aufruf 
der zugehörigen ISR wird das Flag wieder gelöscht.

Löscht du es aber nicht, weder auf die eine noch auf die andere Weise, 
dann wird der ADC nicht mehr getriggert. Denn wenn es gesetzt ist, dann 
kann es ja nicht wieder gesetzt werden. Der ADC spricht aber auf genau 
diesen VOrgang, das Setzen des Flags an.
Moderator Persönliche Seite #3324778
Lesenswert?

spess53 schrieb:
>> Dafür brauchst du aber keinen Interrupt. Der Überlauf selbst ist der
>> entsprechende Triggerpunkt für den auto-trigger-Modus.
>
> Nein. Das Overflow-IR-Flag triggert den ADC.

Ah, OK, jetzt sehe ich es auch.  Das hamm'se gut im Text versteckt:
1
… A conversion
2
will be triggered by the rising edge of the selected Interrupt Flag. …

Gut, dann braucht man die
1
EMPTY_ISR(TIM1_OVF_vect);
Gast #3324780
Lesenswert?

Handelt es sich dabei um das TOV0-Flag im TIFR0-Register?

Im Datenblatt stehtm, dass ich dieses Flag setzen muss, damit es 
gerlöscht ist. Gehe ich richtig ind er Annahme, dass ich einfach in der 
ISR des ADC dieses Flag setze?

Übrigens: Ich hab jetzt noch mal versucht auf den Free-Running mode 
umzuschalten. Das funktionietr nicht. Ich nehme an, dass die 
Taktfrequenmz mit 128kHz im Vergleich zu den 64kHz des ADC einfach zu 
gering ist...

Antwort schreiben

Bitte melde dich an, um einen Beitrag zu schreiben.

oder

Mit Google-Account einloggen

Die Registrierung ist kostenlos und dauert nur eine Minute.

Jetzt registrieren