Hallo miteinander,
ich bin relativ neu in der Mikrocontroller-Programmierung. Ich habe mit
Arduino angefangen und bin mittlerweile mit normaler C-Programmierung am
experimentieren.
Nun habe ich ein kleines Problem. Zwar habe einen Testaufbau mit einem
Atmega 328p, einem Drehgeber, einem LCD, ein paar Tastern und LEDs.
Auf dem LCD lasse ich die Zustände der LEDs, die Position des Drehgebers
und einen Sekundenzähler anzeigen.
Ab und zu habe ich das Problem, dass es mir die Position des Drehgebers
an einer anderen Position auf dem LCD nochmals anzeigt.
Ich habe das Gefühl, dass der Befehl zum ausgeben des Drehgeberwertes
vom Drehgeberinterrupt gestört wird und so der Fehler entsteht. Jedoch
weiss ich nicht wie man dies anders lösen könnte.
Ich benutze übrigens die LCD Library von Peter Fleury.
Ich weiss, dass die Programmierung ziemlich lausig ist, ich bin noch
Anfänger und hatte nie eine richtige Einführung zum Thema.
Gewisse Dinge wurden weggelassen wie z.B. debouncing der Taster und des
Drehgebers(Hardwaremässig gelöst) und die Drehgeberauswertung ist auch
ziemlich schlecht.
Danke und Gruss
Robin
Hier noch das Programm:
Du behandelst zb negative Zahlen nicht richtig.
Ersetz mal deine komplette UpdateDisplay durch diese hier
1
voidupdate_display()
2
{
3
charbuff[10];
4
5
sprintf(buff,"%4d",encoderpos);
6
lcd_gotoxy(0,3);
7
lcd_puts(buff);
8
9
encoderpos_last=encoderpos;
10
}
PS:
Die sei() und cli() in den ISR sind kontrapoduktiv. Die willst du da
nicht haben. Wobei der anfängliche cli() harmlos ist, denn während eine
ISR läuft, sind die Interrupts sowieso automatisch gesperrt. Aber der
sei() kommt zu früh! Allerdings musst du dich auch darum nicht kümmern,
denn die Interrupts werden bei Beendigung einer ISR automatisch wieder
freigegeben. Und zwar zum richtigen Zeitpunkt, so dass sich Interrupts
nicht endlos ineinander schachteln können.
Karl Heinz Buchegger schrieb:> Ersetz mal deine komplette UpdateDisplay durch diese hier
Danke für die Hilfe. Habe die Interrupts bereinigt und das
update_display() ersetzt.
Das mit dem %4d ist sehr hilfreich. Habe mich immer gefragt ob man das
Problem nicht einfach lösen könnte.
Es funktioniert alles noch wie gewohnt. Jedoch kriege ich ab und zu
immer noch Zahlen an falschen Stellen. Es scheint ziemlich zufällig zu
passieren. Manchmal kann ich minutenlang am Drehgeber drehen, ohne ein
Problem und manchmal passiert es schon beim ersten Dreh.
> und des Drehgebers(Hardwaremässig gelöst)
was ist darunter zu verstehen?
Dir ist bewusst, dass du mit einer falsch ausgelegten
Hardware-Entprellung den µC massiv stören kannst? Bis hin zum Absturz
des µC?
R. S. schrieb:> debouncing ... des Drehgebers(Hardwaremässig gelöst)
Was willst du mit Debouncing beim Drehgeber?
Bei Grey-Code, wie er vom Drehgeber generiert wird, hat ein Prellen der
Kontakte keinen störenden Einfluß auf den Zählerstand. Der Code wurde
genau für Abtastung von mehrphasigen Zählsignalen entwickelt.
Karl Heinz Buchegger schrieb:> was ist darunter zu verstehen?
Ich habe jeweils einen 0.1 uF Keramikkondensator zwischen den Outputs
und Ground.
Dies funktioniert bis jetzt einwandfrei. Dies aber auch nur, da ich
einen relativ hochwertigen Alps Drehgeber verwende. Bei einem no-name
Drehgeber hatte ich mit meinem Code grosse Schwierigkeiten.
Ich habe diesen Code verwendet, da ich mit den anderen gefundenen
Beispielen nichts habe anfangen können. Dies liegt daran, dass sie für
mich zu kompliziert aufgebaut waren und ich den Code nicht verstanden
habe.
Ich werde mich nochmal damit auseinander setzten müssen.
Meinst du das LCD Problem kann da her kommen?
Die beiden in den ISR gesetzten Variablen müssen als volatile definiert
werden, also
volatile int encoder_flag = 0;
volatile int timer_flag = 0;
Warum verschwendest Du für zwei simple Flags einen ganzen int? uint8_t
wäre angebrachter, damit das Rücksetzen der beiden Flags auch atomar
passieren kann - außerhalb einer ISR schon sinnvoll.
Also:
volatile uint8_t encoder_flag = 0;
volatile uint8_t timer_flag = 0;
Weiterhin solltest Du prüfen, ob weitere Variablen nicht zumindest als
unsigned erklärt werden könnten.
R. S. schrieb:> Karl Heinz Buchegger schrieb:>> was ist darunter zu verstehen?>>> Ich habe jeweils einen 0.1 uF Keramikkondensator zwischen den Outputs> und Ground.
Jau. Das hatte Pollin auch.
Mit dem Effekt, dass deren Boards auch immer abgestürzt und seltsame
Sachen gemacht haben.
Jedesmal, wenn du den Taster schliesst, erzeugt dein Kondensator einen
kleinen Kurzschluss, wenn er geladen wird.
Frank M. schrieb:> Die beiden in den ISR gesetzten Variablen müssen als volatile definiert> werden
Danke für den Tipp.
Den Integer volatile zu deklarieren ist vor allem dann wichtig wenn der
Compiler den Code optimiert, oder? Bei einer Debug Version sollte dies
jedoch keinen Einfluss haben, richtig?
Karl Heinz Buchegger schrieb:> Jedesmal, wenn du den Taster schliesst, erzeugt dein Kondensator einen> kleinen Kurzschluss, wenn er geladen wird.
So weit ich informiert bin, besteht die Gefahr hauptsächlich darin, dass
wenn der Drehgeber zwischen zwei Pinstates alterniert, das Programm
ständig Interrupts ausführt und so die anderen Funktionen blockiert.
Die Kondensatoren werden ja durch die Pull-up Widerstände geladen.
Kannst du bitte noch genauer erläutern, was das für einen Einfluss auf
die Stabilität haben könnte?
R. S. schrieb:> Die Kondensatoren werden ja durch die Pull-up Widerstände geladen.
Wo kommen da jetzt auf einmal Pull-up Widerstände her?
Dann eben bei dir anders rum. Wird der Taster betätigt, dann schliesst
er den Kondensator kurz. Auch nicht gut.
> Kannst du bitte noch genauer erläutern, was das für einen Einfluss auf> die Stabilität haben könnte?
Kurzschlüsse sind nie gut, egal wie kurz sie sind. Sie verursachen
zumindest Spikes auf der Versorgungsspannung, die wiederrum das
restliche System gefährden können.
Such im Forum nach der MOdifikation des Pollin Boards. Normalerweise
steht da dann die Erklärung dabei (oder es gibt einen Link darauf)
R. S. schrieb:> Den Integer volatile zu deklarieren ist vor allem dann wichtig wenn der> Compiler den Code optimiert, oder? Bei einer Debug Version sollte dies> jedoch keinen Einfluss haben, richtig?
Für mich ist diese Regel unabhängig vom Optimierungsgrad des Compilers.
Ich machs einfach grundsätzlich, um mich an die Regel zu halten. Diese
heisst: Wird eine globale Variable in einer ISR und außerhalb einer ISR
benutzt, muss die Variable als volatile deklariert werden.
Und ich würde niemals den Optimierer ausschalten, weil ich evtl. mit
Optimierer ein Laufzeitproblem mit meinem Programm sehe. Damit verstecke
ich nur meine eigenen Programmierfehler.
Ausserdem: Im Gegensatz zu vielen anderen Compilern kann man beim gcc
den Debug-Mode unabhängig vom Optimierungsgrad wählen. D.h. wenn ich ein
Programm mit Debug-Mode übersetze, habe ich deswegen noch lange nicht
den Optimierer abgeschaltet.