2023年12月9日发(作者:俄文字母)
AT指令框架
通信模块:BC28
主控:HC32F176KATA
背景:
在公司接受相应的通讯模块,发现要频繁的使用AT指令,然而公司使用的AT指令都是一条条的写的,需要逐条维护,十分麻烦。借着写
nbiot项目时,便自己写了统一的AT指令框架,便于以后对于通讯模块的统一维护。
思路:
结合状态机原理,建立一个二维数组,即表格样式。里面分别存有at指令当前状态,下一状态,发送指令,接受正确应答指令,指令发送后
没有应答的超时时间,重发次数,串口状态,以及特殊处理函数。
特殊处理函数是用来处理非单纯应答正确即可的指令的,比如存储设备的imei号码,我把它放在读取到所有应答数据后的下一步执行。
代码:
定义串口的状态,以及要用到的at指令
typedef enum
{
IDLE = 0,
SUCCESS_REC, //
成功
TIME_OUT, //
超时
NO_REC //
未收到
} rec_state_t;
typedef enum
{
AT = 0, /*
发送
AT
指令测试
*/
CFUN0,
NCSEARFCN,
NCONFIG1,
NCONFIG2,
NCONFIG3,
NCONFIG4,
NBAND,
NCDP,
QREGSWT,
CFUN1,
NCCID,
CIMI,
CGSN,
CPSMS,
// CEDRXS,
NPTWEDRXS,
NRB,
CEREG,
CGATT,
NNMI,
CSQ,
QLWULDATA,
FINISH
} comd_state_e;
定义at指令的状态机对象:
typedef struct
{
comd_state_e cur_state; //
当前状态
comd_state_e next_state; //
下一个状态
char AtSendStr[128]; //
发送字符串(
AT
命令)
char ATRecStr[128]; //
需要返回的正确字符串
int wait_time; //
等待时间,单位为
ms
rec_state_t at_status; //
接收状态
int try_cnt; //
重试次数
uint8_t (*recv_deal)(char* data, uint8_t len); //
动作
:
需要对某些返回的数据记录或者错误处理
}fsm_state_t;
定义完整的at指令表格,程序基本按照表格里的at指令顺序执行
fsm_state_t ATCmds[] =
{
//
参数分别为
//
当前状态
下一个状态
向
NB-IOT
发送字符串(
AT
命令)、
模块应该返回的正确指令、
设置超时(毫秒)、
AT
指令接收状
态、设置重发次数
{AT, CFUN0, "ATrn", "OK", 10000, IDLE, 10,default_deal},//
发送
at
指令,确定模块是否正
常
{CFUN0, NCSEARFCN, "AT+CFUN=0rn", "OK", 5000, IDLE, 3, default_deal},//
关闭射频功能(不
进行无线通讯)
{NCSEARFCN, NCONFIG1, "AT+NCSEARFCNrn", "OK", 300, IDLE, 3, default_deal},//
清除存储的频
点
{NCONFIG1, NCONFIG2, "AT+NCONFIG=CR_0354_0338_SCRAMBLING,TRUErn", "OK", 300, IDLE, 3, default_de
al},//
打开扰码控制
{NCONFIG2, NCONFIG3, "AT+NCONFIG=CR_0859_SI_AVOID,TRUErn", "OK", 300, IDLE, 3, default_deal},//
打开扰码控制
{NCONFIG3, NCONFIG4, "AT+NCONFIG=AUTOCONNECT,TRUErn", "OK", 300, IDLE, 3, default_deal},//
配
置模块自动连接网络
{NCONFIG4, NBAND, "AT+NCONFIG=CELL_RESELECTION,TRUErn", "OK", 300, IDLE, 3, default_deal},//
小
区重选
{NBAND, NCDP, "AT+NBAND=5rn", "OK", 300, IDLE, 3, default_deal},//
设置频段为电信的频
段
{NCDP, QREGSWT, "AT+NCDP=221.229.214.202,5683rn", "OK", 300, IDLE, 3, default_deal},//
云平台接
入
ip
地址及端口设置
{QREGSWT, CFUN1, "AT+QREGSWT=1rn", "OK", 300, IDLE, 3, default_deal},//
设置为
1
,模块
在重启并连接到网络后会触发自动注册物联网平台
{CFUN1, NCCID, "AT+CFUN=1rn", "OK", 5000, IDLE, 10, default_deal},//
开启射频功能
{NCCID, CIMI, "AT+NCCIDrn", "OK", 300, IDLE, 3, default_deal},//
确认
sim
卡是否存在
{CIMI, CGSN, "AT+CIMIrn", "OK", 300, IDLE, 3, default_deal},//
返回
IMSI
码
{CGSN, CPSMS, "AT+CGSN=1rn", "rn+CGSN:", 300, IDLE, 3, default_deal},//
返回
IMEI
码
{CPSMS, NPTWEDRXS, "AT+CPSMS=0rn", "OK", 300, IDLE, 3, default_deal},// PSM
模式设置
// {CEDRXS, NRB, "AT+CEDRXS=0,5rn", "OK", 300, IDLE, 3, default_deal},// eDRX
模式设置
{NPTWEDRXS, NRB, "AT+NPTWEDRXS=3,5rn", "OK", 300, IDLE, 3, default_deal},// eDRX
模式设置
{NRB, CEREG, "AT+NRBrn", "+QLWEVTIND:3", 60000, IDLE, 5, default_deal},//
模块重启
{CEREG, CGATT, "AT+CEREG?rn", "rn+CEREG:0,1", 5000, IDLE, 10,default_deal},//
查询网络注册
状态
{CGATT, NNMI, "AT+CGATT=1rn", "OK", 300, IDLE, 3, default_deal},//
使能网络附着
{NNMI, CSQ, "AT+NNMI=1rn", "OK", 300, IDLE, 3, default_deal},//
接收到一个下行消息后会
发送新消息指示
{CSQ, FINISH, "AT+CSQrn", "rn+CSQ:", 300, IDLE, 3, CSQ_deal},//
查询信号强度
{QLWULDATA, FINISH, "AT+QLWULDATA=", "OK", 1000, IDLE, 3, QLWULDATA_deal},//
发送数
据
};
接下来是AT指令的接收,发送函数:
fsm_state_t cur = {0,0,0,0,0,0,0,0}; //
相当于一个游动指针,表示当前状态
,
执行完就更新
static void At_nd(fsm_state_t cmd)
{
if(_status == IDLE)
{
Uart__SendString(Str,strlen(Str));
at_recv_time = _time;
}
}
static void At_recv(fsm_state_t *cmd)
{
uint8_t i;
if(_cnt == 0) //
发送次数用完处理
{
//
暂定初始化重来
_status = NO_REC;
}
//
尚有发送次数时
el
{
if(at_recv_time > 0) //
接收时间未超时
{
_status = NO_REC; //
没收到数据
//while( (Uart__flag != 1) && (at_recv_time > 0) );
if(Uart__flag == 1) //
规定时间内
nbiot
串口接收到数据
{
Uart__flag = 0;
memt(atbuff, 0, sizeof(atbuff));//
清空
at
指令接收缓存
for(i=0; i 接收到的数据复制到缓存 { atbuff[i] = U1_RxBuffer[i]; } if( strstr(atbuff, cmd->ATRecStr ) != NULL) { _status = SUCCESS_REC; // 接收状态赋值为成功 cmd->recv_deal(atbuff, Uart__cnt); // 接收 nb 模块数据处理 // 接收到数据后,更新当前执行状态机状态 _state = _state; _state = ATCmds[_state].next_state; _cnt = ATCmds[_state].try_cnt; _status = ATCmds[_state].at_status; } Uart__cnt = 0; // 串口接收缓存清零 } } el if(at_recv_time == 0) // 超时处理 { _cnt--; _status = IDLE; } } } 封装相应的初始化函数和任务函数,后续注册给相应的通讯模块,放进主循环即可:void AT_init(){ _state = ATCmds[AT].cur_state; _state = ATCmds[AT].next_state; _cnt = ATCmds[AT].try_cnt;}void At_task(){ if(_state != FINISH ) { At_nd(ATCmds[_state]); At_recv(&ATCmds[_state]); } ZD_NB_transfer();}-
本文发布于:2023-12-09 21:27:01,感谢您对本站的认可!
本文链接:https://www.wtabcd.cn/zhishi/a/1702128421116498.html
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系,我们将在24小时内删除。
本文word下载地址:AT指令框架.doc
本文 PDF 下载地址:AT指令框架.pdf
留言与评论(共有 0 条评论) |