#include <16F819.h> 
#pragma sharedAllocation 
void Delay1ms( uns16 ms); 
void pause(void); 
void senden(char DATAUS); 
char empfang(void); 
void EEPROMWR(char adresse,char Data); 
char EEPROMRD(char adresse); 
void SerString(const char *__putstr); 
#pragma config |= 0b.10.1111.0000.0010 
#pragma bit Opin @ PORTA.0                  // Ausgang für serielle Daten definieren 

#pragma bit Ipin @ PORTA.1                  // Eingang für serielle Daten definieren 
void main(void){ 
    int data[3]; 
    char state[8]; 
    uns8 speicher; 
    int i; 
    bit io; 
    ADCON1= 0b.0000.0110; 
    TRISA = 0b.0000.0010;                 //Bit0 des PortA ist serielle Ausgang 
    TRISB = 0b.0000.0000; 
    speicher=EEPROMRD(0x00);              //Zustand nach Neustart aus dem EEPROM lesen 
    PORTB=speicher;                //und setzten 
    for(i=0;i<=7;i++){ 
        state[i]=(speicher % 2)+48; 
        speicher=speicher >>1; 
    } 
    start:    
    data[0]=empfang();                //Date empfangen und entscheiden was angekommen ist 
    if (data[0] == 83){               //Bei einem 'S' auf weitere Bytes warten 
                        Delay1ms(10); 
                        data[1]=empfang(); 
                        Delay1ms(10); 
                        data[2]=empfang(); 
                        switch(data[2]){ 
                                case 48: io=0;break; 
                                case 49: io=1;break; 
                                } 
                        switch(data[1]){      //Die Ports setzten 
                                case 65: PORTB.0=io;state[0]=io+48; break; 
                                case 66: PORTB.1=io;state[1]=io+48; break; 
                                case 67: PORTB.2=io;state[2]=io+48; break; 
                                case 68: PORTB.3=io;state[3]=io+48; break; 
                                case 69: PORTB.4=io;state[4]=io+48; break; 
                                case 70: PORTB.5=io;state[5]=io+48; break; 
                                case 71: PORTB.6=io;state[6]=io+48; break; 
                                case 72: PORTB.7=io;state[7]=io+48; break; 
                                } 
                        if (EEPROMRD(0x00)!= PORTB)EEPROMWR(0x00,PORTB);//Neuen Zustand in das EEPROM schreiben 
                        Delay1ms(10);          
                        } 
    else if(data[0] == 71){            //Bei 'G' kurz warten und dann die Zustände einzeln verschicken 
                        Delay1ms(500); 
                        for(i=0;i<=7;i++){ 
                            senden(i+65); 
                            Delay1ms(80); 
                            SerString("\n");
                            Delay1ms(80);
                            senden(state[i]); 
                            Delay1ms(80); 
                            SerString("\n");
                            Delay1ms(80); 
                            } 
                        senden(0x39);         //und mit 'G' quittieren 
                        SerString("\n");  
                        }    
    goto start; 
} 


//++++++++++++++++++++++ Ende des Hauptprogramms  +++++++++++++++++++++++++++++++++++++++++ 

void Delay1ms( uns16 ms) 
{ 
while(ms)               // Schleife verlassen wen ms=0 ist 
    { 
    OPTION = 2;         // Vorteiler auf 8 einstellen 
    TMR0 = 131;         // 125 * 8 = 1000 (= 1 ms) 
    while (TMR0);       // abwarten einer Milisekunde 
    ms--;               // "ms" mit jeder Milisekunde ernidrigen 
    } 
} 


void pause(void) 
 { 
 char ZAEHL ; 
 char tau ; 
 tau=0x1F; 
    #asm 
        movf    tau,w               ; Pause von ein Bit-Dauer 
        movwf   ZAEHL               ; (104)32*3=96+4=100mks 
wdh1    decfsz  ZAEHL,f 
        goto    wdh1 
    #endasm 
 } 

void pause1(void) 
 { 
 char ZAEHL ; 
 char tau ; 
 tau=0xF; 
    #asm 
        movf    tau,w       ; Start-Pause Halbe Bit-Dauer 
        movwf   ZAEHL       ; 34 mks 
wdh2    decfsz  ZAEHL,f 
        goto    wdh2 
    #endasm 
 } 
//++++++++++++++++++++++ Daten senden  +++++++++++++++++++++++++++++++++++++++++ 
void senden(char DATAUS) 
{ 
char BIT ; 
    #asm 
        movlw   08              ; 8 Bit 
        movwf   BIT             ; Bitzaehler mit 8 laden 
        comf    DATAUS,f        ; Zusendende Byte Invertieren(weil kein hardwahre Invertor da ist) 
        bsf     Opin            ; Startbit = 1 
        call    pause 
wdh4    rrf     DATAUS,f        ; Register mit Daten wird rechts rotiert(ganz rechte Bit wird in Carry geschoben) 
        btfss   STATUS,Carry    ; Carrybit pruefen 
        goto    setzen          ; Carrybit = 0: Setzen ueberspriengen 
        bsf     Opin            ; Carrybit = 1: Seriele AusgangsPin setzen (5V) 
        goto    weiter 
setzen  bcf     Opin            ; Seriele Pin ruecksetzen (0V) 
weiter  call    pause           ; warte 64 mks 
        decfsz  BIT,f           ; Bitzaehler runterzaehlen 
        goto    wdh4            ; Wiederholen 8 mal 
        bcf     Opin            ; Stoppbit = 0, einstellen stopbit 
        call    pause           ; warte 64 mks 
        nop 
    #endasm 
} 
//++++++++++++++++++++++ Daten empfangen  +++++++++++++++++++++++++++++++++++++++++ 
char empfang(void) 
{ 
char DATAUS; 
char BIT; 
    #asm 

strtbit     btfss   Ipin        ; Ueberpruefen auf Start-bit = 0 
            goto    strtbit     ; warte bis es 1 wird 
            call    pause1      ; warte Halbe Bit-Dauer damit Werterfassung in der mitte des impulses passiert 
            btfss   Ipin        ; Start-bit immer noch = 0, alles von anfang(2 prüfung des startimpulses 
            goto    strtbit     ; is dafuer, damit kein zufaelige Impuls der Einleseforgang startet) 
            movlw   08          ; 
            movwf   BIT         ; Bitzaehler mit 8 laden 
            clrf    DATAUS      ; Variable leern 
empfg       call    pause       ; warten 64 mks (damit sind wir in der mitte des Datenbits) 
            rrf     DATAUS,f    ; Rechts Schieben 
            bsf     DATAUS,7    ; Immer Bit7 setzen 
            btfss   Ipin 
            bcf     DATAUS,7    ; falls am Eingang Bit=0, Bit7 ruecksetzen 
            decfsz  BIT,f       ; 8 Bits abzaehlen 
            goto    empfg       ; Wenn noch nicht abgezaehlt,naechste Bit empfangen 
            call    pause       ; Warten wegen Stoppbits 
            comf    DATAUS,f    ; Inwertiren empfangene Byte 
        #endasm 
 return (DATAUS); 
} 
//++++++++++++++++++++++ EEPROM SCHREIBEN  +++++++++++++++++++++++++++++++++++++++++ 
void EEPROMWR(char adresse,char Data){ 

    EEADR = adresse;        // Adresse in Adressregister übertragen 
    EEDATA = Data;          // Daten in Datenregister übertragen 
    EEPGD=0;                // Auswahl: Programmspeicher lesen oder EEPROM 
    WREN=1;                 // Schreiben ins EEPROM erlauben 
    GIE=0;                  // Interrups verbieten 
    EECON2=0x55; 
    EECON2=0xAA; 
    WR=1;                   // Starten des Sreibens 
    Delay1ms(10); 
    GIE=1;                  // Interrups erlauben 
    WREN=0;                 // Schreiben ins EEPROM verbieten 
} 

//++++++++++++++++++++++ EEPROM LESEN  +++++++++++++++++++++++++++++++++++++++++ 

char EEPROMRD(char adresse) 
{ 
    char antwort; 
    EEADR = adresse;        // Adresse in Adressregister übertragen 
    EEPGD=0;                // Auswahl: Programmspeicher lesen oder EEPROM 
    RD=1;                   // Starten des Lesesn 
    Delay1ms(10); 
    antwort = EEDATA;       // Daten aus Datenregister auslesen 
    return antwort; 
} 

void SerString(const char *__putstr)    // Funktion zum senden eines Strings 
{ 
 char __ps;                             // Variable definieren 

 __ps = *__putstr;                      // Physiche Variablenadresse wird geändert 
                                        // __ps zeigt auf Stringanfang in Programmspeicher 
  while(__ps>0)                         // solande Zeichen(in String) keine 0 Wert hat 
   { 
    __putstr++;                         // Zeiger auf nächste Zeichen des Strings setzen 
    if (__ps== 0) break;                // Ein String hat am ende eine Zeichen mit Wert 0 
   senden(__ps);                        // Zeichen senden 
    __ps = *__putstr;                   // __ps kriegt Zeiger auf nächste Zeichen (sehe 3 Zeilen höcher) 
   }                                    // Um diese unterprogramm zu verstehen muss mann Pointer kennen. 
}
