十年单片机开发方案公司深圳英锐恩分享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
//------------------------------------------------------------