CONTACT US

Epsum factorial non deposit quid pro quo hic escorol.

  • Dezentral.ch

    Energie im Griff

  • Dezentral.ch

    Energie im Griff

Change language

einfacher Arduino Timer2 Scheduler ohne Callback's

von admin (Kommentare: 2)

Ein Standard Arduino SDK Sketch sieht z.B. so aus :

/*
  Blink
  Turns on an LED on for one second, then off for one second, repeatedly.
 
  This example code is in the public domain.
 */
 
// Pin 13 has an LED connected on most Arduino boards.
// give it a name:
int led = 13;

// the setup routine runs once when you press reset:
void setup() {                
  // initialize the digital pin as an output.
  pinMode(led, OUTPUT);     
}

// the loop routine runs over and over again forever:
void loop() {
  digitalWrite(led, HIGH);   // turn the LED on (HIGH is the voltage level)
  delay(1000);               // wait for a second
  digitalWrite(led, LOW);    // turn the LED off by making the voltage LOW
  delay(1000);               // wait for a second
}

Für kleine Anwendungen mit wenigen Tasks, die gleichzeitig ablaufen sollen, ist eine Codierung mit fixen Pausen (delay's) ein pragmatischer Weg. Falls aber mehrer Steuerungsaufgaben gleichzeitig ablaufen müssen und z.B. eine Antwortzeit von 1msec gewünscht ist (z.B. für ein Notaus) , ist ein solcher Ansatz nicht praktikabel.

 

Lösungsansatz

 

Ein möglicher Lösungsansatz ist mit einem in Atmel Chips integrierten Timer zu arbeiten. Es ensteht dabei sicher ein Overhead, aber ein Arduino Uno R3 mit 16MHz Systemtakt hat z.B. mit 1msec Antwortzeit immer noch 16'000 Zyklen zum abarbeiten komplexer Tasks. Auch macht es keinen Sinn auf Assemblerprogrammierung auszuweichen, solange genügend Programm und Datenspeicher vorhanden ist.

Erstellen Sie also in Eclipse ein C++ Projekt --> AVR Cross Target Application --> Empty Project

und geben Sie einen sinnvollen Namen; z.B. MySimpleScheduler ein. Wichtig ist, dass Sie im neuen Projekt unter Properties --> C/C++ Build --> Settings --> Tool Settings die richtigen Einstellungen in AVR Compiler, AVR C++ Compiler und AVR C++ Linker gemacht haben.

Z.B. müssen Sie in Directories Ihre selbst compilierte ArduinoCore Lib einbinden.

Von da an ist alles recht einfach. In diesem Beispiel werden 3 Files benötigt:

ScheduleExample.cpp

Timer2 kann auf ca. 1msec und 10msec. eingestellt werden. Bitte toSchedule.everyMsec in Tasks.h anpassen. Einzelne Tasks sind in Tasks.h parametrisiert und werden in Tasks.cpp abgearbeitet.

/*
 * ScheduleExample.cpp
 *
 *  Created on: 05.04.2013
 *      Author: arduino
 */

#include "Arduino.h"

#include <avr/interrupt.h>
#include <avr/io.h>

#include <Tasks.h>


Tasks t;

/*
 * use TIMER2_COMPA_vect for interrupt
 * ISR (interrupt service routine) called by timer interrupt
 */


ISR(TIMER2_COMPA_vect) {
  //toggle the pin
  for (int i=0; i<NUM_TASKS; i++) {
      t.taskList[i].taint++;
      if (t.taskList[i].taint > t.taskList[i].everyMSec) {
          t.taskList[i].callMe = true;
          t.taskList[i].taint = 0;
      }
  }
}

/*
computations for timers on arduino uno r3 with 16MHz
change for another CPU and master Clock !!!!!!!!!!!!!

two "tickers" are available

ticEveryMilliSec: one tic is about 1 msec
ticEvery10Millisec: one tic is about 10 msec

*/

void ticEveryMilliSec() {
  // set prescaler to /256 --> bin 110
  TCCR2B = _BV(CS22) | _BV(CS21) ;

  // set WGM to CTC mode (010) : timer2 counts up until matching
  // In this mode Timer2 counts up until it matches OCR2A OCR2A --> interrupt
  TCCR2A = _BV(WGM21);

  OCR2A = 63;        // it is not 1ms, but 0.992 msec, with 62 --> 1.008 msec

  // OCR2A matches timer2 --> interrupt
  TIMSK2 = _BV(OCIE2A);
}

void ticEvery10MilliSec() {
  // set prescaler to /1024 --> bin 111
  TCCR2B = _BV(CS22) | _BV(CS21) | _BV(CS20);

  // set WGM to CTC mode (010) : timer2 counts up until matching
  // In this mode Timer2 counts up until it matches OCR2A OCR2A --> interrupt
  TCCR2A = _BV(WGM21);

  OCR2A = 156;        // it is not 10ms, but 10.16 msec

  // OCR2A matches timer2 --> interrupt
  TIMSK2 = _BV(OCIE2A);
}


void setup() {

  cli();        // disable  interrupts

  // init tasks
  for (int i=0; i < NUM_TASKS; i++) {
      t.setup(i);
  }
  ticEvery10MilliSec();

  sei();        // enable interrupts
}


void loop() {
  // wake up tasks ...

  for (int i=0; i < NUM_TASKS; i++) {
    if (t.taskList[i].callMe) {
      t.taskList[i].callMe = false;
      t.work(i);
    }
  }
  // add code here, to do more
}

//===========================
int main() {
  init();
  setup();
  for (;;) {                 // do forever (as in Arduino SDk structure)
    loop();
  }
  return 0;
}

Tasks.cpp

Sehr einfaches Beispiel mit 3 Tasks.

.

  • task0: LED Arduino Port 13 toggeln
  • task1: LED Arduino Port 12 toggeln
  • task2: LED Arduino Port 11 toggeln
/*
 * Tasks.cpp
 *
 *  Created on: 06.04.2013
 *      Author: arduino
 */

#include <Arduino.h>
#include "Tasks.h"

// task 0 code

void Tasks::work (int num) {
    switch(num) {
      case 0:
        task0();
        break;
      case 1:
        task1();
        break;
      case 2:
        task2();
        break;
      default:
        task0();
        break;
    }
}

void Tasks::setup (int num) {
    switch(num) {
          case 0:
              initTask0();
            break;
          case 1:
              initTask1();
            break;
          case 2:
              initTask2();
            break;
          default:
            task0();
            break;
    }
}

void Tasks::task0() {
    t0state = 1 - t0state;
    digitalWrite(t0Pin, t0state);
}

void Tasks::initTask0() {
    pinMode(t0Pin, OUTPUT);
}

// task 1 code


void Tasks::task1() {
    t1state = 1 - t1state;
    digitalWrite(t1Pin, t1state);
}

void Tasks::initTask1() {
    pinMode(t1Pin, OUTPUT);
}

// task 2 code

void Tasks::task2() {
    t2state = 1 - t2state;
    digitalWrite(t2Pin, t2state);
}

void Tasks::initTask2() {
    pinMode(t2Pin, OUTPUT);
}

Tasks::Tasks() {
    t0Pin = 13;
    t0state = 0;
    t1Pin = 12;
    t1state = 0;
    t2Pin = 11;
    t2state = 0;
}

Tasks::~Tasks() {

}

Tasks.h

Datenstruktur für Tasks.cpp und ScheduleExample.cpp

/*
 * Tasks.h
 *
 *  Created on: 06.04.2013
 *      Author: arduino
 */
#ifndef TASKS_H_
#define TASKS_H_

#include <Arduino.h>

#define NUM_TASKS 3      // number of taks to schedule
#define TASK_NAME_LETTERS 20 // number of letters in struct task




class Tasks {

  private:
  int t0Pin = 13;
  int t0state = 0;

  int t1Pin = 12;
  int t1state = 0;


  int t2Pin = 11;
  int t2state = 0;

  public:

  struct toSchedule {
    char name[TASK_NAME_LETTERS];
    bool callMe;
    long everyMSec;
    long taint;
  } taskList [NUM_TASKS] = {
    {"task0", false, 50, 0},  // task 1
    {"task1", false, 25, 0},  // task 2
    {"task2", false, 12, 0}};  // task3

   Tasks();
   ~Tasks();
   void work(int num);
   void setup(int num);

   void task0();
   void initTask0();
   void task1();
   void initTask1();
   void task2();
   void initTask2();
};

#endif /* TASKS_H_ */

fertig ....

noch ein Bild des Tests auf der Hardware:

Zurück

Einen Kommentar schreiben

adf
sadf
asdf
asdf

Kommentar von asdf |

oppoi
ipopoi
iopfsdpo

Kommentar von asdf2 |