- 12V Akku mit 280 Ah bauen         
Seite 3 von 3 ErsteErste 123
Ergebnis 21 bis 25 von 25

Thema: NIBOBee und Timer- für Anfänger

  1. #21
    Neuer Benutzer Öfters hier
    Registriert seit
    26.02.2010
    Ort
    Kreuzung BAB3 und B470
    Beiträge
    25
    Anzeige

    LiFePo4 Akku selber bauen - Video
    Ach, ich dachte der Thread Titel lautet "NiboBee und Timer für Anfänger";

    und ob eine LED 60x oder 58x / Sekunde blinkt ist für jemanden, der mit Netzfrequenz getakteten Radioweckern aufgewachsen ist eigentlich wurscht.

    Aber Rabenauge hat recht, zu einem delay(x) addiert sich noch die Ausführungszeit der Hauptschleife, und je nach dem was sie gerade zu tun hat ist diese unterschiedlich lang.

    Aber wie sollte man 4 Leds mit 2 Timern unabhängig von einander unterschiedlich blinken lassen?

    In diesem Beispiel Programm wird also die Hauptschleife abgearbeitet, während im Hintergrund eine Zeit tickt. Vor dem nächsten Durchlauf der Hauptschleife wird gewartet, bis die volle Millisekunde um ist. Die Hauptschleife wird also alle ms 1x durchlaufen. Somit habe ich überall in der Schleife einen festen Zeitbezug. Allerdings darf man die Funktion delay() dann nicht mehr verwenden. Wenn die Zeit von 1 ms nicht mehr reicht, verstellt man die Zykluszeit eben auf 2, 4, 5 oder 10 ms. Die Zykluszeit ist dann auch die minimale Zeitbasis (bei 10ms kann man dann auch nur in 10ms Schritten verzögern).

    Also ich denke, dass mit den Kommentaren auch Anfänger zurechtkommen sollten.
    Beim Kompilieren gibt es 6 Warnungen; das liegt daran, dass in main() uninitialisierte Variablen abgefragt werden. Diese Variablen gehören eigentlich oberhalb von main() deklariert (ist aber alles Demo).

    Und jedesmal, wenn eine timer Variable gesetzt wird, sollte es "Timersollwert"/Zykluszeit heissen - wenn also die Zykluszeit erhöht werden muss, würde der Zeitwert noch stimmen. 2000 / Zykluszeit blieben 2 Sekunden, egal ob Zykluszeit 1ms oder 5ms oder 10ms ist.

    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...

  2. #22
    Moderator Robotik Visionär Avatar von radbruch
    Registriert seit
    27.12.2006
    Ort
    Stuttgart
    Alter
    61
    Beiträge
    5.799
    Blog-Einträge
    8
    Hallo

    In der Hauptschleife auf die ISR zu warten ist nicht so optimal. Basierend auf dem Code von oben würde ich das etwa so angehen:
    Code:
    // Vier LEDs ansteuern mit Timer 0                                      21.3.2010 mic
    
    #include <nibobee/iodefs.h>
    #include <avr/interrupt.h>
    
    volatile uint8_t p=0; // Auf diese Variable greift die ISR und das Programm zu!
    
    int main(void)
    {
       TCCR0 = (1<<CS02) | (1<<CS00);      // Normal Mode, kein OC0-Pin, prescaler /1024
       TIMSK |= (1<<TOIE0);                // Timer0 Overflow-Interrupt erlauben
    
    	DDRB |= 0x0f;                       // alle Leds sind Ausgang
    	PORTB &= ~0x0f;                     // und low
    	enable_interrupts();
    
       while(1)
       {
    		if(!p)
    		{
    			p=4*57; 								// alle 4 Sek. (atomar weil byte!)
    			PORTB ^= 0x0f;                // alle LEDs umschalten
    		}
    		// nix zu tun
       }
    
    }
    ISR(TIMER0_OVF_vect)
    {
       static uint8_t led0=0, led1=0, led2=0, led3=0;
       
       if(led0) led0--; else { PORTB ^= 1; led0=57; } 		// eine Sek.
       if(led1) led1--; else { PORTB ^= 2; led1=57/2; } 	// 1/2 Sek.
       if(led2) led2--; else { PORTB ^= 4; led2=57/3; } 	// 1/3 Sek.
       if(led3) led3--; else { PORTB ^= 8; led3=57/4; } 	// 1/4 Sek.
       if(p) p--;                                         // Usertimer :)
    }
    Das ist natürlich auch nur eine Möglichkeit von vielen...

    Gruß

    mic
    Bild hier  
    Atmel’s products are not intended, authorized, or warranted for use
    as components in applications intended to support or sustain life!

  3. #23
    Neuer Benutzer Öfters hier
    Registriert seit
    26.02.2010
    Ort
    Kreuzung BAB3 und B470
    Beiträge
    25
    Bei sourceforge gibt es neue Dateien von Nils Springob für die NiboBeeLib = Revision 25 vom 16.3.2010:

    Der Timer 2 isses:

    Weil der mit einer festen Taktfrequenz zählt, und die PWM über Compare Match erzeugt wird, wird mit dem Timer 2 Overflow auch gleich für die NiboBee Software Clock zum Ticken gebracht.

    Die Odometrie geht auf eine Regelung der Motordrehzahl, sogar Streckenvorgabe ist möglich. Probiert habe ich noch nicht, nur mal angeschaut. Ich weiß allerdings nicht sicher, ob die Uhr weitertickt, wenn die Motoren gestoppt werden. Das sollte aber so sein, weil in clock.c auch die Sekunden seit dem Einschalten des Nibobee gezählt werden.

    Um im Simulator zu sehen, was die Bibliotheken mit den Registern machen, muss man die entsprechenden Header und Source Dateien direkt in das Projekt mit einbinden und gemeinsam mit der eigen main() compilieren. Beobachten, welches Bit in welchem Register gesetzt wird, geht einfacher, als all die defines durchzudenken.

  4. #24
    Erfahrener Benutzer Robotik Einstein Avatar von Rabenauge
    Registriert seit
    13.10.2007
    Ort
    Osterzgebirge
    Alter
    55
    Beiträge
    2.199
    Klingt interessant.
    Leider (nunja, soo leider auch nicht) muss ich die Timer-Geschichte einige Tage zurückstellen, da ich mir fürs Bienchen was gebastelt habe, und es funktioniert sogar.
    Werde aber demnächst (muss den Basteltüdel erst wieder hübsch machen) unbedingt reinschauen.

  5. #25
    Benutzer Stammmitglied
    Registriert seit
    12.01.2010
    Beiträge
    53
    Hallo Leute,

    oh nein, und ich habe mir in den letzten Wochen selber eine Regelung zusammengebaut - sie kann regeln, Strecke fahren und definierte Kurven fahren. Und was les ich hier? Nicai hat es selber der Bibliothek zugefügt.

    Allerdings fahre ich einen ganz anderen Ansatz. Zum einen ist meins kein echter PID-Regler und zum anderen ist mein Regelalgorithmus langsamer und verbraucht deshalb viel weniger CPU-Resourcen.

    Hintergrund: Ich habe die Biblitothek von Grund auf neu geschrieben. Bin allerdings noch mittendrin. Herzstück ist ein Timer-System, dass durchaus ähnlich den Tasks von NXC / NXQ ist. Man kann damit Funktionen zu einem zukünftigen Zeitpunkt ausführen, Auflösung ist 1 ms und maximale Verzögerung ist 60 s.

    Bisher funktioniert das Timer-System, Tastenentprellung (Fühler), Motorsteuerung und die Motorregelung. Die LED-Steuerung hab ich noch von Nicai - die will ich aber auch noch überarbeiten. Das Thema Liniensensoren hab ich noch gar nicht in Angriff genommen...

    Als nächstes habe ich eine ganz andere Geschichte auf dem Programm: Ich habe an den Port mit der USART einen IR-Empfänger angeschlossen und will da erstmal einen RC5-Receiver zusammenschustern. Dann kann man die Biene schön mit einer FB steuern

    Ich habe auch geplant, das ganze auf sourceforge zu veröffentlichen, will mich vorher noch mit Nicai abstimmen. Nicht, dass Herr Springob noch sauer wird...

    Ciao bantyy

Seite 3 von 3 ErsteErste 123

Berechtigungen

  • Neue Themen erstellen: Nein
  • Themen beantworten: Nein
  • Anhänge hochladen: Nein
  • Beiträge bearbeiten: Nein
  •  

12V Akku bauen