Datum:
Angehängte Dateien:Gerade Anfänger haben oft das Problem, das erstmal alles wunderbar läuft, aber plötzlich muß noch irgendwo gewartet werden. Und ruchzuck ist die Performance im Eimer, aber der MC soll doch noch so viele andere Sachen auch erledigen. Wie macht man das also, Warten ohne Rechenzeitverschwendung ? Eine mögliche Lösung ist der hier vorgestellte Scheduler. Das Programm wurde mit WINAVR auf einem ATMega8 compiliert und belegt etwa 900 Byte. In dem Zip-File ist die Beschreibung und alle Source-Files. Viel Spaß damit. Peter
Datum:
Nachtrag: So ein Scheduler hat natürlich auch seine Einschränkungen. Im Beispiel wird er alle 65536 Zyklen ausgeführt, d.h. die Main-Loop sollte in der Regel in dieser Zeit mindestens einmal durchlaufen worden sein. Dauert sie manchmal länger ist das meist auch kein Beinbruch. Exakte Zeiten, wie z.B. Uhrzeit+Datum, Frequenzmessung sollte man deshalb nicht im Scheduler sondern direkt im Timerinterrupt machen. Wichtig ist also voher eine grobe Abschätzung der maximalen und minimalen Zeitintervalle zu machen. Im Beispiel ist die minimale Zeit: 1 / (11,0592MHz 256 256) = 5,9ms. Das ist relativ schnell (das Beispiel hat ja fast nichts zu tun), meistens sollten aber Zeiten von 100ms...500ms ausreichend sein. Die maximale Zeit ergibt sich daraus, daß der Delayzähler 16-Bittig ist, zu 65536 * 5,9ms = 6,4min. Im main.h kann der Delayzähler als 8-, 16- oder 32-Bittig festgelegt werden. Das hat dann Einfluß auf die Codegröße sowie die Größe der Liste im RAM. Für ein ordnungsgemäßes Funktionieren des Schedulers ist zu beachten, daß man auch versteckte Wartezeiten vermeiden sollte. Z.B. ist zu empfehlen, für die UART Sende- und Empfangspuffer anzulegen, die dann im UART-Interrupt gefüllt bzw. geleert werden. Das hängt aber immer auch von der konkreten Anwendung ab. Z.B. je 10 Bytes bei 115200Baud im Pollingmode zu senden, dürfte kaum einen kritischen Zeitverbrauch bewirken. Ein Scheduler ist also auch kein Zaubermittel, aber für komplexe Zeitsteuerungen (z.B. Lichteffekte) fast unschlagbar einfach. Peter
Datum:
Hallo Peter, muss man erst hingelinkt werden... http://www.mikrocontroller.net/forum/read-1-155162... Klasse Idee, hatte ich schon mal aufm AVR Seminar was von gehört. Sehe ich mir gerne mal an. Danke (876ter DL) AxelR.
Datum:
Hallo Peter, da ich auf der Suche nach einer Guten Entprell variante in C Suche bin ich auf diese Seite gestossen! Leider bin ich noch anfänger um komme mit dem Code überhaupt nicht zurecht er ist halt einfach zu komplex! Im Prinzip möchte ich nur einen Port als Eingschalten bzw. Port B und dann mit den Einzelnen Pins bei Betätigung einen Funktion aufrufen oder variablen um 1 erhöhen, leider geliegt es mir nicht den Code so aus einander zu nehmen das ich ihn benutzen kann! Ich wäre dir echt dankbar wenn du gerade für anfänger dieses Thema nochmal bearbeiten könntest da das entprellen ja fast das wichtigste ist was man am anfang benötigt! Vielen Dank Tina
Datum:
@Tina die Schedulerfunktion laß einfach links liegen. if( get_key_press( 1<<LED0 ) ) testet ein Bit (gedrückte Taste) und löscht es. Zur Funktion der Tastenerkennung und Entprellung steht hier was: http://www.mikrocontroller.net/forum/read-4-20549.html#new Peter
Datum:
Hallo, vielen Dank für ds wirklich schöne Codestück - schon die Entprellroutine ist toll, die Timer sind ebenfalls sehr nützlich. Dennoch ein Verbesserungsvorschlag: der Code initialisiert den PortC nicht, schaltet also auch die Pullups nicht ein. Out-of-the-zip hat das bei mir sehr schöne Random-Muster zur Folge gehabt - gegen völlig wild schwingende Eingänge hilft eben auch 4-fach Abtastung noch nicht. Aber kaum macht man es richtig, da funktioniert es auch. hase
Datum:
Moin Peter, nachdem ich den Scheduler (also die Timer) auch schon erfolgreich eingesetzt habe, wollte ich auch mal Danke sagen. Die Idee ist nicht neu, aber funktionierend und effektiv fertig vorzufinden ist natürlich schön :-) Vielen Dank Peter. 900ss
Datum:
Hallo Peter, ich versuche gerade deinen Scheduler auf einem Atmega16 zum laufen zu kriegen (16Mhz). Aber es tut sich irgendwie nichts. Als Beispiel sollen drei LEDs eingeschaltet werden. Wenn ich test() ausführe passiert dies auch. Mit timmeradd passiert aber nichts.
#include <avr/io.h> #include <util/delay.h> #include <avr/interrupt.h> #include <avr/pgmspace.h> #include "MAIN.h" int main (void) { //Für Scheduler TCCR0 = 1<<CS02; //divide by 256 * 256; Timereinstellungen für Scheduler TIMSK = 1<<TOIE0; //enable timer interrupt timerinit(); //Initialisierung Timertick für Scheduler sei(); timeradd( test, SECONDS( 1 ) ); for(;;) // main loop { if( f_timer_tick ) { f_timer_tick = 0; timertick(); } } } void test(void) { DDRC = 0b00000111; PORTC = 0b00000000; } |
Die SCHEDULE.c habe ich nicht verändert und die MAIN.c sieht so aus:
#include <avr/io.h> #include <avr/interrupt.h> //#include <signal.h> #define XTAL 16e6 #define TIMERTICK (XTAL / 256 / 256) // timer ticks per second #define SECONDS(x) ((uint)(TIMERTICK * x + 0.5)) #define uchar unsigned char #define uint unsigned int #define bit uchar #define idata #define code typedef void (code *funcp)(void); //#define t_res uchar // define time resolution 8 bit #define t_res uint // define time resolution 16 bit extern uchar key_state; // debounced and inverted key state: // bit = 1: key pressed extern uchar key_press; // key press detect or repeat extern uchar f_timer_tick; // timer flag extern uchar get_key_press( uchar key_mask ); void timertick(void); bit timeradd( funcp func, t_res delay ); bit timerremove( funcp func ); void timerinit(void); extern void test(void); |
Woran könnte das liegen? Schonmal danke für deine Hilfe!
Datum:
Hmmm.... mal sehen.... polier die Glaskugel ;-)
Da du den Code nicht vollständig gepostet hast, kann man nur raten.
Die ISR fehlt zum Beispiel.
Aber hier:
extern uchar f_timer_tick; // timer flag
Hier fehlt das volatile. Die Variable sollte natürlich auch als volatile
definiert sein. Das könnte der Fehler sein.
Hast du geprüft, ob deine ISR überhaupt anläuft?
Wird der Zweig in
if( f_timer_tick ) {...}
aufgerufen? Kannst du doch einfach prüfen (Leds einschalten).
Datum:
Doch ich habe meinen ganzen Code gepostet. Meine main.c und meine main.h. der Rest ist der scheduler von Peter Dannegger. Da habe ich ja nichts verändert.
Datum:
Bene Jan schrieb: > Doch ich habe meinen ganzen Code gepostet. Stimmt, hab mal nachgesehen in dem Code von Peter. Vorher fehlte mir dir ISR. Die ist dann im Modul TOV0.C 1) Setze mal volatile für die oben angegebene Variable. 2) Prüfe, ob die ISR anläuft. 3) Prüfe ob if( f_timer_tick ) {...} durchlaufen wird.
Datum:
Bene Jan schrieb: > void test(void) > { > DDRC = 0b00000111; > PORTC = 0b00000000; > } ääähm... wierum genau hast du denn deine leds angeschlossen..? könnte dein problem vielleicht einfach nur sein, das du portC auf 0x00 stehen lässt...?
Datum:
dunno.. schrieb: > könnte dein problem vielleicht einfach nur sein Bene Jan schrieb: > Als Beispiel sollen > drei LEDs eingeschaltet werden. Wenn ich test() ausführe passiert dies > auch @dunno: alles klar? @Bene Jan: Wenn es funktioniert dann schreib es.
Datum:
Hallo, ich verwende schon lange den Taskscheduler von PEDA und habe hier eine Beispiel mit kompletten Code veröffentlicht. Beitrag "Re: 3fach Timer (einschaltverzögerung)" Damit solltest Du zum Erfolg kommen ! Es gibt auch von mir einige Anpassungen, aber damit komme ich immer sicher ans Ziel bei meiner Projekte.
utimer_t delta; |
kann 16-Bit oder 32-Bit je nach Problem haben und mit der Nutzung i.a. von GPIOR0 - GPIOR2; siehe |main.h|:
#ifdef GPIOR0 # define f_timer_tick SBIT(GPIOR0,0) #endif |
wird der Code kleiner und schneller. .
Datum:
Also mit oder ohne volatile ändert sich leider nichts. Habe mal versucht in der if( f_timer_tick ) die LEDs einzuschalten. Funktioniert nicht! Also wird f_timer_tick nicht 1. Was wiederrum heißt, dass die ISR in TOV0.c nicht ausgeführt wird. Ich weiß aber noch nicht warum?!?
Datum:
Bene Jan schrieb: > Also mit oder ohne volatile ändert sich leider nichts. Du mußt das volatile in zwei Modulen einsetzen, in dem ISR-Modul und in main.h, überall wo eine Deklaration oder Definition von f_timer_tick steht. Um zu prüfen, ob die ISR durchlaufen wird, brauchst du doch nur dort (also in der ISR die LEDs einschalten. Ansonsten die Timerinitialisierung prüfen. SIGNAL(...) für die Interrupttoutine ist alt. Evtl. liegt es daran, was ich aber nicht glaube. Siehe avrlibc-Doku.
Datum:
Ich hab jetzt nochmal volatile benutzt und auf einmal geht es! Ich bin mir 100%-sicher das ich es eben genauso gemacht habe und da hat es nicht funktioniert...
Datum:
Bene Jan schrieb: > Ich hab jetzt nochmal volatile benutzt und auf einmal geht es! Das ist doch schön :-) > Ich bin mir 100%-sicher das ich es eben genauso gemacht habe und da hat > es nicht funktioniert... Daran hab ich meine Zweifel und die darfst du auch haben ;-)
Datum:
Hallo zusammen, ich benutze den Scheduler in verschiedenen Projekten und dieser funktioniert auch super. Jetzt würde ich gerne auch die Entprellfunktion nutzen, diese funktioniert aber leider noch nicht bei mir: Eingelesen werden sollen PE4 und PE5. Dort sind zwei Kurzhubtaster gegen GND angeschlossen. Für dieses Beispiel werte ich aber nur PE5 aus! In meinem Beispiel soll ein kleiner Text über die UART ausgegeben werden. Ausgaben über die UART funktionieren einwandfrei, daran kann es also nicht liegen. Wenn ich den Controller starte wird 1x der Text ausgegeben, ohne das ich den Taster drücke. Das kann ja auch schon nicht normal sein?! Wo liegt mein Fehler? Vielen Dank für eure Hilfe. Hier mein Code: getkey.c
#include "../main.h" uchar get_key_press( uchar key_mask ) { cli(); key_mask &= key_press; // read key(s) key_press ^= key_mask; // clear key(s) sei(); return key_mask; } |
tov0.c
#include "../main.h" uchar f_timer_tick; uchar key_state; // debounced and inverted key state: // bit = 1: key pressed uchar key_press; // key press detect or repeat SIGNAL (SIG_OVERFLOW0) { static char ct0, ct1; char i; i = KEY_INPUT & (1<<KEY4^1<<KEY5); i ^= ~key_state; // key changed ? ct0 = ~( ct0 & i ); // reset or count ct0 ct1 = ct0 ^ (ct1 & i); // reset or count ct1 i &= ct0 & ct1; // count until roll over ? key_state ^= i; // then toggle debounced state key_press |= key_state & i; // 0->1: key press detect f_timer_tick = 1; } |
Veränderungen in der main.h:
#define KEY_INPUT PINE #define KEY4 4 #define KEY5 5 |
main.c
TCCR0B = 1<<CS02; //divide by 256 * 256; Timereinstellungen für Scheduler TIMSK0 = 1<<TOIE0; //enable timer interrupt key_state = 0; key_press = 0; while(1) { if( f_timer_tick ) { f_timer_tick = 0; timertick(); } if( get_key_press( 1<<KEY5 ) ) { //0xFF ^= 1<<PG0; // toggle LED2 on key press uputs0("Taste gedrueckt!"); } } |
Datum:
Hast Du externe Pullups oder schaltest Du sie ein? Bene Jan schrieb: > Hier mein Code: Das ist kein Code, sondern Bröckchen, wie man sie einem Hund hinwirft. Was soll damit jemand anfangen? Er müßte ein neues Projekt machen und die Änderungen mühsam eintragen. Und dabei können Fehler passieren. Hänge das komplette compilierfähige Programm (als Zip) an. Es darf keine Warnungen und Fehlermeldungen geben. Willst Du Änderungen markieren, kommentiere die Originalzeile aus und schreibe die neue darunter. Oder nimm #ifdef, #else, #endif zum Unterscheiden. Peter
Datum:
@Peter: dein Text im ersten Post klingt wie ein Werbetext ;) Hab den Beitrag erst jetzt entdeckt. Werde ich mir mal anschauen.



