普通代码发送at指令的,至少我去年搜这方面资料的时候,很多都是堵塞性的,主体框架大部分是
:send AT rec ok send ATEO rec OK ... 将连接网络的at流程全部走一遍,然后再正常调用网络发送接收的数据。这样就是堵塞式的收发流程。尤其在低功耗场景下。设备发送完就立刻低功耗,这样堵塞的时间占比明显就过高。故此退出以下框架。
/*
* 作者: GG
* 邮箱: guotaoyuan1998@163.com
* VX: qingya_1998
* 创建日期: 22/08/17
* 更新日期: 22/08/18
* 版本: V1.3
* 更新说明:
* (BETA):增加了指令错误多次后的处理函数
* (BETA):统一的失败判定,默认为重发,特殊需求自改
* (V1.3):新增了部分地方注释,将大部分要移植微调的部分加入标识(GG修改@GSM)区别
* 与之前写的库。
* (V1.3):新增了csq,ccid等外部接口
* ps: 计划下个版本内容:外部接口多场景测试,除了AT和ATE的action判定修改
*
* 使用方式: 调用 g_GsmWork.send();-> g_GsmWork.rec(USART_RX_BUF); (推荐可以在串口完成标志判断后调用)
* -> 对应界面逻辑方面修改,尤其是标识部分
*/
#define AT_SENDDATA printf
static GG_GsmSignSta_TypeDef s_AT_SignSta;
static GG_GsmSendSta Gsm_SignRecHandleCallback(unsigned char *buf);//接收处理(GG修改@GSM)
typedef struct
{
GG_ATStepName Step;//当前步骤
GG_ATStepName NextStep;//下一步骤
void (*action)();//当前步骤指令发送
void (*outTimeAction)(); //超时处理
void (*delAction)(); //多次超时错误处理
uint16_t outtime;//超出单位时间
uint16_t outtimeloop;//超时错误次数
}GG_ATWORK_TypeDef;
static GG_ATWORK_TypeDef s_atBobyHandleMap[] =
{
{AT,ATEO,AT_Action,OutTimeAction,DelAction,100,5},
{ATEO,CCID,ATEO_Action,OutTimeAction,DelAction,100,5},
{CCID,CGDCONT,CCID_Action,OutTimeAction,DelAction,100,5},
{CGDCONT,CSQ,CGDCONT_Action,OutTimeAction,DelAction,100,5},
{CSQ,CREG,CSQ_Action,OutTimeAction,DelAction,100,5},
{CREG,QMTCFG,CREG_Action,OutTimeAction,DelAction,100,5},
{QMTCFG,QMTOPEN,QMTCFG_Action,OutTimeAction,DelAction,100,5},
{QMTOPEN,QMTCONN,QMTOPEN_Action,OutTimeAction,DelAction,100,5},
{QMTCONN,QMTSUB,QMTCONN_Action,OutTimeAction,DelAction,100,5},
{QMTSUB,QMTPUBEX,QMTSUB_Action,OutTimeAction,DelAction,100,5},
{QMTPUBEX,ATWAIT,QMTPUBEX_Action,OutTimeAction,DelAction,100,5},
{QMTPUBEX,ATWAIT,QMTPUBEX_Action,OutTimeAction,DelAction,100,5},
};//(GG修改@GSM)
GG_GsmWork_TypeDef g_GsmWork =
{
Gsm_Process_Send,
Gsm_Process_Rec,
};
如上代码所示,MAP第一个属性是第一个步骤,第二个属性是下一步,之后就是对应的处理,超时或错误处理,和多次超时错误处理。最后是时间和错误允许次数
用的时候自行添加步骤和下一步。
static void AT_Action(void)
{
AT_SENDDATA("AT\r\n");
}
static void ATEO_Action(void)
{
AT_SENDDATA("ATEO\r\n");
}
static void CCID_Action(void)
{
AT_SENDDATA("AT+CCID\r\n");
}
static void CGDCONT_Action(void)
{
AT_SENDDATA("AT+CGDCONT?\r\n");
}
action里面如上代码,自行填入处理,这样做增加了代码量但是维护起来无疑更方便,可以直接跳转,并对特殊指令自行拼接。
static GG_GsmSendSta Gsm_SignRecHandleCallback(unsigned char *buf)
{
//uint8_t sta;
char *p;
switch(s_AT_SignSta.Step)
{
case AT:
{
if(NULL != (p = strstr( (char*)buf,"OK")))
{
//printf("1111");
return WAIT;
}
else
{
return ERR;
}
break;
}
case ATEO:
{
if(NULL != (p = strstr( (char*)buf,"OK")))
{
//printf("1111");
return WAIT;
}
else
{
return ERR;
}
break;
}
之后在上述代码中修改如何判定字符返回是否正确,目前由于初次写,当前框架是ok都算对,后续可以改代码字符“ok”来匹配不同指令回复,因为指令回复和发送不同,回复的变数比较小,基本属于定值,除了接收数据协议帧,所以用了一个长的switch case
//用户接口
//信号,ccid,获取写入
void Gsm_GSQSetData(uint8_t csq);
uint8_t Gsm_GetCSQData(void);
void Gsm_CCIDSetData(uint8_t *buf);
uint8_t* Gsm_GetCCIDData(void);
//联网后发送数据
void Gsm_NetSendData(uint8_t *buf);
//网络连接成功标志,自行放在at指令发送处理中
void Gsm_NetWorkStaSetBit(void);
用户接口除了刚刚说的,也就这块要修改了,ccid和csq读取等接口,因为是初测,没有写这块函数处理,只开通的读取和写入的接口。
测试平台stm32f1,移植在原子基本例程
发送错误或者超时都会重发,五次后会重新发at(这个多次超时接口默认的重新开始,其他功能比如模块断电啥,可以自己从map跳转修改)
该框架原则将驱动和应用层分离。用户调用方便调用方法见本人git链接https://github.com/gglingyishu/AT_INSTRUCT