Hallo Zusammen,
ich habe hier ein Programm geschrieben das verschiedene Eingänge, Geräte
nacheinander auslesen soll.
Zur hardware:
Ich habe einen Mega128 und an diesem eine Tasterturmatrix,Lesegerät per
RS485 und noch einen Port der ausgelesen werden muss.
Das Gerät an der RS485 Schnittstelle hat eine Baud Rate von 9600 diese
ist fix.
Nun soll dieses Gerät im 500ms Rythmus ausgelesen werden die Matrix alle
40ms und der Port alle 40ms.
Es laufen noch andere Timer der State mashine insgesammt 15 Abläufe.
Ich habe den Timer0 so programmiert das dieser jede Millisekunde einen
Interruppt auslöst.
Durch diesen Interrupt wird eine Variable Timer_MSek hochgezählt.
Im Programm verwende ich 2 Integer Variablen delay_MSek_01 und
delay_MSek_02 diese zeigen mir ob ein Timer gestartet ist und welcher
abgelaufen ist.
Jedes Bit dieser Variablen steht für einen "TIMER".
Will ich nun Timer 1 Starten setze ich das LSB auf "1" und schreibe und
eine Variable Timer_Msek_01 den Wert von der Variable Timer_MSek +
xxxMSek.
Nun wird im Interrupt von Timer0 jedesmal geprüft welche Timer_MSek_xx
abgelaufen sind mittels vergleichen der Timer_MSek und Timer_MSek_xx.
Sind beide Werte gleich ist die Zeit abgelaufen und das Bit wird im
delay_MSek_01 gelöscht und im delay_MSek_02 gesetzt.
Im Programm schaue ich nach welche Timer von der Variable delay_MSek_02
abgelaufen sind und führe die dementsprechenden Befehle aus.
Das ganze funktioniert auch ganz gut nur die beim Auslesen der
Tasterturmatrix wird nach einer undefinierten Zeit das Bit gelöscht.
Ich habe mich nun auf die suche gemacht wo dieses gelöscht wird konnte
jedoch keinen fehler erkennen.
Nun habe ich mal das JTAG MK2 drangehängt und dabei ist mir folgendes
aufgefallen.
Es sind 2 Timer am Laufen alle 30ms der eine Tasterturmatrix der andere
auslesen eines Ports.
Wenn ich nun mir die Zustände der delay_MSek_01 und delay_MSek_02
mitlogge schreiben in ein Array dann sehe ich folgenden Ablauf
1. Timer Tasterturmatrix gesetzt --> Zeit nicht abgelaufen also
delay_MSek_01
2. Timer Portauslesen gesetzt --> Zeit abgelaufen also delay_MSek_02
3.Prüfen Timer Portauslesen abgelaufen (Funktion) --> JA Bit löschen
4. Nach diesem Vorgang prüfe ich in der Funktion ob der Timer
Tasterturmatrix noch gesetzt ist und dieser ist OK --> Per Breakpoint.
5. Nun prüfe ich in der if Schleife als erstes ob der Timer
Tasterturmatrix noch gesetzt ist per if Abfrage und dort ist er
gelöscht.
Nun laufen die seriellen Schnittstellen auch per Interrupt
senden,empfangen etc.
Kann es sein das in einem ungünstigen Zeitpunt ein Interrupt ausgelöst
wird und danach irgendwie dieses BIT gelöscht wird?
Das ganze Programm läuft mal 2Std,4Std,8Std,24Std,48Std ohne Probleme
und dann ist dieses Bit gelöscht.
Nun gut ich könnte in der for(;;) Schleife reinschreiben das ich das Bit
setze wenn beide nicht gesetzt sind nur somit habe ich das Problem nicht
gelöst.
Gruß
Thomas
Hallo Zusammen,
ich denke das ich das ganze beim letzten Versuch einfach schlecht und zu
komplex erklären wollte.
Da jedoch das Problem immer noch vorhanden ist und mir die Ideen
ausgehen starte ich einen neuen Versuch.
Also ich wollte mein Programm komplett zeitgesteuert ablaufen lassen
also per Timer.
Hierzu habe ich 2 Integer verwendet bei dem jedes Bit für einen
Zeitablauf steht z.B 0x0001 ist der Timer um die Tasterturmatrix
auszulesen,0x0002 ist um eine Anfrage an einen Transponderleser zu
senden usw.
Der erste Integer delay_mSek_status_1 wird verwendet um einen
Timerablauf zu starten, beim start des Timerablaufs wir das
entsprechenede Bit gesetzt und ein Ablaufwert in eine Variable
gespeichert
Die Variable Timercounter_mSek wird ISR des Timer1 hochgezählt danach
wird Bitweise das delay_mSek_status_1 durchsucht ob ein Timerablauf
aktiviert ist ist dies der Fall wird die Variable hier delay_mSek_002
mit dem Timercounter_mSek verglichen ist dieser gleich wird das
entsprechende Bit im delay_mSek_status_1 gelöscht und im
delay_mSek_status_2 gesetzt.
Alle Bits die im delay_mSek_status_2 gesetzt sind stehen für einen
abgelaufenen Timer.
Im main wird nun delay_mSek_status_2 per Funktion durchsucht ob zB. Bit
0x0001 gesetzt ist, ist dieses gesetzt wird der entsprechende Code
abgearbeitet.
Die seriellen Schnittstellen funktionieren auch per Interrupt.
Ich habe nun folgendes Problem.
1. Manchmal wird nicht erkannt das "delay_mSek_002 == Timercounter_mSek"
und das entsprechende Bit nicht gelöscht/gesetzt. Dann läuft das ganze
65.535 Sekunden lang bis Timercounter_mSek erneut den Wert von
delay_mSek_002 hat.
2. Manchmal fehlen beide Bits also das eine was den Timer startet und
das andere welches das erreichen des Ablaufs signalisiert.
Ich habe den Code scho zig mal durchsucht aber diese Bits werden im
gesammten Code nur einmal gesetzt,gewechselt(beim Ablauf ISR) und
gelöscht.
Kann es sein das in einem ungünstigen Augenblick ein ISR ausgelöst wird
und danach eines dieser Phänomene auftritt?
Ich habe die ISR's mal komplett in den Anhang gepackt.
Die ISR von Timer1 und 0 ist zwar etwas lang jedoch habe ich das deshalb
so gemacht damit die Variablen bei jedem Interupt vergliechen werden.
Ich habe leider nicht zu State Mashine gefunden nur das man das damit
macht jedoch kein Beispiel(Code).
Ich beschäftige mich noch nicht so lange mit uC's und bin sozusagen
fortgeschrittener Anfänger.
Gruß
Thomas
Alle Achtung, Hut ab.
Dir ist schon klar, dass du einen kleinen 8-Bitter vor dir hast? Mit
32-Bit-Variablen und -Vergleichen und -Berechnungen. Das dauert.
Und dann solche Monster-Interrupt-Routinen...
Donnerwetter, das zwingt den stärksten Kerl in die Knie.
> Kann es sein das in einem ungünstigen Zeitpunt ein Interrupt ausgelöst> wird und danach irgendwie dieses BIT gelöscht wird?
Ich würde sagen, du hast
1. ein Semaphoren-Problem (dein gelöschtes Bit)
2. ein Rechenleistungsproblem (deine Long-Variablen)
Ich habe mir deinen Code nicht näher angeschaut, aber ich habe den
Eindruck, dass du etwas Einfaches kompliziert aufziehst... :-/
EDIT:
@ Matthias Lipinsky
Du hast es auf den Punkt gebracht ;-)
Du hast entweder ein volatile oder atomicity Problem bzw. beides.
Interruptvariablen > 8Bit müssen im Main atomar zugegriffen werden.
Interruptvariablen = 8Bit, die im Main gelesen, geändert und geschrieben
werden, müssen auch atomar zugegriffen werden.
Z.B. X |= Y ist so ein Read-Modify-Write:
1
#include<util\atomic.h>
2
...
3
ATOMIC_BLOCK(ATOMIC_FORCEON)
4
{
5
X|=Y;
6
}
7
...
Ausnahme, X ist ein IO-Port und in Y ist nur ein Bit gesetzt. Das geht
atomar (SBI,CBI).
Peter
@ Matthias Lipinsky,
in Deinem Betrag gehst Du davon aus das immer ein fester Ablauf gegeben
ist.
1-2-3-4-5-...
Dies trifft bei mir jedoch nicht zu es muss alles flexibel sein das was
gerade bearbeitet werden soll wird gemacht.
Vergebe ich nun einer Ablaufvariablen eine feste Nummer wie kann ich
dann sagen es soll sowohl 1-3-6 bearbeitet werden.
Daher habe ich es Bitbasierend gemacht.
Somit kann das Programm erkennen was bearbeitet wewrden soll.
Meine Displaysteuerung funktioniert nach Deiner Methode für jeden
Schritt eine Nummer dort ist es logisch.
@Lothar,
OK die Longs sind vielleicht nicht gut gewählt aber das schnellste
Ereignis ist alle 40ms danach 60,250,1000,6000.
Ist also ein Timer abgelaufen wird er zwar wieder gestartet aber der
Mega128 hat genügend Zeit.
Die UARD arbeitet mit 9600 und gesendet wird alle 250ms.
Ich denke das ich das Long eventuell in ein Byte oder int ändern kann.
Es kann schon sein das das lesen schreiben per UARD kompliziert
geschrieben ist wollte UARD0 und 1 in eine Variable packen vieleicht
sollte ich 2 byte variablen daraus machen.
Gute Denkanstoß
@Peter,
> Interruptvariablen > 8Bit müssen im Main atomar zugegriffen werden.> Interruptvariablen = 8Bit, die im Main gelesen, geändert und geschrieben> werden, müssen auch atomar zugegriffen werden.
Ich verstehe Deinen Beitrag nicht ganz was meinst Du mit "atomar
zugegriffen werden"
Gruß
Thomas
> Ich verstehe Deinen Beitrag nicht ganz was meinst Du mit "atomar> zugegriffen werden"
Wenn Du in C schreibst:
var |= mask;
Macht Dein Compiler (ungefähr) daraus:
tmp1 = var;
tmp1 = tmp | mask;
var = tmp1;
Und überall kann ein Interrupt dazwischen funken und "var" z.b. ändern.
Dann kommst Chaos raus.
Und es kommt noch schlimmer. Alles was länger als 8 Bit ist, ist nie
atomar. Also aus
unsigned long var = ...;
unsigned long mask = ...;
var |= mask;
macht der Compiler (ungefähr):
char * ptr1 = (char *) &var;
char * ptr2 = (char *) &mask;
char tmp1, tmp2;
tmp1 = *ptr1;
tmp2 = *ptr2;
tmp1 = tmp1 | tmp2;
*ptr1 = tmp1;
*ptr2 = tmp2;
ptr1 = ptr1 + 1;
ptr2 = ptr2 + 1;
tmp1 = *ptr1;
tmp2 = *ptr2;
tmp1 = tmp1 | tmp2;
*ptr1 = tmp1;
*ptr2 = tmp2;
ptr1 = ptr1 + 1;
ptr2 = ptr2 + 1;
tmp1 = *ptr1;
tmp2 = *ptr2;
tmp1 = tmp1 | tmp2;
*ptr1 = tmp1;
*ptr2 = tmp2;
ptr1 = ptr1 + 1;
ptr2 = ptr2 + 1;
tmp1 = *ptr1;
tmp2 = *ptr2;
tmp1 = tmp1 | tmp2;
*ptr1 = tmp1;
*ptr2 = tmp2;
Und überall kann ein Interrupt dazwischen funken.
Un das was der Compiler wirklich erzeugt, kann auch vollkommen anders
aussehen, weil er optimiert, umsortiert etc.
@unbekannter,
danke für die ausführliche Beschreibung hat mir viel geholfen um das
Problem zu verstehen.
Werde versuchen das ganze etwas zu vereinfachen und wenn möglich nur mit
8Bit Werten zu arbeiten.
Bis das läuft werde ich mal versuchen zu erkennen wann etwas
dazwischenfunkt und dann die Werte auf einen Grundwert zu setzen damit
das ganze dann wieder am Anfang anfängt.
Ich habe mir eine Variable vorgestellt die wärend das Programm läuft
immer hochgezählt wird.Sollte das Programm mal wieder nicht mehr alle
Programmteile bearbeiten wird die Variable nicht mehr verändert das wird
erkannt und alles wieder Grundeingestellt.
Thomas
Hallo Zusammen,
ich habe nun einiges verändert und viele Bitorientierte Abfragen gegen
Schrittketten abgeändert.
Nur bei einen bitorientierten Ablauf komme ich irgentwie nicht weiter da
ich diesen nicht durch eine Schrittkette ersetzen kann.
Ich habe z.B. ein Integerwert bei dem jedes Bit für einen Zeitablauf
steht.
Es kann also sein das ein oder mehrere Abläufe bearbeitet werden müssen.
Bisher habe ich das entsprechende Bit immen in der Timer ISR
(1ms)gesetzt.
In main habe ich die einzelnen Bits abgefragt und den/die entsprechenden
Abläufe bearbeitet.
Die Abläufe sollten unabhängig voneinander ablaufen allso keine
Schrittkette.
Ich könnte natürlich für jeden Ablauf einen Variable setzen und diese
dann wieder im Main zurüchsetzen jedoch habe ich dann 16 Variablen für
16 Abläufe plus 16 Variablen(Integer) für die Timerablaufwerte.
Das wird dann etwas unübersichtlich finde ich.
Solle mir nichts einfallen kann ich den 16 Bit Integerwert auch in zwei
8 Bit Werte ändern muss dan nur mal nachsauen ob die auch weniger
Schritte bedeutet.
Danke schon mal für Eure Meinungen/Anregungen
Thomas
Du könntest eine Struktur bauen, welche einen 1ms Zähler und einen
Funktionszeiger besitzt, das ganze 16 mal (Array).
In der Timer-ISR werden alle 1ms-Zähler dekrementiert.
Die main() prüft, ob einer der Zähler Null geworden ist, und führt die
zugehörige Funktion aus (und der 1ms Zähler wieder neu setzen).
@StinkyWinky
Dein Gedanke ist eigentlich ganz gut jedoch werden mehrere Funktionen
per Timerablauf ausgefürt.
Ich denke ich werde ein Array erstelle int - char - char und das ganze
16 mal.
Der Integer beinhaltet den Timerablaut der 2 Char Wert wird gesetzt wenn
der Timer aktiviert ist und der letzte wenn er abgelaufen ist.
So muss ich in Main nur abfragen ob der char Wert true ist oder nicht.
Und das Rücksetzen ist auch einfacher als zuvor.
@Peter
sowas wie Du vorschlägst habe ich eigentlich schon zumindest so ähnlich.
Ich habe mir den Code mal angeschaut jedoch für mich als nucht mehr ganz
Anfänger doch etwas hoch.
Thomas
>in Deinem Betrag gehst Du davon aus das immer ein fester Ablauf gegeben
<ist.
>1-2-3-4-5-..
Wenn du das korrekt liest, wirst du sehen, das das nicht stimmt.
Du kannst am Ende jedes Schrittes (zB 2) entscheiden, wie es weiter
gehen soll. Die Nummerierung ist willkürlich und kann zB auch so gehen:
0-44-1-43-912-41-12-543-...
@ Matthias Lipinsky,
OK ich werde mir dein Beispiel nochmal anschuen, wenn es stimmt was Du
geschrieben hast und davon gehe ich aus könnte ich es verwenden.
@genau so,
Dein Codeschnipsel ist vom setzen des Ablaufwertes.
Wenn ich schaue nach ob der Ablaufwert erreicht ist es in der ISR also
dort kann nichts passieren.
Ich hatte mal mehrere Tage einen JTAG MKII drangehängt und dabei habe
ich gesehen das das Bit das signalisiert das ein neuer Ablaufwert
gesetzt wurde fehlt und das setzten ist mit den Code unten. Dieser ist
nicht in der ISR und ich denke das es wie oben schon beschrieben wurde
nur beim setzen des Bits ein Interrupt ab und an dazwischenfunkt.