Hallo
Dann testen wir mal ob ich die Funktion kapiert habe:
Der TSOP IC2 (=IR-Empfänger) des asuro reagiert auf IR-Signale die mit 36kHz moduliert sind (es gibt auch welche für andere Frequenzen) und ist an Port PD0 des Mega8 angeschlossen. Die IR-LED D10 liegt mit der Anode an PB3 und mit der Kathode an PD1. Sie leuchtet, wenn PD1 ein auf low geschalteter Ausgang ist und an PB3 gleichzeitig ein high ausgegeben wird. (Senden mit dem USART muss mit "UCSRB = 0;" ausgeschaltet sein, sonst hat man keine Kontrolle über PD1!)
"Zufällig" ist PB3 auch der Ausgangspin OC2 des Timer2. Deshalb wird der Timer so parametriert, dass er 36000 mal pro Sekunde den Ausgang auf high schaltet und ebensooft wieder auf low. Das ergibt dann eine Trägerfrequenz von 36kHz mit der die LED blinkt, wenn gleichzeitig PD1 ein low ausgibt.
Dieser Absatz erklärt, wie das Timersetup funktioniert, das ist für das Verständniss der IR-Abstandsmessung nicht so wichtig: Beim Start des Counters wird der OC2-Pin auf low gesetzt, beim Erreichen des Wertes im OCR2-Register wird der OC2-Pin nach high umgeschaltet. Der Counter zählt dann weiter bis zum Überlauf, dann wird das Zählregister wieder auf null gesetzt und die Overflow-ISR angesprungen. Bei 8MHz dauert eine 36Khz-Periode ca. 222 Zähltakte, wenn man für den Counter keinen Prescaler verwendet. Beim Berechen des Counterstartwertes und des Umschaltpunktes setzt man nun am Besten am Ende einer Periode beim Überlauf des Zählregisters an. Für 111 Takte vor dem Überlauf muss man den Wert im OCR2-Register auf 256-111=145 oder 0x91 setzen, 222 Takte davor muss das Zählregister starten. Für das Laden des Zählregisters braucht man noch zusätzliche drei Takte: 256-222+3=37 oder 0x25. Die betreffenden Zeilen im Timersetup in asuro.c:
Code:
Im Init():
OCR2 = 0x91; // duty cycle for 36kHz
In der ISR:
SIGNAL (SIG_OVERFLOW2)
{
TCNT2 += 0x25;
...
Das += bewirkt, dass inzwischen schon erfolgte Zähltakte nicht ignoriert werden.
Der TSOP erkennt nach maximal 12 Pegelwechseln der IR-LED, dass er angeblinkt wird und schaltet dann seinen Ausgang auf low. Dabei unterscheidet er weder zwischen direkter oder indirekter Einstrahlung, noch erkennt er den Abstand zu einem reflektierenden Gegenstand. Allerdings wird ein sich weiter entfernender Gegenstand irgendwann mal nicht mehr erkannt, weil die Menge an nutzbarem reflektiertem Signal für den TSOP zuwenig wird. Und genau hier setzt waste mit seinem Setup des Timers an: Man verkleinert den Signalanteil der Trägerfrequenz durch Veränderung des Impuls-Pauseverhältnisses. Das erreicht man durch Änderung des OCR2-Wertes. Je näher dieser Wert an 256 liegt, umso kürzer ist die Leuchtzeit der LED und umso näher muss sich ein Gegenstand befinden, wenn man ihn erkennen möchte.
Beim eigentlichen Scanvorgang ändert man den Wert in OCR2, wartet kurz (12 Flanken sind 6 Perioden oder Sleep(6) ;) und prüft dann den Eingangspin PD0:
OCR2 = 0xFE;
if (PIND & (1 << PD0)) ....
Bei der IR-Kommunikation muss das OCR2-Register wieder auf den normalen Wert gesetzt werden:
Code:
if (sw)
{
OCR2 = 0x91;
PrintInt(sw);
SerPrint(" ");
PrintInt(ocr2);
SerPrint("\r\n");
}
Achtung! Dabei wird der USART wieder eingeschaltet und kontrolliert PD1!
Uff. Willkommen im RN-Forum.
Gruß
mic
[Edit]Ungetestet:
Code:
/*******************************************************************************
*
* Description: Asuro IR-Detektor Testprogramm
*
*****************************************************************************/
/***************************************************************************
* *
* This program is free software; you can redistribute it and/or modify *
* it under the terms of the GNU General Public License as published by *
* the Free Software Foundation; either version 2 of the License, or *
* any later version. *
***************************************************************************/
#include "asuro.h"
#include <stdlib.h>
static unsigned char ocr2 = 0x91; // Wert für 50:50 Pulsweite laden
void InitIRDetect(void)
{
UCSRB = 0; // USART ausschalten
DDRD |= (1 << DDD1); // Port D1 als Ausgang
PORTD &= ~(1 << PD1); // PD1 auf LOW
}
void InitUart(void)
{
OCR2 = 0x91; // duty cycle fuer 36kHz
}
int main(void)
{
unsigned char sw;
Init(); // Library initialisieren
InitIRDetect(); // IR-Funktion initialisieren
while (1)
{
OCR2 = ocr2; // Puls-Pause-Verhältniss setzen
Sleep(10); // kurz warten bis TSOP genügend Flanken erkennt
if (PIND & (1 << PD0)) // TSOP-Eingang auf IR Echo überprüfen
StatusLED(GREEN); // kein Echo
else
StatusLED(RED); // Echo!
sw = PollSwitch();
if (sw & 0x01) // K6 neben Schalter
ocr2 = 0xFE; //Pulsbreite 1
if (sw & 0x02)
ocr2 = 0xFD; //Pulsbreite 2
if (sw & 0x04)
ocr2 = 0xFB; //Pulsbreite 4
if (sw & 0x08)
ocr2 = 0xF7; //Pulsbreite 8
if (sw & 0x10)
ocr2 = 0xEF; //Pulsbreite 16
if (sw & 0x20)
ocr2 = 0x90; //Pulsbreite 110
if (sw) // bei Tastendruck Wert zum Terminal senden
{
InitUart(); // Pulsbreite für IR-Kommunikation setzen
PrintInt(sw);
SerWrite(" ",1);
PrintInt(ocr2);
SerWrite("\r\n",2);
InitIRDetect(); // Abstandsmessung aktivieren
Msleep(100);
}
}
return 0;
}
Lesezeichen