Hallo
Ich versuche den Timer5 des ATMEGA 2560 zu nutzen, doch klappt das
leider nicht. Ich möchte, dass die ISR jede Sekunde einmal aufgerufen
wird. Bisher habe ich folgendes gemacht:
1
#define wait_ms 1000
2
3
voidsetup(){
4
//Init Serial
5
Serial.begin(9600);
6
7
//init Timer
8
TCCR5B|=(1<<CS51);//8 prescaler -> 0.5us cycles
9
TIMSK5|=(1<<ICIE5)+(1<<OCIE5A);//Interupt enable and compare A enable
10
OCR5AH=(wait_ms*1000*1000/500)>>8;
11
OCR5AL=(wait_ms*1000*1000/500);
12
TCNT5=0;
13
sei();//global Interrupt
14
}
15
16
voidloop(){
17
18
}
19
20
ISR(TIMER5_COMPA){
21
Serial.write('x');
22
TCNT5=0;
23
}
Leider gibt es mir keinen Interrupt. Habe ich den ISR Interrupt Vektor
falsch benannt?
Gruss Gary
Hallo,
da hast Du nicht in das Datenblatt des AVR gesehen, und dir fehlen
grundlegende C Kenntnisse.
Bit Manipulation. Bit-Masken werden über ODER (OR) verknüpft.
Wenn man diesen Interrupt ICIE5 freigibt, dann sollte man auch einen
Interrupthandler dazu linken.
Im Datenblatt steht auch, wie man den CTC Modus aktiviert.
Dazu muss man die richtigen Bits in den Registern TCCR5A und TCCR5B
setzen.
Mode 4: CTC WGM5[3:0] = 0100
Dann muss man auch OCR5A Register für den als TOP-Wert wählen.
Auch passen bei 8MHz = 8*10⁶Hz mit einem Vorteiler von 8, also Timer5
Clock = 8*10⁶Hz /8 = 1*10⁶Hz diese nicht in einen 16Bit Zähler (OCR5A).
Maximal also: 2¹⁶-1 = 65535
Somit muss man den Zähler 5 noch um einen Softwarezähler um weitere Bits
erweitern, oder einen anderen Vorteiler (Prescaler) verwenden.
Mit T5 Prescaler = 1024 ergibt sich:
T5 PRELOAD = uint16_t(1.0 * 8*10⁶ /1024 +.5) -1 = 7812 ; mit Aufrunden
Der Fehler ist dann minimal.
Deine Interrupt Service Routine ist fehlerhaft, man nutzt dort kein
Serial.write() und setzt nicht das Zählerregister 5 auf 0.
S. Landolt schrieb:> Verstehe ich das richtig: 10^9/500 für OCR5AL?
Ja der Wert ist zwar flasch (-1) fehlt, abe der Compiler verwendet nur
die untersten 8Bit.
Man könnte das auch als uint8_t(10^9/500) schreiben und die -1 nicht
vergessen.
ICIE ist imho Input Capture Interrupt Enable, was du suchst ist
vielleicht der Timer Overflow bzw der Timer Output Compare A/B
Interrupt.
Input Capture findet am ICP Pin statt.
Karl M. schrieb:
> abe der Compiler verwendet nur die untersten 8Bit.
Und der meldet bei dieser Konstantenzuweisung keinen Overflow, wie es
z.B. mein Assembler macht?
OCR5AH = (wait_ms*1000*1000/500)>>8;
OCR5AL =(wait_ms*1000*1000/500);
???
bist du dir sicher das, dass richtig ist ?
Nutz man nicht den Wert des Quarzes als Basis der Berechnung ?
Muss der Wert nicht bei jeder ISR wieder hinterlegen werden ?
ich denke mal eher so:
OCR5AH = (wait_ms*1000*1000/500)<<8;
OCR5AL =(wait_ms*1000*1000/500)&0xFF;
oder eher so:
bei 16MHz F_CPU
OCR5AH = (65535-(F_CPU/8/100))<<8;
OCR5AL =(65535-(F_CPU/8/100))&0xFF;
macht aber dann alle 10ms die ISR
Also, größeren Teiler !!
ähm... :
1000*1000*1000/500=2000000 ???
sind doch mehr wie 16bit !?
P.S.
Vorher mal auf nem Blatt Papier mal Rechnen ,
Was macht der ATmeag da eigentlich ?
Wie viele Impulse bekomme ich bei einem Teiler von zum Beispiel 8 in den
Timer , pro Sekunde ???
MFG
N.Sekan schrieb:> Nutz man nicht den Wert des Quarzes als Basis der Berechnung ?
Dieser Wert ist in den 500 eingeflossen: die 500 stellen die 500ns cycle
dar, aufgrund des prescalers 8.
N.Sekan schrieb:> 1000*1000*1000/500=2000000 ???> sind doch mehr wie 16bit !?
Das stimmt, habe das nun geändert, geht aber immer noch nicht.
1
#define wait_us 1000000
2
3
voidsetup(){
4
//Init Serial
5
Serial.begin(9600);
6
7
//init Timer
8
TCCR5B|=(1<<CS52);//256 prescaler -> 16us cycles
9
TIMSK5|=(1<<ICIE5)+(1<<OCIE5A);//Interupt enable and compare A enable
Gary,
ich habe Dir alle Fehler aufgezeigt und auch zwei Beispielrechnungen
gegeben, wenn Du es nicht für nötig ansiehst im Datenblatt das zu
verifizieren und auch zu verwenden, na dann..
Dann brauchst Du hier auch nicht mehr schreiben.
Selbst Die Formel für die verschiedenen Zählereinstellungen stehen im
Datenblatt.
20.4.2 Clear Timer on Compare Match (CTC) Mode
Die Formel ist als "waveform frequency" angegeben !
Eine Formel umstellen wird bestimmt noch klappen.
>#define wait_us 1000000
wenn ich mich recht erinner dann doch nur so:
#define wait_us 1000000UL
sonst kommt das eh nicht an
und:
>int val = wait_us/16-1;
dann so
int val = (wait_us/16UL)-1UL;
oder
int val = (int)((unsigned long)(wait_us/16UL)-(unsigned long)1UL);
wenns richtig ankommen soll, evtl. habe ich irgendwo doppelt gemoppelt,
aber vergessene cast sind schlimmer
wie gesagt :
Mit wie viel MHZ läuft der Chip ?
bei 16MHz
durch 256 = 62500 Takte pro Sekunde
also muss 62500 als Vergleichswert im OCRA stehen !
Denk ich mal
Datenblatt mal lesen !!!
steht meist alles drin !!
Du kannst übrigens in C direkt OCR5A = uint16_t value schreiben, also
z.B. OCR5A = 65000;.
Weiterhin wie bereits erwähnt: Du hast den Input Capture Interrupt an!
Aber du hast nur den COMPA Interruptvektor definiert.
ISR gehört btw. über die main() wegen C forward Deklaration aber kann
sein dass das in C++ umwichtig ist.
Karl M. schrieb:> C-Grundlagen !>> was kommt hier wohl bei 16 Bit Arithmetik heraus ?#define wait_us> 1000000> int val = wait_us/16-1;
62499, was ein valider Wert für OCRxA ist. Aber wenn man es in einen int
packt, führt der Überlauf zu...32767 oder so? In dem Fall wäre der
Interrupt einfach doppelt so schnell wie gewollt. Das kanns nicht sein.
Nur mal so interessehalber...was hindert dich daran, deine Setup-Routine
mal mit Serial.Write zuzupflastern und bei jeder Zeile zu gucken was
hinten rauskommt? Das ist ein Debugging-Tool, das sollte man zum
debuggen verwenden!
Fuse-Settings wären ganz gut, Vielleicht ist die Watchdog-Fuse gesetzt.
Aber der Rest ist auch interessant.
uint16_t val = (wait_us/64UL)-1;
OCR5A = val;
Geht auch OCR5A = 15624;.
wait_us/64UL (unsigned long! Für 6 bit!) wird beim kompilieren eh genau
dazu.
Bist du dir sicher, dass es nur mit Werten kleiner 64 geht?
TCCR5B |=(1<<CS52)+(1<<CS50)+(1<<WGM52);
Das mit den Pluszeichen wäre mir neu. Guck dir mal das AVR-GCC Tutorial
OBEN LINKS an.
Karl M. schrieb:> Ja der Wert ist zwar flasch (-1) fehlt, abe der Compiler verwendet nur> die untersten 8Bit.
Das scheint zu stimmen, TCNT5 geht nur bis 255. Der Timer5 ist aber ein
16bit Timer?
S. Landolt schrieb:> Au contraire, das ist steinalt, so habe ich es vor Ewigkeiten in der> Schule in Schaltalgebra gelernt.
Die hat aber nichts mit der Programmiersprache C zu tun. ;-)
Allerdings ist das in diesem Falle egal, wenn man zwei Zahlen addiert,
in denen je ein Bit gesetzt ist, welches in beiden Zahlen verschieden
ist (das ist hier gegeben), dann hat eine Addition das gleiche Ergebnis
wie eine VerODERung.
Ja, volatile für die Auswertevariable ist auf jeden Fall Pflicht.
Gary schrieb:> uint16_t val = (wait_us/64UL)-1;
Pure Logik sollte dich stutzig werden lassen: da taucht nirgends ein
F_CPU auf, aber ganz offensichtlich sollte der Wert von der Frequenz
abhängen.
> Die hat aber nichts mit der Programmiersprache C zu tun. ;-)> Allerdings ist das in diesem Falle egal
Wir wollen Assembler nicht vergessen.
Und einen kleinen Unterschied gibt es: ein Zehnfingerschreiber tut sich
mit dem '+' leichter als mit dem '|'.
Jörg Wunsch schrieb:
> Die hat aber nichts mit der Programmiersprache C zu tun. ;-)
Übrigens ist diese Bitsetzerei in den SFRs sehr wohl reinste
Schaltalgebra, was sonst?
S. Landolt schrieb:>> Die hat aber nichts mit der Programmiersprache C zu tun. ;-)>> Allerdings ist das in diesem Falle egal>> Wir wollen Assembler nicht vergessen.> Und einen kleinen Unterschied gibt es: ein Zehnfingerschreiber tut sich> mit dem '+' leichter als mit dem '|'.
Eigentlich nicht, aber ich habe ein QWERTY Keyboard auf meinem Thinkpad
drauf und da gibts die Taste nicht. Daher trotzdem danke.
Und ja: Es ist boolsche Algebra und ja, das Pluszeichen ergibt Sinn. Ich
habe ja auch nur gesagt, dass es mir NEU ist.
Habe das nochmal überarbeitet, doch am Wert im OCR5A liegt es nicht, der
ist richtig. Sobald der prescaler zu hoch ist, ändert sich der Wert in
TCNT5 nicht mehr.
Diese Ignoranz !
Ich habe Dir die Formel noch hingeschrieben und was machst Du daraus ?
Code der falsch ist !
Was steht wohl in val ?
Welchen Prescaler verwendest Du ?
//8 prescaler -> 0.5us cycles, activate CTC
S. Landolt schrieb:> Übrigens ist diese Bitsetzerei in den SFRs sehr wohl reinste> Schaltalgebra, was sonst?
Trotzdem musst du dich bei der Notation an die Regeln der verwendeten
Programmiersprache halten.
0x20 + 0x20 ist eben etwas anderes als 0x20 | 0x20.
if(val > 65536) {
Serial.write("error");
Also wenn val ein int ist, ist der auf AVR wenn ich mich nicht irre ein
signed int 16 bit. Wie kann der bitte größer als 65536 werden? Nichtmal
ein uint16_t könnte das!
val = int(wait_us*(F_CPU/1000000)/prescaler+0.5)-1;
Hier wüsste ich selbst nicht so wirklich was dabei rauskommt. Versuch:
wait_us*(F_CPU/1000000)= 16 Mio. Furchtbar schlau, erst eine Million
wegzudividieren, um sie danach wieder draufzumultiplizieren.
16 Mio / prescaler = 15625
+0.5 = vermutlich 15625.
Das ganze in einen int casten (wobei ein cast eher
(uint16_t)ZuCastenderWert) ist): 15625
1 abziehen: 15624. Wie gut dass ich das vor einer Stunde schon so
geschrieben hatte. Systematisch Fehlerquellen zu eliminieren (wie deine
komplizierten Berechnungen) ist nicht so dein Ding, was.
Und was hindert dich an Serial.write(val)? Oder falls das nicht klappt,
die bekannte itoa-Angelegenheit.
Gary schrieb:> OCR5AH bleibt immer 0, egal wie ich die Zuweisung mache:
Glaub' ich nicht.
Lad' doch mal das erzeugte ELF-File mit hoch.
Wenn es so wäre, müsste übrigens alles trotzdem noch funktionieren,
nur halt sehr viel schneller als erwartet.
Karl M. schrieb:> schreibe doch bitte die Timer 5 OCR5A Init genau so und berichte bitte:
Habe das nun so gemacht und hier dazu noch das .ELF
OCR5AH bleibt immer noch 0.
S. Landolt schrieb:> itoa(OCR1AL,buff,10);> itoa(OCR1AH,buff,10);
Das gibt mit 8 für OCR1AL und 0 für OCR1AH.
Wenn ich OCR1A=256 setzte, gibt mir das 0 für OCR1Al und 0 fürOCR1AH,
als wäre kein OCR1AH vorhanden.
Mir ist aufgefallen, dass bei meinem Arudino Mega 2560 made in china
draufsteht, sollte doch made in italy sein, habe den auf ebay gekauft
und der war nicht gerade billig. Wenn es sich um eine Fälschung handelt,
ist es möglich, dass die irgendetwas verbaut haben, dass nur 8bit Timer
hat?
S. Landolt schrieb:> Jetzt bin ich etwas irritiert (und war auch reingefallen): nicht eins,> sondern fünf: OCR5A!?
Sorry, habe das nur zum testen geändert, auch wenn ich alles auf Timer 5
einstelle ändert sich nichts.
Bevor ich mich in die Fasnet (sic!) verabschiede, eine Bitte:
OCR5A= 0x1234;
itoa(OCR5AL,buff,10);
Serial.println(buff);
itoa(OCR5AH,buff,10);
Serial.println(buff);
Welche Ausgabe liefert dies?
(Hoorig isch die Katz)
Zunächst solltest du deine Registerzugriffe wie folgt abändern, da
dieses Verodern mit dem zuvor enthaltenen Inhalt zu Fehlern führen kann.
Dabei bitte auch Jörgs Anmerkung mit einarbeiten:
S. Landolt schrieb:> OCR5A= 0x1234;> itoa(OCR5AL,buff,10);> Serial.println(buff);> itoa(OCR5AH,buff,10);> Serial.println(buff);
Das Liefert:
52
0
Felix Adam schrieb:> TCCR5A = 0;
Das gibt es doch nicht! Das war tatsächlich der Fehler der OCR5AH immer
0 sein lies.
Arduino belegt den Inhalt wohl als Vorbereitung für irgendwas vor. Daher
beim ersten schreibenden Zugriff auf Register besser nur ein "=" statt
"|=" benutzen und besser alle Register initialisieren.
Hallo,
nicht dass jemand noch schreib, dass das nicht genannt wurde:
Karl M. schrieb:> Dazu muss man die richtigen Bits in den Registern TCCR5A und TCCR5B> setzen.> Mode 4: CTC WGM5[3:0] = 0100Karl M. schrieb:> Noch eine Anmerkung,>> guter Stil ist es alle relevanten Register von Timer5 zu initialisieren.>> TCCR5A = ...> dort finden wir die Bits WGM51 WGM50.
Es kommt leider nur bei Gary mit der Holzhammer Methode an.
Hallo,
vielleicht stand da vorher einer dieser Mode drin:
Timer 5
17.9 Modes of Operation
1: PWM, Phase Correct, 8-bit
5: Fast PWM, 8-bit
oder eine Mode mit TOP: ICR5
8 : PWM, Phase and Frequency Correct
10: PWM, Phase Correct
12: CTC Mode
Danke, Karl M.
Und, Jörg Wunsch, ich komme zwar nie auf die Idee, ein und dasselbe Bit
zweimal zu setzen, aber ich gebe Ihnen unumwunden zu, Ihr letztes
Argument war sehr gut.
Gary schrieb:> Karl M. schrieb:>> schreibe doch bitte die Timer 5 OCR5A Init genau so und berichte bitte:>> Habe das nun so gemacht und hier dazu noch das .ELF>> OCR5AH bleibt immer noch 0.
Hier das entsprechende Stück aus dem Disassembler:
1
00000144 <setup>:
2
144: 26 e0 ldi r18, 0x06 ; 6
3
146: 40 e8 ldi r20, 0x80 ; 128 ; 0x2580 => 9600
4
148: 55 e2 ldi r21, 0x25 ; 37
5
14a: 60 e0 ldi r22, 0x00 ; 0 ; 0x22D => Adresse von Serial (Objekt, this-Pointer)
Danach folgt noch die Ausgabe von val und OCR5AH.
Da wird OCR5A auf 0xFFFF (oder 65535) gesetzt, und nicht auf den
Wert von val!
Irgendwie passt das Compilat nicht zum Sourcecode.