/* adconv01.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 sendet den gemessenen Wert eines A/D Pins per Infrarot an mein IR-LCD.
Welcher A/D Port benutzt wird, lässt sich vom IR-LCD aus einstellen (1. und 2. Taste des IR-LCD).
Mit der 3. Taste (IR-LCD) wird ein ein Messwert zu diesem übertragen.
Wird Taste 3 zusamme nit Taste 4 gedrückt, überträgt das Program dauerhaft A/D Werte zum IR-LCD.
Dieser Modus lässt sich nur durch drücken des Tasters an PIND4 (Universalbox1) verlassen, da
das IR-LCD nicht senden kann, solange die Universalbox1 selber sendet.


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
u16 adwert;
u08 adpin;
u08 endless;

//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
warte(20000);
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


void adwandlung(u08 kanal) { //führt eine AD Wandlung auf dem übergebendem Pin durch (proceeds an AD conversion)
outp(kanal, ADMUX); //Kanal wählen (select AD channel)
outp(inp(ADCSR) | BV(ADSC), ADCSR); //setzt das ADSC Bit, aus (set the ADSC Bit, from): www.mikrocontroller.net/forum/read-1-2718.html#2761
while (inp(ADCSR) & BV(ADSC));      //wartet, bis die Wandlung komplett ist (waits until the conversion is complete)
temp01 = ADCW;     //das Ergebnis der Wandlung wird in temp01 geschrieben (the result of the conversion is written into temp01)
}

void schreibead(void) {
adwandlung(adpin);
adwert = temp01;
//zweite zeile
sendebuff = 0xd*4;
zumsenden();
sendebuff = ((adwert / 1000)+48)*4;
zumsenden();
sendebuff = (((adwert / 100) % 10)+48)*4;
zumsenden();
sendebuff = (((adwert / 10) % 10)+48)*4;
zumsenden();
sendebuff = ((adwert % 10)+ 48)*4;
zumsenden();
}

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)
//initialisiert die ad wandler
outp(BV(ADEN) | BV(ADSC) | BV(ADPS0) | BV(ADPS1) | BV(ADPS2), ADCSR);
while (inp(ADCSR) & BV(ADSC));//wartet, bis der erste Konvertierung komplett ist (wait until the first conversion is done)
sei();         //Aktiviert Interrupts
//------------------------------------------------------------------------------------------------------------------------------
//--------------------------------------------------Die Endlosschleife, der Code------------------------------------------------
//------------------------------------------------------------------------------------------------------------------------------
for (;;) {

temp02 = empfang; //um zu verhindern, dass sich die Variable "empfang" zwischen Vergleichen und Senden ändert
if ((temp02 | 0x3c) == 0xbd) {
endless = 0;
empfang = 0; //Byte löschen um Empfangsmodus zu verlassen
commode = 0; //Empfangsmodus verlassen
cbi(PORTB,2);//Status LED aus
temp02 = temp02 & 0x3c;//extrahiere taster
if (temp02 == 0x20) {
adpin++;
}
if (temp02 == 0x10) {
adpin--;
}
if (adpin == 255) {
  adpin = 5;
}
if (adpin == 6) {
adpin = 0;
}
warte(60000);
warte(60000);
if ((temp02 == 0x10) || (temp02 == 0x20)) {
sendebuff = 137*4;//cls
zumsenden();
sendebuff = 136*4;//return home,
zumsenden();
sendebuff = 65*4; //A
zumsenden();
sendebuff = 47*4; ///
zumsenden();
sendebuff = 68*4; //D
zumsenden();
sendebuff = 32*4; //
zumsenden();
sendebuff = 80*4; //P
zumsenden();
sendebuff = 111*4; //o
zumsenden();
sendebuff = 114*4; //r
zumsenden();
sendebuff = 116*4; //t
zumsenden();
sendebuff = 58*4; //:
zumsenden();
sendebuff = 32*4; //
zumsenden();
sendebuff = (adpin +48)*4;
zumsenden();
}
if (temp02 == 0x04) { //empfange ad wert
schreibead();
}
if (temp02 == 0x0c) { //dauersenden
endless = 1;

}
//outp(temp02,UDR);
}// ende, was empfangen
if (bit_is_set(PIND,4)) {
endless = 0;
}
if (endless == 1) {
schreibead();
}
}//ende endlosschleife
}

