Forum: Compiler & IDEs Multitasking im AVR-Studio in "C"


von Mad M. (madang)


Lesenswert?

Brauche wieder einmal eure Hilfe!
Bin noch ein Anfänger, möchte aber mehrere Dinge parallel laufen lassen.
Was ich bräuchte ist, ein Grundegrüst, damit ich darauf aufbauen kann.
Anbei ein Übungsprogramm, von dem ich nicht weiss, ob der Ansatz so 
stimmt, oder komplett falsch ist.
Wo bekommen ich Info's bzw. kann mir jemand den Code anbei 
aktualisieren. Wäre euch dankbar!
Momentan (jetziges Programm ist noch länger wie dies im Anhang) läuft 
mein Programm nicht gut, d.h: es macht was es will. Glaube die Funkt. im 
"Compare-Match-Teil sind zu lang!?!?.
Vorab schon Mal vielen Dank!
Mad

//======================== Programmbeschreibung ========================
// 1.) Die Zeitkritischen Funkt. werden über einen Switch/Case-Schleife 
mittels "i_ext" gesteuert
// 2.) 1x pro Millisek. sollten jene Funktionen aufgerufen werden, die 
sich ausserhalb  der Switch-Case-Schleife befinden.
// 3.)Im "main-Teil" sind nur zeitunkritische Funktionen!
//=====================================================================

#include "definition.h"
#include "LCD_def.h"
#include "lcd_drv.c"

uint8_t  Funktion_LED_1(uint16_t ms);
uint8_t  Funktion_LED_2(uint16_t ms);
uint8_t  Funktion_LED_3(uint16_t ms);

uint8_t  Tastaturabfr(uint16_t ms);
uint8_t  In_Out_Abfr(uint16_t ms);

extern uint8_t i_ext = 0;    // Eventhandler (steuert die zeitkritischen 
Funktionen) dekl. & init

//************** Beginn zeitkritische Funktionen !!!**********
ISR (TIMER0_COMP_vect)
{
switch(i_ext)       // Eventhändler zum steuern des Ablaufs!!!
  {
       case 10: Funktion_LED_1(100); break;  // bestimmen der 
Blinkfrequenz Led 1
//   case 11: Funktion_LED_2(100); break;  // bestimmen der 
Blinkfrequenz Led 2
//   case 12: Funktion_LED_3(100); break;  // bestimmen der 
Blinkfrequenz Led 3
  }
//Tastaturabfr_4x3(100); break;    // längere Funktionen mit LCD Ausgabe
//In_Out_Abfr(100); break;    // längere Funktionen mit LCD Ausgabe

}
//************** Ende zeitkritische Funktionen !!!**********

int main()
{

//********************************************************************** 
**
//  Timer Konfig. (Compare Match) zählt bis xx-Wert hoch (zB.: 8) --> IR
//********************************************************************** 
**
  TIMSK |= (1 << OCIE0);   // IRQ bei Compare Match
  OCR0 = 8;       // Vergleichswert 8 einstellen => ca. 1000 Hz (1ms) 
--> (8000000/1024/8)
  sei();      // IRQs enable (Interrupt global einschalten)
  TCCR0 |= (1 << WGM01);  // CTC-Modus (Vergleichmodus)
  TCCR0 |= (1 << CS00) | (1 << CS02);  // Prescaler: 1/1024 (zB.: 
CPU-Takt 8000000/ Teiler 1024)
//********************************************************************** 
**
//  I2C & LCD Konfiguration
//********************************************************************** 
**
  lcd_init();       // LCD initialisieren
//  i2c_init();             // initialize I2C library
//********************************************************************** 
**
// Port Konfig.
//********************************************************************** 
**
 DDRA = 0x00;  // Eing. Def.
   PORTA= 0xFF;  // Alle Pin via Pullup auf High
DDRB = 0xFF;  // Ausg. Def.
PORTB= 0xFF;  // Alle Pin via Pullup auf High
lcd_pos(2,0);
lcd_text("Guten Tag!");
_delay_ms(1000);

     while(1)  //endlos
      {
   lcd_clear();
  lcd_pos(2,0);
  lcd_text("Step 1!");
  _delay_ms(1000);// was mich stört sind, diese sinnlosen delay's

  i_ext = 10;    //Aufruf  Zeitk.-Funktion_LED_1() im 
Compare-Match-Modus;
  _delay_ms(1000);

  lcd_pos(2,0);
  lcd_text("Step 2!");
  _delay_ms(1000);
  i_ext = 0;    // Zeitkritischen-Funktionsaufruf sperren

  LCD_Ausg();
  _delay_ms(1000);

//usw:
     }  // ENDE while(1);
return 0;
} ENDE main();
//********************************************************************** 
**
//    ZEIT-Kritische Funktion 1 wird mit einer Variable (i_ext) 
gesteuert
//********************************************************************** 
**
uint8_t  Funktion_LED_1 (uint16_t ms) // Funktionsaufruf mit 
Wertübergabe
{
     static uint16_t i_zaehler = 0;    // Zähler auf 0 setzen (einmalig)
  if (i_zaehler >= ms)       // Zählerstand > wie Wert der Funktion --> 
rein in die Schleife
  {  PORTB ^= (1 << PB1);    // Toggle Pin 2 von PORT B
       i_zaehler = 0;    // Zähler wieder auf 0
     }
       i_zaehler ++;    // sonst erhöhe Zähler um 1
    return 0;      // zurück ins HP
 }

//********************************************************************** 
**
//  NICHT-Zeitkritische Funktion
//********************************************************************** 
**
void LCD_Ausg(void)
  {
  lcd_clear();    // kompl. LCD löschen!!!!
  _delay_ms(30);
  lcd_text("  Hallo wie geht    ");
  lcd_pos(2,0);
  lcd_text("      es dir        ");
  lcd_pos(3,0);
  lcd_text("      heute?        ");
  lcd_pos(4,0);
  lcd_text("   gut/schlecht?    ");
  }

von Karl H. (kbuchegg)


Lesenswert?

Madang Madang schrieb:
> Brauche wieder einmal eure Hilfe!
> Bin noch ein Anfänger, möchte aber mehrere Dinge parallel laufen lassen.
> Was ich bräuchte ist, ein Grundegrüst, damit ich darauf aufbauen kann.

1
volatile uint8_t DoLCD;
2
volatile uint8_t DoLED;
3
4
5
ISR( ... )
6
{
7
  ...
8
9
  if( ... )
10
    DoLCD = 1;
11
12
  if( ... )
13
    DoLED = 1;
14
15
  ...
16
}
17
18
int main()
19
{
20
  ....
21
22
  sei();
23
24
  while( 1 ) {
25
26
    if( DoLCD ) {
27
      DoLCD = 0;
28
29
      Bearbeite das LCD
30
    }
31
32
    if( DoLED ) {
33
      DoLED = 0;
34
35
      Bearbeite die LED
36
    }
37
38
    if( ... )
39
    {
40
      ...
41
    }
42
  }
43
}

Die _delay_xx Funktionen solltest du gleich mal vergessen. Die sind Gift 
wenn es darum geht, mehrere Dinge 'parallel' abzuarbeiten.

Statt dessen wird die jeweilige Funktionalität von einem 'Job-Flag' 
abhängig gemacht. Ist die Funktionalität auszuführen, so setzt irgendein 
Code (muss nicht die ISR sein), das Job-Flag auf 1. Bei nächsten 
Durchgang durch die Hauptschleife wird das registriert und die 
Funktionalität ausgeführt und das Job-Flag zurückgesetzt.

Auf die Art werden immer nur die Aktionen gemacht, die auch tatsächlich 
notwendig sind. Bei lang andauernden Aktionen, kann es auch sein, dass 
man diese in mehrere Teile unterteil mit jeweils einem eigenen Job-Flag, 
damit die Hauptschleife gelegenheit bekommt einmal rundum zulaufen und 
auch andere 'Parallel-Aktionen' eine Chance haben eine kurze Zeitscheibe 
abzukriegen.

von Falk B. (falk)


Lesenswert?

@  Madang Madang (madang)

>Brauche wieder einmal eure Hilfe!

Ja, vor allem in Netiquette. Lange Quelltexte postet man als Anhang!

>Bin noch ein Anfänger, möchte aber mehrere Dinge parallel laufen lassen.

Siehe Artikel Multitasking und Interrupt.

MfG
Falk

von anf (Gast)


Lesenswert?

Interessant wird es doch jetzt wenn man einen Job genau zweimal 
ausführen will.
Es könnte doch sein das ich das Flag schon wieder setzen muss obwohl es 
noch garnicht abgearbeitet wurde.

Was wären denn nun die Strategien ?

- Abfrage auf Flag schon wieder zurückgesetzt wurde im HP
- Flag Variable als Zähler benutzen
- Eine Que/Pipe

Was gäbe es da noch ?

von Ziff (Gast)


Lesenswert?

Wie soll man etwas geanu zweimal ausfuehren, ohne zu zaehlen ? Was 
spricht gegen eine Zaehlvariable ?

von g457 (Gast)


Lesenswert?

> Interessant wird es doch jetzt wenn man einen Job genau zweimal
> ausführen will.
> Es könnte doch sein das ich das Flag schon wieder setzen muss obwohl es
> noch garnicht abgearbeitet wurde.

Da hast Du im wesentlichen genau zwei Möglichkeiten:

1. Die Jobs sind echt zeitkritisch. Falls die zweite 'Aufforderung' 
kommt und die erste noch gar nicht abgearbeitet wurde, dann hast Du Pech 
gehabt.

2. Die Jobs sind nicht (oder wenig) zeitkritisch, d.h. es können auch 
(kurzzeitig) schneller Auslöser kommen als abgearbeitet wird, es darf 
aber (zahlmäßig) keiner verloren gehen. Für sowas nimmt man eine hübsche 
Zählvariable, und zwar (z.B.) derart dass der 'Auslöser' die Variable 
hochzählt und der 'Ausführende' (sofern die Variable > 0 die Aktion 
ausführt und) die Variable wieder runterzählt. Also Semaphor-artig.

HTH

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.