Hallo Leute,
Ich habe versucht bei einem Arduino Programm den Timer1 mit
einzubeziehen. Programmiert auf einem Arduino Micro.
Normalerweise bereiten Timer mir keine Probleme, aber hier bin ich auf
den Fehler gestoßen, dass ich irgendwie das high-Byte, des
Output-Compare-Registers B des Timer1 einfach nicht setzen kann.
Ich habe mich bereits durch das Datenblatt des ATmega32u4 gearbeitet und
auch einige Stunden rechachciert, konnte aber keine funktionsfähige
Lösung finden.
Daher meine Frage an euch:
Weiß jemand, woher das kommt, bzw wie ich das OCR1BH beschreiben kann?
Teil des Setups:
1
TCCR1B=11;
2
TIMSK1=(1<<OCIE1B);
Teil der void Loop:
1
OCR1BH=frequenz/256;
2
OCR1BL=frequenz%256;
3
Serial1.println(OCR1BL);
4
Serial1.println(OCR1BH);
Frequenz ist eine 16Bit Variable in der ich den Wert abgespeichert habe,
der in das Compare-Register geladen werden soll.
Falls ihr weiter informationen zum Code braucht, bitte bescheid sagen.
Schon mal danke fürs Lesen und für die Kommentare, die kommen werden.
Myster schrieb:> Weiß jemand, woher das kommt, bzw wie ich das OCR1BH beschreiben kann?
Hab es jetzt nicht für jeden Fall ausprobiert, aber wenn man das
Register TCCR1A mit 0 initialisiert sollte es funktionieren.
Offensichtlich braucht der Timer erst mal eine Initialisierung.
Dabei scheint TCCR1A massgeblich zu sein, also dieses mindestens
einmal beschreiben, dann kann man sich ja immer noch den anderen
Registern widmen.
........Ich muss grade über mich selbst den Kopf schütteln.
man merkt, meine Konzentration ist nicht die beste grade.
Hatte ich doch tatsächlich geschrieben, dass dann ja kein Vorteiler und
CTC eingeställt wären.....Nur, dass es TCCR1*B* wäre, du aber meintest,
dass ich TCCR1*A* beschreiben soll. Ja, nicht meine meisterleistung im
Mitdenken.
Ich hab´s ausprobiert und es funktioniert.
Würde ich hier gerne sagen. Aber aktuell stürzt mein Terminal-Programm
immer ab, wenn ich versuche etwas an den Arduino zu senden.
also wird die Rückmeldung wohl noch etwas brauchen.
Okay, Terminal Programm geschickt umgangen und jetzt kann ich es
bestätigen:
Es funktioniert!
Also, vielen Dank an "ei leik" für die Hilfe!
Immer wieder eine Rettung, dass hier immer Jemand zu sein scheint, der
eine Antwort hat.
Ja, ich muss nochmal zurückrudern......
Ich hab heute mich drangesetzt weiterzuarbeiten und hab ein paar
ungereimtheiten festgestellt.....
Wenn ich TCCR1A auf 0 setze werden zwar die Compare-Werte richtig
gesetzt, aber der Timer läuft gar nicht.
Die frage ist: Wieso? Laut Datenblatt sind die bits 2-7 des TCCR1A für
Output modi, was ich aber nicht brauche und Bit´s 0-1 sind Fast-PWM, was
ich auch nicht brauche. Ich setze in TCCR1B das CTC-Bit (Bit3) und
Vorteiler auf 64, also insgesammt B00001011 ausgeschrieben. Unter diesen
werten wird die Compare-ISR aber nichtmehr ausgelößt...
Wofür ein Haus das verrückte macht, dieser Timer tuts grade auch. xD
Jemand ne Idee was hier bei mir vor sich geht?
Myster schrieb:> aber der Timer läuft gar nicht.
Sry, im nachinein im Lesen, das ist nicht ganz korrekt, der Timer zählt
hoch, die Compare-ISR wird nur nicht ausgelößt, obwohl ich am TCCR1B
nichts geändert habe.
Sei(); sollte nicht das Problem sein, da es funktioniert, wenn ich
TCCR1A die WGM10 /WGM11 setze, was ja aber der PWM-Modus ist, nicht der
normale CTC.
1
charPortexpander[9]={0x27,0x23,0x24,0x20,0x25,0x21,0x26,0x22,'\0'};//Adressen der 8 Portexpander im Uhrzeigersinn.
2
charExpanderNr[129];//Zu welchem portexpander gehört die LED?
3
charledzahl[129];//Welche LED soll am entsprechenden Expander angesteuert werden?
4
charhighbyte[9];//Übertragung an die Portexpander Byte1
5
charlowbyte[9];//Übertragung an die Portexpander Byte2
6
charbufer[257];//Buffer
7
StringDataIN,Befehl,AZ;//Datenstrings anlegen
8
uint8_ti,x=0,a,anzahl,modulo;//Variablen anlegen
9
uint16_tz,frequenz;//
10
floatrechenvariable;
11
12
voidsetup()
13
{
14
Wire.begin();//Initialisieren der Bibliothek
15
Serial.begin(9600);//festlegen der Baud-Rate
16
Serial1.begin(9600);
17
Serial1.println("begin");
18
19
TCCR1A=B00000000;
20
TCCR1B=B00001011;//Prescaler to 64; CTC on (Clear-Timer-on-Compare)
Beim Arduino gilt die Regel, grundsätzlich alle Register eines Timers
auf die gewünschten Werte zu setzen.
Und ganz grundsätzlich sollte man das immer mit (1<< <Bitname>) machen.
Niemand hat Lust, deine magischen Zahlen im Datenblatt nachzurechnen.
Oliver
ei leik arduino schrieb:> Deinen Code durchblicke ich nicht
an Myster:
Aus meinem Beispiel entnehme ich dass du eine Timer-
Konfiguration wählst die es erfordert den Timer "von Hand"
in der ISR zurückzusetzen.
Oliver S. schrieb:> Beim Arduino gilt die Regel, grundsätzlich alle Register eines Timers> auf die gewünschten Werte zu setzen.>> Und ganz grundsätzlich sollte man das immer mit (1<< <Bitname>) machen.> Niemand hat Lust, deine magischen Zahlen im Datenblatt nachzurechnen.>> Oliver
Genauso ist das. Zusätzlich kann man sich das Gehampel mit low und high
Byte schenken. OCR1B = '16Bitwert' ist einfacher.
ei leik arduino schrieb:> Aus meinem Beispiel entnehme ich dass du eine Timer-> Konfiguration wählst die es erfordert den Timer "von Hand"> in der ISR zurückzusetzen.
Das würde bedeuten, kein CTC, was wiederum heißt, dass der Timer
überläuft, aber stehenbleiben tut ein timer normalerweise nicht von
alleine.
Außerdem habe ich das TCCR1B auf den selben wert gesetzt, wie du in
deinem Beispiel? Es hat also genauso den CTC modus?
Es muss nicht sein. Ist eine gute Vorsichtsmaßnahme, aber hier nicht
zwigend notwendig.
Durch Volentile würde die variable direkt aktualisiert werden. d.h. wenn
ich in der ISR noch mit der variable weiterarbeiten wollte, müsste ich
volentile nehmen, um sicherzustellen, dass die variable auch ihren
korrekten wert hat, da es sonst sein kann, dass sie erst nach dem
beenden der ISR richtig aktualisiert wird.
So habe ich es zumindest verstanden.
Naja, so unfreundlich/aggresiv/generft (schwer auszumachen, welches und
ich will keine Unterstellungen machen) ei leik in seiner letzten Naricht
auch war, sein Test programm funktioniert und daher möchte ich mich
bedanken, da unabhängig von der Art, Er immernoch geholfen hat und das
ist nicht selbstverständlich.
Oliver S. schrieb:> Lass das doch lieber den Compiler machen. Der kommt mitOCR1B = frequenz;> schon klar.
Auch danke für die Zusicherung, dass der Compiler die 16Bit den Timer1
auf einmal setzen kann. Ich war mir da nicht Sicher und wollte daher auf
Nummer sicher gehen und habe sie daher seperat gesetzt.
Wie ihr wahrscheinlich gemerkt habt, egal wie gut ich bin(ich sage
nicht, dass das extrem viel ist, nur mehr als meine Freunde die ich
kenne :/), fehlt mir etwas die Erfahrung. Daher werde ich mir auch das
setzen von Registern mit
Oliver S. schrieb:> Und ganz grundsätzlich sollte man das immer mit (1<< <Bitname>) machen.> Niemand hat Lust, deine magischen Zahlen im Datenblatt nachzurechnen.
angewöhnen.
Alles in allem hab ich hier wieder mal das ein oder andere gelernt und
möchte mich eben bei allen beteiligen bedanken.
Marco H. schrieb:> Ich ich hatte das Problem auch schon mal und es lag daran das> dieser> Timer im Framework verwendet wurde.
Framework? Das sagt mir jetzt erstmal nix.
Okay, jetzt wird´s komisch.
Ich habe ja gesagt, dass das Beispielprogramm von ei like funktioniert.
Das stimmt auch.
Aber wenn ich die Comparewerte ändere, dann nicht mehr. also
1
OCR1BH=0x00;
2
OCR1BL=0x00;
zu z.B.
1
OCR1BH=0x00;
2
OCR1BL=0xFF;
dann geht plötzlich gar nichts mehr.
Ändere ich es wieder zurück zu 0x00, geht es wieder. Hat jemand auch
dafür ne antwort?
Auf Deutsch... der Timer wird in der Arduino IDE benutzt um gewisse
Dinge zu realisieren... Systick etc... deine Register werden von Code
der IDE überschrieben...
okay, dsa ist schon mal gut zu wissen, merk ich mir.
Bleibt noch die Frage, wieso der Timer keinen höheren compare-wert
nimmt, als 0xFA im Low-byte. (250 in Dezimal)
Ich hab die Werte mal systematisch durchprobiert und sobald ich einen
höheren Compare-Wert als 250 einstelle, funktioniert es nicht mehr...
Angewendet und gestestet mit diesem Textprogramm:
ei leik arduino schrieb:> Im Anhang ein Beispiel wie es funktioniert.
okay, versuch ich nacher mal.
Obwohl das schon sehr komisch wäre, wenn der das nicht schaffen würde.
Würde ja die ganze funktion eines 16Bit Timers nutzlos machen. Dann kann
ich auch gleich Timer2 verwenden.
Ich würde ja schon lieber Klassisch C statt Arduino verwenden, aber hab
hier grade leider keine Wahl.
Es hieß die Anwendung ist nicht so Zeitkritisch, dass ich Timer
bräuchte, also mach Ich´s jetzt mit der Programmablaufzeit.
Ich bin halt etwas perfektionistisch, also hätte ich es eigentlich gerne
wirklich exakt gemacht. --> mit Timer. Aber naja.... xD
Michael F. schrieb:> Nein, das "volatile" ist zwingend erforderlich wenn eine Variable sowohl> in einer ISR als auch im restlichen Programm genutzt wird:
Stimmt so allgemein nicht. Die Frage, die man sich stellen muss, ist: Wo
wird die Variable überall geändert?
Richtig ist jedoch: Änderungen in der ISR sieht der Compiler nicht. Wird
die Variable nur dort geändert können Optimierungen des Compilers
Abfragen der Variablen außerhalb der ISR weg optimieren.
M. K. schrieb:> Richtig ist jedoch: Änderungen in der ISR sieht der Compiler nicht. Wird> die Variable nur dort geändert können Optimierungen des Compilers> Abfragen der Variablen außerhalb der ISR weg optimieren.
Ähh....kannst du das bitte nochmal in einfach wiederholen?
Hallo,
wollen wir es jetzt richtig machen? Was ich mitbekommen habe ist, dass
der Timer im CTC Mode mit variabler Frequenz laufen soll. Laut deiner
Config CTC Mode 4. Übrigens sind Binär- und Hexzahlen nicht hilfreich.
Du hast konfiguriert:
<Ironie Tag an>
Das blöde ist, im CTC Mode gibts kein OCR1B was man für TOP nutzen kann.
Das heißt du verwendest die völlig falschen Register. Generell kann man
je nach Mode nur ORCnA oder ICRn für TOP verwenden.
<Ironie Tag aus>
Schau in die Tabelle der Modi welches Register für TOP zuständig ist.
Mode 4: OCR1A
Mode 12: ICR1
Das wäre dazu die Grundlage.
Die Formel zur Frequenzberechnung steht unter Timing Diagramm im CTC
Abschnitt.
Beachte den geänderten ISR Vector.
Ich lösche immer zuerst TCCR1B, damit ist der Timer gestoppt und ich
setzte TCCR1B als letztes, damit alles konfiguriert ist bevor er
überhaupt wieder läuft. Warum? Weil sich darin die Prescaler Bits
befinden die das steuern. Die Zuweisung kann man auch optisch aufteilen.
Die Variable z die du in der ISR änderst muss volatile sein und du musst
mittels atomic den Wert auslesen. Ansonsten handiert dein Programm nur
mit Zahlenmüll bzw. Zufallszahlen.
Übrigens, wegen deinen Einwand
> Ich würde ja schon lieber Klassisch C statt Arduino verwenden,> aber hab hier grade leider keine Wahl.
Das hat hiermit überhaupt nichts zu tun. Das hier gezeigte ist direkte
Registerprogrammierung. Direkter gehts nichts. Hättest du demzufolge
wissen müssen - laut deinem Einwand. Beim nächstenmal schiebste die
Schuld bitte nicht auf Arduino. In der IDE kannste auch "klassisch" C
programmieren. Arduino ist übrigens C++. Also auch ganz klassisch. Du
kannst auch main/while statt setup/loop verwenden, dann biste wirklich
auf dich allein gestellt und musst auch keine vorbelegten Register
löschen. Hast dann aber auch keine fertige Serial zur Verfügung usw.