Forum: Mikrocontroller und Digitale Elektronik Takteinstellung ATtiny84A


von Hans Peter (Gast)


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!

von Conny G. (conny_g)


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.

von Hans Peter (Gast)


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

von Thomas E. (thomase)


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.

von Hans Peter (Gast)


Lesenswert?

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 :)

von Thomas E. (thomase)


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.

von Hans F. (dani1632)


Lesenswert?

Ok, dann lass ich das mit der Taktänderung... Vielen Dank für die 
Hilfe!!

von Hans Peter (Gast)


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

von Karl H. (kbuchegg)


Lesenswert?

Da hab ich mal deine ganzen _delay in Verdacht.
Ob die delay Makros mit der niedrigen Taktfrequenz (du hast doch F_CPU 
auf 128000 gestellt?) überhaupt klar kommen, weiß ich nicht.

von Karl H. (kbuchegg)


Lesenswert?

Hans Peter schrieb:

> 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?

Ich denke eher es liegt am Code.
128kHz sind zwar in Relation recht langsam. Es sind aber immer noch rund 
100-tausend Operationen pro Sekunde.

von Hans Peter (Gast)


Lesenswert?

Ok danke für den Hinweis... Jetzt weiß ich dass es sich lohnt 
weiterzuschaun...

Hmmm... aber woran könnte das liegen? Kann ich bei der Initialisierung 
irgendwas besser machen?

von Karl H. (kbuchegg)


Lesenswert?

Den Haupthinweis hast du doch schon.
_delay_ms

Prüf halt mal mit einem Testprogramm nach, ob die dadurch erreichten 
Zeiten überhaupt stimmen. Die paar Zuweisungen an Register sind ganz 
sicher nicht das Problem.

von Hans Peter (Gast)


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 :(

von Karl H. (kbuchegg)


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.

: Bearbeitet durch User
von Hans Peter (Gast)


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!!

von spess53 (Gast)


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

von Hans Peter (Gast)


Lesenswert?

1
ISR(ADC_vect)
2
{
3
  adc_result = ADCL;
4
  adc_result += (ADCH << 8);
5
}

von spess53 (Gast)


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

von Hans Peter (Gast)


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

von Jörg W. (dl8dtl) (Moderator) Benutzerseite


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?

von Hans Peter (Gast)


Lesenswert?

Ich denke, diese Optimierung ist defaultmäßig eingestellt, wo kann ich 
das im AVR Studio 6 nachschaun/einstellen?

von Jörg W. (dl8dtl) (Moderator) Benutzerseite


Lesenswert?

Hans Peter schrieb:
> wo kann ich das im AVR Studio 6 nachschaun/einstellen?

Sorry, da kenn ich mich nicht aus damit.

Muss irgendwo ein -Os oder -O1 auf der Compiler-Kommandozeile 
auftauchen.

von Karl H. (kbuchegg)


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>

: Bearbeitet durch User
von Hans Peter (Gast)


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!

von spess53 (Gast)


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

von Hans Peter (Gast)


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!!!

: Bearbeitet durch User
von Karl H. (kbuchegg)


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.

: Bearbeitet durch User
von Hans Peter (Gast)


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

von spess53 (Gast)


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

von Jörg W. (dl8dtl) (Moderator) Benutzerseite


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.

: Bearbeitet durch Moderator
von spess53 (Gast)


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

von Karl H. (kbuchegg)


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.

: Bearbeitet durch User
von Hans Peter (Gast)


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!

von Karl H. (kbuchegg)


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.

von Jörg W. (dl8dtl) (Moderator) Benutzerseite


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);

von Hans Peter (Gast)


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...

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.