- 12V Akku mit 280 Ah bauen         
Seite 1 von 4 123 ... LetzteLetzte
Ergebnis 1 bis 10 von 40

Thema: nibobee IR-Abstandsmessung

  1. #1
    Erfahrener Benutzer Roboter Genie Avatar von pinsel120866
    Registriert seit
    18.12.2007
    Ort
    Hohenems
    Alter
    58
    Beiträge
    847
    Anzeige

    LiFePo4 Akku selber bauen - Video
    Hallo,

    ich möchte euch meine neue Erweiterung zeigen. Es soll eine IR-Abstandmessung werden.

    Ich verwende hierzu 4 Ports:

    - Die Anoden der rechten IR-LEDs hängen mit Vorwiderstand an PA0 (X1-AN0)
    - Die Anoden der linken IR-LEDs hängen mit Vorwiderstand an PA1 (X1-AN1)
    - Die Kathoden beider IR-LEDs sind mit PA3 (X3-AN3) verbunden
    - Der Empfänger SFH5110 ist mit PA2 (X2-AN2) verbunden

    Der Code für das Testprogramm sieht so aus:
    Code:
    #include <nibobee/iodefs.h>
    #include <nibobee/delay.h>
    #include <nibobee/analog.h>
    #include <nibobee/led.h>
    #include <stdlib.h>
    
    #define FALSE 0
    #define TRUE 1
    
    uint8_t objekt_sichtbar_rechts(uint8_t distance_r)
    {
    	uint16_t j,z;
    	
    	PORTA |= (1 << PA0);   // PA0 auf HIGH (LED ausschalten) 
       	DDRA |= (1 << DDA1);   // PA1 als Ausgang
       	PORTA &= ~(1 << PA1);   // PA1 auf LOW
    
    	OCR2  = 254-distance_r;   // wenn OCR2=0xFE dann Objekt sehr nahe 
    	z=0;
    	for(j=0;j<30;j++) // loop time: 5ms
    	{
    		if (PINA & (1 << PA3))z++;
    		delay(6); // 6*Sleep(6)=1ms
    	}
    	if (z>=29) return FALSE; // Objekt nicht gefunden
    	else return TRUE;
    }
    
    uint8_t objekt_sichtbar_links(uint8_t distance_l)
    {
    	uint16_t i,y;
    
    	PORTA |= (1 << PA1);    // PA1 auf HIGH (LED ausschalten)
       	DDRA |= (1 << DDA0);   // PA0 als Ausgang
       	PORTA &= ~(1 << PA0);   // PA0 auf LOW
    
    	OCR2  = 254-distance_l;   // wenn OCR2=0xFE dann Objekt sehr nahe 
    	y=0;
    	for(i=0;i<30;i++) // loop time: 5ms
    	{
    		if (PINA & (1 << PA3))y++;
    		delay(6); // 6*Sleep(6)=1ms
    	}
    	if (y>=29) return FALSE; // Objekt nicht gefunden
    	else return TRUE;
    }
    
    
    
    uint8_t abstand_rechts()
    {
    	uint8_t k,n;
    	
    	k=255;
    	for(n=0;n<8;n++)
    	{
    	  if (!objekt_sichtbar_rechts(n)) k=n; // solange kein Objekt, Distanz erhoehen
    	}  
    	return k;
    }
    
    uint8_t abstand_links()
    {
    	uint8_t l,m;
    	
    	l=255;
    	for(m=0;m<8;m++)
    	{
    	  if (!objekt_sichtbar_links(m)) l=m; // solange kein Objekt, Distanz erhoehen
    	}  
    	return l;
    }
    
    
    
    /*************************************************************************
    
    	Hauptprogramm
    
    *************************************************************************/
    int main(void)
    {
       	led_init();
    	uint8_t n,m;
    
       	while(1)
    	{
    	   	n=abstand_rechts();
    	   	m=abstand_links();
    	   		
    		if ((n!=255) && (m!=255))
    	   	{
    	   		if (n<2) led_set(LED_R_RD, 1);
    			if (m<2) led_set(LED_L_RD, 1);
    
    
    			delay(10);
    		}
    	}
    
    }
    Das Problem ist nur - die IRLEDs leuchten nicht...

    Kann mir jemand helfen?

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

    Ich habe mich noch nicht richtig in dein Programm eingelesen, aber ein paar Punkte stechen mir sofort ins Auge:

    Code:
       PORTA |= (1 << PA0);   // PA0 auf HIGH (LED ausschalten)
          DDRA |= (1 << DDA1);   // PA1 als Ausgang
          PORTA &= ~(1 << PA1);   // PA1 auf LOW
    Wenn die Anoden an PA0/1 angeschlossen sind und die Kathoden an PA3, dann schaltet ein High an PA0 die Led ein. Hier passt dein Kommentar nicht? Wo wird denn PA3 auf Ausgang und Low geschaltet? Wie groß ist der berechnete Strom für PA0/1 und der für PA3? Der SFH5110 benötigt eine Trägerfrequenz für das IR-Signal, wo wird diese erzeugt und auf die IR-LEDs geschaltet?

    Code:
       for(j=0;j<30;j++) // loop time: 5ms
       {
          if (PINA & (1 << PA3))z++;
          delay(6); // 6*Sleep(6)=1ms
    Hoffentlich optimiert der Kompiler die for-Schleife nicht weg, was wird hier an PA3 abgefragt, warum werden aus 1ms plötzlich 6?

    Du solltest den Code mal nur auf eine Seite und das Wesentliche reduzieren und besser kommentieren.

    Ein kleine Beschreibung der Funktion und der Anschlüse im Programmkopf würde das lästige switchen zwischen Editor und Forumbeitrag überflüssig machen...

    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. #3
    Erfahrener Benutzer Roboter Genie Avatar von pinsel120866
    Registriert seit
    18.12.2007
    Ort
    Hohenems
    Alter
    58
    Beiträge
    847
    Hallo,

    danke dass du dir die Mühe gemacht hast, den Code anzusehen.

    Ich habe versucht Anleihen von meiner ASURO-Erweiterung zu nehmenm wo die Anwendung einwandfrei funktioniert hat:https://www.roboternetz.de/phpBB2/ze...427&highlight=

    Als Programmierpflaume ist es mir offensichtlich wieder einmal nicht möglich die Erweiterung richtig zu programmieren.

    Wie erzeuge ich die Trägerfrequenz und lege sie auf die IR-LEDs? Kannst du mir Verbesserungsvorschläge machen?

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

    Bisher war es noch keine Mühe *kicher*

    Hier habe ich gezeigt, wie man die 36kHz (ich nehme mal an, dies ist auch die Frequenz deines SFH) auf die LineLEDs bringt:
    https://www.roboternetz.de/phpBB2/vi...=470683#470683

    Davon brauchst du eigentlich nur das Timersetup:
    Code:
       TCCR2 = (1 << WGM21) | (1 << CS20); // CTC-Mode, no prescaling, no OC2-PIN!
       OCR2  = 208; // 36kHz @15MHz
       TIMSK |= (1 << OCIE2);
    Zwei Halbwellen mit 72kHz, (15000000/72000)-1 sind ca. 208

    Und eine angepasste ISR bei der PA3 mit 72kHz getoggelt wird:
    Code:
    ISR (TIMER2_COMP_vect)
    {
       static uint8_t status=0;
       if(status)
       {
          led_set(LED_R_YE, 1);
          PORTA |= (1<<PA3);
          status=0;
       }
       else
       {
          led_set(LED_R_YE, 0);
          PORTA &= ~(1<<PA3);
          status=1;
       }
    }
    Zusammen sollte das dann ungefähr so funktionieren:
    Code:
    // nibobee IR-LEDs an PA0 und PA1 im Wechsel mit 36kHz ansteuern        10.1.2010 mic
    
    // https://www.roboternetz.de/phpBB2/vi...=479870#479870
    
    // Die Anoden der rechten IR-LEDs hängen mit Vorwiderstand an PA0 (X1-AN0)
    // Die Anoden der linken IR-LEDs hängen mit Vorwiderstand an PA1 (X1-AN1)
    // Die Kathoden beider IR-LEDs sind mit PA3 (X3-AN3) verbunden
    // Der Empfänger SFH5110 ist mit PA2 (X2-AN2) verbunden
    
    #include <nibobee/iodefs.h>
    #include <nibobee/delay.h>
    #include <nibobee/led.h>
    #include <stdlib.h>
    
    #define FALSE 	(1==0)
    #define TRUE 	(1==1)
    
    int main(void)
    {
       led_init();
       delay(2000); // wait4programmer
    
    	// Timer2-Setup für 72kHz
    	TCCR2 = (1 << WGM21) | (1 << CS20); // CTC-Mode, no prescaling, no OC2-PIN!
       OCR2  = 208; // 36kHz @15MHz
    
       DDRA |= (1<<PA1) | (1<<PA0); // Anoden der LEDs mit Vorwiderstand (??? Ohm) an PA0/1
       PORTA &= ~((1<<PA1) | (1<<PA0)); // low = LEDs aus
       DDRA &= ~(1<<PA3); // keine 72kHz-Ansteuerung
       PORTA &= ~(1<<PA3); // deshalb Kathoden-Pin auf Ausgang ohne PullUp
       
       if(TRUE) led_set(0,1); // true-Test ;)
       sei(); // und los
    
       while(1)
    	{
    	   DDRA |= (1<<PA3); 		// Trägerfrequenz an Kathoden einschalten
    	   TIMSK |= (1 << OCIE2);  // ISR aktivieren
    
    		led_set(2,1);
    		PORTA |= (1<<PA0); 		// rechte IR-LEDs einschalten
    	   delay(1000);            // zwei Sekunden mit 36kHz blinken
    	   PORTA &= ~(1<<PA0);     // IR-Leds wieder ausschalten
    	   led_set(2,0);
    
    		led_set(1,1);
    		PORTA |= (1<<PA1); 		// dito für linke IR-LEDs
    	   delay(1000);
    	   PORTA &= ~(1<<PA1);
    	   led_set(1,0);
    	   
    	   TIMSK &= ~(1 << OCIE2);	// ISR ausklinken
    		DDRA &= ~(1<<PA3);      // keine Trägerfrequenz an Kathoden
    	   PORTA &= ~(1<<PA3);     // bedeutet alle IR-LEDS aus
    	   led_set(LED_R_YE, 0);   // Kontroll-LED aus
    	   delay(2000);            // zwei Sekunden dunkel
    	}
    }
    
    ISR (TIMER2_COMP_vect)
    {
       static uint8_t status=0;
       if(status)
       {
          led_set(LED_R_YE, 1); // Kontroll-LED
          PORTA |= (1<<PA3);
          status=0;
       }
       else
       {
          led_set(LED_R_YE, 0);
          PORTA &= ~(1<<PA3);
          status=1;
       }
    }
    Kontrolle mit Digicam, ich kann es natürlich nicht selbst testen. Ein asuro oder RP6 müßte das Signal auch erkennen.

    Das war jetzt etwas Mühe ;)

    btw. ist delay() echter Schrott! Mit dieser ISR könnte man auch die Sleep()-Funktion ala asuro nachbilden.

    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!

  5. #5
    Erfahrener Benutzer Roboter Genie Avatar von pinsel120866
    Registriert seit
    18.12.2007
    Ort
    Hohenems
    Alter
    58
    Beiträge
    847
    Super erklärt Radbruch,

    es funktioniert, die LEDs leuchten. \/

    Danke für deine Mühe!

  6. #6
    Erfahrener Benutzer Roboter Genie Avatar von pinsel120866
    Registriert seit
    18.12.2007
    Ort
    Hohenems
    Alter
    58
    Beiträge
    847
    Nochmals hallo,

    ich habe nun versucht mic's Code in mein Programm einzubauen:
    Code:
    #include <nibobee/iodefs.h>
    #include <nibobee/delay.h>
    #include <nibobee/led.h>
    #include <stdlib.h>
    
    #define FALSE    (1==0)
    #define TRUE    (1==1)
    
    uint8_t objekt_sichtbar_rechts(uint8_t distance_r)
    {
    	uint16_t j,z;
    	
    	PORTA |= (1 << PA0);   // PA0 auf HIGH (LED einschalten) 
       	DDRA |= (1 << DDA1);   // PA1 als Ausgang
       	PORTA &= ~(1 << PA1);   // PA1 auf LOW (andere LED ausschalten)
    
    	OCR2  = 254-distance_r;   // wenn OCR2=0xFE dann Objekt sehr nahe 
    	z=0;
    	for(j=0;j<30;j++) // loop time: 5ms
    	{
    		if (PINA & (1 << PA3))z++;
    		delay(1);
    	}
    	if (z>=29) return FALSE; // Objekt nicht gefunden
    	else return TRUE;
    }
    
    uint8_t objekt_sichtbar_links(uint8_t distance_l)
    {
    	uint16_t i,y;
    
    	PORTA |= (1 << PA1);    // PA1 auf HIGH (LED einschalten)
       	DDRA |= (1 << DDA0);   // PA0 als Ausgang
       	PORTA &= ~(1 << PA0);   // PA0 auf LOW (andere LED ausschalten)
    
    	OCR2  = 254-distance_l;   // wenn OCR2=0xFE dann Objekt sehr nahe 
    	y=0;
    	for(i=0;i<30;i++) // loop time: 5ms
    	{
    		if (PINA & (1 << PA3))y++;
    		delay(1);
    	}
    	if (y>=29) return FALSE; // Objekt nicht gefunden
    	else return TRUE;
    }
    
    
    
    uint8_t abstand_rechts()
    {
    	uint8_t k,n;
    	
    	k=255;
    	for(n=0;n<8;n++)
    	{
    	  if (!objekt_sichtbar_rechts(n)) k=n; // solange kein Objekt, Distanz erhoehen
    	}  
    	return k;
    }
    
    uint8_t abstand_links()
    {
    	uint8_t l,m;
    	
    	l=255;
    	for(m=0;m<8;m++)
    	{
    	  if (!objekt_sichtbar_links(m)) l=m; // solange kein Objekt, Distanz erhoehen
    	}  
    	return l;
    }
    
    /*************************************************************************
    
    	Hauptprogramm
    
    *************************************************************************/
    int main(void)
    {
       	led_init();
    	uint8_t n,m;
    
       delay(2000); // wait4programmer
    
       if(TRUE) led_set(0,1); // true-Test ;)
       sei(); // und los
    
       	while(1)
    	{
    	   // Timer2-Setup für 72kHz
    	   TCCR2 = (1 << WGM21) | (1 << CS20); // CTC-Mode, no prescaling, no OC2-PIN!
    	   OCR2  = 208; // 36kHz @15MHz
    
    	   DDRA |= (1<<PA1) | (1<<PA0); // Anoden der LEDs mit Vorwiderstand (??? Ohm) an PA0/1
    	   PORTA &= ~((1<<PA1) | (1<<PA0)); // low = LEDs aus
    	   DDRA &= ~(1<<PA3); // keine 72kHz-Ansteuerung
    	   PORTA &= ~(1<<PA3); // deshalb Kathoden-Pin auf Ausgang ohne PullUp
    
    	   	n=abstand_rechts();
    	   	m=abstand_links();
    	   		
    		if ((n!=255) && (m!=255))
    	   	{
    	   		if (n<2) led_set(LED_R_RD, 1);
    			if (m<2) led_set(LED_L_RD, 1);
    
    
    			delay(10);
    		}
    	}
    }
    
    ISR (TIMER2_COMP_vect)
    {
       static uint8_t status=0;
       if(status)
       {
          led_set(LED_R_YE, 1); // Kontroll-LED
          PORTA |= (1<<PA3);
          status=0;
       }
       else
       {
          led_set(LED_R_YE, 0);
          PORTA &= ~(1<<PA3);
          status=1;
       }
    }
    Wenn sich von links oder rechts ein Gegenstand nähert, soll die linke oder rechte rote LED leuchten.
    Leider funktioniert der Code wieder nicht, was ist nun jetzt wieder falsch?

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

    Das wird so nichts, weil die IR-Abstandsmessung nach Waste beim asuro mit variablen Halbwellen der Trägerfrequenz arbeitet. Das ist letzlich die Meisterleistung seiner Modifikation der asuro-Lib bei der IR-Abstandsmessung.

    Wir erzeugen im Moment ein symetrisches Signal bei dem die Impuls- und Pausenzeiten des IR-Signals 50:50 sind. Waste hat den Timer im PWM-Mode betrieben und die Dauer der Halbwellen mit dem OCR2-Register gesteuert. Das kann meine Ansteuerung nicht, weil der OC2-Pin bei der bee zur Motordrehrichtungsansteuerung (PD7, DIR_R) verwendet wird und deshalb nicht zur freien Verfügung steht. (Das ist meiner Meinung nach einer der wenigen Kritikpunkte bei der bee) Um das nachzubilden müßten wir in der ISR zusätzlich eine Software-PWM einbauen. (was natürlich nicht ausschliest, dass wir das noch machen werden;)

    Weil ich deine Erweiterungen (noch) nicht an meiner bee angebaut habe, kann ich weiterhin nur "theoretisch" programmieren. Testen mußt du selbst. Das folgende Programm sendet jeweils auf einer Seite ein IR-Signal, prüft, ob der SFH ein IR-Echo empfängt und zeigt das Ergebniss an den roten Leds an:
    Code:
    // nibobee Einfache Abstandsmessung mit Pinselbee-Umbau               11.1.2010 mic
    
    // Es werden im Wechsel die rechten und linken IR-Leds mit 36kHz angesteuert
    // und jeweils das Echo ausgewertet und an den roten Leds angezeigt.
    // LED3 leuchtet, wenn die ISR aktiv ist.
    
    // https://www.roboternetz.de/phpBB2/vi...=480142#480142
    
    // Die Anoden der rechten IR-LEDs hängen mit Vorwiderstand an PA0 (X1-AN0)
    // Die Anoden der linken IR-LEDs hängen mit Vorwiderstand an PA1 (X1-AN1)
    // Die Kathoden beider IR-LEDs sind mit PA3 (X3-AN3) verbunden
    // Der Empfänger SFH5110 ist mit PA2 (X2-AN2) verbunden
    
    #include <nibobee/iodefs.h>
    #include <nibobee/delay.h>
    #include <nibobee/led.h>
    #include <stdlib.h>
    
    #define FALSE	(1==0)
    #define TRUE	(1==1)
    
    uint8_t detect_right(void)
    {
    	uint8_t echo;
    
    	DDRA |= (1<<PA3); 		// Trägerfrequenz an Kathoden einschalten
    	TIMSK |= (1 << OCIE2);  // ISR aktivieren
    
    	PORTA |= (1<<PA0); 		// rechte IR-LEDs einschalten
    	delay(1);            	// 36 IR-Impulse senden (10 sollten dem SFH genügen) ???
    	//delay(10);            // delay(1) ist nicht immer 1/1000 Sek!!!
    
       // SFH Ausgang wird low, wenn er Trägersignal erkennt => echo ist true ;)
    	echo=((PINA & (1<<PA2)) == 0);   // SFH hängt an PA2
    
    	PORTA &= ~(1<<PA0);     // IR-Leds wieder ausschalten
    	TIMSK &= ~(1 << OCIE2);	// ISR ausklinken
    	DDRA &= ~(1<<PA3);      // keine Trägerfrequenz an Kathoden
    	PORTA &= ~(1<<PA3);     // bedeutet alle IR-LEDS aus
    	led_set(LED_R_YE, 0);   // ISR-Kontroll-LED aus
    	return(echo);
    }
    
    uint8_t detect_left(void)
    {
    	uint8_t echo;
    
    	DDRA |= (1<<PA3);       // 36kHz-Trägersignal senden
    	TIMSK |= (1 << OCIE2);
    
    	PORTA |= (1<<PA1);
    	delay(1);
    	//delay(10);
    
    	echo=((PINA & (1<<PA2)) == 0);   // Echo empfangen?
    
    	PORTA &= ~(1<<PA1);     // Trägersignal ausschalten
    	TIMSK &= ~(1 << OCIE2);
    	DDRA &= ~(1<<PA3);
    	PORTA &= ~(1<<PA3);
    	led_set(LED_R_YE, 0);
    	return(echo);
    }
    
    int main(void)
    {
       led_init();
       PORTB |= 15; 	// alle LEDs an
       delay(2000); 	// wait4programmer
       PORTB &= ~15;	// alle LEDs aus
    
    	// Timer2-Setup für 72kHz
    	TCCR2 = (1 << WGM21) | (1 << CS20); // CTC-Mode, no prescaling, no OC2-PIN!
       OCR2  = 208; // 36kHz @15MHz
    
       DDRA |= (1<<PA1) | (1<<PA0); // Anoden der LEDs mit Vorwiderstand an PA0/1
       PORTA &= ~((1<<PA1) | (1<<PA0)); // low = LEDs aus
       DDRA &= ~(1<<PA3); // keine 72kHz-Ansteuerung
       PORTA &= ~(1<<PA3); // deshalb Kathoden-Pin auf Ausgang ohne PullUp
       
       if(TRUE) led_set(0,1); // true-Test ;)
       sei(); // und los
    
       while(1)
    	{
    	   if(detect_right()) led_set(2,1); else led_set(2,0);
    	   if(detect_left()) led_set(1,1); else led_set(1,0);
    	   delay(1000);
    	}
    }
    
    ISR (TIMER2_COMP_vect)
    {
       static uint8_t status=0;
       if(status)
       {
          led_set(LED_R_YE, 1); // Kontroll-LED
          PORTA |= (1<<PA3);
          status=0;
       }
       else
       {
          led_set(LED_R_YE, 0);
          PORTA &= ~(1<<PA3);
          status=1;
       }
    }
    Der SFH reagiert nach ca. 10 Signalwellen auf eine IR-Trägerfrequenz. Wir senden jeweils ca. 36 Wellen (mit dem schrottigen delay() gemessen) und prüfen dann, ob der SFH etwas erkannt hat. Das funktioniert vermutlich nur zufriedenstellend, wenn die IR-Leds eine deutliche Richtungswirkung haben. Das kann man z.B. mit Schrumpfschläuchen (wie beim Probot) über den Leds erreichen.

    Ob das Programm wie erwartet fumktioniert mußt du testen. Bei meiner bee ohne deine Erweiterung ist der X3-Slot nicht belegt und die PA2/3-Pins hängen frei in der Luft. Deshalb kann ich mit dem Daumen eine Brücke zwischen GND und PA2 machen und so einen SFH-Empfang simulieren ;)

    Wie groß sind eigentlich die Vorwiderstände der IR-LEDs? Vorsichtshalber sollten nie beide Seiten eingeschaltet sein um eine Überlastung von PA3 zu vermeiden.

    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!

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

    Weil ich ja schon immer mal etwas mit einer PWM-Ansteuerung spielen wollte, habe ich mal Grundlagenforschung betrieben. Ich denke, obwohl das folgende noch Betastatus ist, hat es sich gelohnt. Meine bee kann jetzt ein pulsweitenmoduliertes 36kHz-IR-Signal erzeugen und es mit den LineLEDs abstrahlen.

    Basis ist der Timer2 der im Phase-Correct-PWM-Mode betrieben wird. Das hört sich zwar übelst kompliziert an, ist aber eigentlich ganz einfach;) Anders als in den "normalen" Modi zählt hier der Counter von null bis 255 und dann wieder zurück nach null. Wenn er beim Runterzählen bei null angekommen ist, wird der Overflow-Interrupt ausgelöst und der Zyklus beginnt erneut. Deshalb dauert in dieser Betriebsart ein Zyklus 512 Countertakte (Das genaue Timing muss ich noch überprüfen)

    Um nun auf die 36kHz zu kommen, benötigt man bei der bee 15MHz/36kHz=416,irgendwas Takte. Deshalb verwende ich den selben Trick wie Waste beim asuro und lade das Zählregister in der Overflow-ISR mit einem neuen Startwert ab dem der Counter dann weiter bis 255 und wieder zurück bis null zählt. Den Wert errechnet man so: 512-416=96. Zusätzlich benötigt man noch 3 Takte für das Laden des Wertes in das Zählregister, damit sind es 99 die in der Overflow-ISR in das Zählregister geladen werden um den 36kHz-Takt zu erzeugen.

    Um nun die IR-LEDs mit dieser Frequenz anzusteuern verwendet man das OCR-Register. Jedesmal, wenn der Zählwert so groß wie der Wert im OCR ist, wird ein CompareMatch-Interrupt ausgelöst. Und zwar jedesmal, wenn die Werte gleich sind, also auch beim Runterzählen. Wenn beim Start des Timers die LED aus ist, wird sie bei OCR eingeschaltet, bleibt an während der Zähler 255 erreicht und brennt dann weiter, bis der Zähler beim Runterzählen wieder OCR erreicht. Dann wird die LED wieder getoggelt, also ausgeschaltet und bleibt solange aus, bis der Zähler nach Erreichen von null und Laden von Startwert in der OVF-ISR den OCR-Wert erneut erreicht. An diesem Punkt ist dann eine Periode beendet.

    Der Wert fürs OCR-Register bestimmt die Hell- und Dunkelanteile einer Periode des Signals. Um 50:50 zu erhalten, muss die LED ca. 208 Takte eingeschaltet und 208 Takte ausgeschaltet sein, also 104 Takte vor 255 einschalten beim Hochzählen und beim Runterzählen auch nach 104 Takten. Das ergibt als Wert für das OCR2-Register 255-104=151. Alle Werte die größer sind, verringern den Leuchtanteil der IR-LEDs, Werte kleiner 100 sind nicht erlaubt. Ebenso funktioniert es bei Werten über 253 nicht mehr.

    Dieses kleine Demo zeigt wie es gemacht wird und wie es funktioniert:
    Code:
    // Nibobee 36kHz mit Timer2 in PhaseCorrect-PWM-Mode.                 12.1.2010 mic
    
    #define LineLEDs_on 		PORTB &=~(1<<PB4)
    #define LineLEDs_off 	PORTB |= (1<<PB4)
    
    #include <nibobee/iodefs.h>
    #include <nibobee/led.h>
    #include <nibobee/sens.h>
    
    volatile uint8_t count36kHz;
    
    void Sleep(uint8_t pause); 
    void Msleep(uint16_t pause); 
    
    int main(void)
    {
    	led_init();
      	sens_init();
    
    	// Setup Timer2
    	TCCR2 = (1 << WGM20)|(1 << CS20); // PhaseCorrect-PWM, no prescaling, no OC2-Pin!
    	TCNT2  = 96; // (512-416) 36kHz @15MHz
    	OCR2 = 151; // (255-(208/2)) 151 ist 50:50 Compare Match für symetrische Halbwellen
    	TIMSK |= (1 << OCIE2)|(1 << TOIE2); // Comp und OVF-ISR enable, Overflow bei Bottom!
    	enable_interrupts();
    
      	Msleep(2000); // wait4programmer
      	led_set(0,1);
    	DDRB |= (1<<PB4); // LineLED ist ein Ausgang
    	LineLEDs_on; 		// LineLED schaltet gegen GND!
    	
    	while(!sens_getLeft() & !sens_getRight()) // solange keine Taste gedrückt wird
    		{Msleep(200); PORTB ^= (1<<PB0);} // hektisches Blinken mit LED0
    
    	while(1)
    	{
    	   if(sens_getLeft() == -1) {OCR2=200; PORTB &= ~15; led_set(0,1);}
    	   if(sens_getLeft() == 1)  {OCR2=230; PORTB &= ~15; led_set(1,1);}
    	   if(sens_getRight() == 1) {OCR2=250; PORTB &= ~15; led_set(2,1);}
    	   if(sens_getRight() == -1){OCR2=253; PORTB &= ~15; led_set(3,1);} // minwert!
    	   Msleep(100);
    	}
    	return(0);
    }
    ISR (TIMER2_COMP_vect)
    {
    	PORTB ^= (1<<PB4); // LineLEDs togglen
    }
    // Frequenzkorrektur 512-416 plus 3 Takte fürs Laden von TCNT2?
    ISR (TIMER2_OVF_vect)
    {
    	TCNT2  = 99;
    	if(count36kHz) count36kHz--;
    }
    
    void Sleep(uint8_t pause) // 1/36000 Pause blockierend
    {
    	count36kHz=pause;
    	while(count36kHz);
    }
    void Msleep(uint16_t pause) // 1/1000 Pause blockierend
    {
    	while(pause--) Sleep(36);
    }
    Zusätzlich ist noch die Sleep()-Funktion eingebaut für die asuro-Umsteiger;) Sie ersetzt hier die delay()-Funktion der nibobee-Lib. Als IR-Detektor dient mein RP6:
    Code:
    // Status des TSOP an LEDs anzeigen                                   12.1.2010 mic
    // Funktion kann einfach mit einer Fernbedienung getestet werden
    
    #include "RP6RobotBaseLib.h"
    
    int main(void)
    {
    	initRobotBase();
    	powerON();
    
    	while(1)
    	{
    	   if(PINB & ACS) setLEDs(1); else setLEDs(63);
    	}
    	return(0); // wird nie erreicht
    }
    Das Video ist dazu ist äzend, ich zeige es nur weil es eben existiert:

    Bild hier  
    http://www.youtube.com/watch?v=Lrj1Xzp791c

    Möglicherweise stimmt das Timing nicht 100%ig. Da ich kein Oszi habe, kann ich das Signal nicht genau ausmessen. Vermutlich passt es nicht Taktgenau (512, 104, 151, 99?), aber es ist offensichtlich innerhalb der TSOP-Toleranz. Grundsätzlich funktioniert das wohl auch mit dem SFH.

    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!

  9. #9
    Erfahrener Benutzer Roboter Genie Avatar von pinsel120866
    Registriert seit
    18.12.2007
    Ort
    Hohenems
    Alter
    58
    Beiträge
    847
    Hi Radbruch,

    du bist ein echter Tüftler - toll wie da an die Sache rangehst.

    Ich habe dein Programm von gestern nun geflasht und beide roten LEDs leuchten durchgehend, sollten die nicht kurz aufleuchten?

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

    Der Status der roten LEDs wird einmal in der Sekunde aktuallisiert. Wenn dann ein IR-Echo erkannt wird, leuchten sie. Getestet habe ich es nicht, weil ich noch keinen IR-Empfänger an meine bee gebaut habe. Wenn du aber den Stecker an X1 (Anoden der Leds) abziehst wird kein Signal gesendet und die roten Led sollten ausgehen. Wenn das funktioniert könntest du deinen SFH (immer noch ohne eingesteckten X1) mit einer Fernbedienung anblinken, die roten Leds sollten dann reagieren (eventuell den delay(1000)-Befehl dazu auskommentieren)

    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!

Seite 1 von 4 123 ... LetzteLetzte

Berechtigungen

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

12V Akku bauen