Guten Abend liebes Forum,
ich sitze hier nun seit Tagen an einem Programm und ich komme einfach
nicht dahinter, was schief läuft. Irgendwie beachte ich irgendeine
Programmiervorschrift nicht - ich hoffe, ihr könnt mir auf die Sprünge
helfen.
Ich habe zwei Probleme, beide haben mit Interrupts zu tun.
Zuersteinmal, ich nutze einen ATMEGA8-16 TQ und programmiere in der
Platine mit nem AVRISP MK2. Meine Platine hat ein LCD tc1602a-09, ein
25LC256 SPI Flash, ein Inkrementalgeber sowie einen Komparator bestückt,
welcher einen Münzeinwurf detektiert.
Was passieren soll: Münze wird eingeworfen, Text vom Flash gelesen,
ausgeben - und das alles in einer Schleife.
Beim Hochlauf des uC möchte ich vorher noch 2 Ausgaben allgemeiner Art
machen, die eine kurze Zeit eingeblendet werden, bevor ich in die
Münzschleife falle.
Relevant sind in meinem Fall nur TMR2 und der INT1 - TMR2 soll zu Beginn
steuern, wie lang die Einblendungen sind; INT1 soll auf Low-Flanken für
den Münzeinwurf reagieren.
Zu Beginn der main-function ist entsprechend folgende Init:
1
cli();
2
MCUCR |= (1 << ISC01) | (1 << ISC11);
3
TCCR2 |= (1 << CS22) | (1 << CS21) | (1 << CS20);
4
5
DDRD = 0xF0;
6
DDRB = 0xFF;
7
PORTB = 0x00;
8
DDRC = 0x3F;
Danach kommt noch ein wenig SPI-Init.
Nun kommt die LCD-Init und das erste mal Warten:
1
lcd_clrscr();
2
itoa(quote_count, buffer, 10);
3
lcd_puts(buffer);
4
lcd_puts(" Eintraege\ngefunden");
5
6
TMR2_done = 0;
7
8
TCNT2 = tmr0_preload;
9
TIMSK |= (1 << TOIE2);
10
11
sei();
12
13
while(1) {
14
nop();
15
nop();
16
nop();
17
quote_count = scan_eeprom();
18
if (TMR2_done)
19
break;
20
nop();
21
}
Dazu die ISR
1
ISR( TIMER2_OVF_vect ) {
2
cli();
3
TIMSK &= (0 << TOIE2);
4
TMR2_done = 1;
5
sei();
6
}
TMR2_done wird global mit static int TMR2_done = 0; initialisiert.
Gedacht war, dass die Anzeige soweit stehen bleibt, bis TMR2 abläuft und
das Flag auf 1 setzt. Die nop()s sowie den SPI-Scanvorgang hab ich
eingefügt, weil ich vermutet hatte, dass aus mir unerfindlichen Gründen
die Schleife zu kurz zum Interrupten ist (das ist mehr Verzweiflung
gewesen - Hinweis: SPI funktioniert ohne Ints). Leider bleibt der
unendlich in der Schleife drin und ich weiß nicht wieso.
Was mich daran verwirrt, anschließend kommt die klassische
while(1)-Schleife - innerhalb der Schleife funktioniert solch ein
Konstrukt dann (es ist hier dann mit TMR1 gemacht) :
Direkt im Anschluß zum obrigen Code - einfach das Laden des Timers und
die Warteschleife wegdenken
1
int init = 1;
2
while(1) {
3
if (init) {
4
TMR1_done = 0;
5
TCNT1H = 0xC0;
6
TCNT1L = tmr1l_preload;
7
TIMSK |= (1 << TOIE1);
8
sei();
9
init = 0;
10
}
11
if (scroll & TMR1_done) {
12
...
Kann mir das jemand erklären? Ich weiß nich obs daran liegt, dass ich
das immer nach der Arbeit mach und die geistige Höhe fehlt oder es
einfach zu lang her is - ich komm einfach nich drauf - und
Debugmöglichkeiten bietet das AVRISP MK2 ja keine in dem Fall.
Eine hübschere Lösung wie diese hier funktioniert wiederrum nicht -
warum auch immer -.-
1
if (init == 1) {
2
if (TMR1_done == 1) {
3
init = 0;
4
lcd_gotoxy(0,0);
5
lcd_clrscr();
6
GICR |= (1 << INT1);
7
}
8
else {
9
TMR1_done = 0;
10
TCNT1H = 0xC0;
11
TCNT1L = tmr1l_preload;
12
TIMSK |= (1 << TOIE1);
13
sei();
14
}
15
}
TMR1_done wird mit 0 initialisiert.
Mein zweites Problem habe ich mit INT1. Wenn die Init durch ist, wird
INT1 aktiviert und in der Hauptschleife wird auf das Signal scroll
gewartet. Ablauf: Wenn scroll == 1, Lade den Text, Gebe ihn aus, lösche
Signal scroll - warte auf INT1.
Nach dem Auslösen von INT1 wird INT1 deaktiviert und nach Löschen des
Signals wieder aktiviert - ich kann in der Zeit mit den Ints eh nichts
anfangen.
Deaktiviert wird der Interrupt mit GICR &= (0 << INT1);
Die ISR ist auch denkbar einfach:
1
ISR( INT1_vect ) {
2
cli();
3
GICR &= (0 << INT1);
4
scroll = 1;
5
sei();
6
return;
7
}
Ich hoffe ihr könnt mir helfen - ich dreh mich im Kreis :(
Vielen Dank
Gruß
Jonas
Hallo,
geh dein Programm nochmal in aller Ruhe durch und überlege jede Zeile
z.B haben in kurzen ISR cli und sei nichts zu suchen
und was tut das return; da
Jonas Arndt schrieb:> ISR( INT1_vect ) {> cli();> GICR &= (0 << INT1);> scroll = 1;> sei();> return;> }
auch eine while-Schleife mit
Jonas Arndt schrieb:> if (TMR2_done)> break;
zu beenden ist suboptimal
ein.
FAQ: Was hat es mit volatile auf sich
und nächstes mal zeig bitte deinen ganzen Code im Zusammenhang. Auch
Details, wie hier das volatile, können und sind wichtig.
so werden keine Bits gelöscht.
Bitmanipulation> Deaktiviert wird der Interrupt mit GICR &= (0 << INT1);
Du hättest genausogut
1
GICR=0;
schreiben können. Denn genau darauf läuft deine Anweisung hinaus.
Hinweis: ein
0<<irgendwas
ist niemals sinnvoll. Denn eine binäre 0 kannst du nach links schieben
so oft du willst. Das Ergebnis ist trotzdem wieder 0. 0 mal irgendeine
Zahl ist nun mal 0.
in einer ISR haben cli() und sei() nichts verloren.
Wenn die ISR betreten wird, sind die Interrupts sowieso abgeschaltet und
beim Verlassen der ISR werden sie wieder aktiviert. Der sei() in deiner
ISR ist ein effektives Problem, weil die Interrupts dadurch einen Tick
zu früh aktiviert werden.
wozu brauchst du zum banalen Abfragen eines Eingangs einen Interrupt.
Deine Münze wird wohl kaum so schnell fallen, dass deiner µC das
verpassen könnte.
Generell: Wenn es nicht unbedingt sein muss (weil man sonst mit der
Eingabepulsdauer nicht hin kommt) - keine externe Interrupts für
Eingabepins. Letzten Endes verkompliziert das alles nur und du kriegst
nichts dafür.
wenn du solche Dinge hast, in denen 2 Register zusammengehören und
logisch gesehen ein 16 Bit Register bilden, aber aus technischen Gründen
als 2 Stück 8 Bit Register ausgeführt sind, dann nimmt der der Compiler
die Arbeit des Auteils ab. Du kannst ganz einfach schreiben
1
TCNT1=400;
und der Compiler sorgt dafür, dass die Zahl entsprechend in Bytes
zerlegt und in die richtigen Register bugsiert wird.
Lass sowas den Compiler machen, denn bei manchen derartigen
Registerpärchen ist die Reihenfolge in der die Zuweisungen gemacht
werden wichtig!
Wenn du Dinge wie einen Automaten nachprogrammierst, dann bietet sich
ein Ansatz an, den man in der Informatik eine "Zustandsmaschine" nennt.
Statemachine
Die Idee hinter so einer abstrakten Maschine ist es genau, einen
dertigen Automaten nachzubauen, bzw. den Lösungsansatz seiner
Problemstellung in so etwas zu überführen.
Daher eignen sich derartige Dinge ganz hervorragend, um mit diesem
Mechanismus abgebildet zu werden.
isnah schrieb:> Hoffentlich goutiert Jonas Arndt beim Morgenessen dieses> "Privat-Tutorial".> Gratulation zu dieser engagierten Forumsbetreuung.> isnah
In der Tat bin ich überwältigt von euren Beiträgen - Vielen lieben Dank!
Die meisten Optimierungshinweise hatte ich erwartet, vorallem der Tipp
mit dem Zustandsautomaten - diese Dinge sind mir bewusst, nur ist dieses
Programm zur Inbetriebnahme der Hardware gedacht gewesen - daher hatte
ich noch keinen saubereren Ansatz gewählt.
Ich merke an den ganzen kleinen Hinweisen, dass es einfach verdammt lang
her ist mit dem Zeug - und sich wohl Dinge von ASM und C gemischt haben,
vorallem beim deaktivieren/aktivieren der INTs in den ISRs.
Wenn ich heute abend wieder von Arbeit komm, werd ich nochmal näher
drauf eingehen - nochmals vielen lieben Dank!
Gruß
Jonas
Hi Jonas,
Karl Heinz hat ja schon auch auf viele Code-Probleme hin gewiesen.
Generell solltest Du Dir aber Gedanken über die grundsätzliche
Programmstruktur machen (dabei spielt es übrigens keine Rolle ob Du in
Assembler oder C programmierst).
Die Ausgabe am Start kannst Du z.B. ohne jegliche ISR machen. Warte doch
einfach in einer Delay-Schleife nach der Ausgabe. Es handelt sich ja um
eine Statusanzeige, unmittelbar nach dem Einschalten. Oder erwartest Du
dann schon das jemand eine Münze ein wirft und der Automat darauf
reagieren muss?
Was die Münzerkennung angeht ist es wirklich besser keine ISR Routine zu
verwenden. Nutze den Timer als Taktquelle mit konstanter Frequenz. Du
kannst in der ISR (gesteuert durch den Taktgeber, nicht den
Port-Eingang) eine Pin-Abfrage per Polling machen
(https://www.mikrocontroller.net/articles/Entprellung). Das funktioniert
zuverlässig und Du hast gleichzeitig eine Zeitbasis mit der Du z.B. LED
blinken lassen, oder die LCD-Anzeige Texte abwechselnd darstellen lassen
kannst. Die ISR ist dabei immer nur der Verwalter der Ereignisse. Da die
Verweildauer der CPU in der ISR kurz sein sollte werden hier keine
langen Berechnungen oder Schleifen bearbeitet.
Deine Main-Routine wertet die Ereignisse aus und führt dann die Arbeiten
aus, enthält also den programmierten Automaten.
Jonas Arndt schrieb:> Die meisten Optimierungshinweise
Optimierung?
Du hast das falsch verstanden. Da gehts nicht um 'Optimierung'. Die
meisten gemeldeten Dinge sind ernsthafte Probleme!
Hallo Karl-Heinz,
Karl Heinz Buchegger schrieb:> Jonas Arndt schrieb:>>> Die meisten Optimierungshinweise>> Optimierung?> Du hast das falsch verstanden. Da gehts nicht um 'Optimierung'. Die> meisten gemeldeten Dinge sind ernsthafte Probleme!
Optimierung wahr sicherlich das falsche Wort, enschuldige bitte.
>> Verrate mir dochmal, was die vielen NOPs sollen.>> Wirst Du nach Zeilen bezahlt oder nach Flashverbrauch?
er hat es oben im Text angedeutet. Ich verbuche das einfach unter
"Verzweiflungstat". Das ist aber sicher das kleinste Problem.
Danke übrigens für Deine Entprellroutine!
Ich verwende die C-Variante sehr gerne und erfolgreich. Die Kritik an
der Komplexität kann ich nicht nach vollziehen. Der Code ist vielleicht
nicht auf Anhieb einfach zu verstehen, aber man kann ihn gut und einfach
einsetzen, auch wenn man nur eine einzige Taste abfragt und die Repeat
Funktion nicht benötigt.
Karl Heinz Buchegger schrieb:> Jonas Arndt schrieb:>>> Die meisten Optimierungshinweise>> Optimierung?> Du hast das falsch verstanden. Da gehts nicht um 'Optimierung'. Die> meisten gemeldeten Dinge sind ernsthafte Probleme!
Hallo Karl-Heinz,
das sollte keine Geringschätzung sein - ich werde die Tipps alle
mitnehmen und hoffentlich heute Abend umsetzen. D.h. ich werd das
Programm fix neuschreiben, es ist ja überschaubar. Ich wollte nur
andeuten, dass vorallem Dinge wie der Programmablauf zum einen dem
geschuldet sind, dass das Programm selbst einfach wuchs, um die
einzelnen Hardwareteile zu testen, zum anderen sind Teile wie die nop()s
wie oben beschrieben dann durch die Verzweiflung eingezogen -
klassisches Trial'n'Error.
Was mich aber weiterhin wundert, dass man hier immer wieder liest, bloß
keine Interrupts zu verwenden. Wenn ich beim Beispiel mit dem
Münzeinwurf bleibe - Ich habe einen Zustandsautomaten im Zustand
"Münzeinwurf abwarten" - warum sollte ich nun nicht das Steuersignal für
diesen Zustand durch nen ISR steuern? Nichts anderes sollte das werden.
Die Timer nutz ich zum Teil als Taktgeber schon - wenn ich
beispielsweise die Buchstaben übers Display scrolle. Bin aber selbst
wenig zufrieden mit den Timern - ein Kahlschlag und Neukonzept sollte
das Richtige sein :)
Bis heute Abend
Besteht weiterhin der Wunsch, das jetztige komplette Programm
anzuhängen?
@Peter - Wie Wolfgang schon schrieb, ich hatte es oben erklärt - es war
einfach ne Idee um etwas ausschließen zu können.
Jonas Arndt schrieb:> Was mich aber weiterhin wundert, dass man hier immer wieder liest, bloß> keine Interrupts zu verwenden.
Das ist so nicht richtig.
Interrupts schon. Aber die richtigen.
externe Interrupts braucht man selten. Eigentlich nur dann, wenn man
wirklich in µs bzw. Bruchteilen davon auf ein Signal reagieren muss,
bzw. wenn die Pulslänge sich in diesem Bereich abspielt.
Als Faustregel: Alles was mit Mensch zu tun hat, sei es Tastendruck oder
sonst irgendwas banal mechanisches, ist so langsam, dass es aus Sicht
des µC einer extremen Superzeitlupe gleichkommt.
> Wenn ich beim Beispiel mit dem> Münzeinwurf bleibe - Ich habe einen Zustandsautomaten im Zustand> "Münzeinwurf abwarten" - warum sollte ich nun nicht das Steuersignal für> diesen Zustand durch nen ISR steuern?
Weil es das Problem nicht vereinfacht. Was bringt dir ein Interrupt
wenn, um beim Beispiel zu bleiben, es ein
1
while(PINB&(1<<PB0))
2
;
auch tut um darauf zu warten, dass der Pin auf 0 geht?
oder eben im Falle einer Statemachine eine entsprechende Abfrage samt
Verzweigung in einen anderen Zustand?
1
switchState
2
{
3
caseState1:
4
...
5
if(PINB&(1<<PB0))// AH Benutzer hat gedrückt
6
State=State2;
7
...
Was genau macht dir da ein externer Interrupt auf der Taste einfacher?
> Nichts anderes sollte das werden.> Die Timer nutz ich zum Teil als Taktgeber schon - wenn ich> beispielsweise die Buchstaben übers Display scrolle. Bin aber selbst> wenig zufrieden mit den Timern - ein Kahlschlag und Neukonzept sollte> das Richtige sein :)
Praktisch jedes ernsthafte Programm benötigt sowas wie einen internen
Taktgeber in Form eines Timers, der zb im Millisekundenabstand eine ISR
aufruft. Und das ist dann auch der perfekte Platz um dort eine
Tastenabfrage und Entprellung unterzubringen
Siehe Entprellung
(Komfortroutinen)
Stellt man das ganze so ein, dass die ISR alle 5ms kommt (hier gehts um
die Größenordnung. ob das 5 oder 10ms sind, ist hingegen wieder
wurscht), dann übersieht diese Entprellung keinen Tastendruck. So
schnell bist du als Mensch nicht, dass du eine Taste schnell genug
drücken und wieder loslassen könntest, dass ein µC der 200 mal pro
Sekunde einen Blick auf den Portpin wirft, das nicht mitbekommen würde.
Und ja: Man kann durchaus in ein und derselben ISR auch mehrere
Aufgabenstellungen behandeln. Hab ich eine ISR, die alle 5ms kommt, dann
kann ich neben der Entprellung zb darauf aufbauend auch noch eine Uhr
machen, oder Ablauftimer oder eben auch Display Scrollen.
Karl Heinz Buchegger schrieb:>> Wenn ich beim Beispiel mit dem>> Münzeinwurf bleibe - Ich habe einen Zustandsautomaten im Zustand>> "Münzeinwurf abwarten"
Nenne den Zustand um in 'Grundzustand'.
Denn dann ist völlig klar, dass ein Münzeinwurf nichts anderes ist, als
eine Möglichkeit wie die Zustandsmaschine aus diesem Grundzustand heraus
in einen anderen Zustand übergeht.
D.h. die Betonung liegt nicht mehr darauf, dass hier auf einen
Münzeinwurf gewartet wird.
Es kann ein Münzeinwurf vorkommen.
Es könnte aber auch ein Timer ablaufen, der dem Zustand signalisiert den
Text im Display um 1 Stelle weiterzurücken.
Es könnte auch jemand auf eine Taste gedrückt haben um sich zu
informieren, was denn der Kaffee kostet.
d.h. an dieser Stelle wird nicht explizit auf einen Münzeinwurf
gewartet, sondern ein Münzeinwurf ist EINE Möglichkeit, was in diesem
Zustand an Ereignissen passieren kann. Eine Möglichkeit, aber beileibe
nicht die einzige.
Wenn geht, vermeide auch umgangssprachlich das Wort 'warten'. Denn es
führt dich oft in die falsche Richtung. Dein Programm wartet nicht.
Sondern es ist in einem Zustand und durch Ereignisse kann es in andere
Zustände übergehen.
Jonas Arndt schrieb:> @Peter - Wie Wolfgang schon schrieb, ich hatte es oben erklärt - es war> einfach ne Idee um etwas ausschließen zu können.
Was erwartest Du denn, was ein bzw. sogar 3 NOPs ausschließen könnten?
Wenn ich Code einfüge, dann muß ich mir dabei doch was gedacht haben.
Auch beim Debuggen sollte man das Gehirn nicht total abschalten.
Bei erfahrenen Programmierern wirst Du kaum ein NOP finden. Das NOP ist
die mit Abstand am wenigsten genutzte Instruktion.
In früheren Zeiten gab es Lochkarten als Speicher, da konnte man
fehlerhaften Code durch NOPs ersetzten. Die NOPs dienten als
Platzhalter, damit Sprünge und Calls weiterhin auf das richtige Ziel
zeigten und nicht sämtliche Karten nochmal neu gestanzt werden mußten.
Heutzutage ist das NOP aber fast ausgestorben.
Na ja, so mancher Computervirus braucht jede Menge davon. Stichwort
"Nop-Rutsche" ;)
Auf einem AVR benötigt man NOPs immer noch genau dann, wenn man
zyklengenau Zeit vebraten muß. Ab und an kommt das mal vor.
Oliver
Peter Dannegger schrieb:> Jonas Arndt schrieb:>> @Peter - Wie Wolfgang schon schrieb, ich hatte es oben erklärt - es war>> einfach ne Idee um etwas ausschließen zu können.>> Was erwartest Du denn, was ein bzw. sogar 3 NOPs ausschließen könnten?> Wenn ich Code einfüge, dann muß ich mir dabei doch was gedacht haben.> Auch beim Debuggen sollte man das Gehirn nicht total abschalten.>> Bei erfahrenen Programmierern wirst Du kaum ein NOP finden. Das NOP ist> die mit Abstand am wenigsten genutzte Instruktion.>> In früheren Zeiten gab es Lochkarten als Speicher, da konnte man> fehlerhaften Code durch NOPs ersetzten. Die NOPs dienten als> Platzhalter, damit Sprünge und Calls weiterhin auf das richtige Ziel> zeigten und nicht sämtliche Karten nochmal neu gestanzt werden mußten.> Heutzutage ist das NOP aber fast ausgestorben.
Es war wie gesagt schon recht verzweifelt - im Übrigen habe ich damals
auf dem 8052 von Atmel einen Bug gehabt, der sich eben genau mit dem
Einfügen von NOPs beheben ließ - allerdings in ASM, aber gut.
Ich hab den Wink mit dem Zaunpfahl schon verstanden, mich mal wieder auf
alle brav gelernten Programmierstrukturen zu besinnen - ich hoffe ich
werde die Erwartungen entsprechend mit der nächsten Programmversion
erfüllen.
Guten Abend liebe Forumsleser,
so, ich habs fertig, das neue Programm - es funktioniert wunderbar. Eine
Funktion get_actualquote() muss noch implementiert werden - das mach ich
später, ich brauch nach dem Erfolg erstmal ein wenig was zu essen.
Ich hänge das Programm mal an, würde mich über Kritik und Hinweise
natürlich sehr freuen.
Vielen Dank nochmal an euch und eure Geduld :)
Grüße
Jonas
PS: Includiert ist die Lib von Peter Fleury
PPS: Kann der uC zur Laufzeit sich umprogrammieren? Ich würde gerne ein
Zählbyte speichern, sodass es bei Strom weg nicht verloren geht. Ich hab
zwar ein EEPROM dran, aber mich würd interessieren ob es da nichts
internes gibt - dem Datenblatt nach wohl nicht :/
Hi Jonas,
sieht doch gut aus! Deine ISR ist ja extrem kurz :-) Wenn Du es ganz
genau nimmst kannst Du die zwei Zeilen in der ISR noch vertauschen. Das
erhöht die Genauigkeit beim Timing ein wenig. Sichtbar ist das in Deiner
Anwendung aber sicherlich nicht.
Ich würde dann noch die Deklaration der SM_ Variablen als ENUM
schreiben. Das ist aber eher Geschmackssache. Meiner Meinung nach erhöht
das die Lesbarkeit.
Diesen Codeblock:
SPDR = SPI_READ;
while(!(SPSR & (1<<SPIF)));
SPDR = EEPROM_START_HIGH;
while(!(SPSR & (1<<SPIF)));
SPDR = EEPROM_START_LOW;
while(!(SPSR & (1<<SPIF)));
Kannst Du noch als Makro codieren. Dann kannst Du dem einen sinnvollen
Namen geben und Änderungen wirken sich an den zwei Stellen im Code
gleichzeitig aus.
Du hast ein externes EEPROM dran? Der MEGA8 hat doch eines eingebaut.
Kannst Du das nicht nehmen, oder ist der Speicher zu klein. Für den
Zugriff auf das interne EEPROM gibt es spezielle Makros.
https://www.mikrocontroller.net/articles/AVR-GCC-Tutorial#EEPROM
Das sich der ATMEGA8 selbst programmieren kann ist mir nicht bekannt.
Wenn Du einen zweiten einbaust können die sie gegenseitig programmieren.
Aber ich vermute mal das interne EEPROM hilft Dir weiter.
Wolfgang Heinemann schrieb:> Hi Jonas,> sieht doch gut aus! Deine ISR ist ja extrem kurz :-) Wenn Du es ganz> genau nimmst kannst Du die zwei Zeilen in der ISR noch vertauschen. Das> erhöht die Genauigkeit beim Timing ein wenig. Sichtbar ist das in Deiner> Anwendung aber sicherlich nicht.>> Ich würde dann noch die Deklaration der SM_ Variablen als ENUM> schreiben. Das ist aber eher Geschmackssache. Meiner Meinung nach erhöht> das die Lesbarkeit.>> Diesen Codeblock:>> SPDR = SPI_READ;> while(!(SPSR & (1<<SPIF)));> SPDR = EEPROM_START_HIGH;> while(!(SPSR & (1<<SPIF)));> SPDR = EEPROM_START_LOW;> while(!(SPSR & (1<<SPIF)));>> Kannst Du noch als Makro codieren. Dann kannst Du dem einen sinnvollen> Namen geben und Änderungen wirken sich an den zwei Stellen im Code> gleichzeitig aus.>> Du hast ein externes EEPROM dran? Der MEGA8 hat doch eines eingebaut.> Kannst Du das nicht nehmen, oder ist der Speicher zu klein. Für den> Zugriff auf das interne EEPROM gibt es spezielle Makros.>> https://www.mikrocontroller.net/articles/AVR-GCC-Tutorial#EEPROM>> Das sich der ATMEGA8 selbst programmieren kann ist mir nicht bekannt.> Wenn Du einen zweiten einbaust können die sie gegenseitig programmieren.> Aber ich vermute mal das interne EEPROM hilft Dir weiter.
Hallo Wolfgang,
danke für das Feedback. Das mit den Anweisungen im ISR war mir bewusst,
aber wie du selbst sagst, ist diese Ungenauigkeit verkraftbar :)
Das mit dem Makro ist ne super Idee, danke!
Ich brauch 25KByte Platz, da ist das interne EEPROM leider raus. Für das
Ablegen von ein paar Byte wäre es natürlich ideal - Danke für den Link -
genau danach hab ich gesucht.
Gruß
Jonas