/*---------------------------------------------------------------------------- ; PIC16F688 MCU - Neoway M590E GPRS module integration ;----------------------------------------------------------------------------- ; ; DISCLAIMER ----------------------------------------------------------------- ; ; This software is distributed in the hope that it will be useful. THE ; SOFTWARE IS PROVIDED IN AN "AS IS" CONDITION. NO WARRANTIES, WHETHER ; EXPRESS, IMPLIED OR STATUTORY, INCLUDING, BUT NOT LIMITED TO, IMPLIED ; WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE APPLY ; TO THIS SOFTWARE. THE AUTHOR SHALL NOT, IN ANY CIRCUMSTANCES, BE LIABLE ; FOR SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES, FOR ANY REASON WHATSOEVER. ; ;----------------------------------------------------------------------------- ; Project Info ;----------------------------------------------------------------------------- ; This is the main source file of a MCU controlled GSM unit project. The ; unit looks for 3 trigger events: motion detection, door opening and ; mains power outage. When any one or more trigger appears on input pins ; the unit awaknens the GSM modem and sends a warning sms. ; ; Main considerations: ; * Stability: the unit must operate for extended time (for months) with ; no human interaction or maintainance, including reseting the unit. ; * Reliability: the unit must be able to operate in low GSM network ; signal conditions like rural areas, basements etc. ; * Low power consumption: both MCU and GSM modul supplied with low ; voltage levels to keep the power usage low. GSM module is only ; powered up on demand. ; * Extreme low TCO: MCU, power supply units and GSM modul all together ; costs less than 5 USD. ; ;----------------------------------------------------------------------------- ; Module Info ;----------------------------------------------------------------------------- ; Filename : sms_sender.c ; Since : 14 Feb 2017 ; Date : 19 Aug 2017 ; File Version : 1.0.0.0 ; MCU : PIC16F688 ; Language : MicroC ; MPLAB-X Ver : V8.36 ; ; Engineer : nobilis ; Company : Liberty Global Operations B.V. ; Site : https://www.instructables.com/member/Nobilis ; Email : ventusbull@freestart.hu ;----------------------------------------------------------------------------- ; Component Info ;----------------------------------------------------------------------------- ; ; ██████╗ ██╗ ██████╗ ██╗ ██████╗ ███████╗ ██████╗ █████╗ █████╗ ; ██╔══██╗██║██╔════╝███║██╔════╝ ██╔════╝██╔════╝ ██╔══██╗██╔══██╗ ; ██████╔╝██║██║ ╚██║███████╗ █████╗ ███████╗ ╚█████╔╝╚█████╔╝ ; ██╔═══╝ ██║██║ ██║██╔═══██╗██╔══╝ ██╔═══██╗██╔══██╗██╔══██╗ ; ██║ ██║╚██████╗ ██║╚██████╔╝██║ ╚██████╔╝╚█████╔╝╚█████╔╝ ; ╚═╝ ╚═╝ ╚═════╝ ╚═╝ ╚═════╝ ╚═╝ ╚═════╝ ╚════╝ ╚════╝ ; ; MCU : PIC16F688 8 bit MCU ; 2x256 byte data memory (used: 192 byte, 75.0%) ; 4096 word program memory (used: 965 byte, 23.6%) ; Oscillator : external 4 MHz ; USART : asynhronous, 38400 bit/s ; GSM/GPRS : Neoway M590E V1.31 2G GSM modem ; ;----------------------------------------------------------------------------- ; Pin Diagram ;----------------------------------------------------------------------------- ; ; ╔═════════╗ ; ║ o ║ ; Vdd ══║1 14║══ GRND ; CLK IN ══║2 13║═> RA0 SMS/operation LED ; CLK OUT ══║3 12║<> RA1 GSM modem power line ; MCLR ══║4 11║═> RA2 (unused) ; (unused) RX ═>║5 10║<═ RC0 steps sensor ; TX <═║6 9║<═ RC1 door sensor ; (unused) RC3 ══║7 8║<═ RC2 mains failure sensor ; ║PIC16F688║ ; ╚═════════╝ ; ;----------------------------------------------------------------------------- ; Operation ;----------------------------------------------------------------------------- ; ; 1. Powering On the MCU: ; At startup there is a double flash on SMS LED. ; ; 2. Standby ; After every cycle (3 seconds) the LED blinks. Triggers are observed. ; ; 3. After one or more of the input pins are triggered: ; ; 0. If RA1 (GSM modem power control pin) read HIGH then another device ; is using the modem. The microcontroller stays in standby mode and ; waits until the next trigger cycle to send the SMS. ; ; 1. LED is flashing for 45 seconds while the GSM modem is initialising ; and connecting to the modile network. ; ; 2. LED glares while SMS sending is in progress. This takes about 25 ; seconds. ; ; 3. LED flashes for 15 seconds while GSM modem is shutting down. ; ; 4. GSM modem power is off, the microcontroller goes back to standby. ; ; ; Notes and limitations: ; ; a. As a feature the same trigger does not initiate another SMS sending ; process within the trigger's defined timeframe. ; ; b. While sending SMS (about 85 seconds) triggers are unobserved, however ; at the next cycle it will be processed by the algorithm. ; ; c. A trigger could be a just short impulse as the PIC's port register ; will keep it's value until the next read. So it is guaranteed that ; any trigger event will be caught. ; ; d. The microcontroller has limited capacity in terms of RAM. It does ; not bother to read the serial port and check the answers from the ; GSM modem. So it does not know if SMS sending has succeeded or even ; there is a modem on the other end of the TX port. There are tried ; timings in the algorithm which makes the controling of the modem ; relatively reliable. However by design the SMS sending is not a ; guaranteed service of this unit and depends on outer factors such as ; the SIM, mobile network service, mobile network operator etc. ; ; e. As watchdog is enabled the microcontroller's robustness and ; reliability is pretty high. ; ; f. There are 2 more free input pins available to use for other trigger ; events. ;----------------------------------------------------------------------------- */ #undef SIMULATION // ----------------- CUSTOMIZABLE VALUES -------------------------- #ifdef SIMULATION #define _XTAL_FREQ 5000 // with MPLAB X IDE simulation mode this // value works best #else #define _XTAL_FREQ 6000000 // 6 MHz external crystal. Required for // symbol definition of __delay_ms() macro #endif // These are delays for recurring SMS sending, defined separately for every // single trigger type. #define STEPS_CYCLES 7200 // send another SMS after this value x 3 secs //#define STEPS_CYCLES 100 // send another SMS after this value x 3 secs #define DOOR_CYCLES 7200 // send another SMS after this value x 3 secs #define MAINS_CYCLES 7200 // send another SMS after this value x 3 secs // ----------------- Pin definitions -------------------------- #define LED_SMS RA0 // digital OUT #define GSM_POWER RA1 // digital OUT for GSM power enable pin #define TRIGGER_STEPS RC0 // digital IN for PIR sensor trigger #define TRIGGER_DOOR RC1 // digital IN for door opening sensor trigger #define TRIGGER_MAINS RC2 // digital IN for mains power outage trigger // ----------------- AT command declarations ------------------ // every string are in the EEPROM program memory to save data RAM space //const char * AT_CREG = "AT+CREG?"; // query network status char AT[] = "AT"; char power_off[] = "AT+CPWROFF"; char mode_text[] = "AT+CMGF=1"; // to set text mode char char_mode[] = "AT+CSCS=\"GSM\""; // to set character mode char param[] = "AT+CSMP=17,167,0,16"; // set a one day validity char mobile_no[] = "AT+CMGS=\"+36301111111\""; // recipient's number char terminator = 0x1A; // Control+Z terminator character // ------------------------------------------------------------ /* WDTE Watchdog Timer Enable bit CP Program memory code protection bit CPD Data Code Protection bit BOREN Brown Out Detect IESO Internal/External Switchover bit FCMEN Fail-Safe Clock Monitor Enabled bit FOSC FOSC<2:0>: Oscillator Selection bits: 100 = INTOSCIO oscillator: I/O function on RA4/OSC2/CLKOUT pin, I/O function on RA5/OSC1/CLKIN 001 = XT oscillator: Crystal/resonator on RA4/OSC2/CLKOUT and RA5/OSC1/CLKIN When the SCS bit of the OSCCON register = 0, the system clock source is determined by configuration of the FOSC<2:0> bits in the Configuration Word register (CONFIG). */ #pragma config WDTE=ON, PWRTE=ON, MCLRE=ON, CP=OFF, \ CPD=OFF, BOREN=ON, IESO=OFF, FCMEN=ON, \ FOSC=XT // ----------------- CONSTANT DEFINITIONS --------------------- #define HIGH_LEVEL 1 #define LOW_LEVEL 0 #define ON 1 #define OFF 0 #define stealth 2 // stealth mode: no LED flashes #define false 0 #define true 1 // ------------------------------------------------------------ #include #include #include // ----------------- GLOBAL VARIABLES ------------------------- char response_buffer[25]; // reusable buffer memory for texts // ----------------- SUBROUTINES ------------------------------ void wait(unsigned char second, unsigned char isFast) { CLRWDT(); for (unsigned char i = 0; i < second; i++) { if (isFast == stealth) { __delay_ms(900); } else if (isFast == false) { LED_SMS = OFF; __delay_ms(499); LED_SMS = ON; __delay_ms(399); } else { LED_SMS = OFF; __delay_ms(250); LED_SMS = ON; __delay_ms(200); CLRWDT(); LED_SMS = OFF; __delay_ms(250); LED_SMS = ON; __delay_ms(200); } CLRWDT(); } } void send_to_modem(char *s) { while (*s) { while(TXIF == 0); TXREG = *s++; CLRWDT(); } while(TXIF == 0); TXREG = 13; // carriage return __delay_ms(800); CLRWDT(); } void send_sms(char *s) { send_to_modem(s); while(TXIF == 0); TXREG = terminator; // "press" Ctrl-Z wait(20, stealth); } // ------------------------------------------------------------ void main(void) { // PIC init config CMCON0bits.CM = 0b111; // comparators off SCS = 0; // System Clock Select bit: 0, the system clock // source is determined by configuration of the // FOSC<2:0> bits in the Configuration Word // register (CONFIG) OSTS = 1; // Oscillator Start-up Time-out Status bit: // 0 = Device is running from the internal // oscillator (HFINTOSC or LFINTOSC) // I/O port init ANSEL = 0b00000000; // setting every pin to digital (not analogue) PORTA = 0; // switch off every in/output PORTC = 0; // switch off every in/output TRISA = 0b00000000; // setting everything as output TRISC = 0b00001111; // setting RC0,1,2,3 as input // initially switch off the GSM modem GSM_POWER = HIGH_LEVEL; // negated working, high means OFF // power-up phase --------------------------------------- wait(2, false); // at startup there is a double flash on SMS LED __delay_ms(1000); CLRWDT(); // to ignore recurring trigger events we need separated cycle counters unsigned int cycleCounters[] = { STEPS_CYCLES, DOOR_CYCLES, MAINS_CYCLES }; char triggerCode = 0x0; // lower bits indicates trigger events wait(120, true); // give the user some time after power on to leave the area LED_SMS = OFF; __delay_ms(1000); CLRWDT(); __delay_ms(1000); CLRWDT(); while (1) { if (TRIGGER_STEPS == LOW_LEVEL && (STEPS_CYCLES <= cycleCounters[0])) { // step trigger is a reversed sensor: LOW means activated triggerCode |= 0b00000001; // set bit #0 to HIGH cycleCounters[0] = 0; // start counting } if (TRIGGER_DOOR == LOW_LEVEL && (DOOR_CYCLES <= cycleCounters[1])) { // door trigger is a reversed sensor: LOW means activated triggerCode |= 0b00000010; // set bit #1 to HIGH cycleCounters[1] = 0; // start counting } if (TRIGGER_MAINS == HIGH_LEVEL && (MAINS_CYCLES <= cycleCounters[2])) { triggerCode |= 0b00000100; // set bit #2 to HIGH cycleCounters[2] = 0; // start counting } if (triggerCode > 0) { // has any trigger set? wait(40, stealth); // give the user 1 minute to turn off the alarm system // is the modem in use by another (outer) device? TRISA = 0b00000010; // setting RA1 (GSM_POWER) as input __delay_ms(300); if (GSM_POWER = LOW_LEVEL) { // negated working, low means ON wait(5, stealth); // wait until the modem is available } else { TRISA = 0b00000000; // setting everything as output __delay_ms(300); // init UART SPBRG = 9; // with this config this means 38400 bit/s BAUDCTLbits.BRG16 = 0; TXSTAbits.BRGH = 1; // high baud rate RCSTAbits.CREN = 1; // RCSTA bit 4: enables the receiver circuitry of the EUSART TXSTAbits.SYNC = 0; // TXSTA bit 4: 0 = asynchronous operation RCSTAbits.SPEN = 1; // RCSTA bit 7: enable serial port TXSTAbits.TXEN = 1; // TXSTA bit 5: enables the transmitter circuitry // power up the modem GSM_POWER = LOW_LEVEL; // negated working, low means ON wait(40, stealth); // wait for startup and the "+PBREADY" which indicates mobile service connection // build the custom alert message char msg[8]; char message[25] = "Alarm: "; if ((triggerCode >> 0) & 1) { // has bit 0 set? memset(msg, '\0', 8); strcpy(msg, "Steps\n"); strcat(message, msg); } if ((triggerCode >> 1) & 1) { // has bit 1 set? memset(msg, '\0', 8); strcpy(msg, "Door\n"); strcat(message, msg); } if ((triggerCode >> 2) & 1) { // has bit 2 set? memset(msg, '\0', 8); strcpy(msg, "Mains\n"); strcat(message, msg); } // negotiate baud rate send_to_modem(AT); // send "AT" string then wait a while __delay_ms(1000); // prepare and send SMS send_to_modem(mode_text); send_to_modem(char_mode); send_to_modem(param); send_to_modem(mobile_no); send_sms(message); triggerCode = 0x0; // clear triggers // power off GSM_POWER = HIGH_LEVEL; // negated working, high means OFF TXSTAbits.TXEN = OFF; // turn off transmitter circuitry to save power RCSTAbits.SPEN = OFF; // disable the serial port } // end else } if (cycleCounters[0] < STEPS_CYCLES) { cycleCounters[0]++; } if (cycleCounters[1] < DOOR_CYCLES) { cycleCounters[1]++; } if (cycleCounters[2] < MAINS_CYCLES) { cycleCounters[2]++; } // wait a while before the next trigger cycle __delay_ms(1200); CLRWDT(); __delay_ms(1448); CLRWDT(); LED_SMS = ON; __delay_ms(40); LED_SMS = OFF; } }