Ziel ist es eine Stoppuhr mit internen Timer zu programmieren. Wie genau
das sein muss sei mal dahin gestellt.
Selbst wenn ich das ganze ohne die Externen Interrupts laufen lasse und
den zaehler so einstelle das die Zehntel Sekunden direkt bis 9
hochzählen sollten, springt er nach der 4 (zehntel sek) direkt wieder
auf 2 und das in der Endlosschleife.
Was ich mir gedacht habe:
Vllt. haut da was mit der Freigabe der Overflow Timer nicht hin.
Ausgewählt hatte ich am Anfang einen Atmega16. Datenblatt für Atmega16
finde ich jedoch nicht. Sondern nur für Atmega16(plus irgendwelche
Zahlen und Buchstaben).
Geöffnet habe ich nebenher Atmel ATmega16M1/32M1/64M1 [DATASHEET].
Da wird zwischen TIMSK0 und TIMSK1 unterschieden. Ebenso ist das TCCR0
in A und B aufgeteilt. Der Compiler erkennt aber nur TIMSK und TCCR0
ohne A und B.
Hier noch der Code:
1
#define TAKT 1000000LU /* Controlertakt 1Mhz*/
2
3
4
#include<asf.h> // Bibliothek für STK600 (glaub ich)
Bitte den Code als solchen formatieren oder als Datei anhängen. Steht
alles vor dem Eingabefeld für den Post.
Sonst verstehe ich deine Logik nicht wirklich. Deine ISR zählt
irgendeine Zeiteinheit, die man normalerweise nur noch mit Modulo in
Sekunden, Minuten, ... aufteilen müsste.
Dein Zähler ist ein char, welcher signed oder unsigned sein kann. Wenn
der überläuft könnte der Wert erstmal negativ sein. Außerdem hat der
Wertebereich nur 256 Werte und danach fängt alles wieder von vorne an.
Wenn du jetzt einen größeren Zähler nimmst denke daran, dass die Bytes
dann nicht mehr alle gleichzeitig gesetzt werden. Damit bekommst du in
Main sporadisch sehr falsche Werte, wenn mitten in der Auswertung die
ISR zuschlägt.
Jens N. schrieb:> Selbst wenn ich das ganze ohne die Externen Interrupts laufen lasse und> den zaehler so einstelle das die Zehntel Sekunden direkt bis 9> hochzählen sollten, springt er nach der 4 (zehntel sek) direkt wieder> auf 2 und das in der Endlosschleife.
Und was sagt dein Simulator/Debugger, warum der Zähler verfrüht zurück
springt.
Gewöhnlich macht ein µC genau das, was man ihm sagt. Wenn er etwas
anderes tut, als man erwartet, hat man einen Denkfehler.
Isoliere deine Zählersteuerung in einer separaten Funktion und teste
sie, bevor du Timer und Interruptsteuerung dazu nimmst.
p.s. Warum hast du deine ganzen uint8_t Variablen als char
deklariert?
Bist du sicher, dass dein Compiler die so behandelt, wie du hoffst?
M.K. B. schrieb:> Sonst verstehe ich deine Logik nicht wirklich. Deine ISR zählt> irgendeine Zeiteinheit, die man normalerweise nur noch mit Modulo in> Sekunden, Minuten, ... aufteilen müsste.
Die Modulo Funktion läuft auf eine Division hinaus.
Da der µC bei der Stop-Uhr Anwendung wahrscheinlich sowieso nur
Langeweile hat, ist das natürlich eine schöne Methode, um ihn zu
beschäftigen. Laufzeiteffizient ist das auf einem µC ohne HW-Division
nicht.
Dann sollte man sich den Zählerstand vor der Rechnerei allerdings mit
einer atomaren Operation in einen Puffer holen.
Jens N. schrieb:> Ausgewählt hatte ich am Anfang einen Atmega16. Datenblatt für Atmega16> finde ich jedoch nicht. Sondern nur für Atmega16(plus irgendwelche> Zahlen und Buchstaben).>> Geöffnet habe ich nebenher Atmel ATmega16M1/32M1/64M1 [DATASHEET].
Tja, es würde vielleicht schon mal helfen, das richtige DS zu benutzen.
Irgendeins das irgendwo Teile des richtigen Chips beinhaltet ist knapp
daneben, also auch vorbei.
Einen Zähler der 9,9,5,9,9 zählt, schafft der Chip so gerade noch.
Wenn man ihn richtig baut, zumindest.
Und nicht so eine unübersichtliche Fehleranfällige Kropsität mit den
verschachtelten IFs...
Zehntel++
Zehntel > 9? Dann Zehntel=0; Einer++
Einer >9? Dann Einer=0; Zehner++
Zehner >5? Dann Zehner=0; Hunderter++
usw. usf.
Wobei man evtl. Minuten, Sekunden und Hunderstel zählen sollte und für's
Display konvertieren. Das Multiplexen würde ich auch in den Interrupt
legen.
Jens N. schrieb:> Hier noch der Code:
Was ist das für abstruser code ?
zaehler++ und zaehler-- aber nie zaehler=0, dafür startet zaehler bei 9
?
Wer bedient Int0 (on_off)? Ein nicht-entprellter Taster ?
> Und was sagt dein Simulator/Debugger, warum der Zähler verfrüht zurück> springt.
Nichts, er macht es einfach.
> Gewöhnlich macht ein µC genau das, was man ihm sagt. Wenn er etwas> anderes tut, als man erwartet, hat man einen Denkfehler.
Kann sein, den versuche ich ja zu finden.
> Isoliere deine Zählersteuerung in einer separaten Funktion und teste> sie, bevor du Timer und Interruptsteuerung dazu nimmst.
Klasse Idee, Danke. Ist nur halt schwierig nachzu vollziehen wenn wegen
der Optimierungen der Debugger sich nicht 100% an die Reihenfolge hält.
Werde es trotzdem mal testen
> p.s. Warum hast du deine ganzen uint8_t Variablen als /char/> deklariert?
was ist eine uint8_t ?
> Bist du sicher, dass dein Compiler die so behandelt, wie du hoffst?
Nein, dazu fehlt mir die Erfahrung.
>> Einen Zähler der 9,9,5,9,9 zählt, schafft der Chip so gerade noch.> Wenn man ihn richtig baut, zumindest.> Und nicht so eine unübersichtliche Fehleranfällige Kropsität mit den> verschachtelten IFs...>> Zehntel++> Zehntel > 9? Dann Zehntel=0; Einer++> Einer >9? Dann Einer=0; Zehner++> Zehner >5? Dann Zehner=0; Hunderter++> usw. usf.
Na er zählt halt die zehntel Sekunden bis 9, anstatt im nächsten
Durchlauf auf zehn zu springen, springt er zu den Sekunden und erhöht
diese um 1, dann stellt er die zehntel auf null.
wenn irgendwann die Sekunden auf 9 sind, geht das mit der stelle für die
zehner Sekunden genauso weiter. Nicht für die Praxis tauglich, aber zum
programmieren üben, ganz gut, denk ich. Will ja nicht einfach fertiges
abtippen.
> Wobei man evtl. Minuten, Sekunden und Hunderstel zählen sollte und für's> Display konvertieren. Das Multiplexen würde ich auch in den Interrupt> legen.
was meinst du mit Multiplexing?
Jens N. schrieb:> Kann sein, den versuche ich ja zu finden.
Dann guck ihm mit Simulator/Debugger auf die Finger, wo genau und warum
es passiert. Ein Zähler verzählt sich nicht mal eben.
Nochmal als Erklärung nachgereicht:
mein Code stößt scheinbar deshalb auf Unverständnis weil Ihr das so
nicht machen würdet. Da ich aber das programmieren und das verhalten der
Controller verstehen will, bringt es mir wenig einfach fertige
Musterlösungen abzutippen. Später im Beruf geht das ja auch nicht mehr,
sonst bräuchte man einen ja nicht.
Also zur Funktion:
Der Timer Overflow wurde nachträglich eingeführt da die erste Übung
einfach nur eine Stoppuhr sein sollte. Genauigkeit wurde erstmal nicht
verlangt.
Vorher war es so das einfach die Ausgabe der 7-Segment anzeige ungefähr
100ms lief und dann eine zehntel Sekunde dazu addiert wurde. Und wenn
die zehntel "voll" waren, sprang er rüber zu den Sekunden um diese um 1
zu erhöhen, mit anschließender Nullung der zehntel Sekunden.
Mit Timer Overflow ist es nun so das dieser Zählvorgang immer dann
durchgeführt werden darf solange der zaehler größer null ist. Der
Overflow erhöht den zaehler, die eigentlliche Zählschleife (die
verschachtelten IF) verringert ihn wieder.
Char Variablen sind es deshalb weil ich ja nur max. eine 9 Brauche und
char ja von -128 bis 127 reicht.
Jens N. schrieb:> Na er zählt halt die zehntel Sekunden bis 9, anstatt im nächsten> Durchlauf auf zehn zu springen, springt er zu den Sekunden und erhöht> diese um 1, dann stellt er die zehntel auf null.> wenn irgendwann die Sekunden auf 9 sind, geht das mit der stelle für die> zehner Sekunden genauso weiter. Nicht für die Praxis tauglich, aber zum> programmieren üben, ganz gut, denk ich. Will ja nicht einfach fertiges> abtippen.
Dein Lied hört sich genau so an wie meins, nur anders.
Deins hat einen Fehler. Meins tut. hm.
Du musst diese verschachtelten Ifs mal genau durchdenken...
Jens N. schrieb:> was meinst du mit Multiplexing?
Du gibst am Ende die Daten auf ein Display, wie's aussieht.
Da wird immer auf PortA die Stelle gewählt und auf PortB die jeweilige
Ziffer.
Das ist in der Form doof, weil nicht isochron. Im Interrupt wäre es das,
dann wäre die Anzeige flackerfrei
Jens N. schrieb:> Optimierungen der Debugger sich nicht 100% an die Reihenfolge hält.
Das kann man dem Compiler verbieten. Wenn alles läuft, werden die
Optimierungen wieder eingeschaltet.
Jens N. schrieb:> mein Code stößt scheinbar deshalb auf Unverständnis weil Ihr das so> nicht machen würdet
... weil er extrem kompliziert, unnoetig lang und eben fehlertraechtig
ist.
Das wiederholte Nullsetzen der Variablen sollte schon zu denken geben.
Weiter obem wurde schon eine kompakte Loesung gepostet. Vergleich mal
die Zeilenanzahl. Du lernst nicht mehr oder besser durch langen Code -
im Gegenteil
leo
Ich habe mir deinen Code mal etwas näher angeschaut und glaube, ihn
größtenteils verstanden zu haben :)
Der Zählalgorithmus
1
if(zaehler>=1){//wenn >1 darf eine zehntel dazu addiert werden
2
...
3
}// Ende zähler
ist zwar etwas holprig programmiert, aber bis auf eine Kleinigkeit
korrekt. In der Zeile
1
zaehler--;
wird zuerst die Variable zaehler erst vom Speicher gelesen, dann
dekrementiert und schließlich wieder in den Speicher geschrieben. Wird
zwischen dem Lesen und dem Schreiben ein Timer-Interrupt ausgelöst und
damit zaehler inkrementiert, bleibt diese Inkrementierung ohne
Wirkung, d.h. es können sporadisch Zählerinkremente verloren gehen. Das
hat aber lediglich den Effekt, dass die Uhr ein ganz winziges Bisschen
langsamer läuft als erwartet. Dieses Problem kannst du dadurch beheben,
dass du für die Dauer der obigen Anweisung die Interrupt sperrst, bspw.
so:
1
cli();
2
zaehler--;
3
sei();
oder mit dem ATOMIC_BLOCK-Makro wie hier erläutert:
https://www.nongnu.org/avr-libc/user-manual/group__util__atomic.html
Das erklärt noch lange nicht diesen von dir beschriebenen Fehler:
Jens N. schrieb:> Selbst wenn ich das ganze ohne die Externen Interrupts laufen lasse und> den zaehler so einstelle das die Zehntel Sekunden direkt bis 9> hochzählen sollten, springt er nach der 4 (zehntel sek) direkt wieder> auf 2 und das in der Endlosschleife.
Da die Ursache dafür nicht in deinem Zählalgorithmus liegt, muss
woanders etwas schief laufen. Deswegen folgende Fragen:
Ist bei diesem Test der Timer-Interrupt aktiviert?
Wie wird genau gezählt? 0,0s, 0,1s, 0,2s, 0,3s, 0,4s, 0,2s?
Und was passiert danach? Geht es weiter mit 0,3s?
Bleiben die Variablen zehntel, ein_sec, zehn_sec und ein_min
irgendwann nach einer größeren Anzahl von Schleifendurchläufen auf
festen Werten stehen? Wenn ja, wie lauten diese Werte?
Wie stellst du die Zählreihenfolge fest? Schaust du mit flinkem Auge
aufs LED-Display? Oder lässt du das Programm im Simulator/Debugger
laufen und hast einen Breakpoint gesetzt? Wenn letzteres, in welcher
Codezeile liegt dieser Breakpoint?
Yalu X. schrieb:>> wird zuerst die Variable zaehler erst vom Speicher gelesen, dann> dekrementiert und schließlich wieder in den Speicher geschrieben. Wird> zwischen dem Lesen und dem Schreiben ein Timer-Interrupt ausgelöst und> damit zaehler inkrementiert, bleibt diese Inkrementierung ohne> Wirkung, d.h. es können sporadisch Zählerinkremente verloren gehen. Das> hat aber lediglich den Effekt, dass die Uhr ein ganz winziges Bisschen> langsamer läuft als erwartet. Dieses Problem kannst du dadurch beheben,> dass du für die Dauer der obigen Anweisung die Interrupt sperrst, bspw.> so:>>>
1
>cli();
2
>zaehler--;
3
>sei();
4
>
>
Das Problem habe ich zwar nicht bedacht, doch ist es nicht so
gravierend, da der Zählvorgang sowieso viel schneller abläuft als wieder
ein timer Overflow eintritt. hat mir dennoch geholfen den Vorgang an
sich zu verstehen, danke.
>>> Ist bei diesem Test der Timer-Interrupt aktiviert?
Ich hatte tatsächlich vergessen ihn zu deaktivieren. das ergeniss ist
ohne allerdings das gleiche.
> Wie wird genau gezählt? 0,0s, 0,1s, 0,2s, 0,3s, 0,4s, 0,2s?>> Und was passiert danach? Geht es weiter mit 0,3s?>> Bleiben die Variablen zehntel, ein_sec, zehn_sec und /ein_min/> irgendwann nach einer größeren Anzahl von Schleifendurchläufen auf> festen Werten stehen? Wenn ja, wie lauten diese Werte?
ein_sec/zehn_sec/ und ein_min werden garnicht erst hochgezählt. Wenn man
bedenkt das ja die zehntel eh nur bis 9 zählen sollten uach erstmal
nicht überraschend.
>> Wie stellst du die Zählreihenfolge fest? Schaust du mit flinkem Auge> aufs LED-Display? Oder lässt du das Programm im Simulator/Debugger> laufen und hast einen Breakpoint gesetzt? Wenn letzteres, in welcher> Codezeile liegt dieser Breakpoint?
Ich habe zuhause keine Hardware, also nur im Simulator. Ich habe ein
Breakpoint gesetzt und zwar in der Zeile PORTA = 0x02; Er stoppt also
genau nachdem bzw. während an Port B die zehntel ausgegeben werden.
Habe mir mal die Mühe gemacht und einzeln durchgesteppt (Optimierungen
abgestellt) und was abgefahrenes entdeckt:
Nachdem die zehntel die 4 erreicht haben, macht er zunächst normal
weiter. Von PortA=0x03 springt er dann zurück zu PortA=0X02 und zeigt an
PortB plötzlich eine 1 an obwohl kein Befehl dazu abgearbeitet wurde.
Beim nächsten zehner=4 das gleiche wieder.
Der anfangs auf 9 gesetzte zaehler sollte ja auch irgendwann mal auf
null kommen, tut er aber nicht.
Bevor ich das ohne ext_interrupt durchlaufen lies, hat er auch immer den
ON_Off abgestellt. Also aus irgend einen Grund kommt er da ins stolpern.
Zum Durchsteppen mit dem Debugger solltest du den Optimizer
deaktivieren. Das geht mit der Compiler-Option -O0.
Ansonsten bekommt der Debugger Schwierigkeiten, den Zusammenhang
zwischen generiertem Maschinencode und Quelltext zu erfassen. Dies
äussert sich typischerweise daran, dass Variablen scheinbar
verschwinden, ihren Wert nicht wie erwartet ändern oder dass der
Programmzeiger unerwartet springt.
Danke, hab ich schon gemacht, nachdem ich ewig gebraucht habe die
Einstellungen dafür zu finden.
Achso: Oben in meinem Screenshot heißt zehntel noch hundertstel. Hoffe
das verwirrt nicht zu sehr.
Und was mich grad überrascht:
habe sei(); mal rausgenommen und auf einmal funzt es. Aber wo soll ein
Interrupt herkommen der so merkwürdig stört wenn die Taster nicht
betätigt werden und TIMSK &= 0x00 ist?
Jens N. schrieb:> Von PortA=0x03 springt er dann zurück zu PortA=0X02 und zeigt an> PortB plötzlich eine 1 an obwohl kein Befehl dazu abgearbeitet wurde.
Da ist etwas faul, was nicht mit deinem Code zusammenhängt. Zumindest
die 8 aufeinanderfolgenden Port-Zugriffe müssen – unabhängig von den
Optimierungseinstellungen – sauber der Reihe nach abgearbeitet werden.
Bist du sicher, dass der Binärcode, den du im Simulator laufen lässt,
auch wirklich zu deinem Quellcode gehört? Gibt es im AVR-Studio einen
Menüpunkt "rebuild all" o.ä., mit dem sichergestellt werden kann, dass
das komplette Projekt noch einmal vollständig kompiliert und gelinkt
wird?
Jens N. schrieb:> Von PortA=0x03 springt er dann zurück zu PortA=0X02 und zeigt an> PortB plötzlich eine 1 an obwohl kein Befehl dazu abgearbeitet wurde.
Da ist etwas faul, was nicht mit deinem Code zusammenhängt. Zumindest
die 8 aufeinanderfolgenden Port-Zugriffe müssen – unabhängig von den
Optimierungseinstellungen – sauber der Reihe nach abgearbeitet werden.
Bist du sicher, dass der Binärcode, den du im Simulator laufen lässt,
auch wirklich zu deinem Quellcode gehört? Gibt es im AVR-Studio einen
Menüpunkt "rebuild all" o.ä., mit dem sichergestellt werden kann, dass
das komplette Projekt noch einmal vollständig kompiliert und gelinkt
wird?
Jens N. schrieb:> Achso: Oben in meinem Screenshot heißt zehntel noch hundertstel. Hoffe> das verwirrt nicht zu sehr.
Nicht, wenn das die einzige Änderung war.
> habe sei(); mal rausgenommen und auf einmal funzt es. Aber wo soll ein> Interrupt herkommen der so merkwürdig stört wenn die Taster nicht> betätigt werden und TIMSK &= 0x00 ist?
In dem von dir anfangs geposteten Code ist TIMSK=0x01. Gibt es da
vielleicht noch mehr Änderungen? Mach mal den sei() wieder rein, lass es
durch den Simulator laufen, um zu sehen, ob der Fehler dann wieder
auftritt, und poste dann den aktuellen Code ohne Kosmetik und sonstige
Änderungen, am besten als angehängte Datei.
Ich hatte TIMSK nur eben auf 0x00 gestellt um zu überprüfen ob es daran
liegen könnte. Im Grunde dürfte der timer_overflow auch Garnicht
dazwischen grätschen, denn solange On_off = 0 ist, wird ja innerhalb der
Overflow ISR nichts ausgeführt. Dennoch ist TIMSK nun &= 0x00.
1
#define F_CPU 1000000LU /* Info für delay*/
2
3
4
#include<asf.h> // Bibliothek für STK600 (glaub ich)
5
#include<avr/interrupt.h>
6
#include<util/delay.h>
7
8
volatilecharzaehler=9;// damit eine Hundertstel Sekunde dazu gezählt wird
9
volatilecharreset=0;// für den Reset der Stoppuhr
10
volatileintausgleich=0;// Auslgiech für Ungenauigkeit
Yalu X. schrieb:> Bist du sicher, dass der Binärcode, den du im Simulator laufen lässt,> auch wirklich zu deinem Quellcode gehört? Gibt es im AVR-Studio einen> Menüpunkt "rebuild all" o.ä., mit dem sichergestellt werden kann, dass> das komplette Projekt noch einmal vollständig kompiliert und gelinkt> wird?>
Ausprobiert habe ich: clean solution, rebuild solution und natürlich
build solution. Was anderes hab ich noch nicht gefunden.
Grad noch die build(Projektname) punkte probiert und das gleiche.
Compile bringt uach nichts anderes. Da frag ich mich doch wo da die
Unterschiede sind.
Jens N. schrieb:> mein Code stößt scheinbar deshalb auf Unverständnis weil Ihr das so> nicht machen würdet.
Ja genau, aber das ist auch nicht böse gemeint. Ich begründe mal, warum
ich es anders machen würde und du kannst dir ja überlegen, ob und wie du
das umsetzt.
Der Mikrocontroller arbeitet im Binärsystem. Ich würde deshalb im Code
Zeiten nicht als Sekunden, Minuten usw. zählen, sondern einfach nur als
Summe der kleinsten Einheit z.B. Millisekunden. Genauso wenig würde ich
im 10er System zählen. Die Konvertierung würde ich dann nur für die
Anzeige machen. Beim Zeitstempel der Systemzeit (UNIX Zeit) ist das auch
so.
Sollte man die Stoppuhr später erweitern, sodass man Zeiten speichern
und vergleichen kann wird die Rechnung dadurch viel leichter.
Jens N. schrieb:> if(zaehler>=1) //wenn >1 darf eine zehntel dazu addiert werden
Da stimmt Code und Kommentar aber nicht überein.
if (zaehler >= 1) kann man auch als if (zaehler > 0) schreiben.
Moin,
Schau dir nochmal an wie man Daten an einen Port setzt. Du sendest dem
Port einfach knallhart Bitmuster und hast nicht bedacht was mit einem
Bit passiert das bereits 1 ist und was passiert wenn man eine weitere 1
hinterher schmeißt.
hust toggle... hust
gruß (:
Stefanus F. schrieb:> Zum Durchsteppen mit dem Debugger solltest du den Optimizer> deaktivieren. Das geht mit der Compiler-Option -O0.
Besser noch, -Og:
Optimize debugging experience. -Og should be the optimization level of
choice for the standard edit-compile-debug cycle, offering a reasonable
level of optimization while maintaining fast compilation and a good
debugging experience. It is a better choice than -O0 for producing
debuggable code because some compiler passes that collect debug
information are disabled at -O0.
Toggle?! schrieb:> Moin,>> Schau dir nochmal an wie man Daten an einen Port setzt. Du sendest dem> Port einfach knallhart Bitmuster und hast nicht bedacht was mit einem> Bit passiert das bereits 1 ist und was passiert wenn man eine weitere 1> hinterher schmeißt.>> hust toggle... *hust*>> gruß (:
Das musst du mir näher erklären.
Ich sende die ja per "=" und addiere nicht. Was hab ich da nicht
verstanden?
M.K. B. schrieb:> Ja genau, aber das ist auch nicht böse gemeint. Ich begründe mal, warum> ich es anders machen würde und du kannst dir ja überlegen, ob und wie du> das umsetzt.>> Der Mikrocontroller arbeitet im Binärsystem. Ich würde deshalb im Code> Zeiten nicht als Sekunden, Minuten usw. zählen, sondern einfach nur als> Summe der kleinsten Einheit z.B. Millisekunden. Genauso wenig würde ich> im 10er System zählen. Die Konvertierung würde ich dann nur für die> Anzeige machen. Beim Zeitstempel der Systemzeit (UNIX Zeit) ist das auch> so.> Sollte man die Stoppuhr später erweitern, sodass man Zeiten speichern> und vergleichen kann wird die Rechnung dadurch viel leichter.
Mit dem was ich jetzt alles weiß, würde ich das so auch nicht mehr
bauen. Trotzdem möchte ich nachvollziehen können wieso er so wild
rumspringt.
Aber: Wenn ich eine INT Variable als zehntel Sekunde deklariere, und die
dann hochzählen lasse, ist sie dann nicht quasi automatisch im 10er
System?
Jens N. schrieb:> Wenn ich eine INT Variable als zehntel Sekunde deklariere, und die> dann hochzählen lasse, ist sie dann nicht quasi automatisch im 10er> System?
Nein. Der Computer arbeitet immer noch mit Binärzahlen, nur dass deine
Einheit dann 1/10 Sekunde ist, statt Sekunde. Ist bei den sonst üblichen
Millisekunden nicht anders.
Jens N. schrieb:> Das musst du mir näher erklären.>> Ich sende die ja per "=" und addiere nicht. Was hab ich da nicht> verstanden?
Vergiss es, was "Toggle" Dir schrieb. Das war einfach Unsinn.
Neuere AVR besitzen das Feature, dass ein Schreiben von Einsen auf PINx
(nicht PORTx!) ein Toggle der jeweiligen Pins bewirkt. Da Du gar nicht
auf PINx schreibst, ist das für Dich ohne Belang.
Soooo….
Ich habe nun mit neuem Wissen, von hier und aus anderen Quellen, eine
neue Stoppuhr zusammen gebastelt.
Sie tut sogar was sie soll =)
Ich hatte allerdings Probleme bool variablen zu nutzen. Das soll in C ja
jetzt gehen und sie sollen mit _bool betitelt werden. Das schlägt mir
der Compiler auch vor, doch gibt's da immer Fehler Meldungen.
Die dabei auftauchende Fehlermeldung blieb auch, nachdem ich das _bool
entfernt hatte und so musste ich den Code in ein neues Projekt einfügen.
Fand ich schon ziemlich merkwürdig. vllt. würde das ja auch bei meinem
ursprünglichem Problem helfen, hmmm.
Gibt's eigentlich irgendwo eine Liste mit den ganzen
Bibliotheksfunktionen die man im Alltag so braucht?
vllt. hat auch einer Lust mir zu sagen ob das entprellen der Taster so
Praxis tauglich ist.
Nachtrag: Müsste man nicht, um eine genauere Stoppuhr zu haben, auf den
Preload soviele Takte hinzu aaddieren wie sie in Summe vom Overflow bis
zum neuen Preload verbraucht werden?
Hi
>Müsste man nicht, um eine genauere Stoppuhr zu haben, auf den>Preload soviele Takte hinzu aaddieren wie sie in Summe vom Overflow bis>zum neuen Preload verbraucht werden?
Nein, man benutzt einfach den CTC-Mode und nicht dieses vorsinflutliche
Preload.
MfG Spess
Jens N. schrieb:> Gibt's eigentlich irgendwo eine Liste mit den ganzen> Bibliotheksfunktionen die man im Alltag so braucht?
Die Funktionen, die in der C Standardbibliothek sind findest du hier.
https://en.cppreference.com/w/c
Ich hab mir mal den Code angeschaut. Deine Lesen und Schreiben auf den
Port ist nicht ganz korrekt.
Beispiel:
1
if(PIND==0x01)
Du vergleichst hier den ganzen Port D. Drückt dein Benutzer beide Tasten
gleichzeitig, dann hat PIND aber den Wert 0x03.
Besser:
1
if(PIND&0x01)
Das selbe gilt auch für das Schreiben auf PORTA bzw. PORTB, wenn du noch
andere Pins an den Ports hängen hast.
Beispiel, wenn PORTA nur 3 Bits für die Displayübertragung benutzt (ich
kenne deine Setup nicht genau).
1
PORTA=(PORTA&~0x07)|(wert&0x07)
2
// Das & 0x07 stellt sicher, dass der Wert nicht aus dem Bereich rausschreibt.
3
// Bei Konstanten kann man das auch weglassen.
Ich hoffe ich hab jetzt auf die Schnelle alles richtig gemacht.
Außerdem hat deine Umrechung noch eine Macke (vielleicht auch mehrere).
Dein zaehler hat die Einheit 0.01s. Wenn zaehler den Wert 6000 hat, dann
würde ich min=1 erwarten. zaehler=10000 ist auch lustig.
> Du vergleichst hier den ganzen Port D. Drückt dein Benutzer beide Tasten> gleichzeitig, dann hat PIND aber den Wert 0x03.> Besser:>
1
if(PIND&0x01)
Das gleichzeitige drücken von Stopp und Reset habe ich mit Absicht
ignoriert, man kann eben nicht alles haben ;) Das mit den "&" macht voll
sinn, danke.
>
1
>PORTA=(PORTA&~0x07)|(wert&0x07)
2
>// Das & 0x07 stellt sicher, dass der Wert nicht aus dem Bereich
3
>rausschreibt.
4
>
Das muss ich mir nochmal in Ruhe angucken...
>> Außerdem hat deine Umrechung noch eine Macke (vielleicht auch mehrere).> Dein zaehler hat die Einheit 0.01s. Wenn zaehler den Wert 6000 hat, dann> würde ich min=1 erwarten. zaehler=10000 ist auch lustig.
Jup, da habe ich mich um eine Zehnerpotenz verhauen.
Ansonsten nochmal was grundsätzliches:
Der Code wird ja von oben nach unten abgearbeitet. Demnach würden oben
erst alle Stellen ausgerechnet werden, und dann unten der Reihe nach
ausgegeben. eine Änderung während der Ausgabe würde daher garnicht
erfasst, bzw. erst im nächsten durchlauf ja? Denke das wäre wichtig
falls ich sowas mal programmiere und die Werte sich schneller ändern als
ein Durchgang der 7 Segment anzeige dauert.
Jens N. schrieb:> Denke das wäre wichtig falls ich sowas mal programmiere und die Werte> sich schneller ändern als ein Durchgang der 7 Segment anzeige dauert.
Ja richtig, wenn deine Anzeige langsamer als die Zeit ist, dann sollte
die Anzeige aber immerhin konsistent sein.
Dann würde ich aber auch am Anfang der Schleife den globalen Zähler in
eine lokale Variable kopieren. Wenn dein Timerinterrupt z.B. zwischen
dem Berechnen der Minuten und Sekunden zuschlägt und du genau bei 59
Sekunden bist, dann könnte deine Anzeige kurzzeitig 1:59 anzeigen und
danach dann 1:00.