At90S2313 EEPROM auslesen mit Wartezeit

Hallo,

bei meinem ersten AVR-Projekt bin ich nun an einer Stelle zum Stehen gekommen, wo ich nicht mehr weiter weiss und mal um Euren Rat fragen möchte.

Gebaut werden soll eine Motorsteuerung mit einem At90S2313. Zum Programmieren nutze ich BASCOM AVR, geflasht wird mit WinAVR. Der Motor ist über einen BUK 100 am PWM Ausgang PB3 angeschlossen. Timer1 ist so konfiguriert:

Config Timer1 = Pwm , Pwm = 8 , Prescale = 1 , Compare A Pwm = Clear Down , Compare B Pwm = Clear Down

Durch Verändern des Wertes von Compare1a wird die Motordrehzahl gesteuert. Einfluss auf die Motordrehzahl haben 2 Tasten UP/DOWN, ankommende Befehle des UART (RS-232) und 4bit Informationen, die auf Int0 an den Eingängen PB0,PB1,PB2,PB4. Mit den Tasten wird der gesamte mögliche Wertebereich für Compare1a (byte) durchschritten, bei den übrigen Ereignissen wird Compare1a auf einen Wert zwischen 0-255 gesetzt (Tabelle).

Es läuft soweit alles, die Ansteuerung über Tasten, UART und auch von extern 4bit+strobe an Int0 klappen.

Als nächstes sollen Geschwindigkeits- und Zeitinformationen als Sequenz im EEPROM abgelegt werden. Das Schreiben (Writeeeprom) und das Auslesen (Readeeprom) der Daten funktioniert bereits.

Aber nun kommt das Problem:

Das Programm soll bis zum Auslesen des nächsten Befehls eine definiert lange Pause machen, bis der nächste Wert geholt wird. Dabei darf aber der sonstige Programmablauf nicht angehalten werden wie das bei einem WaitMs der Fall ist. Als Geschwindigkeitsinformation dient das obere nibble, als Zeitinformmation das untere nibble des im EEPROM hinterlegten bytes.

Ich suche also eine Möglichkeit, im Hintergrund eine Zeit verstreichen zu lassen (einstellbare Dauer). Ich habe dabei an den noch vorhandenen timer0 gedacht... der sollte doch in der Lage sein, unabhängig von allen anderen Ereignissen einen internen Interupt auszulösen wenn die voreingestellte Zeit verstrichen ist und so das Übernehmen des nächsten EEPROM Wertes einleiten können (Subroutine). Aber genau hier komme ich nicht weiter... Wer hat eine Idee, wie ich das Auslesen des EEPROM in den Hintergrund legen kann, ohne dass mit einem WaitMS das ganze Programm angehalten wird?

Hier mein bisheriges Quellcodegewurstel zum Angucken:

formatting link

Für Verbesserungsvorschläge am gesamten Code bin ich natürlich auch jederzeit dankbar... wie gesagt, es ist mein erstes AVR Projekt und ich stelle mich bestimmt noch ungeschickt dabei an...

Danke

Kai

--
Die angegebene Mailadresse ist replyfähig, sie verfällt
jedoch zum Ende eines jeden Quartals und wird durch eine
 Click to see the full signature
Reply to
Kai Ebersbach
Loading thread data ...

Autsch... ich stelle gerade mit Ercshrecken fest, dass wir ein neues Quartal haben und die alte Mailadresse schon gelöscht ist...

Benutzbar ist nun snipped-for-privacy@kai-ebersbach.de

Ich bitte um Entschuldigung!

Kai

--
Die angegebene Mailadresse ist replyfähig, sie verfällt
jedoch zum Ende eines jeden Quartals und wird durch eine
 Click to see the full signature
Reply to
Kai Ebersbach

[...]

Allgemeinzu Deinem Programm: Versuch Dich mal von dieser strukturierten Programmierung, wie man das früher mal gemacht hat, zu lösen und zu einer eventorientierten Programmierung zuzuwenden. Solche Sachen wie das auslesen der UART-Daten gehören direkt in die IRQ-Routine der UART, sonst kann es bei Deinen Waits auch sporadisch mal passieren, das Deine Daten in der UART überschrieben werden. Kann ja auch mal eine Störung in die UART kommen und dann ist das Byte weg.

Unter eventorientierten Programmierung verstehe ich, dass man wie bei einem Betriebssystem kleine Treiber schreibt (UART, Taster, Timer), die die Hardware managen. In der Regel sind das IRQ-Routinen, aber auch Routinen zur Initialisierung und zum Setzen und Abfragen von Werten. Dabei sollte man sich auch gleich angewöhnen, jeden Treiber in eine eigene Datei zu packen. Ideal ist es, wenn man aus dem Haptprogramm auf die Hardware nur noch mit "SetValue()" und "GetValue()" zugreift. Ereignisse, die sofort bearbeitet werden müssen, macht die IRQ-Routine selbst, die welche mehr Zeit haben/brauchen (z.B. Taste X wurde gedrückt) trägt jeder Treiber in eine Liste ein (kann man auch noch priorisieren), die dann von Hauptprogramm abgearbeitet wird.

Abläufe welche erst mal in jedes Modul schauen, ob irgendwas zu tun ist, fressen nur sinnlos Zeit. (insbesondere wenn die Programme größer werden).

-----------------------------------------------------------------

Zu Deinem Timer Problem: Versuch mal das zu implementieren, dann kannst Du die Funktionen

void setTimer(unsigned int duration, char type); void killTimers(char type);

verwenden. In diesem Beispiel wird (wenn die Timer-ISR alle 1ms kommt) wenn setTimer( 100, TIMER_LS_OBEN) aufgerufen wird. die Funktion processLSoben() nach 100ms gestartet (on_timer wird einfach nur erweitert). In diesem Beispiel können max. 15 Timer gleichzeitig aktiv sein (TIMER_BUFFER_SIZE evtl. erweitern).

-----------------------------------------------------------------------------------------------------------

#define TIMER_EMPTY 0 #define TIMER_DELAY 1 #define TIMER_1 2 #define TIMER_2 3 #define TIMER_LS_UNTEN 4 #define TIMER_LS_OBEN 5 #define TIMER_TLE6220 6 #define TIMER_KEY 7 #define TIMER_DISPLAY 8 #define TIMER_TAS_LICHT 10 #define TIMER_LICHT 11 #define TIMER_RECEIVE 12 #define TIMER_SEND 13 #define TIMER_RECEIVE_EXIT 14 #define TIMER_RECEIVE_DELAY 15

#define TIMER_BUFFER_SIZE 15 #define TIMER_IRQ_PRIORITY 1

#pragma INTERRUPT ta0int /* Declares interrupt handler ta0 */

void initTimer( void); void delay_ms( unsigned int delay); void on_timer(char type); void setTimer(unsigned int duration, char type); void process_timers( void); void killTimer(char type);

struct TIMER { char timer_id; unsigned int end_time; };

static struct TIMER timer_queue[TIMER_BUFFER_SIZE] = {0}; unsigned int global_ms_timer; unsigned char ucDelayTimerOn;

/****************************

  • Start of code *
****************************/

void initTimer( void) { ta0ic = 0; // disable timer irq ta0mr = 0x40; // set Timer Mode ta0ud = 0; // set count down ta0 = 0x800; // set 1mS ta0s = 1; //get ready ta0ic = TIMER_IRQ_PRIORITY; }

void delay_ms( unsigned int delay) {

ucDelayTimerOn = 1; setTimer( delay, TIMER_DELAY); while( ucDelayTimerOn); }

void on_timer(char type) { switch (type) { case TIMER_DELAY: ucDelayTimerOn = 0; break; case TIMER_LS_UNTEN: processLSunten(); break; case TIMER_LS_OBEN: processLSoben(); break; case TIMER_TLE6220: processTLE6220(); break; case TIMER_KEY: processKey(); break; case TIMER_TAS_LICHT: processTasterLicht(); break; case TIMER_LICHT: processLicht(); break; case TIMER_DISPLAY: processDisplay(); break; case TIMER_SEND: processSend(); break; case TIMER_RECEIVE_EXIT: processReceive( type); break; case TIMER_RECEIVE_DELAY: receiveOn(); break;

} }

void far ta0int(void) {

global_ms_timer++; process_timers();

}

void setTimer(unsigned int duration, char type) { char i;

ta0ic = 0x00; // Disable timers

for (i = 0; i < TIMER_BUFFER_SIZE; i++) { if (timer_queue[i].timer_id == TIMER_EMPTY) // Suche nach freien Timern { timer_queue[i].timer_id = type; timer_queue[i].end_time = duration + global_ms_timer; ta0ic = TIMER_IRQ_PRIORITY; // Re-enable timers return; } }

ta0ic = TIMER_IRQ_PRIORITY; // Re-enable timers

}

void process_timers( void) { char i;

for (i=0;i

Reply to
Dirk Ruth

Hallo Dirk,

Dirk Ruth schrieb:

Leichter gesagt, als getan ;-) Ich bin ja schon froh, dass der Atmel erst mal das tut, was ich möchte... wenn auch noch nicht alle Wünsche implementiert sind...

Hmmm... wird denn der Wert nicht bis zur nächsten Abfrage im entsprechenden Register gehalten? Wie das bei Störungen aussieht kann ich natürlich nicht beurteilen...

OK, das sehe ich ein... ich muss es jetzt "nur noch" verstehen und umsetzen können...

[Quellcode (war es C?) gelöscht]

Uih... schwere Kost ;-) Das muss ich erst noch 20-30 mal lesen und begreifen, was Du damit gemeint hast...

Vielen Dank für Deine Anregungen und einen schönen Feiertag!

Kai

--
***          homepage: http://www.erosoft.de            ***
Die angegebene Mailadresse ist replyfähig, sie verfällt
 Click to see the full signature
Reply to
Kai Ebersbach

Wird schon noch.

Schon richtig. Aber wenn ein neuer Wert kommt (worst case: Störung) oder Du Dich bei Deinen Wartezeiten vertan hast, dann ist es weg.

Viele Designs arbeiten auch mit Batterieversorgung, dann frist das polling auch nur sinnlos Strom.

Es war C.

Was ich da gepostet hatte war ein Entwurfsmuster (Pattern) für eine Timerroutine (hier für einen M16C). Du must lediglich die Timer-Initialisierung anpassen, dann läuft die auf jedem Microcontroller. Brauchst also nicht mehr jedesmal von vorn anfangen und die Fehler da zu suchen.

Kann man natürlich noch erweitern, dass auch Callback-Funktionen möglich sind, aber das gibt's in Basic ohnehin nicht.

Tschö Dirk

Reply to
Dirk Ruth

In meinem Projekt habe ich all diese Geschichten mit einem Timer gelöst, der immer mitläuft und jede ms ausgelöst wird. Wann immer das Hauptprogramm eine Aktion ausführen will, macht sie das nicht selbst, sondern setzt ein Flag (z.B. updateLCD). Wenn der Timer überläuft, wird der Flagwert dekriminiert (falls > 0). Ist er null, wird die entsprechende Routine aufgerufen und führt die Aktion aus. Wenn man keine Boolean-Variablen verwendet (gibt's beim AVR sowieso nicht), kann man auch festlegen, daß eine Aktion z.B. nur alle 10ms ausgeführt wird (Flag auf 10 setzen, 9 Timer verstreichen ohne Aktion, bei der 10. wird ausgeführt). Außerdem läßt sich die Aktion damit auch mehrfach ausführen (Aktionsroutine setzt selbst das Flag wieder auf 10). Zur Initialisierung muß dann nur einmalig das Flag gesetzt werden. Außerdem kann das Hauptprogramm ein Update "außer der Reihe" anordnen, indem das Flag auf 1 gesezt wird (Update beim nächsten Timer, unabhängig vom aktuellen Zählerstand).

Zusätzlich kann man natürlich noch Queues einbauen (jede Aktion führt genau einen Queue-Befehl aus). Etwas haushalten sollte man nur mit den Zähl- bzw. Flagvariablen (ich muß CF lesen, brauche also von den 1024 Bytes allein 512 für den Sektorbuffer, variable Strings etc. brauchen auch ganz schön); schließlich müssen das globale Variablen sein und belegen dauerhaft Speicher. Also char verwenden (evtl. unsigned, mehr als 256 Timer-Ticks wird man nicht brauchen - sonst paßt man die Timerfrequenz entsprechend an).

Wenn Du magst, kann ich Dir auch gerne meinen Quellcode schicken (AVR-GCC, ist auch nur rudimentär kommentiert, form follows function ;o)) --> PM

Sebastian

Reply to
Sebastian Voitzsch

Hallo Sebastian,

Sebastian Voitzsch schrieb:

So in der Form hatte ich es auch mal überlegt... das Ganze wurde dann allerdings so aufwendig, dass Bascom AVR in der Demo Version streikte, weil da nur 1024 byte Code zulässig sind...

Ich habe nun erst einmal MaWins Vorschlag verfolgt und es funktioniert momentan so wie es soll. Da das ganze Projekt allerdings noch nicht endgültig ausgetüftelt ist, kann und wird sich sicher noch einiges ändern und ich versuche dabei auch gern andere Ansätze, man wird ja nicht dümmer dadurch ;-)

Nun muss ich mir erst mal BASCOM AVR in der Vollversion kaufen, damit ich auch die 2048 byte voll nutzen kann ;-) Kennt da jemand noch eine Bezugsquelle ausser den auf der MSCELEC-Homepage genannten Distributoren?

Ich würde mich sehr darüber freuen, die Adresse snipped-for-privacy@kai-ebersbach.de ist gültig. Ich habe allerdings wie wohl fast jeder Usenetteilnehmer mit einer Masse von Swens zu kämpfen, die das Mailen nicht gerade schöner macht :-(, daher der Wechsel (hoffe Swen verschont die Mailadresse weil "spam" drin vorkommt). Die alte Adresse ist aber auch noch eine Weile gültig.

Viele Grüsse

Kai

--
Die angegebene Mailadresse ist replyfähig, sie verfällt
jedoch zum Ende eines jeden Quartals und wird durch eine
 Click to see the full signature
Reply to
Kai Ebersbach

Hallo Dirk,

Dirk Ruth schrieb:

Ja, mühseelig ernährt sich das Eichhörnchen ;-) Momentan bin ich am 1024 byte Limit der Demo-Version von BASCOM AVR angekommen...

Bei einigen kritschen Anwendungen sicherlich ein wichtiger Aspekt... wenn bei meinem Projekt ein Zeichen verloren geht, muss es eben noch mal gesendet werden... Ich behalte Deine Anregung aber im Hinterkopf.

So weit habe ich noch gar nicht gedacht... aber Du hast völlig recht, für eine Optimierung ein wichtiger Punkt.

Ich habe es mir in meinen Sammelordner abgelegt, aus dem ich mir immer mal häppchenweise etwas zum Verarbeiten raushole... Manchmal qualmt mir allerdings als Hobbyist der Kopf, dann lege ich das alles erst mal zur Seite ;-).

Viele Grüsse

Kai

--
Die angegebene Mailadresse ist replyfähig, sie verfällt
jedoch zum Ende eines jeden Quartals und wird durch eine
 Click to see the full signature
Reply to
Kai Ebersbach

Nimm halt AVR-GCC und Du bist die Lizenzquerelen los. Mich würde es auch nicht wundern, wenn C zu kleinerem Code führt.

SWEN dürfte eher interessieren, ob er die Adresse in irgendwelchen Adreßbüchern oder im Web findet, nicht, ob SPAM drin vorkommt. Von mir jedenfalls gibt's keinen SWEN, IMHO ist KMail dafür nicht anfällig ;o)

Sebastian

Reply to
Sebastian Voitzsch

Vergiss das mit dem Basic. Bei Microcontroller wird es hin und wieder notwendig sein "Low Level" zu programmieren, also auf Adressen zuzugreifen, zu verschieben und überhaupt mit Zeigern zu arbeiten. Mit Basic wirst Du da auf die Dauer nicht glücklich. Und wenn Du die Grundlagen erstmal kapiert hast, dann willst Du auch schnell mehr versuchen.

Besorg Dir einen richtigen Compiler zum programmieren. Der GCC ist dafür nicht schlecht, oder wenn Du Geld ausgeben möchtest, dann kann ich Dir auch den ICC-AVR empfehlen. Da gibt's dann auch die richtigen Librarys im Quellcode dazu.

Basic ist, wie der Name schon sagt, wirlich nur Basic.

Tschö Dirk

Reply to
Dirk Ruth

Wobei auch für den GCC dank der weiten Verbreitung einiges zu haben ist. Und die meisten Leute, die Libs dafür machen, geben die auch unter der GPL weiter. Ich habe immer den Eindruck, daß es nichts gibt, was nicht auch für den GCC zu haben ist - ist allerdings nur meine Hobby-Erfahrung. Industriell mag das anders aussehen (v.a. Support etc.).

Jepp...

Sebastian

Reply to
Sebastian Voitzsch

Hallo Dirk,

Dirk Ruth schrieb:

Ich habe mich nun entschlossen, dasselbe Programm noch einmal zu schreiben und zwar gleich in Assembler. Dazu kann ich auch die kostenlosen Werkzeuge, die Atmel verfügbar macht, benutzen.

Bevor ich mich in eine weitere Hochsprache einarbeite, nehm ich gleich den harten Weg ;-) Da ich ja Zeit habe, kann ich mich da langsam Schritt für Schritt durchwühlen und lerne dabei sicher gleich mehr über den inneren Aufbau der Mikrocontroller.

Herzlichen Dank für alle Anregungen und viele Grüsse

Kai

--
Die angegebene Mailadresse ist replyfähig, sie verfällt
jedoch zum Ende eines jeden Quartals und wird durch eine
 Click to see the full signature
Reply to
Kai Ebersbach

Hallo Sebastian,

Sebastian Voitzsch schrieb:

Wie ich schon zu Dirks Posting schrieb, wähle ich nun den harten Weg und schreibe das Programm Schritt für Schritt in Assembler neu.

In d.a.n.a.m wird z.Zt. diskutiert und ausprobiert, ob Mailadressen die "spam" enthalten verschont werden... daher der Versuch.

Von mir gibts auch keinen, selbst Mozilla führt Tags nihct einfach aus ;-). Gemeint war aber, dass Swen neben lokalen Adressbüchern und HTML-Files auch Newsgroups auf Mailadressen durchforstet und sich dann innerhalb kürzester Zeit mehrfach an die gefundenen Adressen verschickt. Es hat gerade mal eine Stunde gedauert nachdem ich mit der frischen Adresse snipped-for-privacy@kai-ebersbach.de gepostet hatte und die ersten Swens kamen herein :-(. Egal... das ist hier eh OT.

Vielen Dank für Deine Anregungen und viele Grüsse

Kai

--
Die angegebene Mailadresse ist replyfähig, sie verfällt
jedoch zum Ende eines jeden Quartals und wird durch eine
 Click to see the full signature
Reply to
Kai Ebersbach

ElectronDepot website is not affiliated with any of the manufacturers or service providers discussed here. All logos and trade names are the property of their respective owners.