Forum: Compiler & IDEs If Abfrage mit unterschiedlichen Zeiten


von Achim S. (achims)


Lesenswert?

Hallo Freunde
ich möchte eine Variable (wait10), die von einem Timer über die ISR alle 
10ms kommt mehrfach abfragen. Habe mal ein Stück eingestellt:

if (wait10 == 0xFF)     // Steuerung LED 5
  {
    //wait10 = 0;
    led1++;
    if ( led1 == 100 )     // Einstellung Zeit 10ms mal x
  {
      led1 = 0;
      if(!(PINC&(1<<PC5)))     // Abfrage PC5 LED 5 Grün
         leds_set_status(1,5);  // schaltet LED 5 auf ein
      else
         leds_set_status(0,5);  // schaltet LED 5 auf aus
    }
}
if (wait11 == 0xFF)     // Steuerung LED 4
  {
    //wait10 = 0;
    led2++;
    if ( led2 == 50 )     // Einstellung Zeit 10ms mal x
  {
      led2 = 0;
      if(!(PINE&(1<<PE4)))     // Abfrage PortC PC5 LED 5 Grün
         leds_set_status(2,4);  // schaltet LED 5 Grün auf ein
      else
         leds_set_status(0,4);  // schaltet LED 5 Grün auf aus
    }
}
wait10=0;

Habe vorher in jeder Abfrage wait auf 0 gestellt. Ergebnis, die Sachen 
blinken unterschiedlich schnell. Habe dann die wait10=0 ans ende 
gesetzt. Beinflussen sich wieder gegenseitig. Mir ist leider unklar 
wieso. Wie kann ich wait zurücksetzen ohne zusätzliche Timer oder andere 
Variablen? Eigentlich ist es gedacht, irgendwo im Prg mehrfach wait10 zu 
verwenden für alle möglichen wartescheilfen.
achim

von Falk B. (falk)


Lesenswert?

@  Achim Seeger (achims)

>ich möchte eine Variable (wait10), die von einem Timer über die ISR alle
>10ms kommt mehrfach abfragen.

Eher nicht. du willst in erster Linie ein paar LEDs mit verschiedenne 
Zeiten leuchten lassen. Ist das richtig? Das kann man u.a. mit einer 
statemachine.

>gesetzt. Beinflussen sich wieder gegenseitig. Mir ist leider unklar
>wieso.

Uns ist unklar, was du INSGESAMT erreichen willst. Siehe Netiquette.

MfG
Falk

von Achim S. (achims)


Lesenswert?

Hallo Falk
das mit der Statemaschine geht nicht. Das Prinzip ist einfach. Mit dem 
Timer ind der ISR erzeuge ich alle 10ms einen Impuls, das ist wait10. 
Dieser wird gezählt. Sobald ich den richten Wert erreicht habe schaltet 
die LED. Vorteil ist, es braucht dein delay. Dadurch schläft der Proz 
nicht und ich kann verschidene Sachen schnell hintereinander ausführen. 
wait10 wird in die Variablen Led 1 und zwei geschrieben und 
anschliessend wieder auf null gesetzt. LED 1 und 2 beeinflussen sich 
gegenseiti. mir ist leider unklar warum.
achim

von Benjamin U. (utzus)


Lesenswert?

Hey,

also in dem von dir gezeigten Code beeinflussen sich die Variablen nicht 
gegenseitig.

Sinnvol wäre es aber, die Variable wait10 nur einmal abzufragen, damit 
sichergestellt ist, dass sie sich zwischen zwei Abfragen nicht ändert.
Warum fragst zu bei der zweiten If-Abfrage wait11 ab und nicht wait10??

Achim Seeger schrieb:
> if (wait11 == 0xFF)     // Steuerung LED 4

Die Kommentare passen nicht zum porgrammierten Code ;)

Achim Seeger schrieb:
> if(!(PINE&(1<<PE4)))     // Abfrage PortC PC5 LED 5 Grün

Vermutlich musst du noch etwas mehr Code zeigen, denn hier finde ich so 
nichts falsches, außer die Abfrage oben (wait11).

Grüße

von Achim S. (achims)


Lesenswert?

Hallo Benjamin
mit wait 10 und 11 hast du recht. habe es erst später gesehen. Ist aber 
geändert.Ab den If erfogt der Code für die jeweilige LED, daher der 
Code. Viel mehr Code gibt es kaum. Es fehlt der Timer und die ISR, 
Aufruf der Variablen und ein bischen Grundanzeige. Noch mal, damit es 
klar wir, wait10 brungt alle 10ms einen Impuls. Dieser wird in der 
led1++ und led2++ gezählt bis der eingestellte Wert erreicht ist 
(led1==100) das selbe auch in Led2. Am ende setze ich wait10 auf 0. 10ms 
später kommt das nächste. LED zählen wieder einen hoch. Da beide Zeiten 
gleich gestellt sind müssen auch beide gleichzeitig an und aus gehen. 
das machen sie nicht. Bloss woeso?
achim

von Benjamin U. (utzus)


Lesenswert?

Hey,

dein Problem hab ich verstanden, jedoch fürchte ich, kann ich dir nicht 
helfen, wenn du behauptest:

Achim Seeger schrieb:
> Da beide Zeiten
> gleich gestellt sind müssen auch beide gleichzeitig an und aus gehen.

Ich muss im Code aber folgendes Lesen:

Achim Seeger schrieb:
> if ( led1 == 100 )     // Einstellung Zeit 10ms mal x

Achim Seeger schrieb:
> if ( led2 == 50 )     // Einstellung Zeit 10ms mal x

led2 sollte also doppelt so schnell blinken.

so far!

von Karl H. (kbuchegg)


Lesenswert?

Poste doch mal den richtigen Code. Und zwar vollständig.

von Krapao (Gast)


Lesenswert?

Das Resetten von wait10 (wait10=0) auf der obersten gezeigten 
Codeebene ist nicht hilfreich. Du erwischst den Alarmfall (wait10==0xFF) 
nur wenn zwischen dem Resetten und der ersten if-Abfrage die ISR gerade 
wait10 auf 0xFF gesetzt hat. Das ist besonders kritisch, wenn wait10 
innerhalb der ISR hochgezählt wird.

Ein weiteres Problem kann in der nicht gezeigten ISR liegen, in der 
wait10 manipuliert wird: Dein Code kann Events verpassen, wenn in der 
ISR zwischen den beiden if-Abfragen gerade verändert wird. Das ist 
besonders kritisch, wenn wait10 innerhalb der ISR hochgezählt wird.

Ein Codevorschlag ist
1
  // Reset task timers and 10ms alarm flag
2
  // volatile uint8_t wait10; // defined elsewhere (globally)
3
  uint8_t alarm_10ms = 0;
4
  uint8_t led1 = 0;
5
  uint8_t led2 = 0;
6
7
  // init and start wait10 timer interrupt
8
  ...
9
10
  while (1) {
11
    // Check 10ms timer interrupt result/flag
12
    if (wait10 == 0xFF) {
13
      wait10 = 0;     // 10ms stop watch reset
14
      alarm_10ms = 1; // trigger 10ms alarm check
15
    }
16
17
    // Check every 10ms all alarms for task #1, #2, ...
18
    if ( alarm_10ms ) {
19
      alarm_10ms = 0; // reset 10ms alarm flag
20
      // Check Task #1: LED 5: 100 * 10ms = 1s
21
      if ( ++led1 == 100 ) {
22
        led1 = 0;
23
        ...    // pos#1
24
      }
25
      // Check Task #2: LED 4: 50 * 10ms = 0.5s
26
      if ( ++led2 == 50 ) {
27
        led2 = 0;
28
        ...    // pos#2
29
      }
30
      ... other tasks ...
31
      // pos#3
32
    }
33
  }

Die Zeitverzögerung bei der Ausführung von Task #1 und Task #2 hängt 
davon ab, wie lange der Code von pos#1 bis pos#2 braucht. Man kann daran 
arbeiten, diese Zeit zu verkürzen, wenn man an den Positionen pos#1 und 
#2 nur einen Aktionscode berechnet (led1_action = 1 oder 0) und später 
die Aktionen in kurzen Funktionen möglichst nahe beieinander z.B. an 
pos#3 tatsächlich ausführt (leds_set_status(led1_action,5)).

von Matthias L. (Gast)


Lesenswert?

>as mit der Statemaschine geht nicht.

Mööp. Alles lässt sich mit einer Statemaschine realisieren.

(Alles? Nicht alles. Frauen nicht. Aber Frauen sind zeitinvariant und 
nicht kausal)


Zum Thema:
Du musst das folgendermaßen machen.

In der ISR inkrementierst du (alle 10ms) eine Variable. Das ist dein 
durchlaufender TimerTick.

Im Hauptprogramm nimmst du Zeitstempel und prüfst diese auf Differenzen.

Etwa so:
1
#define PORT_LED1   PORTC
2
#define PIN_LED1    PC4
3
4
#define PORT_LED2   PORTC
5
#define PIN_LED2    PC8
6
7
8
9
volatile uint32_t u32TimerTickMs;
10
11
ISR (...) // alle 10ms
12
{
13
  u32TimerTickMs += 10;
14
}
15
16
uint32_t fTimeStampGet( void )
17
{
18
  return u32TimerTickMs;
19
}
20
21
uint32_t fTimeStampDiff( uint32_t u32TStamp )
22
{
23
  return ( u32TimerTickMs - u32TStamp );
24
}
25
26
27
void main ( void )
28
{
29
  uint32_t  u32TimeStamp_1;
30
  uint32_t  u32TimeStamp_2;
31
  ...
32
33
  while ( 1 )
34
  {
35
    ...
36
37
    //-- LED1 alle 500ms toggeln -------------------
38
    if ( fTimeStampDiff(u32TimeStamp_1) >= 500 )
39
    { // alle 500ms
40
      u32TimeStamp_1 = fTimeStampGet();
41
      PORT_LED1 ^= (1<<PIN_LED1);  // LED1 toggeln
42
    }
43
44
    //-- LED 2 alle 1000ms toggeln -----------------
45
    if ( fTimeStampDiff(u32TimeStamp_2) >= 1000 )
46
    { // alle 1000ms
47
      u32TimeStamp_2 = fTimeStampGet();
48
      PORT_LED2 ^= (1<<PIN_LED2);  // LED2 toggeln
49
    }
50
51
    ...
52
  }
53
54
}

von Frank M. (ukw) (Moderator) Benutzerseite


Lesenswert?

Matthias Lipinsky schrieb:
> In der ISR inkrementierst du (alle 10ms) eine Variable. Das ist dein
> durchlaufender TimerTick.

Prinzipiell ist das Konzept richtig, bei Deiner Umsetzung gefallen mir 
ein paar Dinge nicht:

1. Überlauf der TimerTick-Variable: Sobald das passiert, ist für
   eine lange Weile Schluss.

2. Dein Zugriff auf TimerTick ist nicht atomar.

Besser wäre eine TimerTick-Variable, die in ein uint8_t passt und 
gezielt wieder zurückgesetzt wird, statt dass sie überläuft. Dann wäre 
noch zu überlegen, ob man nicht direkt das Register TCNTx dafür 
verwendet.

Gruß,

Frank

P.S.
Wenn es sowieso nur darum geht, eine oder zwei LED zu togglen, kann man 
das direkt auch in der ISR tun - mit Hilfe der Zählvariablen. Der ganze 
Overhead mit fTimeStampGet und fTimeStampDiff entfällt.

von Matthias L. (Gast)


Lesenswert?

>bei Deiner Umsetzung gefallen mir ein paar Dinge nicht:

Du hast recht. Der Zugriff muss atomar erfolgen. Das habe ich bei dem 
Beispiel vergessen. Meineswissens gibt es da Makros??

Der Überlauf allerdings spielt keine Rolle. Es ist ein kontinuierlich 
hochzählender Wert. Im Beispiel sind das Millisekunden. Ein u32 läuft 
dann nach 2E+32ms = 49d 17h 2m 47.296s über. Und selbst wenn. Die 
Zeitdifferenz wird ebenfalls nur! mit 32bit errechnet. Überläufe werden 
ignoriert. Somit klappt das auch während des Überlaufes.
Bsp:
Zeit  =    0x0000_0100 =           256
Stamp =    0xFFFF_FF00 = 4'294'967'040   ¦ -
     ---------------------------------
Diff  = ..FF_0000_0200 =           512

Denn 4'294'967'040 + 512 = 4'294'967'552 ( > 2E+32 => passt nicht in u32 
)
                         - 4'294'967'296 ( = 2E+32 )
                        -----------------
                                     256

Passt also immer.
Einzig Zeiten grösser obige Zahl kann nicht gewartet werden.


>Der ganze Overhead mit fTimeStampGet und fTimeStampDiff entfällt.

Wenn der uC nur zwei LEDs toggeln soll, ja. Wenn man ein komplexes 
Programm hat, ist das (mM) die beste Lösung, zeitliche Abläufe zu 
programmieren. Ausserdem kann man die Fkt ja inlinen. Ich habe sie nur 
extern geschrieben, damit es übersichtlicher wirkt.

Weiterhin hat die Kapselung mit den Get/Diff-Fkt den Vorteil, das nur in 
diesen Fkt. der Zugriff atomar sein muss.

von Volkmar D. (volkmar)


Lesenswert?

Hallo,

Matthias Lipinsky schrieb:
> //-- LED1 alle 500ms toggeln -------------------
>     if ( fTimeStampDiff(u32TimeStamp_1) >= 500 )
>     { // alle 500ms
>       u32TimeStamp_1 = fTimeStampGet();
>       PORT_LED1 ^= (1<<PIN_LED1);  // LED1 toggeln
>     }

Dadurch dass u32TimeStamp_1 (und auch u32TimeStamp_2) auf den dann 
aktuellen TimeStamp gesetzt werden, könnten sich Fehler aufsummieren. 
Falls mal die Abfrage erst nach längerer Zeit erfolgt (so daß die 
Differenz nicht 500 sondern zum Beispiel 510 ergibt), so addieren sich 
diese Unterschiede im Laufe der Zeit. Je nach Anwendung mag es nicht 
wichtig sein oder auch so gewünscht sein, ich würde jedoch den Wert wie 
folgt berechnen:
1
u32TimeStamp_1 += 500;

von Matthias L. (Gast)


Lesenswert?

>könnten sich Fehler aufsummieren.

Prinzipiell hast du recht, aber das Konzept geht davon aus, das die 
Zykluszeit des Programmes (also wie oft kommt der uC an dieser 
Diff-Abfrage vorbei) sehr viel kleiner ist, als die Zeiten, die 
gewartet/verzögert werden sollen.

Also um Zeiten von einigen wenigen Millisekunden zu erzeugen, ist das 
ungeeignet. Das macht man mit OCR in Timern. Aber um Programmabläufe im 
Sekundenbereich oder grösser zu steuern, ist das ideal.

Das setze ich hier in den SPS Anlagen seit geraumer Zeit bestens ein. Da 
nutze ich Zykluszeiten von 1, 2 oder 10ms.

von Falk B. (falk)


Lesenswert?

@  Matthias Lipinsky (lippy)

>>könnten sich Fehler aufsummieren.

>Prinzipiell hast du recht, aber das Konzept geht davon aus, das die
>Zykluszeit des Programmes (also wie oft kommt der uC an dieser
>Diff-Abfrage vorbei) sehr viel kleiner ist, als die Zeiten, die
>gewartet/verzögert werden sollen.

Schon richtig, torotzdem würde ich so ein potentielles Problem nicht 
einbauen wollen. Erst recht nicht, wenn es unlogischer ist als die 
richtige Version.

von Matthias L. (Gast)


Lesenswert?

Für mich ist das die logisch-ste Variante. Ich mach das ja zuhause, also 
im "Leben" auch so.

Was ist denn die richtige Variante? Und wer hat diese als richtig 
deklariert?

von Achim S. (achims)


Lesenswert?

Hallo freunde
war leider ein paar Tge ausser Haus. stelle den kompletten Code rein.

/* Tset LED 25  Testet die Funktion Timer, ist eingestellt auf 10ms und 
wird
mehrfach aufgerufen wiederholt. Abfrage LED auf an, sonst
aus,danach wieder an, by h.j.seeger@web.de  */

#include <nibo/niboconfig.h>
#include <nibo/iodefs.h>
#include <nibo/leds.h>
#include <avr/interrupt.h>
#include <nibo/gfx.h>
#include <nibo/display.h>
#include <nibo/pwm.h>
#include <nibo/bot.h>

volatile uint8_t wait10 = 0;  // Timer 10ms
volatile uint8_t wait11 = 0;  // Timer 10ms
volatile uint8_t wait = 0;  // Timer 1ms
uint8_t led1 = 0;    // Variable für LED 1
uint8_t led2 = 0;    // Variable für LED 2

void nibo_timer2()    // Timer 10ms
  {  TCNT2 = 0;
  OCR2=249;
  TCCR2=(1<<WGM21)|(1<<CS21)|(1<<CS20);
  TIMSK |= (1<<OCIE2);  }

ISR (TIMER2_COMP_vect)    // wait1=1m
  {
  if(  wait<9)    // Takt 0,5s, bei 9 sind es 10ms
    {  wait++;  }  // erhöht
  else      // wenn dann ...
    {  wait=0;    // setzt wait1 auf 0
       wait10=0xFF;     // Signal alle 10ms
     wait11=0xFF;
    }
  }

int main(){    //Start

  sei();    // Freigabe Interrups
  display_init();
  pwm_init();
  gfx_init();
  bot_init();
  leds_init();
  leds_set_displaylight(800);// setzt Displaylicht
  nibo_timer2();    // Aufruf Timer 2 einmalig

  gfx_fill(0x00);  // löschtSchirm
  gfx_move(5, 5);    // Angabe Ort
  gfx_set_proportional(0);// Angabe Schrift
  gfx_print_text("Testprogramm Nibo 2");  // Ausgabe Text
  gfx_move(13, 15);  // Angabe Ort
  gfx_set_proportional(1);// Angabe Schrift
  gfx_print_text("LED 25 Test c HJS 2012");// Ausgabe Text
  gfx_move(0,25);    // Angabe Ort
  gfx_hline(128);    // Ausgabe Strich
    gfx_move(5, 35);    // Angabe Ort
  gfx_set_proportional(1);  // Angabe Schrift
  gfx_print_text("2 x Frequenz mit Timer");// Ausgabe Text

while(1)
{

if (wait10 == 0xFF)     // Steuerung LED 5
  {
    //wait10 = 0;
    led1++;
    if ( led1 == 100 )     // Einstellung Zeit 10ms mal x
  {
      led1 = 0;
      if(!(PINC&(1<<PC5)))     // Abfrage PC5 LED 5 Grün
         leds_set_status(1,5);   // schaltet LED 5 auf ein
      else
         leds_set_status(0,5);  // schaltet LED 5 auf aus
    }
}

if (wait10 == 0xFF)     // Steuerung LED 4
  {
    //wait10 = 0;
    led2++;
    if ( led2 == 100 )     // Einstellung Zeit 10ms mal x
  {
      led2 = 0;
      if(!(PINE&(1<<PE4)))     // Abfrage PortC PC5 LED 5 Grün
         leds_set_status(2,4);    // schaltet LED 5 Grün auf ein
      else
         leds_set_status(0,4);  // schaltet LED 5 Grün auf aus
    }
}
wait10=0;
}
return 0;
}

Habe alles drin, bitte nicht an den Kommentaren stören. Sind verruscht 
und habe mit den Zeiten experentiert. Habe es auch mit Softwaretimer 
getstet. Geht alles. LED schalten gleich und korrekt. Noch mal zum 
Prinzip. Bilde mit dem Timer und ISR einen wait10 (10ms) Impuls. dieser 
kann im gesamten Programm abgefragt werden. Bei jedem Durchlauf schaltet 
er Zähler (if LED ) weiter. Ist die voorgegebene Zeit abgelaufen, 
schaltet z.B. die LED oder anderes. Am Ende des Prg wird wait10 auf 0 
gesetzt und es geht von vorn los. Dadurch verwende ich lein delay im 
gesamten Programm. Ich kann mehrere Arbeiten, Zähler oder Zeiten fast 
gleichzeitig ausühren. Sage immer wieder, kann den Prz 1 Sekunde warten 
lassen oder mit 10ms 100 andere Sachen ausführen. Bei dem oberen Teil 
geht ein LED korrekt, die andere aber nicht. Wie verhält sich die Sache 
, wenn ich noch eibe einfache Abfrage für einen Taster einbaue? Frage an 
KH: Wie kann ich das machen mit deiner Tasterabfrage 1. nur auf ein oder 
aus 2. mit Abfrage der zeit Kurz/lang gedrückt. Im Moment ist die 
Abfrage der taster teilweise 5x so lang wie das eigentlich Prg.
achim

von STK500-Besitzer (Gast)


Lesenswert?

1
      if(!(PINC&(1<<PC5)))     // Abfrage PC5 LED 5 Grün

willst du hier wirklich den Eingangszustand abfragen, oder den 
Ausgangszustand wissen und damit dann die LED togglen?

Was soll dein Programm machen?

von Achim S. (achims)


Lesenswert?

ja das will ich, es soll die LED nur geschaltet werden, wenn si vorher 
aus ist. Hat auch damit zu tun das die Ein und aus Zeit geich ist. Das 
Thema hatten wir vor einiger Zeit hier schon. Es geht eigentlich nur um 
die Funktion des wait10.
Das Prg dient in dieser Form als Testgrund für die Funktion vom Timer 
und ISR und besonders der Anwendung von wait10. Möchta damit die 
Möglichkeut haben, jeder zeit mehrere Aktionen auszuführen ohne delay.
achim

von Simon K. (simon) Benutzerseite


Lesenswert?

Formatiere den Code mal gescheit und bette ich in [ C ] Tags ein.

von STK500-Besitzer (Gast)


Lesenswert?

Achim Seeger schrieb:
> ja das will ich, es soll die LED nur geschaltet werden, wenn si vorher
> aus ist.

Sowas macht man so:
1
PORTC ^= (1<<PC5);

Achim Seeger schrieb:
> Das Prg dient in dieser Form als Testgrund für die Funktion vom Timer
> und ISR und besonders der Anwendung von wait10. Möchta damit die
> Möglichkeut haben, jeder zeit mehrere Aktionen auszuführen ohne delay.
> achim

Und wenn du es 1000 Mal wiederholst, wird es auch nicht besser.

Wieso fragst du wait10 zwei Mal ab?
Die Anwort "Weil das später noch anders werden soll." lasse ich nicht 
gelten.
Es übrigens eine ganz schöne Platzverschwendung, ein ganzen Byte als 
eigenen Status.Flag zu benutzen.
Man kann das auch bitweise machen...

Tut aber gerade nichts zur Sache.
Gewöhn dir bitte an, auch in dem Teil deiner Post, der kein Programmcode 
ist, gelegentlich mal einen bewussten Zeilenwechsel zu machen.
Das würde den Lesefluss doch sehr aufhübschen.
Telegramm-Stil finde ich nicht so richtig prickelnd zu lesen.

von Achim S. (achims)


Lesenswert?

Hallo
du sagst, du lässt es nicht gelten. Wie kann ich den wait10 mehrfach 
abfragen. das erste mal, z.B. um eine LED im Takt von 1s als blinklicht 
zu nehmen. beim 2 mal soll eine Hupe einen wechselnen ton bringen, wie 
bei Maschinen die Rückwärtsfahren, beim 3 mal sollen Anzeigen auf dem 
Display Blinken um den Abstand zu zeigen, beim 4 mal soll ein Taster 
abgefragt werdenum einen Prozess oder Ablauf zu stoppen oder 
zeitverzögernd anzu laufen. Sicher lassen sich noch andere Aufgaben 
finden. Es ist nur wichtig, das sie alle fast gleichzeitig laufen.
Danke für den Hinweis mit der Abfrage. Werde es so berücksichtigen.
achim

von STK500-Besitzer (Gast)


Lesenswert?

Achim Seeger schrieb:
> Hallo
> du sagst, du lässt es nicht gelten. Wie kann ich den wait10 mehrfach
> abfragen. das erste mal, z.B. um eine LED im Takt von 1s als blinklicht
> zu nehmen. beim 2 mal soll eine Hupe einen wechselnen ton bringen, wie
> bei Maschinen die Rückwärtsfahren, beim 3 mal sollen Anzeigen auf dem
> Display Blinken um den Abstand zu zeigen, beim 4 mal soll ein Taster
> abgefragt werdenum einen Prozess oder Ablauf zu stoppen oder
> zeitverzögernd anzu laufen. Sicher lassen sich noch andere Aufgaben
> finden. Es ist nur wichtig, das sie alle fast gleichzeitig laufen.
> Danke für den Hinweis mit der Abfrage. Werde es so berücksichtigen.
> achim

Das tue ich mir jetzt nicht mehr an.
Entweder lässt du den Telegramm-Stil, oder ich bin raus.

von Achim S. (achims)


Lesenswert?

Hallo
Es ist nicht meine Absicht im Telegramm Stil zu schreiben. Ich fasse es 
auch nicht so auf. Ich habe nur versucht, meine Gedanken zum Ablauf des 
Programmes einiger massen klar darzustellen. Werde es nicht mehr machen.
achim

von STK500-Besitzer (Gast)


Lesenswert?

Achim Seeger schrieb:
> Hallo
> Es ist nicht meine Absicht im Telegramm Stil zu schreiben. Ich fasse es
> auch nicht so auf. Ich habe nur versucht, meine Gedanken zum Ablauf des
> Programmes einiger massen klar darzustellen. Werde es nicht mehr machen.
> achim

lol
Du sollst Absätze machen!

von Achim S. (achims)


Lesenswert?

Es kam die Frage, ob ich den vollständigen Code reinstelln könnte. Da er 
verhältnismässig lang ist, habe ich erst mal komplett, ohne 
Zwischenzeilen oder ähnlichen reingestellt.
Damit kann ich auch die Frage beantworten, woher wait10 kommt.
In diesem Code stehen auch die ganzen Ansteuerungen für das Display mit 
drin. Eigentlich sind sie doch für das Verständnis nicht unmittelbar 
erforderlich.
Es kommt doch, so weit ich es überblicken kann, auf die if(wait .. ) an.
achim

von STK500-Besitzer (Gast)


Lesenswert?

1
while(1)
2
{
3
4
  if (wait10 == 0xFF)
5
  {
6
    wait10 = 0;
7
8
    // Steuerung LED 5
9
    led1++;
10
    if ( led1 == 100 )     // Einstellung Zeit 10ms mal x
11
    {
12
      led1 = 0;
13
      PORTC ^= (1<<PC5);
14
    }
15
16
    // Steuerung LED 4
17
18
    led2++;
19
    if ( led2 == 100 )     // Einstellung Zeit 10ms mal x
20
    {
21
      led2 = 0;
22
      PORTE ^= (1<<PE4);
23
    }
24
  }
25
  wait10=0;
26
}

Finde ich jetzt mal schöner...

von STK500-Besitzer (Gast)


Lesenswert?

1
while(1)
2
{
3
4
  if (wait10 == 0xFF)
5
  {
6
    wait10 = 0;
7
8
    // Steuerung LED 5
9
    led1++;
10
    if ( led1 == 100 )     // Einstellung Zeit 10ms mal x
11
    {
12
      led1 = 0;
13
      PORTC ^= (1<<PC5);
14
    }
15
16
    // Steuerung LED 4
17
18
    led2++;
19
    if ( led2 == 100 )     // Einstellung Zeit 10ms mal x
20
    {
21
      led2 = 0;
22
      PORTE ^= (1<<PE4);
23
    }
24
  }
25
}

Da war noch ein "wait10=0;" zu viel drin

von Achim S. (achims)


Lesenswert?

Hallo
danke dir erst mal. Habe das Prg so eingebaut und probiert. Es geht auf 
Anhieb.
Du hattest in der ersten Version noch ein wait10 mehr drin. Das hast du 
in der zweiten rausgenommen.
Habe es auch so gemacht und getestet. Als erstes nur das obere wait10, 
geht alles. Dann nur das untere. Damit werden beide if Abfragen zurück 
gesetzt und die Zeiten sind korrekt.
Kann es jetzt mit der Tastenabfrage testen.
achim

von Achim S. (achims)


Lesenswert?

Hallo
Habe es getestet. So wie es oben steht, geht es.
Habe auch gesehen was du geänder hast.Damit könnte es ein Problem geben.
Wenn ich ein LED Steuerung ausführe, geht es. Die zweite Steuerung komm 
viel später erst im Programm. Damit ist aber ein gemeinsame if nicht 
möglich.

while(1)
{
  if (wait10 == 0xFF)
  {                        // Steuerung LED 5
    led1++;
    if ( led1 == 100 )     // Einstellung Zeit 10ms mal x
    {
      led1 = 0;
      PORTC ^= (1<<PC5);
    }  }

// Normales Programm über viele Zeilen

if (wait10 == 0xFF)
  {                        // Steuerung LED 4
    led2++;
    if ( led2 == 100 )     // Einstellung Zeit 10ms mal x
    {
      led2 = 0;
      PORTE ^= (1<<PE5);
    }  }


// anderes Programm

  }
}
wait10 = 0;
return 0;

von STK500-Besitzer (Gast)


Lesenswert?

Achim Seeger schrieb:
> Die zweite Steuerung komm
>
> viel später erst im Programm. Damit ist aber ein gemeinsame if nicht
>
> möglich.

Warum? Welchen Sinn sollte das haben?
Du hast das Ereignis "10ms sind um".
Damit kannst du dort alles machen, was mit diesem Ereignis 
zusammenhängt.
Wenn du jetzt zwischen den beiden Aktionen noch so viel machst, dass 
wieder 10ms um sind, dann sind das bei der unteren Aktion schon andere 
10ms...
Eine Uhr wirst du damit nicht realisieren können.

Meine Lösung dürfte für diese Anwendung soweit optimal sein.
Wenn du jetzt noch mehr machen willst, was zu anderen Abhängigkeiten 
führt, dann solltest du das schon mal bekannt geben.
Du hast - soweit ich das jetzt mitbekommen habe - noch nicht den 
endgültigen Zweck der Übung gepostet.
Und schreib jetzt nicht wieder, dass durch deine Lösung der Controller 
nicht in einer Warteschleife hängen bleibt, sondern auch noch andere 
Sachen machen kann. Das weiß ich schon.

von Achim S. (achims)


Lesenswert?

Hallo
es gibt einen (mehrere/viele) Beträge im Netz über Scheduler und anderen 
Möglichkeiten verschiedene Sachen gleichzeitig oder kurz hintereinander 
auszuführen.
Einer dieser Beträge läuft unter dem Namen "Warten verboten".
Dort wird beschrieben, wie die Auswirkung bei delay mit 0,5s oder 1s 
ist. Als Lösung wurde vorgeschalgen, delay auf 1ms zu nehmen und die 
einzelnen Ansteuerungen oder Abfragen mehrmals zu machen. Im Text heisst 
es dort: "Wir warten nicht auf die Eingabe, sondern fragen die einzelnen 
Zustände, Zeiten, Zähler usw. regelmässig ab. Das hat den Vorteil, viele 
Sachen ausführen zu können."
Dabei wird eine Schleife durch das ganze Prg verwendet. Diese Schleife 
wird erst am Ende durch delay1ms weitergezählt.
Im Text wird auch darauf hingewiesen, das man delay durch einen Timer 
mit ISR ersetzen kann. In anderen Artikelen, z.B. von Dannegger wird 
auch auf den Aufruf eines Timers z.B. bei Abfrage eines Tasters 
hingewiesen. Ein Sinn dieser Sache besteht z,B, darin, bestimmte 
Abfragen (Sicherheit) zu machen ohne das eigentliche Prg zu 
beenden/unterbrechen. Beispiel: Schalte einen Motor zur Bewegung ein. 
Ein Teil bewegt sich vorwärts, dabei wird eine Kante überfahren und es 
muss der Absturzsensor sofort reagieren. Bei Verwendung von delay kann 
es zu lange dauern.
Es geht mit Schedulern und anderen Anwendungen. Leider sind manche Prg 
grösser als mein Prg und recht kompliziert, mit dem ich arbeite.
Eine Uhr möchte ich damit nicht ansteuern. Es geht im Grunde um die 
Sicherheit.
achim

von Karl H. (kbuchegg)


Lesenswert?

Achim Seeger schrieb:

> Es geht mit Schedulern und anderen Anwendungen. Leider sind manche Prg
> grösser als mein Prg und recht kompliziert, mit dem ich arbeite.
> Eine Uhr möchte ich damit nicht ansteuern. Es geht im Grunde um die
> Sicherheit.

Mir ist noch nicht klar:
Hast du jetzt verstanden, wie die Sache läuft?

Du hast prinzipiell 2 Dinge, die erst mal nichts miteinander zu tun 
haben: Die Erzeugung eines 10-Millisekunden 'Signals' und dann das was 
daran gekoppelt ist.

Das hier
1
ISR (TIMER2_COMP_vect)    // wait1=1m
2
{
3
  if( wait < 9 )          // Takt 0,5s, bei 9 sind es 10ms
4
  {
5
    wait++;
6
  }
7
  else
8
  {
9
    wait=0;
10
    wait10 = 0xFF;     // Signal alle 10ms
11
  }
12
}
13
14
int main(){    //Start
15
16
  ....
17
18
  while(1)
19
  {
20
    if (wait10 == 0xFF)
21
    {
22
      wait10 = 0;
23
      // 10 Millisekunden sind um
24
      ...
25
    }
26
27
    // ... alles was nicht zeitabhängig ist
28
  }
29
}

erzeugt dir erst mal einen 10 Millisekunden 'Herzschlag' im Programm. 
Der markierte Teil in der Hauptschleife, wird in diesem Zeittakt 
ausgeführt. Brauchst du längere Zeiten, dann macht man dann eben zb. 
dort das Abzählen von Vielfachen von 10 Millisekunden, so wie du das mit 
deinen LED machst.

Dinge, die nicht in dieses 10 Millisekunden Raster fallen (wie zb 
Überwachung von Endsensoren) kommen dann eben nicht in diesen 
Programmteil hinein. Sagt ja keiner, das ausnahmslos ALLES in diesem 
Zeitraster gemacht werden muss.

> Schalte einen Motor zur Bewegung ein.
> Ein Teil bewegt sich vorwärts, dabei wird eine Kante überfahren
> und es muss der Absturzsensor sofort reagieren.

'Sofort' ist immer relativ in einem µC. Denn eine Reaktion mit 0-Zeit 
ist nun mal nicht möglich. Aber: In 99.9% aller Fälle genügt es, wenn 
die Reaktion ausreichend schnell erfolgt. Für praktische Zwecke sind ein 
paar µs genau so gut wie 'sofort'. In dieser Zeit kann dein µC zwar ein 
paar hundert Befehle abarbeiten, aber der Motor schafft es nicht das 
Angetriebene mehr als ein paar 10-tausendstel Millimeter (wenn 
überhaupt) weiterzubewegen. Lass dich nicht von deiner Vorstellung von 
'sofort' ins Boxhorn jagen. Was wir Menschen unter 'sofort' einordnen, 
ist für einen µC immer noch 'ooch, da hab ich ja noch Zeit'.

von STK500-Besitzer (Gast)


Lesenswert?

Achim Seeger schrieb:
> Es geht mit Schedulern und anderen Anwendungen. Leider sind manche Prg
>
> grösser als mein Prg und recht kompliziert, mit dem ich arbeite.
>
> Eine Uhr möchte ich damit nicht ansteuern. Es geht im Grunde um die
>
> Sicherheit.


Wieso redest du eigentlich die ganze Zeit um den heissen Brei rum?
Wie ein Scheduler funktioniert, brauchst du nicht zum xten Mal 
rezitieren.
Das weiß ich, Karl-Heinz und noch eine Menge Leute mehr.

Was willst du eigentlich erreichen?

Achim Seeger schrieb:
> Bei Verwendung von delay kann
>
> es zu lange dauern.

Dass delay "böse" ist, hast du ja schon festgestellt.
Was willst am Ende damit steuern?

von Achim S. (achims)


Lesenswert?

Hallo
sorry, muss mal blöd fragen. Ist das wait10 kein "Herzschlag" mit 10ms?
Das mit der abarbeitung des Prg ist mir klar. Ich gehe da von aus, das 
alle Befehle nicht gleichzeitig abgearbeitet werden. Daher versuche ich 
die Zeit relativ klein zu halten für einen Befehl.
Bei anderen Prg hatte ich bisher kaum das Problem mit delay. Je mehr ich 
aber machen will, um so früher kommt das Problem. Um trotzdem einen 
verhältnissässig schnellen Ablauf zu bekommen, habe ich nach einer 
Lösung gesucht. Dabei kommen die Sachen mit dem Scheuler.
Ich habe die Funktion nicht noch mal erklärt. Kann ich gar nicht, da 
meine Kenntnisse nicht reichen. Mir geht es um eine kleine Lösung, die 
relativ einfach ist und nachvollziehbar. Eben für mich als Anfänger zu 
verstehen. Die Lösung mit den LED soll das machen. Bisher noch als 
Beispiel. Hattees auch mit Softwaretimer probiert. Problem dabei ist, 
das ich alles vorher angeben muss und die ISR zu gross werden kann.
Ich möchte genau das damit steuern, was ich angegeben habe. Durch eine 
If Abfrage möchte ich zu jeder x Stelle im Programm genau das machen.
Bei einer einfachen Abfrage des Tasters muss ich das entprellen 
einhalten. Das kann ich mit dealy20ms machen oder aber mit wait10 x 2.
Das Beispiel mit den Motoren war blöd gewählt. Es tritt dabei ja immer 
eine Verzögerung auf durch die mechanik.
Anderes Beispiel. Modell fährt rückwärts. Dabei sollen die LED rot 
blinken und Hupe gehen. Vielleicht noch die Kontrolle ob der Weg keine 
Hindernisse hat.
Habe alle meine Überlegungen dazu angegeben.
achim

von STK500-Besitzer (Gast)


Lesenswert?

Achim Seeger schrieb:
> Ist das wait10 kein "Herzschlag" mit 10ms?

Doch, ist es.

Achim Seeger schrieb:
> Das kann ich mit dealy20ms machen oder aber mit wait10 x 2.
richtig.

> Anderes Beispiel. Modell fährt rückwärts. Dabei sollen die LED rot
> blinken und Hupe gehen.
kein Problem. Sogar unterschiedliche Frequenzen sind dabei möglich - 
allerdings mit einer Auflösung von 10ms...

> Vielleicht noch die Kontrolle, ob der Weg keine Hindernisse hat.

Bei solchen sicherheitsrelevanten Sachen braucht man gar nicht 
entprellen.
Da reicht es, wenn man in regelmäßigen Abständen (bei jedem Durchlauf 
der Hauptschleife) nachguckt, ob der Taster ausgelöst wurde.
Dann reagiert man entsprechend darauf, bis das "Gut"-Signal wieder 
hergestellt ist.
Wobei man dann natürlich darauf achten muss, dass das "Gut"-Signal lange 
genug vorhanden ist, damit der Normalbetrieb wieder aufgenommen werden 
kann.

von Karl H. (kbuchegg)


Lesenswert?

Achim Seeger schrieb:

> Beispiel. Hattees auch mit Softwaretimer probiert. Problem dabei ist,
> das ich alles vorher angeben muss und die ISR zu gross werden kann.

Alles eine Frage der Organisation bzw. der sinnvollen Aufteilung der 
Aufgaben.

ISR sollten in der Durchlaufzeit zu kurz wie möglich sein. Wobei man 
dann aber auch auf eine sinnvolle Reduzierung achten muss.
Ich mache zb einen Uhrenupdate (das hochzählen der Zeit über Sekunden, 
Minuten, Stunden) komplett in der ISR. Das sieht zwar nach viel Code 
aus, wenn man aber mal genauer darüber nachdenkt kommt man drauf: soviel 
ist das gar nicht. Die paar Takte hab ich allemal um eine Uhr komplett 
durchzuzählen. Dafür spar ich mir das Problem, dass an anderen Stellen 
unter Umständen auf eine inkonsistente Zeit zugegriffen wird, bzw. die 
Uhr überhaupt stehen bleibt, weil zb gerade ein Menü auf dem LCD 
angezeigt wird und ich dort vergessen habe, den Uhrenupdate zu machen.

In deinem Fall mit den LED ist es so, dass die 'Aktion' kurz genug ist, 
dass man sie in die ISR mit aufnehmen könnte. Das würde dann wieder ganz 
neue Möglichkeiten eröffnen, indem du für eine LED so etwas wie eine 
Zustandsvariable haben könntest, die 3 mögliche Zustände haben kann: 
aus, ein und blinkend. Willst du an anderen Stellen im Programm die LED 
in einen bestimmten Zustand haben, dann setzt du einfach diese Variable 
auf den richtigen Wert und die ISR kümmert sich um den Rest.


Allgemeine Lösungen sind meistens relativ komplex und aufwändig. Für den 
jeweiligen Fall massgeschneiderte Lösungen können abweichend davon oft 
viel einfacher aussehen. Auch sollte man sich vor Dogmen hüten. Die 
Regel 'ISR so kurz wie möglich' gilt bei klassischen LCD oder UART 
Ausgaben (aber auch da kann es Ausnahmen geben, wenn zb eine Queue 
dazwischen geschaltet wird). Man muss aber auf der anderen Seite auch 
nicht päpstlicher als der Papst sein. 'so kurz wie möglich' bedeutet 
nicht, dass man gar nichts in einer ISR machen darf.

von Achim S. (achims)


Lesenswert?

Hallo
Herzschlag ist also ok. Taster auch. Dein Stück Code geht super. Habe es 
im Prg drin. Wenn ich aber 100 Zeilen später wieder sowas aufrufe, gibts 
Probleme.
Auch wenn ich hintereinander solche Teile nehme, gibts Probleme. Komme 
leider nicht dahinter, woran es liegt.
achim

von Karl H. (kbuchegg)


Lesenswert?

Achim Seeger schrieb:
> Hallo
> Herzschlag ist also ok. Taster auch. Dein Stück Code geht super. Habe es
> im Prg drin. Wenn ich aber 100 Zeilen später wieder sowas aufrufe, gibts
> Probleme.

Wichtig:  Nomenklatur!

Was soll in diesem Zusammenhang 'aufrufen' bedeuten?
Da wird nichts aufgerufen! Eine Funktion wird aufgerufen, aber da ist 
keine Funktion.

> Auch wenn ich hintereinander solche Teile nehme, gibts Probleme. Komme
> leider nicht dahinter, woran es liegt.

Du schachtelst die Dinge gedanklich falsch ineinander.

Ganz aussen steht

  Es ist eine 10 Millisekunden Zeitscheibe abgelaufen

da rein geschachtelt ist

     Was gibt es jetzt alles zu tun?

Und mit "alles" ist auch wirklich ALLES gemeint. Es gibt in deinem 
ganzen Programm nur diese eine 10 Millisekunden Weiche, die für einen 
Zeittakt sorgt. Es DARF nur diese eine geben.

von Achim S. (achims)


Lesenswert?

Hallo Karl Heinz
mit der ISR hast du recht. Man kann was reinschreiben. Kenne auch einige 
Prg, wo Teile von Uhren oder ganze drin sind.
Mir geht es eigentlich um die andere Sache. Ich möchte an jeder Stelle 
im Prg, wo ich es gerade brauche, wait10 nutzen und eine Verzögerung, 
Schleife oder anderes machen.
Bei einzelnen Aufrufen klappt es sehr gut. Das Problem liegt im 
mehrfachen aufruf. Die LED nutze ich hierbei nur als Anzeige eines 
Zustandes. Habe als Beispiel 4 x die LED geschrieben, immer mit anderen 
Nummern. 2 gehen, zwei nicht, obwohl alle Nr stimmen. Habe da irgend ein 
Denkfehler drin.
achim

von Achim S. (achims)


Lesenswert?

Hallo

if (wait10 == 0xFF)        // Steuerung LED 5 grün
  {
    led2++;
    if ( led2 == 100 )     // Einstellung Zeit 10ms mal x
    {
      led2 = 0;
      PORTE ^= (1<<PE4);
    }
    }
......
wait10 =0;

Verwende als einziges wait10 um die led2 zu zählen bis 100 erreicht ist. 
Dann schaltet die LED ein. Es kommen och ein paar LEDs nach dieser Art.
Am Ende setze ich wait10 = 0; Zwei mal LED machen das, die anderen 
nicht.
Es gibt nur diese wai10. keine Andere. Weiter oben ist das ganze Prg 
drin.
achim

von Volkmar D. (volkmar)


Lesenswert?

Achim Seeger schrieb:
> Auch wenn ich hintereinander solche Teile nehme, gibts Probleme. Komme
> leider nicht dahinter, woran es liegt.

Ich glaube, Du hast noch einen Denkfehler. Aus Deinem obigen Beispiel:
1
while(1)
2
{
3
  if (wait10 == 0xFF)
4
  {                        // Steuerung LED 5
5
   ...
6
  }
7
8
// Normales Programm über viele Zeilen
9
10
  if (wait10 == 0xFF)
11
  {                        // Steuerung LED 4
12
   ...
13
  }
14
15
// anderes Programm
16
17
  }
18
}
19
wait10 = 0;
20
return 0;
Hier steht das "wait10 = 0;" an der falschen Stelle. Es muß dann gesetzt 
werden, wenn erkannt worden ist, das wait10 auch den Wert 0xFF hat. Und 
dazu gibt es bei Deinem Beispiel 2 Möglichkeiten:
1
while(1)
2
{
3
  if (wait10 == 0xFF)
4
  {                        // Steuerung LED 5
5
    wait10 = 0;
6
    ...
7
  }
8
9
// Normales Programm über viele Zeilen
10
11
  if (wait10 == 0xFF)
12
  {                        // Steuerung LED 4
13
    wait10 = 0;
14
    ...
15
  }
16
17
// anderes Programm
18
19
  }
20
}
Wenn man es aber so macht, dann wird immer nur eine der beiden if-Zweige 
abgearbeitet und der andere bekommt es nicht mit.

Wenn man es nur an eine von beiden Stellen schreibt, dann hängt es davon 
ab, wann das Flag gesetzt wird. Denk dran, das kann zu jeder 
x-beliebigen Zeit sein und passiert nicht immer (oder besser absolut 
selten) genau am Anfang der while-Schleife.

Wenn Du unbedingt eine Nach-Behandlung benötigst, dann geht das 
eigentlich nur über eine weitere Zwischenvariable:
1
wait10_merker = 0;
2
while(1)
3
{
4
  if (wait10 == 0xFF)
5
  {                        // Steuerung LED 5
6
    wait10 = 0;
7
    wait10_merker = 1;
8
    ...
9
  }
10
11
// Normales Programm über viele Zeilen
12
13
  if (wait10_merker == 1)
14
  {                        // Steuerung LED 4
15
    wait10_merker = 0;
16
    ...
17
  }
18
19
// anderes Programm
20
21
  }
22
}
Für eine konsistente Bearbeitung des Programmes darfst Du (wie 
Karl-Heinz geschrieben hat) den Zeittakt nur einmal abfragen. Sonst 
gibt es inkosistente Abläufe. Und überlege genau, warum Du nicht alles 
in dieser einen Abfrage machen kannst? Ich denke, es gibt nur wenige 
Gründe, wo dies notwendig ist. Im Regelfall ist dies nicht nötig.

von Achim S. (achims)


Lesenswert?

Hallo Volkmar
die erste Version habe ich schon probiert. Dabei ist der Ablauf genau 
der selbe. Manche schalten, manche nicht und die Zeit ist 
unterschiedlich.
Wenn ich für beide if die selbe Zeit einstelle z.B. 100, so müssen doch 
beide fast gleich anfangen und die selbe Zei laufen und fast 
gleichzeitig ausschalten. Machen sie leider nicht.
Zu deiner zweiten version. Ich setze wait10 auf 0 und gleichzeitig den 
Merker auf 1. Ist das nicht das gleiche, als wenn ich wait10 weiter 
verwende?
achim

von Volkmar D. (volkmar)


Lesenswert?

Achim Seeger schrieb:
> Zu deiner zweiten version. Ich setze wait10 auf 0 und gleichzeitig den
> Merker auf 1. Ist das nicht das gleiche, als wenn ich wait10 weiter
> verwende?

Nein, denn Du weißt nicht wann wait10 gesetzt wird. Das kann vor dem 
ersten If sein, das kann aber auch nach dem ersten if sein.

Im ersten Fall sind beide If-Bedingungen gültig und es werden beide LEDs 
behandelt.

Im zweiten Fall wird nur die 2. If-Bedingung als gültig erkannt weil 
danach wait10 wieder zurückgesetzt wird und wenn das Programm zur 1. 
If-Abfrage kommt, die Bedingung nicht mehr erfüllt ist. In dem Fall wird 
die erste If-Bedingung also seltener als gültig erkannt und die LED 
blinkt langsamer.

Wenn wait10 nur einmalig anstatt mehrfach abgefragt wird, dann werden 
alle zugehörigen If-Bedingungen in einem Schleifendurchlauf als gültig 
erkannt. Der wesentliche Unterschied ist hier, daß diese Abfragen dann 
synchron ablaufen. Der Interrupt jedoch, der wait10 setzt, läuft 
asynchron, und da muß man dann immer aufpassen wann der Interrupt 
erfolgt.

von Achim S. (achims)


Lesenswert?

Hallo
habe mein Prg nach deinen Sachen umgestellt. Alle LED schalten jetzt 
korrekt und gleichmässig. Habe wait10_merker erst ganz zum Ende auf 0 
gesetzt.
Soweit ist es jetzt klar mit den LED. Welchen Takt nehme ich denn nun um 
andere Sachen zu machen, z.B. für Abfrage Taster usw. Sind jetzt Wait10 
und wait10_merker gleich?
achim

von Karl H. (kbuchegg)


Lesenswert?

Achim Seeger schrieb:

> Soweit ist es jetzt klar mit den LED.
Sicher?

> Welchen Takt nehme ich denn nun um
> andere Sachen zu machen, z.B. für Abfrage Taster usw.

Die kleinste gemeinsame Zeit, die du brauchst. Taster zb sind aus µC 
Sicht langsam. Kein Mensch kann eine Taste in einer tausendstel Sekunde 
drücken und wieder loslassen. D.h. wenn du alle 10 Millisekunden die 
Tasten überprüfst, kannst du davon ausgehen, dass du einen Tastendruck 
auf keinen Fall übersehen wirst.
Aber du hast ein anderes Problem: Tasten prellen. Das heißt: dein 
Benutzer drückt zwar die Taste nur einmal nieder, für den µC entstehen 
hier aber ein paar kurze 'gedrückt' - 'nicht gedrückt' Sequenzen, bis 
sich dann endlich der Zustand auf gedrückt stabilisiert. Es gibt da ein 
paar clevere Verfahren (die auch auf Zeitsteuerung und Mehrfachabtastung 
beruhen) um dieses Problem in den Griff zu bekommen.
Entprellung

> Sind jetzt Wait10
> und wait10_merker gleich?

Nein!
Wait10 ist die Benachrichtigung von der ISR zum Hauptprogramm, dass 10 
Millisekunden um sind. wait10_merker ist eine  Hilfsvariable, die dafür 
sorgt, dass alle Teile der Hauptschleife sich darüber einig sind, ob 10 
Millisekunden um sind. wait10_merker ist quasi der Zustand der 'Uhr' 
jeweils am Beginn eines neuen Durchgangs durch die Hauptschleife. Dies 
deshalb, weil es sonst zu Inkonsistenzen kommt, wenn sich die Uhr 
ändert, während gerade der Durchmarsch durch den 'Regelsatz' der 
Hauptschleife stattfindet.

von Volkmar D. (volkmar)


Lesenswert?

Achim Seeger schrieb:
> Soweit ist es jetzt klar mit den LED. Welchen Takt nehme ich denn nun um
> andere Sachen zu machen, z.B. für Abfrage Taster usw. Sind jetzt Wait10
> und wait10_merker gleich?

Das hängt davon ab mit welcher Frequenz und zu welchem Zeitpunkt die 
laufen lassen möchtest. Wenn sie auch im 10ms-Raster laufen sollen, dann 
ist Wait10 bzw. wait10_merker OK. Einfach in den jeweiligen if-Zweig 
hängen:
1
wait10_merker = 0;
2
while(1)
3
{
4
  if (wait10 == 0xFF)
5
  {                        // Steuerung LED 5
6
    wait10 = 0;
7
    wait10_merker = 1;
8
    ...
9
    Taster_Abfrage();      // Taster abfragen *****
10
  }
11
12
// Normales Programm über viele Zeilen
13
14
  if (wait10_merker == 1)
15
  {                        // Steuerung LED 4
16
    wait10_merker = 0;
17
    ...
18
    Noch_was_anderes();    // Hier auch mögliche ******
19
  }
20
21
// anderes Programm
22
23
  }
24
}

Wichtig ist halt, daß es nur eine Abfrage auf wait10 gibt!

von Achim S. (achims)


Lesenswert?

Hallo
danke erst mal an alle. Hoffe es wird langsam klar.Versuche jetzt mal 
ein Prg draus zu machen, das gut läuft. Narütlich kommt dann noch die 
Entprellung dazu, wie schon Karl Heinz schreibt. Muss ich den die 
"grosse Version nehmen"? Möchte erst mal mit einer einfachen Sache 
anfangen. Es bleibt dann ja noch die Sache mit dem drücken. 
kurz/mittel/lang,
achim

von Karl H. (kbuchegg)


Lesenswert?

Karl Heinz Buchegger schrieb:

>> Sind jetzt Wait10
>> und wait10_merker gleich?
>
> Nein!
> Wait10 ist die Benachrichtigung von der ISR zum Hauptprogramm, dass 10
> Millisekunden um sind. wait10_merker ist eine  Hilfsvariable, die dafür
> sorgt, dass alle Teile der Hauptschleife sich darüber einig sind, ob 10
> Millisekunden um sind. wait10_merker ist quasi der Zustand der 'Uhr'
> jeweils am Beginn eines neuen Durchgangs durch die Hauptschleife. Dies
> deshalb, weil es sonst zu Inkonsistenzen kommt, wenn sich die Uhr
> ändert, während gerade der Durchmarsch durch den 'Regelsatz' der
> Hauptschleife stattfindet.

Denk mal über folgendes konstuierte Beispiel nach

Situation 'Nachtwächter'.
Dem gibst du eine Checkliste mit, auf der exakt verzeichnet ist, was er 
auf seinem Rundgang in einem bestimmten Raum zu tun hat (und er ist 
normalerweise extrem pünktlich). Er soll sich einfach nur stur an diese 
Regeln halten:
* Um 03:00 öffnest du das Fenster
* Um 05:00 schliesst du das Fenster
(Sinn der Sache ist es offenbar, dass Nachts 2 Stunden lang gelüftet 
wird).
Das geht auch lange Zeit gut. Nur gibst du ihm noch eine zusätzliche 
Aufgabe
* Um 03:00 öffnest du das Fenster
* Um 05:00 drehst du die Heizung auf
* Um 05:00 schliesst du das Fenster
Soweit so gut (mag man denken)
Der Nachtwächter kommt wieder (so wie immer) alle 10 Sekunden in den 
Raum und geht seine Checkliste durch:
er sieht auf seine Uhr und wenn die 03:00 anzeigt, macht er das Fenster 
auf. Er sieht wieder auf seine Uhr und wenn die 05:00 anzeigt, dreht er 
die Heizung auf. Und er sieht ein drittes mal auf seine Uhr und wenn die 
05:00 anzeigt, dann schliesst er das Fenster.

Bis es dann eines Tages soweit ist, dass zwar die Heizung an war aber 
das Fenster nicht geschlossen wurde. Was war geschehen?
Wie immer hat er seine Runden gegangen und ist alle 10 Sekunden in 
diesen Raum gegangen. Um zu entscheiden, ob die erste Regel angewendet 
werden kann, hat er auf seine Uhr gesehen, die hat nicht 03:00 
angezeigt, also hat er das Fenster in Ruhe gelassen. Für die 2.te Regel 
hat er erneut auf die Uhr geblickt und 05:00 abgelesen. Passt. Die 
Ausgangsbedingung für die 2.te Regel ist erfüllt
* Um 05:00 drehst du die Heizung auf
Genau das hat er getan. Aber das Heizungsventil hat etwas geklemmtn so 
dass er länger als gewöhnlich dafür gebraucht hat.
Um seine 3-te Regel abzuarbeiten hat er erst mal wieder auf die Uhr 
gesehen. Er hat 05:01 abgelesen. Und damit war die Ausgangsbedingung für 
die 3.te Regel nicht erfüllt. 05:01 ist nicht dasselbe wie 05:00 und 
daher hat er das Fenster nicht angerührt.

Wo liegt der Fehler?
Der Fehler sind deine Regeln! Die sind unpräzise formuliert und so 
gestaltet, dass es zu solchen Fehlleistungen kommen kann. Das das im 
täglichen Leben kein Problem gibt, liegt daran, dass Menschen mitdenken! 
Etwas was Computer nicht tun.

Die Regeln hätten so formuliert werden müssen
* stelle die aktuelle Uhrzeit fest und merke sie dir
* Ist die gemerkte Uhrzeit 03:00 dann öffne das Fenster
* Ist die gemerkte Uhrzeit 05:00 dann drehe die Heizung auf
* Ist die gemerkte Uhrzeit 05:00 dann mach das Fenster zu

Dadurch, dass er ganz am Anfang erst mal die Uhrzeit feststellt und in 
weiterer Folge nur noch mit dieser gemerkten Uhrzeit operiert, kann das 
'5-Uhr' Problem jetzt nicht mehr entstehen. Denn selbst wenn das 
Heizkörperventil klemmt und er Zeit zur Behebung benötigt, die gemerkte 
Uhrzeit ist immer noch 05:00, selbst wenn die Armbanduhr durch den 
Zeitverzug schon 05:04 anzeigt. Und da das so ist, wird dann auch das 
Fenster geschlossen, weil die Voraussetzungen (Ist die gemerkte Uhrzeit 
05:00?) gegeben sind.

Wodurch ist das Problem entstanden?
Dadurch, dass seine Armbanduhr weiterglaufen ist, während er gearbeitet 
hat.
Wie ist es entschärft worden?
Dadurch, dass die laufende Armbanduhr durch eine Stichzeit die als 
allererstes festgestellt wird, ersetzt wurde. Danach kann die Armbanduhr 
ruhig weiterlaufen, es gilt nur noch diese Stichzeit für diesen einen 
Besuch im Raum. Beim nächsten Besuch gilt dann eine andere Stichzeit. 
Aber die entscheidet sich erst, wenn er das nächste mal wieder 
reinkommt.

von Christian Trohn (Gast)


Lesenswert?

Ich habs mir als Anfänger angewöhnt, immer wenn möglich bei solchen 
Timerfällen auf >= abzufragen. Nun auch mal ne Frage von mir, da ich 
zwar auch Überlegungen zu dem Programm angestellt hab, aber wie gesagt 
noch Anfänger bin und nich sicher ob das Funktioniert.
In der ISR würde ich die Zählvariable ohne die else schleife betreiben. 
Zurücksetzen würd ich sie, wenn wirklich alle Bedingungen im 
Mainprogramm durchlaufen wurden. Dh ich zähle in der ISR bis zu 9 und 
setze im Mainprogramm alles zurück wenn die Bearbeitung abgeschlossen 
ist. Im Mainprogramm wie gesagt >= abgefragt, kann ich auch ruhig mal 
etwas Hardware umbauen und hab bei nem entstehenden Delay dadurch nicht 
gleich Probleme mit meinem Timer, da dieser halt etwas ungenauer ist, 
aber immernoch Funktioniert.
Was würde gegen diese Vorgehensweise sprechen? Zu unübersichtlich in der 
Main die Zählvariable zurückzusetzen? Vielleicht der übersicht halber 
bei fertiger Bearbeitung eine weitere Globale Variable zu setzen, die in 
der ISR die Zählvariable zurücksetzt? (Das würde natürlich die 
Bearbeitungszeit der ISR unnötig erhöhen).
Wäre dankbar wenn jemand meine Gedanken kritisch beurteilt, will mich ja 
weiterentwickeln :)
Mit freundlichen Grüßen
Christian Trohn

von Karl H. (kbuchegg)


Lesenswert?

Christian Trohn schrieb:

> Mainprogramm durchlaufen wurden. Dh ich zähle in der ISR bis zu 9 und
> setze im Mainprogramm alles zurück wenn die Bearbeitung abgeschlossen
> ist. Im Mainprogramm wie gesagt >= abgefragt, kann ich auch ruhig mal
> etwas Hardware umbauen und hab bei nem entstehenden Delay dadurch nicht
> gleich Probleme mit meinem Timer, da dieser halt etwas ungenauer ist,
> aber immernoch Funktioniert.

Skizzier das mal in Code.
Lese ich deine Beschreibung, dann denke ich, dass du in die gleiche 
Falle läufst, wie der TO

> Was würde gegen diese Vorgehensweise sprechen? Zu unübersichtlich in der
> Main die Zählvariable zurückzusetzen? Vielleicht der übersicht halber
> bei fertiger Bearbeitung eine weitere Globale Variable zu setzen, die in
> der ISR die Zählvariable zurücksetzt? (Das würde natürlich die
> Bearbeitungszeit der ISR unnötig erhöhen).

unnötig ist ein relativer Begriff.
Wenn es der Systemstabilität dient, dann ist es nicht unnötig.
Und ja, das wäre mein Ansatz: Zwei LED-Zeitzähler, die in der ISR 
dekrementiert werden bis sie 0 sind. In der Hauptschleife dient diese 0 
als Trigger, die Aktion auszulösen (und dort werden sie dann wieder auf 
einen Startwert gesetzt).

Mit zuvielen Flags und Variablen, die mehrere Aktionen auslösen, kann 
man sich nämlich auch ganz schnell ins Knie schiessen. Irgendwann 
überblickt dann keiner mehr, welche Variable auf welchem Wert stehen 
muss (bzw. Kombinationen von mehreren Variablen mit bestimmten Werten), 
damit welche Aktionen angestossen werden.

von Falk B. (falk)


Lesenswert?

@  Achim Seeger (achims)

>Einer dieser Beträge läuft unter dem Namen "Warten verboten".
>Dort wird beschrieben, wie die Auswirkung bei delay mit 0,5s oder 1s
>ist. Als Lösung wurde vorgeschalgen, delay auf 1ms zu nehmen und die
>einzelnen Ansteuerungen oder Abfragen mehrmals zu machen. Im Text heisst

Meinst du das hier?

http://www.mikrocontroller.net/articles/Multitasking#Ein_einfaches_Beispiel_f.C3.BCr_den_AVR

MfG
Falk

von Chrstian T. (christian_trohn)


Lesenswert?

@Karl Heinz Buchegger
Da mein Laptop defekt iskann ich nur im Wordpad programmieren, was für 
mich als Anfänger sehr, naja, suboptimal ist, weil ich desöfteren 
Leichtsinnsfehler in mein Programm bau. Aber ich habs versucht!
Auch würde ich noch einen Zustand definieren, indem ich das Toggle der 
LED beispielsweise Aus schalten kann, wie in wait10 unten aufgezeigt.
Mein Lösungsweg für diese Funktion wäre folgende:




ISR (TIMER2_COMP_vect)
  {
  if((wait<10)&(wait>0))
    {
    wait++;
    }  //
  if((wait10<10)&(wait10>0))
    {
    wait10++;
    }
  }

In der Main dann die abfragen:
if (wait>=10)
{
    wait=1;
    LED_tog(0);    // irgendeine Funktion halt
}
if (wait>=10)
{
    wait=0;       // Würde den Timer vorerst Deaktivieren bis wait==1
    LED_tog(1);
}

Auch wenns jetzt nicht direkt auf die Fragestellung des TO bezogen ist 
würde ich doch gern ne ehrliche Meinung zu diesem Weg hören.  Das 
einzige Problem was ich in diesem Weg selbst sehe ist, das der Timer 
schon beim setzen der wait=1 funktion bei 254 stehen könnte. Somit wäre 
der erste Umschlag der Zählvariable nicht spürbar. Man könnte diesen 
Fehler durch einen geringeren Prescaler und einen höheren Zählwert 
minimieren. Auch die Programmlaufzeit muss schön überdacht sein, da ich 
ja auch nen Programm mit 500ms Laufzeit haben kann und 10ms die LED 
Toggeln will. Das würde natürlich gar nicht gehen. Aber eigentlich wäre 
ich bei der Lösung frei von ner begrenzten Anzahl an Timern. Ich könnte 
natürlich auch 20 Zähl variablen hochzählen lassen und 20 LEDs toggeln 
mit einem Timer, was meiner Meinung nach die meißten Nachteile aufhebt. 
Vorrausgesetzt ich hab natürlich keinen blöden Leichtsinnsfehler im 
Programm und Merks grad nicht.
Mit freundlichen Grüßen
Christian Trohn

von Chrstian T. (christian_trohn)


Lesenswert?

Sry die 2. Funktion soll natürlich das Beispiel mit wait10 darstellen, 
sonst is ja Glücksache wo das Mainprogramm steht wenn ich 2 mal wait 
abfrage!

von R. M. (rmax)


Lesenswert?

Karl Heinz Buchegger schrieb:

> Denk mal über folgendes konstuierte Beispiel nach [...]

Sehr schöner Vergleich, aber auch Deine entschärfte Version kann noch 
schief gehen. Wenn z.B. das Einschalten der Heizung um 4:59 auf dem 
Programm steht und er drei Minuten mit dem klemmenden Ventil beschäftigt 
ist, bleibt das um 5:00 Uhr zu schließende Fenster wieder auf.

Daher müßten die Bedingungen heißen:"Wenn es X Uhr oder später ist und 
die Aufgabe noch nicht erledigt wurde ..."

von Chrstian T. (christian_trohn)


Lesenswert?

R. Max
Ich glaube du hast sein Beispiel falsch Verstanden. Ich denke er meint, 
dass du auch während er das Ventil repariert um 5 Uhr auf die Uhr schaut 
und sozusagen nen Harken in seine Checkliste bei "muss gemacht werden" 
setzt. Dann kann das Ventil auch 10 Minuten Dauern, der Harken in der 
Checkliste ist gesetzt und muss Bearbeitet werden.

Mit freundlichen Grüßen
Christian Trohn

von Achim S. (achims)


Lesenswert?

Hallo Falk
diesen Artikel meine ich. Eigentlich bin ich dadurch auf diese Sache 
gestossen. Hatte vorher das Problem, wenn der Proz etwas macht, z.B. 
Motor ansteuert, Ventil oder anderes (mechanisch) und es tritt ein 
Verstoss der Sicherheit ein, Kante, Druck oder anderes. Dann arbeitet 
der Proz so lange bis das Teil fertig ist un macht damm sofort was 
anderes, das Gegenteil. Während dieser Zeit ist er blind und taub. Auf 
Grund der Verarbeitung kann ich zwar nicht sofort reagieren, ich brauche 
aber auch nicht unnötig zu warten. Dann habe ich mir die Sachen von 
KH+DA angesehen. Sind sehr gut gemacht. Aber zum schalten von 2 LED viel 
zu lang. Es sollte was einfaches sein, unkompliziert und vor allen für 
mich nachvollziehbar. Habe noch ca. 8 andere Artikel gefunden mit den 
verschiedenen Vorschlägen. Konnten mich aber nicht überzeugen. Ist doch 
was für unsere Kollegen KH+DA. Macht was kurzes prägnanntes draus, was 
überall eingebaut werden kann.
achim

von Falk B. (falk)


Lesenswert?

@  Achim Seeger (achims)

>KH+DA angesehen. Sind sehr gut gemacht. Aber zum schalten von 2 LED viel
>zu lang. Es sollte was einfaches sein, unkompliziert und vor allen für
>mich nachvollziehbar.

Na dann bis DU erstmal in der Pflicht. Nämlich allgemein zu sagen WIE 
deine LEDs geschaltet werden sollten, OHNE deine verquere Lösung da mit 
reinzurühren. Siehe Netiquette. DANN kann man auch ein einfaches, 
problemorientierte Beispiel schreiben.

MfG
Falk

von R. M. (rmax)


Lesenswert?

Chrstian Trohn schrieb:

> Ich glaube du hast sein Beispiel falsch Verstanden.

Glaube ich nicht.

> Ich denke er meint, dass du auch während er das Ventil repariert um 5 Uhr
> auf die Uhr schaut und sozusagen nen Harken in seine Checkliste bei
> "muss gemacht werden" setzt.

Das würde aber der Analogie mit dem Programm widersprechen.

Karl Heinz sagte, der Wächter merkt sich die aktuelle Uhrzeit und 
arbeitet dann alle Tätigkeiten ab, die mit genau diesem Zeitpunkt in der 
Liste stehen. Dauert das zusammen länger als der zeitliche Abstand zur 
nächsten Aufgabe, wird diese Aufgabe immer noch "übersehen", denn beim 
nächsten Blick auf die Uhr ist deren Zeit ja schon um.

von Chrstian T. (christian_trohn)


Lesenswert?

Ja du hast recht, ich hab da wohl irgendwie noch den funktionierenden 
Weg im Kopf gehabt und auf das Beispiel übertragen, mein Fehler.

Mit freundlichen Grüßen
Christian Trohn

Bitte melde dich an um einen Beitrag zu schreiben. Anmeldung ist kostenlos und dauert nur eine Minute.
Bestehender Account
Schon ein Account bei Google/GoogleMail? Keine Anmeldung erforderlich!
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.