www.mikrocontroller.net

Forum: Codesammlung Wartezeiten effektiv (Scheduler)


Autor: peter dannegger (Gast)
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
Autor: peter dannegger (Gast)
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
Autor: AxelR. (Gast)
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.
Autor: Tina Kohler (Gast)
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
Autor: peter dannegger (Gast)
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
Autor: Hartmut Semken (Gast)
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
Autor: 900ss D. (900ss)
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
Autor: Bene Jan (terfagter)
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!
Autor: 900ss D. (900ss)
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).
Autor: Bene Jan (terfagter)
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.
Autor: 900ss D. (900ss)
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.
Autor: dunno.. (Gast)
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...?
Autor: 900ss D. (900ss)
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.
Autor: Uwe S. (de0508)
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.

.
Autor: Bene Jan (terfagter)
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?!?
Autor: 900ss D. (900ss)
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.
Autor: Bene Jan (terfagter)
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...
Autor: 900ss D. (900ss)
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 ;-)
Autor: Bene Jan (terfagter)
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!");
    }
    
  }
Autor: Peter Dannegger (peda)
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
Autor: Markus B. (markus_b77)
Datum:

@Peter: dein Text im ersten Post klingt wie ein Werbetext ;)

Hab den Beitrag erst jetzt entdeckt. Werde ich mir mal anschauen.

Antwort schreiben

Die Angabe einer E-Mail-Adresse ist freiwillig. Wenn Sie automatisch per E-Mail über Antworten auf Ihren Beitrag informiert werden möchten, melden Sie sich bitte an.

Wichtige Regeln - erst lesen, dann posten!

  • Groß- und Kleinschreibung verwenden
  • Längeren Sourcecode nicht im Text einfügen, sondern als Dateianhang

Formatierung (mehr Informationen...)

  • [c]C-Code[/c]
  • [avrasm]AVR-Assembler-Code[/avrasm]
  • [code]Code in anderen Sprachen, ASCII-Zeichnungen[/code]
  • [math]Formel in LaTeX-Syntax[/math]
  • [[Titel]] - Link zu Artikel




Bitte das JPG-Format nur für Fotos und Scans verwenden!
Zeichnungen und Screenshots im PNG- oder GIF-Format hochladen.
Siehe Bildformate
Hinweis: der ursprüngliche Beitrag ist mehr als 6 Monate alt.
Bitte hier nur auf die ursprüngliche Frage antworten,
für neue Fragen einen neuen Beitrag erstellen.

Mit dem Abschicken erkennst du die Nutzungsbedingungen an.

webmaster@mikrocontroller.netImpressumNutzungsbedingungenWerbung auf Mikrocontroller.net