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
1 | |
2 | |
3 | |
4 | |
5 | |
6 | |
7 | |
8 | |
9 | |
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
Verflixt Vorschau mit Absenden verwechselt ich hoffe alles stimmt hier noch der Anhang. Gruß Thomas
Gast
#1128821
Du hast einen
> Mega128
und dann im Programm durchgehend longs:1 | |
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 | |
2 | |
3 | |
4 | |
5 | |
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
Gast
#1128948
> 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.
Gast
#1128951
Argl:
*ptr2 = tmp2;
Mach der Compiler natürlich nicht.
Hier mal ein konkretes Beispiel. Aus:
1 | |
2 | |
3 | |
4 | |
5 | |
6 | |
7 | |
macht der Compiler (mit -O2 und bereinigt):
1 | |
2 | |
3 | |
4 | |
5 | |
6 | |
7 | |
8 | |
9 | |
10 | |
11 | |
12 | |
13 | |
14 | |
15 | |
16 | |
17 | |
18 | |
Und wie gesagt, überall kann ein Interrupt auftreten. Dann kommt alles durcheinander.
@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
Gast
#1179140
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).
Gast
#1179147
Nimm doch einfach ein Betriebssystem. Entweder FreeRtos oder ne embOS Evalversion von Segger.
@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
Gast
#1179704
>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-...
Gast
#1179767
>delay_mSek_002 == Timercounter_mSek
Was soll das ?
Mach da ein <= oder >= draus und gut ist.
@ 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.
1 | |
2 | |
3 | |
4 | |
5 | |
6 | |
7 | |
8 | |
9 | |
Ich brauche also etwas was das setzen des neuen Werts usw. verkürzt. Thomas
Antwort schreiben
Bitte melde dich an, um einen Beitrag zu schreiben.