打印
[产品应用]

介绍在单片机裸机环境下编写AT指令程序的一种方式

[复制链接]
169|2
手机看帖
扫描二维码
随时随地手机跟帖
跳转到指定楼层
楼主
本帖最后由 两只袜子 于 2023-3-24 10:23 编辑

1.写在前面
  AT指令在各种WIFI模块、2G/4G模块以及一些无线通讯模块中应用广泛。但是用过的朋友都知道,这种方式对于单片机编程来说,并不友好……本篇文章将以ESP8266 WIFI模块为例介绍在单片机裸机环境下编写AT指令程序的一种方式。
  2.程序设计
  首先串口底层的收发程序不在这里详细介绍。接收程序一般采用中断方式,采用超时判断的方式判断帧结束。
       先简单介绍一个概念:状态机,状态转移图。对于程序来说,就是将程序分为几个状态,不同状态执行不同程序,判断条件进行状态转移。具体到C语言程序中,就是switch-case语句。
  以ESP8266 WIFI模块的AT指令程序为例,将它的状态分为以下几种:
  1.准备发送AT指令
  2.发送AT指令
  3.等待接收回复数据
  4.接收成功
  5.接收超时
  将几种状态定义成一个枚举类型数据:


  接下来用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()为判断串口接收数据中是否包含指定字符串的函数,如下:




  调用方式
  一般设置时都需要多条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主程序如下。




  该函数在程序主循环中周期循环调用即可。可以完成AT指令的发送,等待的操作,也不影响其它程序的执行。
  3.总结
  本篇文章其实主要介绍了状态机的概念,层层调用。理解起来并不困难,实际编程中非常实用。可以广泛应用于其它程序的编写。







使用特权

评论回复
沙发
caigang13| | 2023-4-3 18:55 | 只看该作者
AT指令就是对应的命名加回调函数

使用特权

评论回复
板凳
jf101| | 2023-4-10 18:46 | 只看该作者
AT 指令着重应用在蜂窝模块、WiFi 模块、BLE 模块中

使用特权

评论回复
发新帖 我要提问
您需要登录后才可以回帖 登录 | 注册

本版积分规则

1883

主题

6437

帖子

8

粉丝