最近在做一个项目,调试单片机与GSM(我这里用的是GSM800A)通信时遇到问题。
实现功能:单片机控制GSM模块发送短信(很基础的功能)。用的的是AT指令,还有就是GSM模块启动工作流程。
当我们要开始动手干活时,首先要想着,整个流程时怎么样的?要用到那些知识?一步一步慢慢来,细心的来。就上边的功能来看。可能是这样一套流程:
(1)当我们选取了GSM模块之后,知道它与单片机之间是以串口的方式通信的,那么我们需要做好串口代码工作,并调试好,确保无误。
(2)详细阅读GSM模块的手册,知道它的一整套工作流程。假如我要发送短信:我就需要GSM模块初始化–>获取GSM模块初始化状态–>检测电话卡是否插入–>如果插入正常就进入发短信状态。
(3)细节实现:AT指令呐,用串口软件调试呐……
刚开始都是准备自己干的。结果部分来新人了,领导就安排GSM模块的调试部分给他做,然后新同事给我给了他封装好的代码,接口函数。我就拿过来测试,有问题。慢慢找。找着找着找到如下问题:
发送AT指令函数如下:
/*
* 函数名:GSMSendAtCmd
* 描述 :发送AT指令
* 输入 :-cmd被发送字符
* 输入 :-size被发送数据长度
* 输出 :无
* 返回 :无
*/
void GSMSendText(unsigned char* cmd, u8 size)
{
u8 i;
for(i=size; i>0; i--)
{
GSMSendChar(cmd[i]);
}
}
…………………………………………………………………………………………………………
/*
* 函数名:GSMInit
* 描述 :GSM初始化
* 输入 :无
* 输出 :无
* 返回 :发送短信状态
*/
u8 GSMInit(void)
{
char * cmd = "AT\r\n";
clean_rebuff();
GSMSendAtCmd(cmd, sizeof(cmd));
return GSM_GET_INIT_STATUS;
}
…………………………………………………………………………………………………………
/*
* 函数名:GSMCheckCard
* 描述 :GSM检查电话卡状态
* 输入 :无
* 输出 :无
* 返回 :发送短信状态
*/
u8 GSMCheckCard()
{
char * cmd = "AT+CNUM\r\n"; //同事写的
//char cmd[] = "AT+CNUM\r\n"; //我修改的
clean_rebuff();
GSMSendAtCmd(cmd,sizeof(cmd)); //发送电话卡检查命令
gsm.out_times = 0; //初始化超时次数
return GSM_GET_CARD_STATUS;
}
以上是两个函数,初始化GSM模块,要发送AT指令给GSM模块,也就是串口发送"AT\r\n"给GSM模块。
上边的函数存在的问题:
先看GSMSendAtCmd()这个函数。这样的实现,岂不是将cmd数组中的内容倒着发过去了么?
我修改成了以下的代码,刚开始学习C语言的时候,我就喜欢用for(i=0; i<size; i++)的方式去做延时,而不喜欢for(i=size; i>0; i–)这样的方式,但是用于简单的空跑,延时,是没有区别的,但是这里区别大了。发现问题,修改,心里嘿嘿。
/*
* 函数名:GSMSendAtCmd
* 描述 :发送AT指令
* 输入 :-cmd被发送字符
* 输入 :-size被发送数据长度
* 输出 :无
* 返回 :无
*/
void GSMSendText(unsigned char* cmd, u8 size)
{
u8 i;
for(i=0; i<size; i++)
{
GSMSendChar(cmd[i]);
}
}
可是还是有问题。继续查找。GSMInit()函数中,定义了指针变量,指向了需要发送给GSM模块的指令。刚开始没有发现什么毛病。char * cmd = “AT\r\n”; 与 GSMSendAtCmd(cmd, sizeof(cmd));
和GSMCheckCard()函数中char * cmd = “AT+CNUM\r\n”; 与 GSMSendAtCmd(cmd,sizeof(cmd));
注意:sizeof(cmd)一直为4哎,(在32位平台上,它是指针变量哎)。所以说:在GSMInit()中,发送了"AT\r\n"。但是没有发送‘\0’;而在GSMCheckCard()函数中,指令没有被正常发送,只发送了"AT+C"。我就把cmd定义成了数组,来解决这个问题。
………………………………………………………………………………………………………………
上边问题解决之后,下边又来问题了。程序没有安装理论上来。我就在中断中放了一个发送到屏幕的函数,显示一下,我可以看 。结果,越来越懵逼。什么问题呢?
串口接收数据不完整。很懵逼,因为我串口测试好的哎,回环测试都正常的。
之前老听别人讲,中断中不要放太多的东西,尽可能让中断简洁。放代码:
void USART3_IRQHandler(void)
{
u8 res;
if(USART_GetITStatus(GSM_USART, USART_IT_RXNE) != RESET) //接收到数据
{
res =USART_ReceiveData(GSM_USART); //读取接收到的数据
if(gsm.recv_cnt < GSM_BUFF_SIZE) //防止缓冲区溢出
{
gsm.recv_buff[gsm.recv_cnt]=res; //记录接收到的值
//array[gsm.recv_cnt] = res;
gsm.recv_cnt++; //接收数据增加1
}
SetTextInt32(0,8,gsm.recv_cnt,1,0);//因为我放的这个代码,导致数据接收不完整。这个代码实现由好多代码去实现的.实现过程如下:
//SetTextValue(0,9,array);
//USART_ClearITPendingBit (GSM_USART, USART_IT_RXNE); //只有在多缓存通信中,才推荐清除。
}
}
………
//这个函数中实现过程太多了,发送指令太多,太耗时。原本6个字节的数据,在波特率115200的时候我只能收到
//2个字节的数据,当波特率在9600的时候,就可以收到5个自己的数据了。当把SetTextInt32(0,8,gsm.recv_cnt,1,0);去掉的时候就会正常。
void SetTextInt32(uint16 screen_id,uint16 control_id,uint32 value,uint8 sign,uint8 fill_zero)
{
BEGIN_CMD();
TX_8(0xB1);
TX_8(0x07);
TX_16(screen_id);
TX_16(control_id);
TX_8(sign?0X01:0X00);
TX_8((fill_zero&0x0f)|0x80);
TX_32(value);
END_CMD();
}