PIC SMS Controller using PIC16F688

Wednesday 26 June 2013

PIC SMS Controller using PIC16F688

After browsing and learning from Elab, starting a project and always left it hanging or unfinished, I finally am able to code an almost complete project (at least the s/w portion).

Now its my time to share specially for those students and other hobbyist who are at lost as how to start an SMS controller  for their various thesis or personal projects that will use SMS as a medium.

This is an SMS controller using a PIC16F688.  Why a PIC16F688?  Well for one, I have this in my parts bin and second of all, it is like an LF series part number operating from 2.0V up to 5.5V.  I am using this on a Nokia mobile phone where the voltage level is around 2.7V.  But it can also be used directly on GSM modems.  This SMS controller utilizes textmode AT commands as the communication protocol.

Below is the base hardware schematic where the code is based.  Once I finalize the code, I will also finalize the hardware schematic.  The code is already working but still needs improvement and additional features.  I am open to more suggestions on additional features or how to further optimize or improve the code.



Uploaded with ImageShack.us

Features:

Very minimalist with  4 output ports and 4 alarm input ports.

The 4 output ports (namely OUT1, OUT2, OUT3 and OUT4)  can be controlled (turned ON or OFF)  using predefined keyword  commands sent to the attached mobile( or gsm modem) to the SMS controller.

OUT1_HIGH to turn on OUT1  port and LED D1
OUT1_LOW to turn off OUT1  port and LED D1

OUT2_HIGH to turn on OUT1  port and LED D2
OUT2_LOW to turn off OUT1  port and LED D2

OUT3_HIGH to turn on OUT1  port and LED D3
OUT3_LOW to turn off OUT1  port and LED D3

OUT4_HIGH to turn on OUT1  port and LED D4
OUT4_LOW to turn off OUT1  port and LED D4

The 4 alarm input ports when set or driven low will by default set or turn on OUT1 (which could be connected to a siren) and send a corresponding SMS Alert message to a predefined Mobile number of the port that was triggered.  It also has a configurable alarm trigger timer (by default 5 mins) such that if the alarm is continously active or continously being triggered within 5 minutes, it will only send 1 SMS alert message within a 5 min. interval for a specific alarm input port.

There is no polling on the received SMS but rather received SMS is delivered directly to SMS Controller.  You should modify the AT+CNMI settings that work on your phone.  Also, SMS alert message are also sent directly to the network and not initially save  then sent from the phone memory.

All in all, code size is 1008 of 4096 program words and RAM used is 117 bytes of 256 bytes so there is still  enough room for additional features.  Compiler used is Hitech C.

BTW, I am simulating this on proteus and an actual Nokia mobile phone attached to my pc.

Below is the code:  main.c

Code: [Select]
/****************************************/
/*    SMS Controller using PIC16F688    */
/*    PIC16F688 SMS Controller v0.02    */
/*                                      */
/*                 by                   */
/*            KentronicsPH              */
/*      KentronicsPH.blogspot.com       */
/*       kentronicsph@gmail.com         */
/*                                      */
/*    YOU ARE FREE TO USE THIS S/W      */
/*         AT YOUR OWN RISK!            */
/*    I scrounged up this code from     */
/*    various sources, compiler sample  */
/*    codes and files, advices from     */
/*    forums and other MCU related      */
/*    websites and modifying them for   */
/*    my own purpose.                   */
/*                                      */
/*    This is not a professional s/w,   */
/*    the purpose of which is to help   */
/*    fellow hobbyist and students      */
/*    a guide to code their own SMS     */
/*    controller.                       */
/****************************************/

#include <htc.h>
#include <stdio.h>
#include <string.h>
#include <ctype.h>
#include "usart.h"

#ifndef _XTAL_FREQ
#define _XTAL_FREQ 8000000
#endif

#define OUT1_HIGH  RC0 = 1;
#define OUT2_HIGH  RC1 = 1;
#define OUT3_HIGH  RC2 = 1;
#define OUT4_HIGH  RC3 = 1;

#define OUT1_LOW  RC0 = 0;
#define OUT2_LOW  RC1 = 0;
#define OUT3_LOW  RC2 = 0;
#define OUT4_LOW  RC3 = 0;

#define LED_IND_ON  RA5 = 1;
#define LED_IND_OFF  RA5 = 0;

/*
Alarm trigger delay
If alarm has been triggered
and remains triggered, SMS
Controller will only send
an SMS message once for every
no. of ticks where 1 tick is
about 250ms
*/

#define alarm_filter 1200

#define mobile_no_01 "+639123456789" 

/* PIC16F688 Configuration Fuses */
__CONFIG(FCMDIS & IESODIS & BORDIS & PWRTEN & WDTDIS & INTIO);

/* Function Declarations */
void Setup_Interrupts(void);
void Setup_16F688HW();
void TMR1_INC(void);
void Setup_Timer1();

/* Global Variables */

unsigned int alarm_timer1;
unsigned int alarm_timer2;
unsigned int alarm_timer3;
unsigned int alarm_timer4;

unsigned char alarm_flag1;
unsigned char alarm_flag2;
unsigned char alarm_flag3;
unsigned char alarm_flag4;


/* Functions */
void interrupt isr()
{
 if (RCIF)
 {
  Write_RXBuff();
 }
 
 if (TMR1IF)
 {
  TMR1_INC();
 }
}

void Setup_Interrupts(void)
{
 INTCON = 0;
    GIE    = 1 ;
    PEIE   = 1 ;
    RCIE   = 1;
 TMR1IE = 1;  //enable timer1 interrupt
}

void Setup_16F688HW(void)
{
 OSCCON = 0b01110001; // Internal Oscillator 8MHz
    ANSEL  = 0x00;         // All ADC off 
    CMCON0 = 0x07;         // Comparators off
 
    /* Digital Inputs, TRIS = 1 (Input) */
    TRISA0 = 1;    // RA0 as alarm input 1
    TRISA1 = 1;    // RA1 as alarm input 2
    TRISA2 = 1;    // RA2 as alarm input 3
    TRISA3 = 1;    // RA3 as alarm input 4

    //Digital Outputs, TRIS = 0 (Output) */
    TRISA5 = 0;    // LED indicator    
    TRISC0 = 0;    // RC0 as alarm output 1
    TRISC1 = 0;    // RC1 as alarm output 2
    TRISC2 = 0;    // RC2 as alarm output 3
    TRISC3 = 0;    // RC3 as alarm output 4

 OUT1_LOW  RC0 = 0;
 OUT2_LOW  RC1 = 0;
 OUT3_LOW  RC2 = 0;
 OUT4_LOW  RC3 = 0;

 LED_IND_OFF  RA5 = 0;
}

void SMS_ATE0(void)  // Sends echo command off
{
 while (1)
 {
  Reset_RXBuff(); 
  printf("ATE0\r");
  __delay_ms(300);
  if (strstr(RXBuff, "\r\nOK\r\n\0") != 0)
   break;
 }  
}

void SMS_ATCMGF(void)
{
 while (1)
 {
  Reset_RXBuff();
  printf("AT+CMGF=1\r");
  __delay_ms(300);
  if (strstr(RXBuff, "\r\nOK\r\n\0") != 0)
   break;
  }   
}

void SMS_ATCNMI()
{
 while (1)
 { 
  Reset_RXBuff();
  printf("AT+CNMI=2,2,2,2,0\r");
  __delay_ms(300);  //wait for ">" character
  if (strstr(RXBuff, "\r\nOK\r\n") != 0)
   break;
  }  
}

void SMS_Send_SM(const char * message, const char * pnum)
{
 printf("AT+CMGS=\"%s\"\r", pnum);
 __delay_ms(300);
 Reset_RXBuff;
 printf("%s\x1a", message);
}


void TMR1_INC(void)
{ 
 TMR1IF = 0;           
    TMR1H = 11;
    TMR1L = 220;
 alarm_timer1++;
 alarm_timer2++;
 alarm_timer3++;
 alarm_timer4++;
 
 if (alarm_timer1 >= alarm_filter)
 {
  alarm_flag1 = 0;
  alarm_timer1 = 0;
 }
 
 if (alarm_timer2 >= alarm_filter)
 {
  alarm_flag2 = 0;
  alarm_timer2 = 0;
 }

 if (alarm_timer3 >= alarm_filter)
 {
  alarm_flag3 = 0;
  alarm_timer3 = 0;
 }

 if (alarm_timer4 >= alarm_filter)
 {
  alarm_flag4 = 0;
  alarm_timer4 = 0;
 }
}

void Setup_Timer1()  // interrupt every 250ms
{ 
 TMR1H = 11;
 TMR1L = 220;
 T1CON = 0b00110101;
}


void main(void)
{ 

 Setup_16F688HW();
 Setup_Interrupts();
 Setup_Timer1();
 uart_init(); // set up the USART - settings defined in usart.h
 __delay_ms(1000);

 SMS_ATE0();
 SMS_ATCMGF();
 SMS_ATCNMI();
 LED_IND_ON;  //Indicates PIC-Phone comms is OK!

 alarm_timer1 = 0;
 alarm_flag1 = 0;

 alarm_timer2 = 0;
 alarm_flag2 = 0;

 alarm_timer3 = 0;
 alarm_flag3 = 0;

 alarm_timer4 = 0;
 alarm_flag4 = 0;

 while (1)
 { 
  /* ALARM MONITORING */
  if (RA0 == 0)
  { if (alarm_flag1 == 0 )
   {
    OUT1_HIGH;
    SMS_Send_SM("IN1 ON", mobile_no_01);
    alarm_flag1 = 1;
    alarm_timer1 = 0;
    __delay_ms(5000);
   }
  }

  if (RA1 == 0)
  { if (alarm_flag2 == 0 )
   {
    OUT1_HIGH;
    SMS_Send_SM("IN2 ON", mobile_no_01);
    alarm_flag2 = 1;
    alarm_timer2 = 0;
    __delay_ms(5000);
   }
  }

  if (RA2 == 0)
  { if (alarm_flag3 == 0 )
   {
    OUT1_HIGH;
    SMS_Send_SM("IN3 ON", mobile_no_01);
    alarm_flag3 = 1;
    alarm_timer3 = 0;
    __delay_ms(5000);
   }
  }

  if (RA4 == 0)
  { if (alarm_flag4 == 0 )
   {
    OUT1_HIGH;
    SMS_Send_SM("IN4 ON", mobile_no_01);
    alarm_flag4 = 1;
    alarm_timer4 = 0;
    __delay_ms(5000);
   }
  }
  

  /* COMMAND MONITORING */
  Reset_RXBuff();
  __delay_ms(100);
  
  if (strstr(RXBuff, "OUT1_HIGH") != 0)
  {
   OUT1_HIGH;
  }
  else if (strstr(RXBuff, "OUT1_LOW") != 0) 
  {
   OUT1_LOW;
  }
  else if (strstr(RXBuff, "OUT2_HIGH") != 0)
  {
   OUT2_HIGH;
  } 
  else if (strstr(RXBuff, "OUT2_LOW") != 0)
  {
   OUT2_LOW;
  }
  else if (strstr(RXBuff, "OUT3_HIGH") != 0)
  { 
   OUT3_HIGH;
  }
  else if (strstr(RXBuff, "OUT3_LOW") != 0)
  { 
   OUT3_LOW;
  }
  else if (strstr(RXBuff, "OUT4_HIGH") != 0)
  { 
   OUT4_HIGH;
  }
  else if (strstr(RXBuff, "OUT4_LOW") != 0)
  {
   OUT4_LOW;
  } 
 }
}

usart.c
Code: [Select]
/****************************************/
/*    SMS Controller using PIC16F688    */
/*    PIC16F688 SMS Controller v0.02    */
/*                                      */
/*                 by                   */
/*            KentronicsPH              */
/*      KentronicsPH.blogspot.com       */
/*       kentronicsph@gmail.com         */
/*                                      */
/*    YOU ARE FREE TO USE THIS S/W      */
/*         AT YOUR OWN RISK!            */
/*    I scrounged up this code from     */
/*    various sources, compiler sample  */
/*    codes and files, advices from     */
/*    forums and other MCU related      */
/*    websites and modifying them for   */
/*    my own purpose.                   */
/*                                      */
/*    This is not a professional s/w,   */
/*    the purpose of which is to help   */
/*    fellow hobbyist and students      */
/*    a guide to code their own SMS     */
/*    controller.                       */
/****************************************/

#define _usart_c_
#include <htc.h>
#include <stdio.h>
#include <string.h>
#include <ctype.h>
#include "usart.h"

bank2 unsigned char RXBuff[rxbuffsize];

volatile unsigned char wptr;

void putch(unsigned char byte) 
{
 /* output one byte */
 while(!TXIF) /* set when register is empty */
  continue;
 TXREG = byte;
}
/*
void puts(const unsigned char * s)
{
 while (*s)
  putch(*s++);
}

void puts2(unsigned char * s)
{
 while (*s)
  putch(*s++);
}
*/
unsigned char getch()
{
 /* retrieve one byte */
 while(!RCIF) /* set when register is not empty */
  continue;
 return RCREG; 
}

unsigned char getche(void)
{
 unsigned char c;
 putch(c = getch());
 return c;
}

void Write_RXBuff(void)
{
 if ((RCSTA & 0b00000110) == 0)
 {
     RXBuff[wptr] = toupper(RCREG);
  //putch(RXBuff[wptr]);
  wptr++;
  if (wptr > (rxbuffsize -1))
   wptr = 0;
 }
 else  /* There is an error! */
 {
  CREN = 0;
  CREN = 1;
 }
  
}

void Reset_RXBuff(void)
{
 wptr = 0;
 memset(RXBuff, 0, rxbuffsize);
}

usart.h
Code: [Select]
/****************************************/
/*    SMS Controller using PIC16F688    */
/*    PIC16F688 SMS Controller v0.02    */
/*                                      */
/*                 by                   */
/*            KentronicsPH              */
/*      KentronicsPH.blogspot.com       */
/*       kentronicsph@gmail.com         */
/*                                      */
/*    YOU ARE FREE TO USE THIS S/W      */
/*         AT YOUR OWN RISK!            */
/*    I scrounged up this code from     */
/*    various sources, compiler sample  */
/*    codes and files, advices from     */
/*    forums and other MCU related      */
/*    websites and modifying them for   */
/*    my own purpose.                   */
/*                                      */
/*    This is not a professional s/w,   */
/*    the purpose of which is to help   */
/*    fellow hobbyist and students      */
/*    a guide to code their own SMS     */
/*    controller.                       */
/****************************************/

#ifndef _SERIAL_H_
#define _SERIAL_H_

#define BAUD 9600      
#define FOSC 8000000L
#define NINE 0     /* Use 9bit communication? FALSE=8bit */

#define DIVIDER ((int)(FOSC/(16UL * BAUD) -1))
#define HIGH_SPEED 1

#if NINE == 1
#define NINE_BITS 0x40
#else
#define NINE_BITS 0
#endif

#if HIGH_SPEED == 1
#define SPEED 0x4
#else
#define SPEED 0
#endif

#if defined(_16F87) || defined(_16F88)
 #define RX_PIN TRISB2
 #define TX_PIN TRISB5
#elif defined(_16F688)
 #define RX_PIN TRISC5  
 #define TX_PIN TRISC4  
#else
  #define RX_PIN TRISC7
 #define TX_PIN TRISC6
#endif

/* Serial initialization */
#define uart_init()\
 RX_PIN = 1; \
 TX_PIN = 1;    \
 SPBRG = DIVIDER;      \
 RCSTA = (NINE_BITS|0x90); \
 TXSTA = (SPEED|NINE_BITS|0x20)

#define rxbuffsize 80

void putch(unsigned char);
/*
void puts(const unsigned char * s);
void puts2(unsigned char * s);
*/
unsigned char getch(void);
unsigned char getche(void);
void Write_RXBuff(void);
void Reset_RXBuff(void);

#ifndef _uasrt_c_
extern bank2 unsigned char RXBuff[rxbuffsize];
extern volatile unsigned char wptr;
#endif

#endif

Complete details and future s/w revisions can be found on this link.

 

No comments:

Post a Comment