Code:
/*! @file nibobee_timer.c
* @brief Timer Routinen für Verzögerungen
* @author Birger Töpelmann
* @date 2010-03-21
*/
/*************************************************************
N I B O B E E T I M E R
*************************************************************/
#include <nibobee/iodefs.h>
//#include <nibobee/motpwm.h>
#include <nibobee/delay.h>
#include <nibobee/sens.h>
//#include <nibobee/odometry.h>
#include <nibobee/led.h>
/*************************************************************
Timer 0 des ATmega16 soll einen periodischen Interrupt auslösen.
Innnerhalb der Interruptserviceroutine (Interrupthandler) wird
ein Softwaretimer jede ms inkrementiert. Aus diesem Softtimer
kann ein feste Zykluszeit (1, 2, 5, 10ms..) für die Hauptschleife
abgeleitet werden. In der Hauptschleife inkrementierte oder
dekrementierte Variablen können dann als weitere Timer mit
Basis Zykluszeit verwendet werden,
--------------------------------------------------------------
Auswahl eines Teilers für das TimerCounterControlRegister:
Systemtakt 15 000 000/s; Überlauf Timer nach 256 Takten (OV);
Teiler /1: 15000000/s / 256 = 58593,75 /s = 58,6 /ms
Teiler /8; 15000000/s / 1024 = 14648,4375 /s = 14,6 /ms
Eine Quarzgenaue "ms" ist so nicht zu erreichen,
Auswahl des Zählerwertes für den Softtimer in der ISR
58: Abweichung = (58 - 58,6) / 58 = -1,03% (eilt vor)
59: Abweichung = (59 - 58,6) / 59 = +0,68% (hinkt nach)
14: Abweichung = (14 - 14,6) / 14 = -4,29%
15: Abweichung = (15 - 14,6) / 15 = +2,67%
*************************************************************/
#define TEILER_T0 0b001 // TCCR0: Systemtakt /1
#define ZAEHLR_T0 59 // ISR: Zusatzteiler s.o.
void timer0_init_mega16() // timer 0 eine ATmega 16 initialisieren
{
TCCR0 |= TEILER_T0; // TimerControlRegister = Teiler /8
TIMSK |= (1 << TOIE0); // Enable Overflow Interrupt
}
volatile uint8_t timer0_ms; // der ms Systemtimer Taktzähler
// volatile == die Variable für jeden Vergleich neu einlesen,
// weil sie in einer anderen Routine (Interrupt) geändert wird
/*
ohne volatile: --> Compiler Optimierung
lade register mit variable
warten:
if register < grenzwert goto warten --> Endlosschleife
mit volatile; --> Compiler soll hier nicht optimieren
warten:
lade register mit variable
if register < grenzwert goto warten
*/
/************************************************************/
// Timer 0 Overflow Interrupt Service Routine
volatile uint8_t tmr0_tick;
// alte Bezeichnung ISR (TIMER0_OVF_vect)
SIGNAL (SIG_OVERFLOW0)
{
if (tmr0_tick == 0)
{
tmr0_tick = ZAEHLR_T0;
timer0_ms++;
}
tmr0_tick--;
}
/************************************************************/
uint8_t timer0_wait(uint8_t ticks)
{
uint8_t merker; // Zwischenspeicher
while(timer0_ms < ticks); // warten auf Systemzeit ms Takte
merker = timer0_ms; // tatsächliche Takte merken
timer0_ms = 0; // Systemtimer Reset
return(merker); // tatsächliche Zykluszeit zurückliefern
}
/******************************************* V A R I A B L E N */
/* ...auch Konstanten sind variabel... ;-) */
// Hier gehören die im Hauptprogramm definierten Variablen rein,
// dann gibt's auch keine 8 Warnungen mehr vom Compiler !!!
uint16_t timer_LED1; // uint16 weil > 255 Definition aber Warnung
uint8_t timer_Sens; // uint8 für Zeiten < 255 ms
/******************************************* F U N C T I O N S */
void led_mask(uint8_t muster);
void led_aus(uint8_t muster);
void led_ein(uint8_t muster);
/***************************************************** M A I N */
int main()
{
timer0_init_mega16(); // Timer0 für periodischen Interrupt initialisieren
sens_init(); // Fühler Taster Initialisieren
led_init(); // LEDs initialisieren
while((sens_getLeft()==0) && (sens_getRight()==0)); // Warten auf Startsignal am Fühler
while(1==1) /* - - - - - - - - - - - M A I N L O O P */
{
enable_interrupts(); // Interrupts freigeben
#define Zykluszeit 1 // Hauptschleife Zykluszeit in ms
uint8_t tmr0_watch = timer0_wait(Zykluszeit); // Zykluszeit abwarten
if(tmr0_watch > Zykluszeit) // Zykluszeit überwachen
{
while(1==1) // Fehlerfalle Zykluszeit überschritten
{
if (tmr0_watch > 10) led_ein(15); // Zykluszeit > 10 alle LED ein
else led_ein(tmr0_watch); // Zykluszeit Binär ausgeben
timer0_wait(250); // Klassische Verzögerung LED Ein Zeit
led_aus(15); // LED aus für Blinklicht
timer0_wait(150); // Klassische Verzögerung LED Aus Zeit
}
}
// Ab hier wird die Hauptschleife in einer festen Zykluszeit abgearbeitet
// Da der Intervall feststeht, können beliebig viele Timer abgeleitet werden
// uint16_t timer_LED1; // uint16 weil > 255 Definition aber Warnung
if(timer_LED1-- == 0) timer_LED1 = 1000; // Zyklischer Timer 1000ms
if(timer_LED1 > 700) led_set(LED_L_YE,1); // LED Blinklicht
else led_set(LED_L_YE,0);
// uint8_t timer_Sens; // uint8 für Zeiten < 255 ms
int8_t SensLeft; // Sensor Status
if(timer_Sens != 0) timer_Sens--;
else
{
timer_Sens = 200 / Zykluszeit; // alle 200ms
SensLeft = sens_getLeft(); // Sensorabfrage
}
// Hier wieder normaler Zyklus
/*
solange der linke Fühler nach hinten gedrückt wird, leuchtet die rote LED links
wird der linke Fühler nach vorne gedrückt sollte die LED blinken, weil aber das
delay() verwendet wird, landet das Programm in der Zyklusüberwachung.
*/
switch(SensLeft)
{
case -1: led_set(LED_L_RD,1); break;
case +1: led_set(LED_L_RD,1);
delay(200);
// dieses delay darf in der Hauptschleife nicht mehr verwendet werden
led_set(LED_L_RD,0);
delay(200);
// dieses delay darf in der Hauptschleife nicht mehr verwendet werden
break;
default: led_set(LED_L_RD,0); break;
}
/* Rechts funktioniert die o.a. Funktion */
int8_t SensRight; // Sensor Status
// timer_Sens auf 1 abfragen, er wird oben bearbeitet und bei Zählerstand 0 neu geladen
if(timer_Sens == 1) SensRight = sens_getRight(); // alle 200ms Sensorabfrage
uint16_t timer_LED_R;
if(timer_LED_R-- == 0) timer_LED_R = 400; // Zyklischer Timer 400ms
switch(SensRight)
{
case -1: led_set(LED_R_RD,1); break;
case +1: if(timer_LED_R > 200) led_set(LED_R_RD,1); // LED Blinklicht
else led_set(LED_R_RD,0);
break;
default: led_set(LED_R_RD,0); break;
}
/*
Ein- und Ausschaltverzögerungen:
Wird der rechte Fühler dauernd betätigt, schaltet nach 2 Sek Verzögerung die rechte gelbe LED ein;
wird der rechte Fühler losgelassen, leuchtet die LED noch 5 Sekunden nach.
*/
uint8_t Flanke_rechts;
int16_t timer_Verz_Ein;
int16_t timer_Verz_Aus;
if((Flanke_rechts == 0) && (SensRight != 0)) timer_Verz_Ein = 2000; // Timer setzen bei
if((Flanke_rechts != 0) && (SensRight == 0)) timer_Verz_Aus = 5000; // Flankenerkennung
Flanke_rechts = SensRight;
led_set(LED_R_YE,0);
if((SensRight != 0) && (timer_Verz_Ein == 0)) led_set(LED_R_YE,1); // Einschaltverzögerung
if((SensRight == 0) && (timer_Verz_Aus != 0)) led_set(LED_R_YE,1); // Ausschaltverzöferung
if(timer_Verz_Ein > 0) timer_Verz_Ein--; // Die Timer sollten immer als Countdown arbeiten,
if(timer_Verz_Aus > 0) timer_Verz_Aus--; // und bei 0 stehen bleiben
} /* - - - - - - - - - - - M A I N L O O P */
return(0);
}
/*****************************************************************
Routinen zum direkten Setzen aller 4 Leds des NiboBee
LED_L_YE = 1, LED_L_RD = 2 ,LED_R_RD = 4, LED_R_YE = 8
led_mask(9); Schaltet gelbe LEDs ein und rote LEDs aus
led_ein(6); Schaltet rote LEDs ein, gelbe LEDs bleiben (Ein o. Aus)
led_aus(6); Schaltet rote LEDs aus, gelbe LEDs bleiben (Ein o. Aus)
*****************************************************************/
void led_mask(uint8_t muster)
{
for(uint8_t c = 0; c < 4; c++)
{
if (((muster >> c) & 1) == 1) led_set(c,1); else led_set(c,0);
}
}
void led_aus(uint8_t muster)
{
for(uint8_t c = 0; c < 4; c++)
{
if (((muster >> c) & 1) == 1) led_set(c,0);
}
}
void led_ein(uint8_t muster)
{
for(uint8_t c = 0; c < 4; c++)
{
if (((muster >> c) & 1) == 1) led_set(c,1);
}
}
Viel Spaß und Erfolg bei eigenen Projekten...
Lesezeichen