单片机裸机环境下编写AT指令程序

1.写在前面
AT指令在各种WIFI模块、2G/4G模块以及一些无线通讯模块中应用广泛。但是用过的朋友都知道,这种方式对于单片机编程来说,并不友好……本篇文章将以ESP8266 WIFI模块为例介绍在单片机裸机环境下编写AT指令程序的一种方式。
2.程序设计
首先串口底层的收发程序不在这里详细介绍。接收程序一般采用中断方式,采用超时判断的方式判断帧结束。
先简单介绍一个概念:状态机,状态转移图。对于程序来说,就是将程序分为几个状态,不同状态执行不同程序,判断条件进行状态转移。具体到C语言程序中,就是switch-case语句。
以ESP8266 WIFI模块的AT指令程序为例,将它的状态分为以下几种:
1.准备发送AT指令
2.发送AT指令
3.等待接收回复数据
4.接收成功
5.接收超时
将几种状态定义成一个枚举类型数据:
typedef enum{ ATCMD_START = 0x00U, ATCMD_SEND = 0x01U, ATCMD_WAIT_REV = 0x02U, ATCMD_REVOK = 0x03U, ATCMD_TIMEOUT = 0x04U} ATCMD_StatusTypeDef;//AT指令状态机 0准备发送确定尝试发送次数 1发送状态 2等待接收 3接收成功 4接收超时
接下来用switch-case语句编写各个状态的程序,如下所示。
//------------------发送AT指令-----------------//参数1:huart 串口号//参数2:cmd AT指令内容//参数3:timeout 单次发送的超时时间//参数4:res 要判断的返回结果//参数5:count 尝试次数//返回值:ATCMD_REVOK 发送且收到回复 ATCMD_TIMEOUT 超时ATCMD_StatusTypeDef AT_CMD_ESP12(UART_HandleTypeDef *huart,uint8_t* cmd,uint16_t timeout,const char* res,uint8_t count){ static ATCMD_StatusTypeDef atcmd_status=ATCMD_START; static uint8_t cnt=1; uint16_t temp; switch(atcmd_status) { case ATCMD_START:        cnt = count;//初始化发送次数 atcmd_status=ATCMD_SEND; break; case ATCMD_SEND: Clr_RxBuf();//清除串口接收缓存        HAL_UART_Transmit_IT(huart,cmd,strlen((const char*)cmd));//发送数据 atcmd_status=ATCMD_WAIT_REV; Esp12cmd_tick=0; break; case ATCMD_WAIT_REV: if(Esp12cmd_tick < timeout) { if(Hand((char*)res,&temp,0))// { atcmd_status=ATCMD_REVOK; } } else { if(cnt>0)//再次发送 atcmd_status=ATCMD_SEND; else atcmd_status=ATCMD_TIMEOUT; cnt--; } break; case ATCMD_REVOK: case ATCMD_TIMEOUT: atcmd_status=ATCMD_START; default: break; } return atcmd_status;}
程序逻辑很简单,其中中Esp12cmd_tick变量为毫秒计数器,在SysTick_Handler中断中进行 1操作。
Hand()为判断串口接收数据中是否包含指定字符串的函数,如下:
//判断串口接收缓存中是否包含substr//参数1 *substr 被判断的字符串//参数2 *index substr在串口缓存中的位置//参数3 start_index串口缓存起始判断位置//返回值 包含返回1 不包含返回0uint8_t Hand(char* substr,uint16_t *index,uint16_t start_index){ uint16_t i,flag=0; char *p; if(Uart5.RxFlag != 1)return 0;//一帧数据未接收完成,直接返回 Uart5.RxFlag = 0; for(i=start_index; i<RX_LEN; i ) { if(Uart5.RxBuf[i]==*substr) { flag=1; p=substr; while(*p) { if(Uart5.RxBuf[i]==*p) { *p ; i ; } else { flag=0; break; } } if(flag==1) { *index = i; break; } } } return flag;}
调用方式
一般设置时都需要多条AT指令,也采用状态机的方式进行设置。以设置WIFI模块为AP模式为例,程序如下:
//-------------------设置为AP模式------------//设置的SSID  密码 和本机IP//成功返回0  返回1表示错误  返回2正在设置uint8_t SetAPMode(UART_HandleTypeDef *huart){  static uint8_t status=0;//  static ATCMD_StatusTypeDef res;    switch(status)  {    case 0:      res = AT_CMD_ESP12(huart,(uint8_t*)'AT CWMODE_DEF=2\r\n',1000,'OK',3);//设置为AP模式      if(res==ATCMD_REVOK)        status=1;      else if(res==ATCMD_TIMEOUT)      {        status=0;        return 1;      }      break;    case 1:      res = AT_CMD_ESP12(huart,(uint8_t*)'AT CWSAP_DEF=\'ESP8266\',\'1234567890\',5,3\r\n',1000,'OK',3);//设置AP       if(res==ATCMD_REVOK)        status=2;      else if(res==ATCMD_TIMEOUT)      {        status=0;        return 1;      }      break;    case 2:      res = AT_CMD_ESP12(huart,(uint8_t*)'AT CIPAP_DEF=\'192.168.5.1\',\'192.168.5.1\',\'255.255.255.0\'\r\n',1000,'OK',3);//设置IP       if(res==ATCMD_REVOK)        status=3;      else if(res==ATCMD_TIMEOUT)      {        status=0;        return 1;      }      break;    case 3://设置UDP      res = AT_CMD_ESP12(huart,(uint8_t*)'AT CIPSTART=\'UDP\',\'192.168.5.255\',8899,8266,0\r\n',1000,'OK',3);      if(res==ATCMD_REVOK)        status=4;      else if(res==ATCMD_TIMEOUT)      {        status=0;        return 1;      }      break;    case 4://设置完成      status=0;      return 0;      default:      break;  }  return 2;  }
上述设置程序中,AT指令接收错误后的操作是返回执行第一条指令,当然也可以进行一些其它操作,比如多次接收错误后模块重新复位等。上述设置程序也可以是WIFI模块主程序的一个状态,WIFI主程序如下。
void ESP12_Task(UART_HandleTypeDef *huart){ switch(WIFI_Status) { case 0://设置为AP模式 if(SetAPMode(huart) == 0)//设置成功,转到等待接收状态 { WIFI_Status=1;      }      break; case 1://等待接收数据 if(Uart5.RxFlag == 1) { Uart5.RxFlag = 0; ESP12_Rev(huart); WIFI_Status = 2; } break; case 2: if(Send_Data(huart,Uart5.TxBuf,Uart5.TxNum)<2)//发送数据 { Uart5.TxFlag = 0; WIFI_Status = 1; } break; default:      break; }}
该函数在程序主循环中周期循环调用即可。可以完成AT指令的发送,等待的操作,也不影响其它程序的执行。
3.总结
本篇文章其实主要介绍了状态机的概念,层层调用。理解起来并不困难,实际编程中非常实用。可以广泛应用于其它程序的编写
(0)

相关推荐

  • STM32如何高效接收串口数据?

    目录 USART3_DR的地址 DMA的通道 DMA的中断 USART接收回调函数 头文件源码 DMA的基本配置 环形队列接收数据 函数原型 参考用例 总结 硬件:stm32f103cbt6 软件:S ...

  • 甲醛检测仪开源项目-产品级开发(一)

    前阵子开源了一个基于TencentOS tiny物联网操作系统的危险气体探测仪项目,这次,我们再来开源一个新的项目-甲醛检测仪,但是做项目之前,有必要了解下接下来要做的一些模块以及如何来进行集成. 1 ...

  • Robomaster电控入门(2)DR16&DT7接收与解码

    套件介绍 Robomaster中遥控机器人的手段是固定的,只能使用大疆提供的DR16&DT7套件进行操控数据的发送和接受.这个套件的手册可以在Robomaster的官网上下载到,里面有详细的说 ...

  • EEDrone开源四旋翼从零开始(4)--DEMO开发

    本贴来详细介绍下Demo工程的开发过程,Demo是完整功能的基础,也可以用来做测试.这里以UART功能DEMO为例,可以从零开始自己编写,也可以参考官方例程,也可以使用cubemx生成. 打开Cube ...

  • STM32 串口DMA接收 Openmv / K210 整数、小数字符串数据 (基于HAL库)

    目录 前言 一.工程配置 二.串口DMA部分代码 1.源文件UART_DMA.c 2.头文件UART_DMA.h 3.stm32f1xx_it.c的修改 4.串口收发DMA测试 三.字符串数字提取代码 ...

  • 你的单片机裸机程序框架是怎样的?

    前言 前不久,我有位做测试的朋友转去做开发的工作,面试遇到了一个问题,他没明白,打电话问了我.题目大概就是: 在单片机裸机开发时,单片机要处理多个任务,此时你的程序框架是怎样的呢? 这其实是个经典面试 ...

  • (7条消息) VS2017环境下开发Linux程序

    参考文章: https://www.cnblogs.com/dongc/p/6599461.html(大部分参考了这位大佬的,做了一些修改,感觉原版有一个小瑕疵) https://blog.csdn. ...

  • Go语言:1分钟写下第一个Go程序,并在终端里以指令方式运行

    这是<Go语言简易入门>系列内容第5篇,所有内容列表见:https://yishulun.com/books/go-easy/目录.html 设置环境变量$GOPATH.$PATH 从官网 ...

  • 复杂环境下的多雷达点迹融合并行处理方法研究

    0 引言 随着电磁环境的日趋复杂以及探测范围的日益扩大,已广泛运用的航迹级融合由于其处理精度低.弱小目标难以捕获等缺陷,逐渐被处理精度更高.稳定性更强的点迹级融合所替代.然而面向多传感器探测信息的点迹 ...

  • 新技术环境下的医院会计档案管理信息化建设

    人工智能环境下会计工作风险及对策 国家动真格!医疗机构这些资金一律收回 新技术环境下的医院会计档案管理信息化建设 医院会计档案是医院日常业务活动的真实记录,反映医院经营过程中的各种经济活动,从会计报表 ...

  • 人工智能环境下会计工作风险及对策

    人工智能环境下会计工作风险及对策 在信息化的大浪潮下, 人工智能已经逐渐渗透到了各行各业, 财会领域亦是如此.然而,人工智能在带来机遇的同时, 也同样隐藏着诸多风险.在探讨人工智能可能会给会计工作带来 ...

  • 研究《信息技术环境下数学学科有效教学策略与方法》 的心得体会

    新课程标准提出了一个重要的数学教育理念,即人人有数学观,人人学习有用的数学.它体现了数学的个性化特征:不同的人在数学上得到不同的发展.遵循这一教学新理念,我在信息技术环境下的数学教学中得到了分层教学的 ...

  • 团队阅读环境下的教师专业成长

    随着教师专业化发展进程的加快,已经有越来越多的教师把专业阅读融入到日常生活中.然而,我们看到,大多数教师的专业阅读一般只关注实用需求,其意义更多地体现在借鉴管理方法.寻找教学支持的便利上.从学校层面来 ...

  • 新媒体环境下,案件报道的诸多隐私“雷区”你该怎样避开

    案件报道,是新闻报道中的重要内容,因具有较高的阅读率.点击率.收看率,被称为新闻报道的"富矿".但案件报道也常因报道不当,引发较多的名誉权.隐私权纠纷,特别是新媒体环境下,信息流动 ...