/* irsend03.c für Universalbox1
(c) 2003 by Malte Marwedel, www.marwedels.de/malte, m.marwedel@onlinehome.de
Diese Datei darf frei kopiert und compiliert werden.
It's allowed to copy and compile this file freely.
Änderungen an der Datei sind erlaubt, solange kenntlich gemacht wird,
dass es sich dann nicht mehr um die original Datei handelt.
It's allowed to modify this file as long it is mentioned that it isn't the original
file any longer.
Es muss immer erkennbar sein, dass die original Datei von mir stammt
It must always be recognizable that the original file is written by me
Die Benutzung des Programmes erfolgt auf eigene Gefahr, ich hafte nicht für Schäden jeglicher art, falls dieses Programm welche verursachen sollte.
The use of this program it at your own risk, I'm not responsible for damage of any kind, if this program should cause which.
Sie sollten das programm nur benutzen, wenn sie es auch verstehen.
You should only use the program, if you understand it.
Programm für gcc, MCU: AT90S4433, 8MHZ Quarz
Program for gcc, MCU AT90S4433 with a frequency of 8MHZ
Zum Kompilieren habe ich winavr20030913 verwendet, Optimierung -O2
I've used winavr20030913 for compiling, optimization -O2

Das Program nimmt Daten der RS232 Schnittstelle entgegen und sendet diese per Infrarot.
Zusätzlich nimmt es Daten per IR Empfänger entgegen und sendet diese per RS232 Schnittstelle
Die Modulation des IR Senders erfolgt mir 38khz
Das Programm ist das Gegenstück für mein IR LCD Projekt.

Anschlussbelegung:
PINB0 : output, LED
PINB2 : output, LED
PIND6 : input, IR Empfänger TSOP 1736
PIND7 : output, IR LED
PIND5 : input, Öffner
PIND4 : input, Schließer
PIND0 : input, RS232 Empfänger
PIND1 : output, RS232 Sender

*/

#include <io.h>
#include <inttypes.h>
#include <interrupt.h>
#include <sig-avr.h>

typedef unsigned char  u08;
typedef unsigned short u16;

u08 volatile commode;//senden oder empfangen oder warten
u08 volatile sende; //ob IRLED an oder aus ist
u16 volatile sendebuff;//was gesendet werden soll
u08 volatile senddurch;//Syncronisation zwischen Hauptschleife und Timer0
u16 volatile temp01;//temonäre Variable
u08 volatile empdurch;
u08 volatile precalc;
u08 volatile empfang;
u08 volatile temp02;//temonäre Variable

//Empfänger
SIGNAL(SIG_OVERFLOW1) {//Timer abfrage
//wird c.a. 703 mal pro sec ausgeführt
//c.a. 140,6 mal pro sec gibt es ein neues Bit
//Ausführung erfolgt also alle 11379 Takte (bei8 MHZ Chip Frequenz)
//der Timer1 läuft immer, es sei denn, es werden selber von dem Device Daten per IR gesendet
//256² - 11379 = 54157 ; theorethischer Wert
//51312, hat sich optimal herausgestellt

if (commode == 0) { //wenn auf empfang gewartet wird,
if bit_is_clear(PIND,6) {//gehe in Empfangsmodus
commode = 1;
empdurch = 0;
precalc = 0;
empfang = 0;
sbi(PORTB,2); //Status LED an
}
}
if (commode == 1){
if bit_is_clear(PIND,6) {//wenn eins, dann erhöhen
precalc++;
}
if (empdurch == 5) { //wenn 5 Sampels
//least sicnificant bit wird zuerst gesendet
empfang = empfang /2;
if (precalc > 2) { //wenn eins empfangen
empfang = empfang | 0x80;//oberstes Bit setzen
}

precalc = 0;
empdurch = 0;
if (empfang == 0) { //ende der Übertragung
commode = 0;
cbi(PORTB,2);//Status LED aus
}
}//ende wenn 5 Samples
empdurch++;
}//ende wenn empfangsmode
outp(0xc8,TCNT1H);//Das hohe Bit muss zuerst beschrieben werden
outp(0x00,TCNT1L);//51200

}

//Sender
SIGNAL(SIG_OVERFLOW0) { //erzeugt 38khz für einen TSOP1738, 8MHZ Takt, AT90S4433
//die IR LED ist 1/5 der Zeit an (nop Befehle), die Restlichen 4/5 aus (Program Abarbeitung)
outp(89,TCNT0); //setzt den Timer0 auf 89, für ein genaues 38khz Timing.
outp(sende,PORTD);//Verhältnis von 1 an zu 4 aus, 33 nops (ein)
                  //Da einzig der PIND7 als Ausgang definiert ist, darf ruhig der komplette PORTD auf H gesetzt werden
 asm volatile("nop");
 asm volatile("nop");
 asm volatile("nop");
 asm volatile("nop");
 asm volatile("nop");
 asm volatile("nop");
 asm volatile("nop");
 asm volatile("nop");
 asm volatile("nop");
 asm volatile("nop");
 asm volatile("nop");
 asm volatile("nop");
 asm volatile("nop");
 asm volatile("nop");
 asm volatile("nop");
 asm volatile("nop");
 asm volatile("nop");
 asm volatile("nop");
 asm volatile("nop");
 asm volatile("nop");
 asm volatile("nop");
 asm volatile("nop");
 asm volatile("nop");
 asm volatile("nop");
 asm volatile("nop");
 asm volatile("nop");
 asm volatile("nop");
 asm volatile("nop");
 asm volatile("nop");
 asm volatile("nop");
 asm volatile("nop");
 asm volatile("nop");
 asm volatile("nop");

//while (inp(TCNT0) < 122){ //wartet 33 (122-89) takte ab, ermöglicht code bis zu 30 taken Länge auszuführen und spart 72 Byte ROM gegenüber reinen 33 nops
//asm volatile("nop");
//}
outp(0,PORTD);//wieder aus
senddurch++;
}

void warte(u16 zeit) { //warte 2857~20ms
temp01 = 0;
while (temp01 < zeit){
  temp01++;
}
}

void zumsenden(void) { //Sendet die Daten an den Empfänger
if (commode == 0) {//es wird grade nicht empfangen
if (sendebuff > 0) {//RS 232 Wert empfangen
sbi(PORTB,0); //Status LED an
outp(0,TCCR1B);//stoppt den Timer1 (stop timer)
//sendetechnik b10DDDDDDDDDDDD01
sendebuff = sendebuff | 0x8001;
//starte Timer0
senddurch = 1;
outp(0,   TCNT0); //setzt den Timer0 auf null (reset timer0)
outp(1,   TCCR0); //startet den Timer0 (start timer0)
while (sendebuff > 0) { //schiebt Bit für Bit nach draußen
if ((sendebuff & 1) == 0) { //wenn Bit null, setze Ausgang
sende = 0;
}else { //wenn bit eins
sende = 0xff;
}
sendebuff = sendebuff /2;
while (senddurch != 0) {
asm volatile("nop");
}//Warteschleife
senddurch++;//höhere Transferraten führten zu Fehlern auf Empfängerseite
}//ende Bit für Bit schieben
outp(0,   TCCR0); //stoppt den Timer0 (stop timer0)
sende = 0; //nur zur Sicherheit
warte(20000); //damit der Empfänger Zeit hat, die Daten zu verarbeiten
outp(1,TCCR1B);//startet den Timer1 (start timer1)
cbi(PORTB,0);//Status LED aus
}//ende RS232 Wert empfangen
}//ende, nicht empfangen
}//ende Prozedur


int main( void ) {
outp(0xff,DDRB);
outp(0x80,DDRD);//setzt portd7 als Ausgang
outp(0x82,TIMSK);//aktiviert Timer0 und Timer1 Interrupt
outp(52,UBRR);   //52 Bedeutet 9600 Baud bei 8MHZ Quarz und eine Abweichung von 0,2%
sbi(UCSRB,RXEN); //Aktiviert den UART Empfänger (Setzt Bit RXEN im 8 Bit Register UCSRB auf 1)
sbi(UCSRB,TXEN); //Aktiviert den UART Sender (Setzt BIT TXEN im 8 Bit Register UCSRB auf 1)
outp(0,TCNT1H);//Das hohe Bit muss zuerst beschrieben werden
outp(0,TCNT1L);
outp(1,TCCR1B);//startet den Timer1 (start timer)
sei();         //Aktiviert Interrupts
for (;;) {
if (bit_is_set(UCSRA,RXC)){
       sendebuff = inp(UDR)*4;
}
if bit_is_clear(PIND,5) {  //Taster (öffner), sendet ein Testsignal
sendebuff = 0x2740; //b0010011101000000
warte(30000);
}
temp02 = empfang; //um zu verhindern, dass sich die Variable "empfang" zwischen Vergleichen und Senden ändert
if ((temp02 | 0x3c) == 0xbd) {
empfang = 0; //Byte löschen um Empfangsmodus zu verlassen
commode = 0; //Empfangsmodus verlassen
cbi(PORTB,2);//Status LED aus
outp(temp02,UDR);
}
zumsenden();

}
}

