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