
/*
 * Projekt:   sms ema pic16f628a
 * File:      main.c
 * Datum:     20.10.2018
 * Autor:     Roland Pudimat
 * Info:      http://www.rolandpudimat.de/html/projekte/projekte.htm
 * Copyright: Freie Nutzung für Privatpersonen. Keine kommerzielle Nutzung.
 *
 * Mikrorechner: PIC 16F628A, Takt: 4 MHz interner Oszillator
 * IDE:          MPLAB X IDE (v4.05.)
 * Compiler:     Microchip XC8 (v1.45)
 * GSM:          A6 GSM/GPRS Module, Ai-Thinker Inc., b=19200 Baud
 *
 * Programmspeicher: 1842 words von 2048
 * Datenspeicher:     195 bytes von  224
 *
 * Das Projekt "sms ema" beinhaltet Programmcode einer Einbruchmeldeanlage (EMA).
 * Der PIC-Mikrorechner verarbeitet Signale von Meldern in Zonen 1-3
 * und gibt über die UART-Schnittstelle Alarmmeldungen an ein GSM-Modul aus,
 * welches mit einer SIM-Karte bestückt ist.
 * Das GSM-Modul versendet Alarm-SMS an ein Mobiltelefon.
 *
 * Ausgänge:
 * Die PIN RA2-RA4 sind mit den Kathoden von LED verbunden.
 * Die Anoden d. LED liegen über 1kOhm an +5V.
 * LEDx = 0; // schaltet LEDx EIN (RAx nahe 0V)
 * Der PIN RB0 ist über einen Transistor mit einem SUMMER beschalten.
 * SUMMER = 1;      // schaltet SUMMER EIN, (RB0 nahe +5 V))
 * PIN8 TX liefert das SMS-Signal an den U_RxD-Eingang des GSM Modul A6.
 *
 * Eingänge:
 * RA1: Start-Stopp-TASTER, unbetätigt offen, mit 10k gegen +5V hochgezogen.
 * RA0,6,7: ZONE1-3, unbetätigt geschlossen, NC-MELDER, NC = normally closed.
 * ZONEx == 1 Melder in ZONEx hat ausgelöst. RAx mit 10k gegen +5V hochgezogen.
 * SCHALTER1 an RB5: Schließer -> mit 10k nach +5V hochgezogen.
 * SCHALTER1 an RB5:  0==GEHTEST, 1==ALARMMODUS
 * SCHALTER2 an RB4: Schließer -> mit 10k nach +5V hochgezogen.
 * SCHALTER2 an RB4:  0==intern (Alarm ohne SMS), 1==extern (Alarm mit SMS)
 *
 * Das Programm basiert auf: "SMS ALARM WITH PIC MICROCONTROLLER" by Nobilis
 * am 28.09.2018 hier:
 * https://www.instructables.com/id/SMS-Alarm-With-PIC-Microcontroller/
 */

/* Einbinden PIC-spezifischer Bibliotheken */
#include <xc.h>      // Funktionsbibliothek aller PIC-Typen
#include <stdint.h>  // Standard Integer
#include <stdio.h>   // Standard Zeichenein- u. ausgabe
#include <stdlib.h>  // Standard Datenumwandlung
#include <string.h>  // Standard Verarbeiten von Strings

/* Konfigurieren des pic16f628a */
#pragma config FOSC  = INTOSCIO  // 4Mhz intern, RA6+RA7: I/O
#pragma config WDTE  = OFF       // Watchdog Timer: AUS
#pragma config PWRTE = ON        // Power-up Timer: EIN
#pragma config MCLRE = OFF       // RA5/MCLR/VPP: RA5 Eingang
#pragma config BOREN = ON        // Brown-out Detect: EIN
#pragma config LVP   = OFF       // Low-Voltage Programming: AUS, RB4: I/O
#pragma config CPD   = OFF       // Data EE Memory Code Protection: AUS
#pragma config CP    = OFF       // Flash Program Memory Code Protection: AUS

/* Einbinden projektspezifischer Dateien, wenn vorhanden */
// #include "main.h"

/* Hinterlegen d. verwendeten Taktfrequenz,
 u.a. um Wartezeit mit Makro "__delay_ms" zu berechnen. */
#define _XTAL_FREQ 4000000  // intern 4MHz mit FOSC=INTOSCIO

/* Definieren von Abkürzungen f. PIN-Belegungen */
//Eingänge
#define TASTER           PORTAbits.RA1 // Start-Stopp-Taster
#define SCHALTER1        PORTBbits.RB5 // Gehtest/Alarmmodus
#define SCHALTER2        PORTBbits.RB4 // Alarm intern/extern
#define ZONE1            PORTAbits.RA6 // PIR, Bewegungsmelder Flur
#define ZONE2            PORTAbits.RA7 // REED1, Wohnungstür
#define ZONE3            PORTAbits.RA0 // REED2, Terassentür

// Ausgänge
#define LED_TASTER       PORTAbits.RA2 // Status Start-Stopp-TASTER, rot
#define LED_GSM          PORTAbits.RA3 // Status GSM Modem, gelb
#define LED_STATUS       PORTAbits.RA4 // Status EMA, grün
#define SUMMER           PORTBbits.RB0 // über Transistor Piezo-Summer

/* globale Variablen */
char eingaenge_status = 0b00000000;  // akt. Zustand d. Eingänge, 1 = aktiviert
                                     // bit0: Melder in ZONE1 ist ausgelöst
                                     // bit1: Melder in ZONE2 ist ausgelöst
                                     // bit2: Melder in ZONE3 ist ausgelöst
char alarm_speicher = 0b00000000;   // Ereignisspeicher, 1 = ZONEx war aktiviert
                                    // bit0: Melder in ZONE1 war ausgelöst
                                    // bit1: Melder in ZONE2 war ausgelöst
                                    // bit2: Melder in ZONE3 war ausgelöst

/* AT-Befehle als Stringvariablen in EEPROM */
char echo_aus[]       = "ATE0";                // Echo aus
char at[]             = "AT";                  // Modem in Arbeitsbereitschaft
char atz[]            = "ATZ";                 // Benutzerprofil aufrufen
char anruf[]          = "ATD01709508389";      // Empfängernummer anwählen
char auflegen[]       = "ATH";                 // nach Anwählen Auflegen
char baudrate[]       = "AT+IPR=19200";        // Baudrate
char textmode[]       = "AT+CMGF=1";           // Textmode
char zeichensatz[]    = "AT+CSCS=\"GSM\"";     // 7-bit Zeichen-Satz
char param_textmode[] = "AT+CSMP=17,167,0,0";  // Param. f. Text-Mode
char rufnummer[]      = "AT+CMGS=\"01709508389\""; // SMS-Empfängernummer
char ctrl_z           = 0x1A;  // = 26 f. EOF (End of File)
char cr               = 0x0D;  // = 13 f. CR (Carriage Return)

uint8_t tx_zone1 = 0;          // Anzahl gesendete SMS "Alarm PIR"
uint8_t tx_zone2 = 0;          // Anzahl gesendete SMS "Alarm REED1"
uint8_t tx_zone3 = 0;          // Anzahl gesendete SMS "Alarm REED2"

/* Unterprogramme */

// Funktion: Frieden schaffen ohne Waffen
// if(Politik != Art 26.1 GG)
// {JVA = UvdL;}

// Funktion: Festlegen von Ein- u. Ausgängen, Ausgänge in Grundzustand setzen
void init_PIC(void)
{
    // Beschreiben v. Steuerregistern f. spezielle Funktionen (SFR)
    INTCON=0b00000000;  // verhindere Interrupts
    CMCON =0b00000111;  // Komparatoren aus, RA0-3 als I/O

    PORTA =  0b00011100;    //
    PORTB =  0b11111111;    //

    TRISA = 0b11100011;   // RA0,6,7: ZONE1-3; RA1: TASTER, RA2-4: LED
    TRISB = 0b11111110;   // RB0:SUMMER,RB1-2:RX,TX, RB4-5: SCHALTER1,2
    SUMMER = 0;           // Summer AUS, weil RB0 nahe Vss = 0V
}

// Funktion: bereite Verbindung zum Modem vor
void init_USART(void)  // initiiere Verbindung zu Modem
{
    __delay_ms(1000);
    LED_GSM = 0;               // schalte gelbe LED_GSM an RA3 ein
    // Konfigurieren serielle Schnittstelle USART
    SPBRG = 12;  // BAUD-Rate Generator
                 // SPRG: 12=(f/16b)-1, mit f= 4000000, b=19200,  +0,16% Fehler
                 // Modul A6 mit AT+IPR=19200 setzen, mit AT&W speichern
    RCSTA = 0b10010000; // SPEN RX9 SREN CREN ADEN FERR OERR RX9D
    // SPEN = 1: serieller Port EIN, RB1=RX, RB2=TX
    // CREN = 1: Empfangsbetrieb EIN
    // RX9  = 0: 8-bit-Mode
    TXSTA = 0b00100100; // CSRC TX9 TXEN SYNC  -   BRGH TRMT TX9D
    // TXEN = 1: Sendebetrieb EIN
    // SYNC = 0: Asynchron-Betrieb
    // BRGH = 1: high speed (b=19200 Baud)
    // TX9  = 0: 8-bit-Mode

    // GSM_POWER = 0;  // ggf. GSM über zusätzl. Relais einschalten
    //__delay_ms(20000);  // warte 20s auf "+PBREADY"= phonebook is ready.
    //__delay_ms(20000);  // warte 20s auf "+PBREADY"= phonebook is ready.
}

// Funktion: 2mal grüne LED_STATUS kurz Blinken
void doppel_BLINK(void)
{
    LED_STATUS = 0;       // LED_STATUS: EIN
    __delay_ms(200);
    LED_STATUS = 1;       // LED_STATUS: AUS
    __delay_ms(200);
    LED_STATUS = 0;       // LED_STATUS: EIN
    __delay_ms(200);
    LED_STATUS = 1;       // LED_STATUS: AUS
}

// Funktion: 2mal 0,2s kurz Piepen
void doppel_PIEP(void)
{
    SUMMER = 1;                // SUMMER: EIN
    __delay_ms(200);
    SUMMER = 0;                // SUMMER: AUS
    __delay_ms(200);
    SUMMER = 1;                // SUMMER: EIN
    __delay_ms(200);
    SUMMER = 0;                // SUMMER: AUS
}

// Funktion: 1mal 2s lang Piepen
void lang_PIEP(void)
{
    SUMMER = 1;                // SUMMER: EIN
    __delay_ms(2000);          // nach 2 s
    SUMMER = 0;                // SUMMER: AUS
}

// Funktion: Entprellen nach Christian Riggenbach. Am 23.03.2018 hier:
// https://www.mikrocontroller.net/articles/Entprellung#Warteschleifen-Verfahren
void entprellen_EINGANG(volatile uint8_t *port, uint8_t maske)
{
    uint8_t   port_puffer;         // akt. Belegung PORTx
    uint8_t   entprellungs_puffer; // Schieberegister, for-Schleifenvariable
    // Schleife wird verlassen, wenn entprellungs_puffer = 0b11111111,
    // for-Schleife ohne Reinitialisierung:
    for(entprellungs_puffer=0b00000000 ; entprellungs_puffer!=0b11111111 ; )
    {
        entprellungs_puffer <<= 1; // verschiebe um 1 Stelle nach links
        port_puffer = *port; // fülle port_puffer mit PORTx-Register
        __delay_us(150);
        if((*port & maske) == (port_puffer & maske))
        // wenn nach der 150us-Verzögerung der akt. Pegel am PORT-Pin
        // noch dem im port_puffer gespeicherten Wert entspricht, dann:
        entprellungs_puffer |= 0b00000001; // setze Bit0 auf 1
    }
}

// Funktion: Abfrage ZONEx, Entprellen, Zustandsspeich. in eingaenge_status
void abfrage_ZONEN(void)
{
    entprellen_EINGANG(&PORTA, 0b01000000); // Prellen an RA6 abwarten
    if (PORTA & 0b01000000) // wenn PIR/ZONE1 an RA6 gerade ausgelöst wurde
        {
            eingaenge_status |= 0b00000001;     // setze Bit0 f. ZONE1/PIR
            alarm_speicher   |= 0b00000001;     // setze Bit0 f. ZONE1/PIR
        }

    entprellen_EINGANG(&PORTA, 0b10000000); // Prellen an RA7 abwarten
    if(PORTA & 0b10000000) // wenn REED1/ZONE2 an RA7 gerade ausgelöst wurde
        {
            eingaenge_status |= 0b00000010;    // setze Bit1 f. ZONE2/REED1
            alarm_speicher   |= 0b00000010;    // setze Bit1 f. ZONE2/REED1
        }

    entprellen_EINGANG(&PORTA, 0b00000001); // Prellen an RA0 abwarten
    if(PORTA & 0b00000001) // wenn REED2/ZONE3 an RA0 gerade ausgelöst wurde
        {
            eingaenge_status |= 0b00000100;    // setze Bit2 f. ZONE3/REED2
            alarm_speicher   |= 0b00000100;    // setze Bit2 f. ZONE3/REED2
        }
}

// Funktion: Gehtest: Funktion der Melder prüfen
void geh_TEST(void)
{
    LED_STATUS = 0;  // LED_STATUS (gn) ein: Fkt. geh_TEST
    while (SCHALTER1 == 0)
    {
    entprellen_EINGANG(&PORTA, 0b01000000); // Prellen an RA6 abwarten
    if(ZONE1 == 1)      // ZONE1/PIR an RA6 ist ausgelöst
    {
        lang_PIEP();
        while(ZONE1 == 1) // solange ZONE1/PIR ausgelöst
            {
                LED_TASTER = 0;      // LED_TASTER (rt) EIN
                __delay_ms(1000);
                entprellen_EINGANG(&PORTA, 0b01000000);//Prellen an RA6 abwarten
            }
        doppel_PIEP();
        LED_TASTER = 1;       // LED_TASTER (rt) wieder AUS
    }

    entprellen_EINGANG(&PORTA, 0b10000000); // Prellen an RA7 abwarten
    if(ZONE2 == 1)      // ZONE2/REED1 an RA7 wurde gerade ausgelöst
    {
        lang_PIEP();           // piepe 1mal lang
        while(ZONE2 == 1)    // solange ZONE2/REED1 ausgelöst
            {
                LED_TASTER = 0;      // LED_TASTER (rt) EIN
                __delay_ms(1000);
                entprellen_EINGANG(&PORTA, 0b10000000);//Prellen an RA7 abwarten
            }
            doppel_PIEP();
            LED_TASTER = 1;       // LED_TASTER (rt) wieder AUS
    }

    entprellen_EINGANG(&PORTA, 0b00000001); // Prellen an RA0 abwarten
    if(ZONE3 == 1)      // ZONE3/REED2 an RA0 ist ausgelöst
    {
        lang_PIEP();           // piepe 1mal lang
        while(ZONE3 == 1) // solange ZONE3/REED2 ausgelöst
            {
                LED_TASTER = 0;      // LED_TASTER (rt) EIN
                __delay_ms(1000);
                entprellen_EINGANG(&PORTA, 0b00000001);//Prellen an RA0 abwarten
            }
            doppel_PIEP();
            LED_TASTER = 1;       // LED_TASTER (rt) wieder AUS
    }
    }
    LED_STATUS = 1;  // LED_STATUS (gn) AUS: Fkt. geh_TEST verlassen
}

// Funktion: Prüfen, ob ein Melder Aktivieren EMA verhindert (Tür/Fenster offen)
void pruefe_MELDER(void)
{
    entprellen_EINGANG(&PORTA, 0b01000000); // Prellen an RA6 abwarten
    if(ZONE1 == 1)      // wenn ZONE1/PIR an RA6 nicht bereit
        {
            lang_PIEP();
            while(ZONE1 == 1) // solange ZONE1/PIR nicht bereit/Person erfasst
                {                                    // blinke LED_TASTER (rt))
                    LED_TASTER = 0;
                    __delay_ms(1000);
                    LED_TASTER = 1;
                    __delay_ms(1000);
                    entprellen_EINGANG(&PORTA, 0b01000000); // Prellen abwarten
                }
        }

    entprellen_EINGANG(&PORTA, 0b10000000); // Prellen an RA7 abwarten
    if(ZONE2 == 1)      // wenn ZONE2/REED1 an RA7 nicht bereit
        {
            lang_PIEP();
            while(ZONE2 == 1) // solange ZONE2/REED1 nicht bereit
                {                                    // blinke LED_TASTER (rt)
                    LED_TASTER = 0;
                    __delay_ms(1000);
                    LED_TASTER = 1;
                    __delay_ms(1000);
                    entprellen_EINGANG(&PORTA, 0b10000000); // Prellen abwarten
                }
        }

    entprellen_EINGANG(&PORTA, 0b00000001); // Prellen an RA0 abwarten
    if(ZONE3 == 1)      // wenn ZONE3/REED2 an RA0 nicht bereit
        {
            lang_PIEP();
            while(ZONE3 == 1) // solange ZONE3/REED2 nicht bereit
                {                                    // blinke LED_TASTER (rt)
                    LED_TASTER = 0;
                    __delay_ms(1000);
                    LED_TASTER = 1;
                    __delay_ms(1000);
                    entprellen_EINGANG(&PORTA, 0b00000001); // Prellen abwarten
                }
        }

    __delay_ms(1000);
    doppel_PIEP();   // alle Melder/Zonen bereit: Doppelpiep und
    doppel_BLINK();  // Doppelblink
}

// Funktion: Aktivieren EMA mit TASTER mit Ausggangsverzögerung
void aktivieren_EMA(void)
{
    uint8_t av = 10;           // Ausgangsverzögerung in s
    unsigned char a = 0;       // Zählvariable f. Pulsen LED_STATUS, SUMMER
    entprellen_EINGANG(&PORTA, 0b00000010); // Prellen an RA1 TASTER abwarten
    while(TASTER == 1) // warte solange Start-Stop-TASTER nicht gedrückt
        {
            entprellen_EINGANG(&PORTA, 0b00000010); // Prellen an RA1 abwarten
        }
    doppel_PIEP();   // TASTER wurde gerade gedrückt: Doppelpiep
    LED_TASTER = 0;       // Doppelblink LED_TASTER (rt)
    __delay_ms(200);
    LED_TASTER = 1;       // schalte LED_TASTER AUS (rt)
    __delay_ms(200);
    LED_TASTER = 0;       // schalte LED_TASTER EIN (rt)
    __delay_ms(200);
    LED_TASTER = 1;       // schalte LED_TASTER AUS (rt)
    __delay_ms(1000);
    for (a = 0; a < av; a++)   // pulse SUMMER u. LED_STATUS während
        {                      // Ablauf Ausgangsverzögerung av
            LED_STATUS = 0;    // schalte LED_STATUS (gn) EIN
            SUMMER = 1;        // schalte SUMMER EIN
            __delay_ms(250);
            LED_STATUS = 1;    // schalte LED_STATUS (gn) wieder AUS
            SUMMER = 0;        // schalte SUMMER wieder AUS
            __delay_ms(200);
            LED_STATUS = 0;    // schalte LED_STATUS (gn) EIN
            SUMMER = 1;        // schalte SUMMER EIN
            __delay_ms(250);
            LED_STATUS = 1;    // schalte LED_STATUS (gn) wieder AUS
            SUMMER = 0;        // schalte SUMMER wieder AUS
            __delay_ms(200);
        }
    __delay_ms(1000);
    alarm_speicher = 0b00000000;   // Alarmspeicher zurücksetzen
    eingaenge_status = 0b00000000; // Status der Eingänge zurücksetzen
    tx_zone1 = 0;                  // SMS-Zähler ZONE1 zurücksetzen
    tx_zone2 = 0;                  // SMS-Zähler ZONE2 zurücksetzen
    tx_zone3 = 0;                  // SMS-Zähler ZONE3 zurücksetzen
    doppel_PIEP();                 // EMA scharf Doppelpiep und
    doppel_BLINK();                // Doppelblink
}

// Funktion: sende AT-Befehle an Modem
sende_an_MODEM(char *s)
{
    while(*s) // solange in s nicht 0 steht
    {
       while (TXIF == 0); // warte solange Pufferspeicher TXREG nicht leer ist
       TXREG = *s++;   // lade Sende-Puffer TXREG mit s erneut
    }
    while(TXIF == 0); // warte solange Pufferspeicher TXREG nicht leer ist
    TXREG = 13; // lade in Sende-Puffer TXREG Zeichen f. "Wagenrücklauf"
    __delay_ms(1000);  // warte 1 s
}

// Funktion: sende SMS
sende_SMS(char *s)
{
    sende_an_MODEM(s);
    while(TXIF == 0);  //mache erst weiter, wenn Pufferspeicher TXREG leer ist
    TXREG = ctrl_z;    // lade in Sende-Puffer TXREG Ctrl+Z (Dateiendezeichen)
    __delay_ms(10000); // warte 10 s
}

// Funktion: Einbruchmelden per SMS
void sms_ALARM(void)
{
    // Generiere SMS-Text in "message"
    char msg[8];   // Stringvariable f. 8 Zeichen
    char message[25] = "Alarm: ";  // Stringvariable f. 25 Zeichen
    if ((eingaenge_status >> 0) & 1)  // falls bit 0 gesetzt
    {
        memset(msg, '\0', 8);  // überschreibe alle 8 Bit v. msg mit '\0'
        strcpy(msg, "PIR\n"); // kopiere PIR nach msg
        strcat(message, msg);   // hänge msg an message (Alarm: PIR)
    }
    if ((eingaenge_status >> 1) & 1)  // falls bit 1 gesetzt
    {
        memset(msg, '\0', 8);  // überschreibe alle 8 Bit v. msg mit '\0'
        strcpy(msg, "REED1\n"); // kopiere REED1 nach msg
        strcat(message, msg);   // hänge msg an message (Alarm: REED1)
    }
    if ((eingaenge_status >> 2) & 1)  // falls bit 2 gesetzt
    {
        memset(msg, '\0', 8);  // überschreibe alle 8 Bit v. msg mit '\0'
        strcpy(msg, "REED2\n"); // kopiere REED2 nach msg
        strcat(message, msg);   // hänge msg an message (Alarm: REED2)
    }

    init_USART();              // initiiere ser. Schnittst. zu Modem
    __delay_ms(1000);          // warte 1s bis Modem bereit

    // zum Testen Mobiltelefon Anklingeln, danach auskommentieren
    sende_an_MODEM(at);        // setze Modem in Arbeitsbereitschaft
    __delay_ms(2000);          // warte 2s bis Modem bereit
    sende_an_MODEM(anruf);     // wähle Empfängernummer
    __delay_ms(10000);         // lasse 10s Klingeln
    sende_an_MODEM(auflegen);  // lege wieder auf
    __delay_ms(2000);          // warte 2s

    //sende SMS: beim Testen zunächst auskommentiert
   /*
    sende_an_MODEM(at);        // setze Modem in Arbeitsbereitschaft
    __delay_ms(1000);          // warte 1s bis Modem bereit
    sende_an_MODEM(textmode);       // benutze Text-Modus
    sende_an_MODEM(zeichensatz);    // setze 7-bit Zeichen-Satz
    sende_an_MODEM(param_textmode); //setze Param. f. Text-Mode
    sende_an_MODEM(rufnummer);      // SMS-Empfängernummer
    sende_SMS(message);             // sende SMS-TXT
    */

    TXSTAbits.TXEN = 0; // TXEN = 0: Sendebetrieb AUS (Stromsparen))
    RCSTAbits.SPEN = 0; // SPEN = 0: serieller Port AUS
    LED_GSM = 1;                 // LED_GSM AUS (RA3 nahe +5 V)
    //eingaenge_status = 0b00000000; // setze eingaenge_status zurück
}

// Funktion: Einbruchmelden per SUMMER
void summer_ALARM(void)
{
    uint8_t sd = 20;           // Einschaltdauer SUMMER in s
    unsigned char b = 0;       // Zählvariable f. Pulsen LED_TASTER, SUMMER
    for (b = 0; b < sd; b++)   // pulse SUMMER u. LED_TASTER sd Sekunden
        {
            LED_TASTER = 0;    // schalte LED_TASTER (rt) EIN
            SUMMER = 1;        // schalte SUMMER EIN
            __delay_ms(250);
            LED_TASTER = 1;    // schalte LED_TASTER (rt) wieder AUS
            SUMMER = 0;        // schalte SUMMER wieder AUS
            __delay_ms(200);
            LED_TASTER = 0;    // schalte LED_TASTER (rt) EIN
            SUMMER = 1;        // schalte SUMMER EIN
            __delay_ms(250);
            LED_TASTER = 1;    // schalte LED_TASTER (rt) wieder AUS
            SUMMER = 0;        // schalte SUMMER wieder AUS
            __delay_ms(200);
        }
}

// Funktion: main, das Hauptprogramm
int main(void)
{
     /* Variablendeklaration, Variablendefinitionen */
    uint8_t av = 20;               // Ausgangsverzögerung in s
    uint8_t ev = 20;               // Eingangsverzögerung in s
    unsigned char a = 0;           // Zählvariable f. Pulsen LED_STATUS, SUMMER

    /* Funktionenaufrufe u. sonstige Anweisungen */
    init_PIC();       // Ein- u. Ausgänge bestimmen und vorbelegen
    doppel_PIEP();    // PIC bereit: Doppelpiep und
    doppel_BLINK();   // Doppelblink grüne LED_STATUS
    __delay_ms(1000);

   anfang:                // Sprungmarke

    /* Aufruf Fkt. geh_TEST, wenn SCHALTER1 == 0 */
    entprellen_EINGANG(&PORTB, 0b00100000); // Prellen an RB5 abwarten
    if (SCHALTER1 == 0)                   // wenn SCHALTER1 an RB5 auf Null
        {geh_TEST();}

    /* Prüfen, ob ein MELDERx oder der PIR Aktivierung EMA verhindert. */
    pruefe_MELDER();       // Pause bis Tür/Fenster geschlossen,
                           //oder Person außerhalb Erfassungsbereich des PIR.

    aktivieren_EMA();      // durch Drücken Start-Stopp-TASTER
                           // Scharfschalten mit Ausgangsverzögerung/ Countdown

    while(1)               // die Programm-Hauptschleife
    {
        abfrage_ZONEN();  // Variable: "eingaenge_status" aktualisieren

        if (eingaenge_status > 0) // wenn irgend ein MELDERx ausgelöst
        {
            for (a = 0; a < ev; a++)   // pulse LED_STATUS während Ablauf
                {                      // Eingangsverzög. ev;  Abbruch mögl.
                    LED_STATUS = 0;
                    __delay_ms(250);
                    LED_STATUS = 1;
                    __delay_ms(200);
                    LED_STATUS = 0;
                    __delay_ms(250);
                    LED_STATUS = 1;
                    __delay_ms(200);
                    entprellen_EINGANG(&PORTA, 0b00000010);//Prellen abwarten
                    if(TASTER == 0)    // wenn STOPP-TASTER >=3s gedrückt
                        {              //breche Alarm ab u. beginne von vorn
                        __delay_ms(3000);
                        entprellen_EINGANG(&PORTA, 0b00000010);
                        while(TASTER == 0);//warte bis wieder losgelassen
                        doppel_PIEP();    // Abbruch: Doppelpiep und
                        doppel_BLINK();   // Doppelblink LED_STATUS
                        goto anfang;   //Wiederaktivieren nur mit TASTER
                        }
                }

            if ((SCHALTER2 == 0) && !(eingaenge_status & 0b00000001))
                // wenn SCHALTER2 geschlossen => Internbetrieb/ Person zu Hause
                // nur Außenhaut überwacht, interner PIR ignoriert
                {summer_ALARM();}   // melde Alarm mit SUMMER, keine  SMS

            if ((tx_zone1<2) && (SCHALTER2==1) && (eingaenge_status&0b00000001))
                {
                sms_ALARM();        // melde Alarm per SMS
                tx_zone1++;         // erhöhe SMS-Zähler tx_zone1 um 1
                }
            if ((tx_zone2<2) && (SCHALTER2==1) && (eingaenge_status&0b00000010))
                {
                sms_ALARM();        // melde Alarm per SMS
                tx_zone2++;         // erhöhe SMS-Zähler tx_zone2 um 1
                }
            if ((tx_zone3<2) && (SCHALTER2==1) && (eingaenge_status&0b00000100))
                {
                sms_ALARM();        // melde Alarm per SMS
                tx_zone3++;         // erhöhe SMS-Zähler tx_zone3 um 1
                }

        }
        eingaenge_status = 0b00000000; // setze eingaenge_status zurück
        /*
        // Pause: Nur im Testbetrieb
        while(TASTER == 1)   // erst weiter, wenn TASTER gedrückt
        entprellen_EINGANG(&PORTA, 0b00000010);//Prellen abwarten
        if(TASTER == 0)
            {
            lang_PIEP();      // TASTE gedrückt: lang Piep
            LED_TASTER = 0;   // rote LED_TASTER 2s ein
            __delay_ms(2000); // 2 s warten
            LED_TASTER = 1;   // rote LED_TASTER aus
            }
        // Ende Pause Testbetrieb
        */
        if (alarm_speicher > 0)   // wenn ein MELDER ausgelöst war
            {                     // blitze rote LED_TASTER
            LED_TASTER = 0;   // rote LED_TASTER ein
            __delay_ms(40);   // 40ms warten
            LED_TASTER = 1;   // rote LED_TASTER aus
            }

        if ((tx_zone1 || tx_zone2 || tx_zone3) > 0)   // wenn SMS gesendet wurde
            {                                         // blitze gelbe LED_GSM
            LED_GSM = 0;      // gelbe LED_GSM ein
            __delay_ms(40);   // 40ms warten
            LED_GSM = 1;      // gelbe LED_GSM aus
            }

        // EMA auf "anfang" zurücksetzen, wenn TASTER >5s gedrückt
        entprellen_EINGANG(&PORTA, 0b00000010);//Prellen abwarten
        if(TASTER == 0)    // wenn STOPP-TASTER >=5s gedrückt
        {                  //breche Alarm ab u. beginne von vorn
            __delay_ms(5000);
            entprellen_EINGANG(&PORTA, 0b00000010);
            while(TASTER == 0); //warte bis wieder losgelassen
            doppel_PIEP();      // Abbruch: Doppelpiep und
            doppel_BLINK();     // Doppelblink LED_STATUS
            goto anfang;        //Wiederaktivieren nur mit TASTER
        }

        __delay_ms(1500); // warte mit dem nächsten Durchlauf
        CLRWDT();

        LED_STATUS = 0; // blitze grüne LED_STATUS nach jedem Durchlauf kurz auf
        __delay_ms(40);
        LED_STATUS = 1;   // schalte grüne LED_STATUS aus

    }// Ende Endlosschleife

    return 0;
}// Ende main
