www.mikrocontroller.net

Forum: Mikrocontroller und Digitale Elektronik Rudimentäres Event System für AVR


Autor: Michael K. (mmike)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hallo Leute,

nachdem ich jetzt schon eine Weile mit den AVR rumspiele und die 
Projekte immer grösser werden hab ich mir mal ein paar Gedanken bzgl. 
eine "Event" Systems gemacht. Dabei werden die Events an sich mittels 
eines enums (in der events.h) definiert. Hier werden auch die maximale 
Anzahl der benötigten Events festgelegt (MAXEVENTS). Danach kann man 
dann eine Funktion bei dem Event - System registrieren und wenn dann so 
ein Event (das man natürlich noch auslösen muss) eintritt, dann wird das 
von der Funktion HandleEvents() abgearbeitet. Hier mal der entsprechende 
Quellcode. Mich würde sehr Eure Meinung dazu interessieren:

events.h
//***********************************************************************************************************************
#ifndef _EVENTS_H__
#define _EVENTS_H__

//***********************************************************************************************************************
#include <inttypes.h>


//***********************************************************************************************************************
#define  MAXEVENTS    3          // Number of max. functions to be used in event system [max is 32]

//***********************************************************************************************************************
// EVENT enum list
typedef enum
{
  EVENT_0,
  EVENT_1,
  EVENT_2
} E_EVENTS;

// Function pointer type
typedef void (*pt2func)();


//***********************************************************************************************************************
// Function prototypes
uint8_t RegisterEvent (uint8_t event, void (*funcp));
void  HandleEvents ();
void   RaiseEvent (uint8_t  event);
void  ClearEvent (uint8_t  event);

#endif


events.c
//***********************************************************************************************************************
// Includes
#include "events.h"

//***********************************************************************************************************************
// Globals
#if   (MAXFUNCS <= 8)
  volatile uint8_t  EventFlagBuffer  = 0;
#elif (MAXFUNCS <= 16)
  volatile uint16_t  EventFlagBuffer  = 0;
#elif (MAXFUNCS <= 32)
  volatile uint32_t  EventFlagBuffer  = 0;
#else
  #error "TOO MANY EVENTS ... check MAXEVENTS";
#endif

volatile pt2func FuncArray[MAXEVENTS]  = { 0 };    // Function pointer array

//***********************************************************************************************************************
// Function to register an event
uint8_t  RegisterEvent (uint8_t event, void (*fp))
{
  if ((fp != 0) && (event < MAXEVENTS))    // Check if function pointer if not NULL or reg. event bigger than MAXEVENTS
  {
    FuncArray[event] = fp;
    return 0;
  }

  return -1;
}

//***********************************************************************************************************************
inline void ClearEvent (uint8_t  event)
{
  EventFlagBuffer &= ~(1 << event);
}

//***********************************************************************************************************************
inline void RaiseEvent (uint8_t event)
{
  EventFlagBuffer |= (1 << event);
}

//***********************************************************************************************************************
// Function to handle all active events
inline void HandleEvents ()
{
  // Locals
  uint8_t  i;

  for (i = 0; i < MAXEVENTS; i++)
  {
    if (EventFlagBuffer & (1 << i))
    {
      if (FuncArray[i] != 0)      // Check if function pointer is not NULL
        FuncArray[i] ();      // Call function
      ClearEvent (i);          // Clear the event
    }
  }
}


main.h
#ifndef _MAIN_H__
#define _MAIN_H__

#include <avr/io.h>
#include <inttypes.h>
#include "events.h"

#endif


und noch die main.c:
#include "main.h"

volatile uint8_t  test = EVENT_1;

//***********************************************************************************************************************
// Test function 0
void Test0 ()
{
  uint8_t i; 
  i = 3;
  i = i * i;
}

//***********************************************************************************************************************
// Test function 1
void Test1 ()
{
  uint8_t i;
  i = 4;
  i = i * i;
}

//***********************************************************************************************************************
// Test function 2
void Test2 ()
{
  uint8_t i;
  i = 4;
  i = i * i;
}

//***********************************************************************************************************************
// Main function
int main ()
{
  // Locals
  volatile uint8_t  dummy = 0;

  // Register EVENT_0 and EVENT_1 with their corresponding handle function
  RegisterEvent (EVENT_0, Test0);
  RegisterEvent (EVENT_1, Test1);
  RegisterEvent (EVENT_2, Test2);
  
  // Endless loop
  for (;;) 
  {
    ++dummy;              // Increment dummy var
  
    if (dummy == 30)          
      RaiseEvent (EVENT_0);      // Raise EVENT_0
    else if (dummy == 100)
      RaiseEvent (EVENT_1);      // Raise EVENT_1
    else if (dummy == 150)
      RaiseEvent (EVENT_2);      // Raise EVENT_1

    HandleEvents ();          // Handle all events
  }
}

Beste Grüße,
Michael

Autor: STK500-Besitzer (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Und was möchte uns der Herr damit sagen?
Code, der veröffentlich werden soll, gehört in die Codesammlung. Da kann 
man dann auch wunderbar darüber diskuttieren...

Autor: Gast (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Prima,

besser hätte man switch+case / if+else / direkte Funktionsaufrufe nicht 
ersetzen können.

Autor: Matthias Lipinsky (lippy)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
uint8_t  RegisterEvent (uint8_t event, void (*fp))
{
 ...
  return -1;
}

Meinst du nicht, das sich das uint8_t als Rückgabewert mit dem -1 von 
return etwas beißt?



Interessant bzgl der notwendigen Rechenleistung dürfte auch das werden:
if (EventFlagBuffer & (1 << i))
                      ^^^^^^^^^

Autor: Michael K. (mmike)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
@STK500-Besitzer: Ich möchte eigentlich nix sagen. Eher was dazu gesagt 
bekommen. In die Codesammlung hab' ich noch nicht geschoben, da ich 
dachte, dass da nur Zeugs reinkommt, was schon "approved" ist ... beim 
nächsten mal, versprochen ;-)

@Gast: Genau das hat mich bzgl. der Übersichtlichkeit immer ein wenig 
gestört ...

Grüße,
Michael

Autor: Michael K. (mmike)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
@Matthias Lipinsky: Nö, warum denn? Kommt halt 0xFF zurück ....

Grüße,
Michael

Autor: Gast (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
was ist übersichtlicher ?

RegisterEvent(...)
...
if (dummy == 30)
 RaiseEvent (EVENT_0);
...
HandleEvents();

oder

if(dummy == 30)
 Test0();

Autor: Michael K. (mmike)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
@Gast: Das ist schon richtig. Meist aber werden die Events ja von 
beispielsweise Interrupts ausgelöst, in denen ein Flag gesetzt wird und 
in der Main wird dieses abgefragt und abgearbeitet. Dabei muss dann in 
der ausführenden Funktion dieses Flag auch wieder gelöscht werden. Bei 
größeren Projekten wurde mit das Ganze dann einfach zu unübersichtlich. 
Angenommen man hat 12 Flags die an unterschiedlichen Stellen gesetzt 
werden, dann hättest Du einen if - else if - else if ... - else Baum mit 
12 Einträgen. So steht bei mir das HandleEvents () in der main -- auf 
der anderen Seite muss ich aber auch alle Events registrieren, eben 12 
mal. Ist wohl Geschmackssache ... mir gefällt so einfach besser ...

Grüße,
Michael

Autor: Michael K. (mmike)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
> Interessant bzgl der notwendigen Rechenleistung dürfte auch das werden:
>
> if (EventFlagBuffer & (1 << i))
> 
>                       ^^^^^^^^^
@Matthias Lipinsky: Könntest Du das bitte ein wenig näher erläutern? 
Braucht das shiften so viel Zeit ?

Grüße,
Michael

Autor: Gast (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
OK jedem das seine :-)

ABER die Ressourcen in einem AVR sind begrenzt, besonders SRAM. Im 
Beispiel mit den 12 Flags wird Platz für 12 indirekte Call Adressen im 
SRAM benötigt. 12 mal if(..) benötigen 0,0 millibit.

Gute Nacht

Autor: Michael K. (mmike)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
@Gast: Das stimmt natürlich ... danke für den Tip ! Dir auch eine gute 
Nacht ...

Grüße,
Michael

Autor: Matthias Lipinsky (lippy)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
> if (EventFlagBuffer & (1 << i))

>Braucht das shiften so viel Zeit ?

Ja. Da dieses Shiften zur Laufzeit gemacht werden muss(es ist ja niht 
bekannt, wieviel Bits zu schiften sind), entsteht dadurch eine Schleife.

Das hingegen:
(1<<PC4) ist eine Konstante und wird zur Compilezeit ermittelt.

(Sieh dir doch einfach mal den ASM-COde dazu an)


Ich würde Dir raten, das eher über eine Maske (im Flash) zu machen:
Das sollte einiges schneller als die Schleife sein
uint8_t   au8Maske[]  PROGMEM = {  0x0001,  0x0002,  0x0004,  0x0008
                                   0x0010,  0x0020,  0x0040,  0x0080,
                                   ....
                                   0x1000,  0x2000,  0x4000,  0x8000  );

if (  EventFlagBuffer & pgm_read_word(au8Maske[i])  )
...

Autor: Michael K. (mmike)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
@Matthias Lipinsky: Hey Klasse ... vielen Dank! Wird sofort eingebaut !

Grüße,
Michael

Autor: Eddy Current (chrisi)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Statt Euch an programmtechnischen Kleinigkeiten aufzuhängen, sollte doch 
eher eine Diskussion über die Notwendigkeit eines Eventsystems auf einem 
AVR in Gang kommen. Manche Menschen fangen halt rechtzeitig an, zu 
abstrahieren und behalten später den Überblick...;-)

Aber mal im Ernst: Immer dann, wenn von einem Programmm viele Dinge 
gleichzeitig zu erledigen sind, sollte man über ein Eventsystem 
nachdenken. Wie rudimentär das sein muss, hängt dann nur noch von der 
Komplexität der Aufgabe ab.

Lohnend war es für mich beispielsweise bei der Umsetzung eine 
Bedienoberfläche, die Messwerte, Uhrzeit usw. anzeigt, die sich 
asynchron vom Vordergrundprogramm ändern. In so einer Umgebung sendet 
der Timer ein Event, das der Bildschirm neu gezeichnet werden möge, weil 
sich die Uhrzeit verändert hat. Auf diese Weise können viele unabhängige 
Prozesse das Neuzeichnen des Bildschirms veranlassen. Gleichzeitig wird 
aber auch auf Tastendrücke per Event reagiert.

Autor: STK500-Besitzer (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
@Lippy ist das nicht etwas umständlich?
Man könnte doch einfach vor der Schleife eine Variable mit 1 
initialisieren und sie dann in der Schleife mit 2 multiplizieren. Mehr 
sind diese shifts ja auch nicht, wobei die Shifts wahnsinnigen Overhead 
erzeugen.

Autor: Michael K. (mmike)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
@Matthias Lipinsky: Noch ne kurze Frage: Statt uint8_t sollte es wohl 
uint16_t sein, oder?

@Eddy Current: Genau dafür mache ich das Ganze. Das Projekt ist eine 
Ansammlung von Tools für meinen Modellbaukram. Also Ladekurven plotten 
mittels der Daten von den Ladegeräten (mit Log auf SD - Karte). Dann ein 
Frequenzscanner mit externem Scan - Empfänger, Servotest, Empfängertest, 
EWD - Messung, Drehzahlmessung, ... etc. Bei den Dingen die ich vorhabe 
ist Geschwindigkeit nicht so wirklich wichtig, da meist das GLCD bedient 
werden muss. Also Controller kommt ein Mega128 zum Einsatz. Aber wenn 
man von vornherein optimieren kann dann bin ich immer sehr dankbar für 
Tipps!

Grüße,
Michael

Autor: Matthias Lipinsky (lippy)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
>Noch ne kurze Frage: Statt uint8_t sollte es wohl uint16_t sein, oder?
Ja. Das war nur, um zu prüfen ob du aufpasst ;-)

>einfach vor der Schleife eine Variable mit 1 initialisieren und sie dann in >der 
Schleife mit 2 multiplizieren
Ja, wäre auch möglich. Nur statt multiplizieren, dann einfach schieben.


>In so einer Umgebung sendet der Timer ein Event, das der Bildschirm neu 
>gezeichnet werden möge, weil sich die Uhrzeit verändert hat.
Meine Philosophie ist eher andersrum: Die Bedienung/Anzeige ist 
unabhängig von der Steuerung (also der eigentlichen Aufgabe). Somit muss 
die Bedienung/Anzeige selbständig entscheiden, ob irgendwas neu 
aufgebaut werden muss..

Autor: Michael K. (mmike)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
@Matthias Lipinsky: Ist zwar schon spät, aber noch komme ich mit ;-)
Zu Deiner Philisophie: Dann müsste die Display Funktion ja eigentlich 
immer schauen, ob sich an den Daten die dargestellt werden sollen was 
geändert hat ... ist das nicht aufwändiger ?

Grüße,
Michael

Autor: Matthias Lipinsky (lippy)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
>Dann müsste die Display Funktion..

Ja. zB bei der Uhrzeit könnte das so aussehen:
if ( SekundeLast != Sekunde )
{
  SekundeLast  = Sekunde;

  // Uhrzeit aktualisieren
}

Das kommt aus meinem Beruf. Da programmiere ich SPS. DOrt vertrete ich 
dasselbe. Somit kann der Ablauf programmiert werden, mit all seinen 
Variablen.

Unabhängig davon kann sich eine Visualisierung um die Anzeige von 
(einigen) Varaiblen kümmern. Evtl. auch Eingabemöglichkeiten bieten.
Wann nun das Display aktualisiert werden muss, ist der Steuerung, also 
dem Ablauf doch sch*egal...

Autor: Michael K. (mmike)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Da hast Du natürlich Recht ... kommt wohl sehr auf den Anwendungsfall an 
...

Autor: Aha (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
@ Michael K. (mmike)
So ein Eventsystem ist akademisch aufgeblaheter Nonsense. Speziell wenn 
das ganze noch dynamisch eingeklinkt wird. Viel pragmatischer ist es in 
der Interruptprocedur eine Boolean zu setzen, und die dann im Main 
abzufragen. Dann kann man noch eine Statusmaschine mitlaufen lassen und 
gut ist.

Autor: Sebastian B. (mircobolle)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Das was du vor hast bezeichnet man in der Softwarearchitektur als 
Observer-Pattern. Dort können sich interessierte Klassen für ein 
bestimmtes Ereignis registrieren, sobald dieses Ereignis dann eintritt, 
werden die registrierten Objekte (Observer) informiert.

Hast du aber mal daran gedacht, dass die Ereignisse dann alle im 
Interrupt Kontext deiner ISR aufgerufen werden?

Beispielsweise registrierst du 20 Module darauf, dass der RTC seine 1 
Millisekunde Periode erreicht hat.

In der ISR der RTC werden nun 20 registrierte Event-Funktionen 
aufgerufen. Sagen wir mal jede braucht im Schnitt 100 Mikrosekunden zur 
Abarbeitung. Das klingt nicht viel, ABER 20 * 100 Mikrosekunden = 2 
Millisekunden.. und schon hättest du dank deines geschickten Designs 
dein System total gesprengt ...

Vielleicht habe ich dein Design, aber gerade auch nur falsch verstanden 
:-)

Du kannst mich gerne aufklären!

Gute Nacht!

Autor: Sebastian B. (mircobolle)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
//***********************************************************************************************************************
// Function to register an event
uint8_t  RegisterEvent (uint8_t event, void (*fp))
{
  if ((fp != 0) && (event < MAXEVENTS))    // Check if function pointer if not NULL or reg. event bigger than MAXEVENTS
  {
    FuncArray[event] = fp;
    return 0;
  }

  return -1;
}
Achso... ich sehe gerade, dass du immer nur eine Funktion auf ein Event 
registrieren kannst.. stimmt das?

Autor: Simon K. (simon) Benutzerseite
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Eine "-1" zurückzugeben, bei einem uint8_t als Typ sorgt meiner Meinung 
nach für Verwirrung.

Besser finde ich:
#define RE_ERROR ((uint8_t) -1)

Da ist die Absicht direkt raus abzulesen.

@Lippy: Meinst du, dass das dereferenzieren mit LPM aus dem Flash 
schneller ist als eine kleine Shift-Schleife? Wenn überhaupt dann nur 
ein/zwei Takte, würde ich sagen.

Autor: Nico (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Deine HandleEvents funktion ist übrigens nicht interrupt-sicher. Normal 
sollte die Reihenfolge so aussehen.

1.) Interrupts sperren
2.) Flag checken -> weiter zu drei, oder raus
3.) Flag clearen
4.) Interrupts freigeben
5.) Funktion aufrufen.

Am Anfang von HandleEvents würde ich erstmal schauen ob EventBuffer 
überhaupt einen Wert hat (EventBuffer != 0). Sonst machst du da bis zu 
32 checks für nichts unter wieder nichts. ;)

Autor: Stefan Ernst (sternst)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
1)
Ich würde mich von dem Gedanken verabschieden, die Events zu 
nummerieren. Benutze als Identifikation gleich die Maske, das spart das 
ineffiziente Geschiebe. Du kannst ja ein paar Makros definieren, dann 
können die Events auch gleich aussagekräftige Namen bekommen:
#define EVENT_TIMER    (1<<0)
#define EVENT_KEY      (1<<1)
#define EVENT_DISPLAY  (1<<2)
...
RaiseEvent( EVENT_DISPLAY );
Und auch das Raisen mehrerer Events ist dann effizienter:
RaiseEvent( EVENT_KEY + EVENT_DISPLAY );

2)
µC-Programme sind praktisch immer starre Konstrukte, keine dynamischen. 
Schon beim Schreiben des Programms steht fest, welche Funktion zu 
welchem Event gehört. Die Funktion RegisterEvent finde ich daher 
reichlich überflüssig. Initialisiere FuncArray doch gleich mit den 
richtigen Werten. Dann kann das Array auch im Flash liegen, was 
wertvolles RAM spart.

3)
Du musst dir unbedingt mehr Gedanken zur Interruptsicherheit machen. 
Das gilt insbesondere für ClearEvent. Aber auch für RaiseEvent, wenn es 
auch außerhalb von Interrupts aufgerufen wird. Bei RaiseEvent ist es 
dann aber mit einem cli/sei-Pärchen nicht getan. Benutze am besten die 
Makros der AVR-Libc.

Autor: Stefan Ernst (sternst)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Ach, noch was:

#if   (MAXFUNCS <= 8)
  volatile uint8_t  EventFlagBuffer  = 0;
#elif (MAXFUNCS <= 16)
  volatile uint16_t  EventFlagBuffer  = 0;
#elif (MAXFUNCS <= 32)
  volatile uint32_t  EventFlagBuffer  = 0;
#else
  #error "TOO MANY EVENTS ... check MAXEVENTS";
#endif
Das ist zwar nett gedacht, aber der restliche Code funktioniert bei 
MAXFUNCS>16 nicht. Da bedarf es schon noch mehr, wenn das alles 
"automatisch" per Präprozessor gehen soll.
(wobei eine Beschränkung auf max 16 Events das einfachste wäre, und 16 
sollten eigentlich auch immer reichen)

Autor: Michael K. (mmike)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
@All: Erst mal vielen vielen Dank für Eure Kommentar! Hab viel gelernt !

@Sebastian B.: Richtig. Nur eine Funktion kann sich für ein Event 
registrieren.

@Simon K.: Alles klar. Ist umgebaut. Bzgl. dem shiften hab ich jetzt so 
gemacht wie STK500-Besitzer es vorgeschlagen hat. Ich initialisiere ein 
lokale Variable mit 1 und shifte diese dann pro Durchlauf immer um eine 
Stelle nach links.

@Nico: Die Handle - Funktionen erledigen normalerweise "low-priority" 
Dinge wie einen Uart String parsen bzw. die Displayausgabe. Die Sollen 
eigentlich unterbrechbar sein, damit der Rest ungestört laufen kann. Der 
Tip mit dem Check "(EventBuffer != 0)" ist klasse und schon eingebaut!

@Stefan Ernst: Das ist natürlich ein Punkt mit den #defines. Auch das 
mehrere Event gleichzeitig "geraised" werden können wäre eine gute 
Sache. Ich hatte am Anfang auch überlegt es so zu machen, aber mit den 
enums muss ich selbst einfach nicht aufpassen, ob die Events auch 
chronologisch definiert sind. Effektiver ist es mit Deinem Vorschlag ... 
keine Frage!
Bzgl. der Interruptsicherheit: Ich verstehe den Punkt, aber leider nicht 
warum es mit einem cli/sei am Anfang und Ende der Raise- bzw. ClearEvent 
Funktionen nicht getan ist? Welche Makros meinst Du genau?
Bzgl. der Präprozessorgeschichte: Habs mittlerweile fest für max. 16 
Events gemacht. MAXEVENTS kann dann Werte von 1 - 16 annehmen.

Grüße,
Michael

Autor: Stefan Ernst (sternst)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Michael K. wrote:

> @Stefan Ernst: Das ist natürlich ein Punkt mit den #defines. Auch das
> mehrere Event gleichzeitig "geraised" werden können wäre eine gute
> Sache. Ich hatte am Anfang auch überlegt es so zu machen, aber mit den
> enums muss ich selbst einfach nicht aufpassen, ob die Events auch
> chronologisch definiert sind.

Der eigentliche Punkt dabei ist, aus RaiseEvent und ClearEvent die 
Konstrukte à la (1<<event) rauszubekommen, denn die sind wirklich sehr 
ineffizient.

> Bzgl. der Interruptsicherheit: Ich verstehe den Punkt, aber leider nicht
> warum es mit einem cli/sei am Anfang und Ende der Raise- bzw. ClearEvent
> Funktionen nicht getan ist?

Weil RaiseEvent sowohl außerhalb, wie auch innerhalb von Interrupts 
aufgerufen werden kann, und innerhalb eines Interrupts macht sich ein 
sei nicht so gut, um es milde auszudrücken. Die Interrupts dürfen 
daher nur dann wieder freigegeben werden, wenn sie auch vorher schon 
freigegeben waren (was auch ganz grundsätzlich ein gutes Vorgehen bei 
atomic Blöcken ist). Und genau um sowas kümmern sich die vorgefertigten 
Makros.

> Welche Makros meinst Du genau?

http://www.nongnu.org/avr-libc/user-manual/group__...

Autor: Michael K. (mmike)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
@Stefan Ernst: Oooookay. Ich denke ich habs verstanden. Das mit dem sei 
in einer ISR ist natürlich "unschön".

> Der eigentliche Punkt dabei ist, aus RaiseEvent und ClearEvent die
> Konstrukte à la (1<<event) rauszubekommen, denn die sind wirklich sehr
> ineffizient.

Das stimmt. Werde mal drauf rumdenken ...

Bzgl. der atomic.h:

Vielen Dank für den Link! Hab auch schon ne Rund google gefragt, aber 
das hab ich leider nicht gefunen. Werde mit das Ganze mal zu Gemüte 
führen !

Grüße,
Michael

Autor: Nico (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Achja, den check auf fp!=0 würde ich in RegisterEvent nicht machen. Du 
checkst das sowieso in HandleEvents verlierst dadurch aber die 
Möglichkeit ein Event zu löschen, weil du es z.B. grad nicht behandeln 
willst.

Autor: Michael K. (mmike)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Mit Nutzung der atomic.h sollten dann meine Raise- und ClearEvent 
Funktionen so aussehen:
inline void RaiseEvent (uint8_t event)
{
  ATOMIC_BLOCK(ATOMIC_RESTORESTATE)
  {
    EventFlagBuffer |= (1 << event);
  }
}

Richtig?

Grüße,
Michael

Autor: Michael K. (mmike)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
@Nico: Danke für den Tip! Ist draussen ...

Grüße,
Michael

Autor: Nico Erfurth (masta79)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
> @Nico: Die Handle - Funktionen erledigen normalerweise "low-priority"
> Dinge wie einen Uart String parsen bzw. die Displayausgabe. Die Sollen
> eigentlich unterbrechbar sein, damit der Rest ungestört laufen kann.

Ja, ABER, das problem ist halt, wenn während deine Handle-Funktion läuft 
und dann der selbe Event nochmal raised wird, dann löscht ClearEvent das 
neue Event wieder. Deine handle funktion startet dadurch beim nächsten 
durchlauf nicht. Das ist in der Form eine sehr labile Konstruktion.

Nico

Autor: Michael K. (mmike)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
@Nico Erfurth: Stimmt. An was man da alles denken muss ... uff. Aber die 
Int auszuschalten in der Zeit wenn beispielsweise das Display neu 
gezeichnet wird ... das kann schon ne "Weile" dauern ...

Was könnte man dagegen unternehmen ?

Grüße,
Michael

Autor: Stefan Ernst (sternst)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Michael K. wrote:

> Was könnte man dagegen unternehmen ?

Erst das Flag löschen, dann die Funktion aufrufen.

Autor: Peter Dannegger (peda)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Für zeitliche Events benutze ich das hier.

Beitrag "Wartezeiten effektiv (Scheduler)"


Wenn ich Flags in einem Interrupt setze, "verschwende" ich meistens ein 
ganzes Byte, das ergibt weniger Code.

In der Regel sind Interrupt-Events zu speziell, um sie zusammen zu 
fassen.
Z.B. ob die UART-FIFO ein Byte empfangen hat, hat überhaupt kein Flag, 
die Funktion kbhit() überprüft, ob beide FIFO-Indexe gleich sind.
Der Timerinterrupt wiederum incrementiert das Flag-Byte. Falls das Main 
mal länger Busy ist, geht somit kein Interrupt verloren.


Peter

Autor: Michael K. (mmike)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
@Stefan Ernst: Cool. Das passt. Wird geändert ...

@Peter Dannegger: Wow. Das ist mächtig. Wird wohl ne Weile dauern, bis 
ich das gerallt hab, aber ich acker mich mal durch!

Grüße,
Michael

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
  • Verweis auf anderen Beitrag einfügen: Rechtsklick auf Beitragstitel,
    "Adresse kopieren", und in den Text einfügen




Bild automatisch verkleinern, falls nötig
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 bestätigst du, die Nutzungsbedingungen anzuerkennen.