十年單片機開發方案公司深圳英銳恩分享PIC18F452單片機GC864發短信控制流水燈方案,基于QL200開發板。
//------------------------------------------------------------
// 實驗介紹: 利用QL200開發板與GSM模塊實現發送信息控制流水燈,
// GSM模塊為GC864,用三根線連接232的收發腳和地。
// MCU: PIC18F452
// 撥碼: S7撥到ON,S11,S12的高四位撥到ON,其余為OFF
// 現象: 發送“開機”到GSM模塊(一定要插SIM卡),流水燈
// 循環跑,發送“關機”到GSM模塊后流水燈熄滅,可反復
// 操作。
// 基于本實驗可發揮想象,拓展功能 :-)
// 詳細信息參見所用GSM模塊的AT指令集
//------------------------------------------------------------
//宏定義及配置位
#include "pic18.h" //18頭文件
__CONFIG(1,OSCSEN&HS); //振蕩方式為HS
__CONFIG(2,BORDIS&PWRTDIS); //4.2V復位
__CONFIG(4,DEBUGDIS&LVPDIS&STVRDIS); //關調式
__CONFIG(5,CPALL);
__CONFIG(6,WPA&WRTEN);// 寫保護
__CONFIG(7,TRPA&TRPALL&SWDTDIS);// 關看門狗
#define LED0 PORTC //燈組1
#define LED1 PORTB //燈組2
//------------------------------------------------------------
//定義變量
static unsigned char rc_buff[100]; //信息接收緩存
static unsigned char rxter; //信息長度計數
static unsigned char *ptr;
static unsigned char on_counter; //開機信息核對
static unsigned char of_counter; //關機信息核對
static unsigned char TAB_counter; //換行計數器
static unsigned char rC_inter; //延時計數器
static unsigned char sC_inter;
const unsigned char exe_on[]={0x35,0x46,0x30,0x30,0x36,0x37,0x33,0x41,0x0D,0x0A}; //開機的Unicode
const unsigned char exe_of[]={0x35,0x31,0x37,0x33,0x36,0x37,0x33,0x41,0x0D,0x0A}; //關機的Unicode
static volatile unsigned char flag @ 0x1a9; //定義標志位
static volatile bit open_flag @ (unsigned) &flag*8+0; //流水燈運行標志
static volatile bit new_flag @ (unsigned) &flag*8+1; //信息取出正確
static volatile bit get_flag @ (unsigned) &flag*8+2; //有新信息標志
//------------------------------------------------------------
//函數申明
void ExeData(void);
void SysInit(void);
void TimeDelay(unsigned int kk);
void RegistInit(void);
void data_send0(void);
void RegistInit(void);
void data_send1(void);
void UartReceive(void);
void JudgeStat(void);
void comsend(unsigned char kk);
//------------------------------------------------------------
//主函數
void main(void)
{
SysInit(); //初始化
RegistInit();
for(;;)
{
UartReceive();
if(open_flag) //指令正確后開機
ExeData();
}
}
//------------------------------------------------------------
//流水燈子函數,轉圈跑
void ExeData(void)
{
unsigned char k;
for(k=0x08;k!=0;k>>=1) //點亮PORTC高四位
{
LED0 |= k;
TimeDelay(5000);
LED0 = 0;
}
for(k=0X01;k!=0X10;k<<=1) //點亮PORTB高四位
{
LED1 |= k;
TimeDelay(5000);
LED1 = 0;
}
}
//------------------------------------------------------------
//中斷服務
void interrupt isr(void)
{
if(TMR2IF) //定時2中斷處理
{
TMR2IF = 0;
if(rC_inter<100)
rC_inter++;
if(sC_inter<250)
sC_inter++;
}
if(RCIE&&RCIF) //接收中斷處理
{
rC_inter = 0;
if (OERR == 0)
{
rc_buff[rxter] = RCREG;
rxter++;
}
else
{
CREN = 0;
asm("nop");
CREN = 1;
}
}
}
//------------------------------------------------------------
//系統初始化
void SysInit(void)
{
flag = 0; //清標志位
on_counter = 0;
of_counter = 0;
rxter = 0;
sC_inter = 0;
rC_inter = 0;
TAB_counter = 0;
TRISA = 0Xf0;
TRISB = 0Xf0;
TRISC = 0Xf0;
PORTA = 0X00;
PORTB = 0X00;
PORTC = 0X00;
}
//------------------------------------------------------------
//特殊功能寄存器初始化
void RegistInit(void)
{
SPBRG = 0XC; //設置波特率為19200BPS
TXSTA = 0X24; //使能串口發送,選擇高速波特率
RCSTA = 0X90; //使能串口工作,連續接收
RCIE = 0X1; //使能接收中斷
GIE = 0X1; //開放全局中斷
PEIE = 0X1; //使能外部中斷
TMR2IE = 1; //TMR2中斷允許
TMR2IF = 0;
PR2 = 249; //定時計數為250US進中斷
T2CON = 0x04; //開啟定時器2,分頻比為0
RBIE = 0; //禁止B口中斷
}
//------------------------------------------------------------
// 延時子程序
void TimeDelay(unsigned int kk) //軟件延時
{
unsigned int k;
for(k=kk;k>0;k--)
{
asm("nop");
asm("nop");
asm("nop");
asm("nop");
}
}
//------------------------------------------------------------
// 提取信息子程序
void data_send0(void)
{
static unsigned char ask[]={'A','T','+','C','M','G','L',0x0d}; //AT+CMGL 回車
unsigned char i;
for(i=0;i<8;i++) //循環發送8個字節
{
TXREG = ask[i];
NOP();
NOP();
TXIE = 0;
while(!TXIF);
}
}
//------------------------------------------------------------
// 刪除信息1子程序
void data_send1(void)
{
static unsigned char ask[]={'A','T','+','C','M','G','D','=','1',0x0d}; //AT+CMGL 回車
unsigned char i;
for(i=0;i<10;i++) //循環發送10個字節
{
TXREG = ask[i];
NOP();
NOP();
TXIE = 0;
while(!TXIF);
}
}
//------------------------------------------------------------
//調試串口發送子程序
void comsend(unsigned char kk)
{
TXREG = kk;
TXEN = 1;
TXIE = 0;
while(!TXIF);
}
//------------------------------------------------------------
// 接收信息
void UartReceive(void)
{
if(rxter>15&&rC_inter>80)// 接收長度大于15且間隔大于20MS認為接收完成
{
JudgeStat(); //對信息進行操作
rxter = 0;
rC_inter = 0;
}
if(get_flag)
{
if(sC_inter >= 100)
{
data_send0(); //25MS后發送AT+CMGL指令提取信息
get_flag = 0;
}
}
}
//------------------------------------------------------------
// 處理信息
void JudgeStat(void)
{
unsigned char i = 0;
ptr = rc_buff;
while(*ptr != 0x2B) //掃描信息串里有無'+'
{
ptr++;
}
if(*(ptr+4) == 0x49) //+CMTI:提示有新的信息
{
get_flag = 1;
sC_inter = 0;
}
else if(*(ptr+4) == 0x4C) //+CMGL:有信息列出
new_flag = 1;
if(new_flag)
{
new_flag = 0;
ptr = rc_buff; //重新指向緩存區
while(TAB_counter < 2)
{
while(*ptr != 0x0A) //掃描兩次換行
{
ptr++;
}
ptr++;
TAB_counter++;
}
for(i=0;i<8;i++,ptr++) //提取漢字信息
{
if(*ptr == exe_on[i])
on_counter++;
if(*ptr == exe_of[i])
of_counter++;
}
//comsend(on_counter);
//comsend(of_counter);
if(on_counter == 0x08) //開機8個字節全正確
open_flag = 1; //開機標志位置位
if(of_counter == 0x08) //關機8個字節全正確
open_flag = 0; //關機標志位置清零
on_counter = 0; //計數器清零
of_counter = 0;
TAB_counter = 0;
for(i=0;i<100;i++)
rc_buff[i] = 0; //清空接收緩存
data_send1(); //刪除此條信息
}
}
//------------------------------------------------------------
// END
//------------------------------------------------------------