首页 > 编程知识 正文

框架模块,at指令是干嘛的

时间:2023-05-05 19:45:42 阅读:148037 作者:2394

通信模块: 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、qrqr 定义at指令的状态机对象:

typedef struct { comd _ state _ ecur _ 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,NCSEARFCN,' AT CFUN=0rn ',' OK ',5000,IDLE,3,default_deaal} //清除存储的频率{NCONFIG1、NCONFIG2、' atnconfig=Cr 3、default_deal}、//扰乱控制{NCONFIG2、NCONFIG3、' at nconce }

ault_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_send(fsm_state_t cmd){ if(cur.at_status == IDLE) { Uart_NB.Uart_SendString(cmd.AtSendStr,strlen(cmd.AtSendStr)); at_recv_time = cmd.wait_time; }}static void At_recv(fsm_state_t *cmd){ uint8_t i; if(cur.try_cnt == 0) //发送次数用完处理 { // 暂定初始化重来 cur.at_status = NO_REC; } // 尚有发送次数时 else { if(at_recv_time > 0) // 接收时间未超时 { cur.at_status = NO_REC; // 没收到数据 //while( (Uart_NB.rx_flag != 1) && (at_recv_time > 0) ); if(Uart_NB.rx_flag == 1) // 规定时间内nbiot串口接收到数据 { Uart_NB.rx_flag = 0; memset(atbuff, 0, sizeof(atbuff));// 清空at指令接收缓存 for(i=0; i<Uart_NB.rx_cnt;i++) // 接收到的数据复制到缓存 { atbuff[i] = U1_RxBuffer[i]; } if( strstr(atbuff, cmd->ATRecStr ) != NULL) { cur.at_status = SUCCESS_REC; // 接收状态赋值为成功 cmd->recv_deal(atbuff, Uart_NB.rx_cnt); // 接收nb模块数据处理 // 接收到数据后,更新当前执行状态机状态 cur.cur_state = cur.next_state; cur.next_state = ATCmds[cur.cur_state].next_state; cur.try_cnt = ATCmds[cur.cur_state].try_cnt; cur.at_status = ATCmds[cur.cur_state].at_status; } Uart_NB.rx_cnt = 0; //串口接收缓存清零 } } else if(at_recv_time == 0) // 超时处理 { cur.try_cnt--; cur.at_status = IDLE; } } }

封装相应的初始化函数和任务函数,后续注册给相应的通讯模块,放进主循环即可:

void AT_init(){ cur.cur_state = ATCmds[AT].cur_state; cur.next_state = ATCmds[AT].next_state; cur.try_cnt = ATCmds[AT].try_cnt;}void At_task(){ if(cur.cur_state != FINISH ) { At_send(ATCmds[cur.cur_state]); At_recv(&ATCmds[cur.cur_state]); } ZD_NB_transfer();}

版权声明:该文观点仅代表作者本人。处理文章:请发送邮件至 三1五14八八95#扣扣.com 举报,一经查实,本站将立刻删除。