📄 gsm12051.c
字号:
#include<reg51.h>
#include<intrins.h>
#define uchar unsigned char
#define uint unsigned int
#define TRUE 1
#define FALSE 0
//#define SEND_TO_GSM
void init(void);
bit Send_Gsm(void); //通过GSM返回信息用 接收采用中断
void Display(void); //7段显示
void Change_and_Save(void); // 对速度进行转化 和 保存
void delay_10ms(uint x);
void watch_dog(void);
bit test_wip(void);
uchar read_out(void);
void write_in(uchar n);
void in5045(bit k, uchar m, uchar *pa, uchar n);
void out5045(bit k, uchar a, uchar *pa, uchar b);
sbit SI = P1^0; // X5045 用
sbit SO = P1^1;
sbit SCK = P1^2;
sbit WDI = P1^3;
bit WAT_DOG; //中断喂狗允许位
bit EN_SEND; //2总线发送允许标记位
bit EN_RETGSM; //通过GSM返回短信的标记
bit COM_TAG; //串口接收数据超时的标签
bit COM1_TAG;
uchar Cont_Num; //D7H 后面的控制字
uchar Tell_Num[6];
uchar Speed[6]; //存放速度值缓冲区
uint Ex_Time; //系统超时 时间
uint Ex1_Time;
uchar Send_to_89C51[5]; //为了传输的可靠 扩展到5个字节 最后一个字节规定为和校验
uchar code gsm0[54]=
{
0xD7,0x35,0x01,0x33,0x80,0x89,0x66,0x99, // 电话号码位 0--7
// 0 1 2 3 4 5 6 7
0x96,0x50,0x90,0x1F,0x72,0x4C, // 限速牌
// 8 9 10 11 12 13
0x7F,0x16,0x53,0xF7,0x00,0x3A,0x00,0x3C, // 编号:<
//14 15 16 17 18 19 20 21
0x00,0x41,0x00,0x4A,0x00,0x30,0x00,0x30,0x00,0x31,0x00,0x3E, // AJ001 >
//22 23 24 25 26 27 28 29 30 31 32 33
0x90,0x1F,0x5E,0xA6,0x8B,0xBE,0x7F,0x6E,0x00,0x3A, // 速度设置:
//34 35 36 37 38 39 40 41 42 43
0x00,0x3C, // <
//44 45
0x00,0x31,0x00,0x32,0x00,0x30, // 120
//46 47 48 49 50 51
0x00,0x3E, // >
//52 53
};
/***********************************主程序*********************************/
void main(void)
{
watch_dog();
delay_10ms(10); //上电沿时1S 保证外设正常上电工作 看门狗需要设置成1.4S 喂狗
init();
out5045(0, 0, Send_to_89C51, 5);
Display();
for(;;)
{
if(EN_SEND==TRUE) //任务就绪
{
EA=FALSE; Change_and_Save();
if(EN_SEND==TRUE) //速度设置合法
{
Display();
EN_SEND=FALSE;
EN_RETGSM=TRUE;
}
EA=TRUE;
}
watch_dog();
if(EN_RETGSM==TRUE) //返回短信
{
EN_RETGSM=FALSE;
Send_Gsm();
}
}
}
/******************************void init(void)******************************
这里2051主要完成对GSM的接收信息和需要的速度传送给89C51所以这完成串口设置
I/O口的初始化和定时器的初始化.
****************************************************************************/
void init(void)
{
watch_dog();
TMOD = 0x21; /* 设置2个定时器的模式 timer1:2 time0:1 */
TL1 = 0xfd;
TH1 = 0xfd;
SCON = 0x50;
TL0 = 0X00;
TH0 = 0XDC;
TR1 = 1;
TR0 = 1;
IE = 0x92;
PT0 = 1; /* 定时器为高优先级 */
P1 = 0XFF;
P3 = 0XFF;
EN_RETGSM = FALSE;
}
/**********************void TIMER0(void) interrupt 1 using 1****************
这为定时器0的中断处理程序。中断函数系统频率,主要用与限时处理,超时出错等.
定时时间为10ms,定时器1用做波特率发生器.
****************************************************************************/
void TIMER0(void) interrupt 1 using 1
{
TL0 = 0x00;
TH0 = 0xDC;
if(--Ex_Time==0)
{ COM_TAG=0; }
if(--Ex1_Time==0)
{ COM1_TAG=0; }
if(WAT_DOG)
{ watch_dog(); }
}
/***************************void communications(void)***********************
串口中断函数,用于接收来自GSM的数据.具体使用待定
***************************************************************************/
void communications(void) interrupt 4 using 2
{
uchar a;
watch_dog();
WAT_DOG=1;
RI=0;
if(SBUF!=0xD7) { WAT_DOG=0; return; }
Ex_Time = 500; /* 超时出错 先设置为1200MS */
COM_TAG = 1; //接收超时标签
TL0 = 0x00;
TH0 = 0xDC;
while((RI!=1) && (COM_TAG)); RI=0; //接收控制字
Cont_Num=SBUF;
// if(Cont_Num!=0x35) { WAT_DOG=0; return; } //if >147 说明是命令 而不是数据
for(a=0; a<6; a++) //保存电话号码
{
while((RI!=1) && (COM_TAG)); RI=0;
Tell_Num[a]=SBUF;
}
if((Tell_Num[0]!=0x01)||(COM_TAG==FALSE)) { WAT_DOG=0; return; }
for(a=8; a<46; a++)
{
while((RI!=1) && (COM_TAG)); RI=0;
if((SBUF!=gsm0[a])||(COM_TAG==FALSE)) { WAT_DOG=0; return; }
}
for(a=0; a<6; a++) //存放速度值
{
while((RI!=1) && (COM_TAG)); RI=0;
if(COM_TAG==FALSE) { WAT_DOG=0; return; }
else { Speed[a]=SBUF; }
}
while((RI!=1) && (COM_TAG)); RI=0;
if(SBUF) { WAT_DOG=0; return; }
while((RI!=1) && (COM_TAG)); RI=0;
if((SBUF!=0x3E)||(COM_TAG==FALSE)) { WAT_DOG=0; return; }
EN_SEND=TRUE; //任务就绪
WAT_DOG=0;
}
/***************************void delay_10ms(uint x)***********************
沿时程序 沿时时间为入口参数 (X*10)ms 无出口参数.
**************************************************************************/
void delay_10ms(uint x) //使用一个局部变量
{
uchar b;
for( ; x>0; x--)
{
_nop_();
for(b=0; b<230; b++)
{
_nop_();
_nop_(); _nop_();
_nop_(); _nop_();
_nop_(); _nop_();
_nop_(); _nop_();
_nop_(); _nop_();
_nop_(); _nop_();
_nop_(); _nop_();
_nop_(); _nop_();
_nop_(); _nop_();
_nop_(); _nop_();
_nop_(); _nop_();
_nop_(); _nop_();
_nop_(); _nop_();
_nop_(); _nop_();
_nop_(); _nop_();
_nop_(); _nop_();
_nop_(); _nop_();
_nop_(); _nop_();
}
}
}
/**************************uchar read_out(void)*************************
读字节程序。功能:从x5045存储区读一个字节数据,下降沿有效。
************************************************************************/
uchar read_out(void)
{
uchar k,f=0;
SCK=1;
for(k=0;k<8;k++)
{
SCK=1; //下降触发
_nop_();
SCK=0;
_nop_();
_nop_();
f<<=1;
if(SO) f+=1;
}
return(f);
}
/*****************************void write_in(uchar n)***********************
写字节程序。功能:传递一个数据写入x5045存储区,上升沿有效。
****************************************************************************/
void write_in(uchar n)
{
uchar k;
WDI=0;
_nop_();
_nop_();
SCK=0;
for(k=0; k<8; k++)
{
if(n&0x80)
{ SI=1; SCK=0; _nop_(); SCK=1; }
else
{ SI=0; SCK=0; _nop_(); SCK=1; }
n<<=1;
}
}
/************************void out5045(uchar data a, uchar data b)*****************
读出x5045存储区指定地址的数据串。功能:k=1为高16页,k=0为低16页,
*pa指向入口数据串首地址,a为首地址,b为数据串长度。
**********************************************************************************/
void out5045(bit k, uchar a, uchar *pa, uchar b)
{
uchar i;
WDI=0;
if(k) write_in(0x0b); //后256字节
else write_in(0x03); //前256字节 READ指令
write_in(a);
for(i=0; i<b; i++)
{
*pa = read_out();
pa++;
}
WDI=1;
}
/********************void in5045(uchar m, uchar *pa, uchar n)*********************
写数据程序。功能:首先测试内部非易失性写操作位wip位,写数据串到x5034存储区指定地址,
m为存储区地址,pa为数据块首地址,n为要写入的数据块的长度。
**********************************************************************************/
void in5045(bit k, uchar m, uchar *pa, uchar n)
{
uchar i;
while(test_wip()); //测试wip位直到wip为0
WDI=0;
write_in(0x06); //WREN 指令
WDI=1;
_nop_();
_nop_();
WDI=0;
if(k) write_in(0x0a); //选高半地址
else write_in(0x02);
write_in(m);
for(i=0;i<n;i++)
{
write_in(*pa);
pa++;
}
WDI=1;
}
/***************************void watch_dog(void)***********************
x5045看门狗的喂狗程序,默认的情况下1.4s 注:程序开始WDI给一次下降沿。
***********************************************************************/
void watch_dog(void)
{
WDI=1;
WDI=0;
_nop_();
_nop_();
WDI=1;
}
/***********************bit test_wip(void)*****************************
读状态寄存器,并返回wip位(即非易失性写操作标记位),1:内部表示忙
************************************************************************/
bit test_wip(void)
{
WDI=0;
_nop_();
write_in(0x05);
if(read_out()&0x01) { WDI=1; _nop_(); _nop_(); return(1); }
else { WDI=1; _nop_(); _nop_(); return(0); }
}
/***************************void Send_Gsm(void)***************************
串口发送数据函数,用于向GSM发送字节数据,入口和出口参数待定.
**************************************************************************/
#ifndef SEND_TO_GSM //Tell_Num[6] Speed[6]
bit Send_Gsm(void)
{
uchar k;
uchar ret[2];
delay_10ms(100);
watch_dog();
SBUF=0XD7; while(TI==0); TI=0;
SBUF=0X35; while(TI==0); TI=0;
for(k=0; k<6; k++) //电话号码
{
SBUF=Tell_Num[k];
while(TI==0); TI=0;
}
for(k=8; k<46; k++) //中文
{
SBUF=gsm0[k];
while(TI==0); TI=0;
}
for(k=0; k<6; k++) //速度数字
{
SBUF=Speed[k];
while(TI==0); TI=0;
}
SBUF=0; while(TI==0); TI=0;
SBUF=0X3E; while(TI==0); TI=0;
WAT_DOG=1;
Ex1_Time=3000; //假设最长的发送时间为 半分钟
COM1_TAG=1;
watch_dog();
while((RI==0)&&(COM1_TAG)); RI=0; //接收 D7H FAH/FBH/BCH
ret[0]=SBUF;
watch_dog();
while((RI==0)&&(COM1_TAG)); RI=0;
ret[1]=SBUF;
if(ret[0]!=0xD7) { WAT_DOG=0; return(0); }
WAT_DOG=0;
switch(ret[1])
{
case 0xfa: return(1); //发送成功
case 0xfb: return(0); //发送失败
case 0xfc: return(0); //模块忙
default : return(0);
}
}
#endif
/****************************void Display(void)******************************
此函数为七段数码管的显示驱动。个位,十位,为七段。百位为一段。百位:P2.7。
十位:P2.0->P2.6 个位:P0.0->P0.6 低电平驱动.
****************************************************************************/
void Display(void) //Send_to_89C51[3]
{
uchar g, s, b;
b=Send_to_89C51[3]/100;
s=(Send_to_89C51[3]%100)/10;
g=Send_to_89C51[3]%10;
switch(s) //高电平驱动
{
case 0: P2=0X3F; break;
case 1: P2=0X06; break;
case 2: P2=0X5B; break;
case 3: P2=0X4F; break;
case 4: P2=0X66; break;
case 5: P2=0X6D; break;
case 6: P2=0X7D; break;
case 7: P2=0X07; break;
case 8: P2=0X7F; break;
case 9: P2=0X6F; break;
default: break;
}
if(b) { P2_7=0; } else{ P2_7=1; }
switch(g)
{
case 0: P0=0X3F; break;
case 1: P0=0X06; break;
case 2: P0=0X5B; break;
case 3: P0=0X4F; break;
case 4: P0=0X66; break;
case 5: P0=0X6D; break;
case 6: P0=0X7D; break;
case 7: P0=0X07; break;
case 8: P0=0X7F; break;
case 9: P0=0X6F; break;
default: break;
}
}
/*****************************void Change_and_Save(void)***********************
此函数为转化和保存函数。主要完成功能:接到GSM的数据后对BCD码数据进行转化为十六
进制数据,然后保存到X5045中去。 转化结果存放在Send_to_89C51[5]数组中。为了保证
传输的可靠性,数组前3字节分别为0X3C,0XF5,0X18,Send_to_89C51[3]放速度,最后一
字节存放校验和. 传输后数据不进行反馈。
*******************************************************************************/
void Change_and_Save(void)
{
Send_to_89C51[0] = 0X01;
Send_to_89C51[1] = 0X17;
Send_to_89C51[2] = 0X2c;
if(Speed[0]||Speed[2]||Speed[4]) { EN_SEND = FALSE; return; }
Send_to_89C51[3] = (Speed[1]&0x0f)*100 + (Speed[3]&0x0f)*10 + (Speed[5]&0x0f);
Send_to_89C51[4]=Send_to_89C51[0]+Send_to_89C51[1]+Send_to_89C51[2]+Send_to_89C51[3];
if((Send_to_89C51[3]<20)||(Send_to_89C51[3]>120)) { EN_SEND = FALSE; return; }
in5045(0, 0, Send_to_89C51, 5);
}
/***********************************结*****束***********************************/
/*******************************************************************************/
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -