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

2023-10-26

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;

接下来用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  不包含返回0
uint8_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.总结

本篇文章其实主要介绍了状态机的概念,层层调用。理解起来并不困难,实际编程中非常实用。可以广泛应用于其它程序的编写

 

欢迎关注公众号"嵌入式技术开发",大家可以后台给我留言沟通交流。如果觉得该公众号对你有所帮助,也欢迎推荐分享给其他人。

图片

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

单片机裸机环境下编写AT指令程序 的相关文章

  • CNCopyCurrentNetworkInfo 不适用于 iOS 14

    我有一个使用 WIFI 连接到外部设备的应用程序 我曾经通过检查 WIFI SSID 来验证 iPhone 是否已连接到该设备 当 iOS 13 发布时 这个问题被阻止了 我通过请求位置权限来获取 SSID 来修复它 我现在尝试使用启用了位
  • 无需连接WiFi即可获取MAC地址

    是否可以在未实际连接的情况下获取 WiFi MAC 地址 假设我有 Android 设备 A 我已经打开了 WiFi 因此我的 Android 设备现在能够检测到附近广播的 WiFi SSID 我附近有一些广播的 WiFi SSID 如下所
  • 如何使用 iPhone 使用蓝牙或 wifi 与 OBD II 通信

    我喜欢为 iOS 创建一个简单的应用程序 它通过 ODB II Wifi 蓝牙设备从汽车读取数据并显示在 iPhone 屏幕上 但我不知道从哪里开始 请有人帮助我实现以下结果 我有蓝牙和 WiFi 适配器 第 1 步 将蓝牙或 Wifi 适
  • Android :: 如何断开与 wifi 网络的连接?

    我用谷歌搜索发现很多网站都在说 禁用 Wifi 无线电 但就我而言 我只想让 Android 设备断开与特定 wifi 网络 SSID 已知 的连接 而不关闭 WiFi 无线电 请给我一些关于这个问题的见解 哇 这不应该花一个月的时间才能得
  • 学习STM32正点原子好吗?

    今日话题 学习STM32正点原子好吗 正点原子的教程内容简单明了 代码也清晰直接 使初学者能够轻松理解其功能和使用方法 尤其对于需要快速完成大学作业等任务的大学生来说 可以直接借鉴并稍作修改 便可满足需求 正点原子提供的资料通俗易懂 适合用
  • 会stm32有机会进大公司吗?

    今日话题 会stm32有机会进大公司吗 我本科期间参与了飞思卡尔和电赛等比赛 使用过多种单片机 但渐渐发现单片机只是其中的一小部分 不要过分迷恋所谓的单片机基础和技巧 更值得深入研究的是C语言 如果你对此感兴趣 我愿意无偿分享一个资源包 其
  • 获取WIFI信号强度-寻求最佳方法(IOCTL、iwlist(iw)等)

    我想扫描从3个AP接收到的信号强度 如果每 300 毫秒 最多 500 毫秒 发生一次 我会很高兴 我在路由器上刷了 OpenWRT 我正在寻找一个好的工具来做到这一点 首先 我发现 iwconfig 可以工作 但仅限于我连接到的网络 所以
  • C 语言文件读取全指南:打开、读取、逐行输出

    C 语言中的文件读取 要从文件读取 可以使用 r 模式 FILE fptr 以读取模式打开文件 fptr fopen filename txt r 这将使 filename txt 打开以进行读取 在 C 中读取文件需要一点工作 坚持住 我
  • iOS 检查 WiFi 辅助是否已启用

    我正在尝试检查 WiFi 辅助是否已启用 当我连接到接入点获取一些数据时遇到问题 当我的连接状况不佳时 我的蜂窝数据会被使用并干扰我的接入点 有什么方法可以检查该选项是否启用 好吧 我想我能帮上一点忙 你需要check SCNetworkR
  • 嵌入式开发--STM32G4系列片上FLASH的读写

    这个玩意吧 说起来很简单 就是几行代码的事 但楞是折腾了我大半天时间才搞定 原因后面说 先看代码吧 读操作 读操作很简单 以32位方式读取的时候是这样的 data IO uint32 t 0x0800F000 需要注意的是 当以32位方式读
  • C# 介绍、应用领域、入门、语法、输出和注释详解

    什么是 C C 发音为 C Sharp 是一种由 Microsoft 创建的面向对象的编程语言 运行在 NET Framework 上 源于 C 家族 与流行的语言如 C 和 Java 相近 首个版本发布于 2002 年 而最新版本 C 1
  • 如何禁用 Android 设备的强制网络助手?

    当用户通过强制门户连接到开放 WiFi 时 Android 设备将打开带有强制门户 登录页面的浏览器实例 我们想禁用它 因为我们使用应用程序进行登录 我在 Android Marshmallow 中遇到了 CaptivePortal 类 我
  • iPhone 802.11 扫描

    我正在开发一个室内位置使用 wifi 的系统 但是我在使用苹果库时遇到了问题 曾经是私人的 现在是公共的 我在哪里使用代码 libHandle dlopen System Library SystemConfiguration IPConf
  • iOS Swift 以编程方式连接 WiFi 并区分密码错误和范围内没有 WiFi

    NEHotspotConfiguration工作正常 但错误是nil当我尝试连接的 SSID 不可用 超出范围或关闭 或我提交的密码不正确时 我究竟做错了什么 我希望能够区分这两种情况 以便我可以相应地通知用户 代码片段 func conn
  • 如何使用 Objective-C 判断 iPhone 是否连接到 wifi 网络?

    在 Objective C iPhone 应用程序的上下文中 我需要能够判断 iPhone 是否已连接到 wifi 网络 并在可能的情况下侦听此状态的变化 有谁知道如何做到这一点 谢谢 加布伊 正如其他人提到的 可达性样本 https de
  • 如何在 .net 中获取可用的 wifi AP 及其信号强度?

    有没有办法使用 NET 访问所有 WiFi 接入点及其各自的 RSSI 值 如果我可以在不使用非托管代码的情况下完成它 那就太好了 或者如果它可以在 Mono 和 NET 中工作 那就更好了 如果可能的话 我将不胜感激代码示例 谢谢 以下是
  • 如何捕获无线路由器的原始信号?

    我现在看到了几个项目 它们从典型无线路由器收集的无线电数据中获取新颖的空间信息 http wisee cs washington edu http wisee cs washington edu http www extremetech c
  • 启用/禁用 Microsoft 虚拟 WiFi 微型端口

    我禁用了我的Microsoft Virtual WiFi Miniport网络适 配器来自Control Panel Network and Internet Network Connections 只需右键单击微型端口网卡并单击 禁用 它
  • 多久轮询一次 wifi 信号强度?

    理想情况下 我希望近乎实时地监控无线网络的信号强度 比如每 100 毫秒一次 但如此高的频率可能有点过大了 我正在使用托管无线网络 http managedwifi codeplex com 库轮询 RSSI 我实例化一个WlanClien
  • 从 ScanResult 构造 WifiConfiguration 或: 解释 ScanResult 的“功能”字符串

    你们中的 Android 专家知道任何开源代码来创建一个WifiConfiguration http developer android com reference android net wifi WifiConfiguration ht

随机推荐

  • Java多线程编程

    1 Java多线程推荐两本比较好的书 Java多线程编程实战指南 核心篇 pdf 2017年出版 内容新 讲解清晰 首推这本 然后是 Java多线程编程核心技术 2015年出版 由浅入深 编程例子多 也不错 本博客只做易忘拾遗 2 this
  • 【100%通过率 】【华为OD机试 c++/java/python】任务总执行时长【 2023 Q1

    华为OD机试 题目列表 2023Q1 点这里 2023华为OD机试 刷题指南 点这里 题目描述 任务总执行时长 任务编排服务负责对任务进行组合调度 参与编排的任务有两种类型 其中一种执行时长为taskA 另一种执行时长为taskB 任务一旦
  • 麒麟 mips mysql_中标麒麟(龙芯CPU)--docker基础镜像制作

    Docker 是一个开源的应用容器引擎 基于 Go 语言 并遵从Apache2 0协议开源 Docker 的出现为开发人员和运维人员带来了极大的便利 Docker在X86下常见的发行版Linux如Ubuntu Centos上应用非常成熟 教
  • 数据结构---插入排序

    插入排序 算法思想 具体流程 JAVA实现 算法时间复杂度为O n2 的排序 冒泡排序 弊端 元素交换次数太多了 选择排序 弊端 当数列包含多个值相等的元素时 选择排序有可能打乱它们原有的顺序 插入排序 算法思想 维护一个有序区 把元素一个
  • spring-session整合redis原理 排查失效原因

    根据网上配置了一个springsession整合redis作为session后 发现session获取失败 redis里面是有值 登录模块设置进去也能获取的到 但是其他的服务就获取不到 记录一下 跟着源码探寻为何失败 auth服务的配置 引
  • Linux下SVN 命令每次都要输入密码

    问题描述 SVN每次操作都需要输入密码 操作相当麻烦 影响效率 解决方法 修改vi subversion config 文件 将password stores的值修改为simple 即 password stores simple auth
  • k8s中文件描述符与线程限制

    背景 linux中为了防止进程恶意使用资源 系统使用ulimit来限制进程的资源使用情况 包括文件描述符 线程数 内存大小等 同样地在容器化场景中 需要限制其系统资源的使用量 限制方法 ulimit docker 默认支持ulimit设置
  • 跑深度学习nvidia驱动忽然失效的详细解决方法

    由于经常跑深度学习 所以对于显卡驱动什么的都还是整的比较明白的不含糊 所以都能跑的起来 但是今天跑pytorch框架时 用到cuda 忽然给我报了个错 RuntimeError No CUDA GPUs are available 这给我整
  • 两个非递减顺序表合并成一个非递减顺序表

    两个非递减顺序表合并成一个非递减顺序表 引入 以下这个例题的描述是关于合并两个有序的数组 然后合并之后同样也是一个非递减的顺序排列 但是我名这里讲的不是顺序表 而是封装成一个顺序表 但是我们这里的顺序表其实底层同样是一个数组 所以解题的思路
  • 脚踏实地《数据结构第二章》第一节:线性表的定义和基本操作

    考点分析 一 线性表的定义 数据结构三要素 逻辑结构 定义 线性表是具有相同数据类型的n n gt 0 个数据元素的有限序列 其中n为表长 当n 0时线性表是一个空表 相同 每个数据元素所占空间一样大 帮助计算机快速找到某一个具体的元素 序
  • Deepin(Linux)下安装tensorflow-gpu(2019-5-28)

    2019 9 7更新 六 6中安装tensorflow gpu不要采用pip install tensorflow gpu 1 9 直接用conda install channel https conda anaconda org anac
  • Spring MVC案例

    文章目录 Spring MVC 基于XML配置与注解的方式使用Spring MVC 一 创建项目SpringMVCDemo01 二 在pom xml中添加依赖 三 添加项目web功能 四 创建登录页面 登录成功页面 登录失败页面 五 创建登
  • 网安之web攻防第三十天

    知识点 1 数据库堆叠注入 根据数据库类型决定是否支持多条语句执行 2 数据库二次注入 应用功能逻辑涉及上导致的先写入后组合的注入 3 数据库Dnslog注入 解决不回显 反向连接 SQL注入 命令执行 SSRF等 4 黑盒模式分析以上 二
  • airpodspro窃听模式_AirPods Pro实时收听怎么关闭? AirPods Pro实时收听的使用方法

    苹果全新AirPods Pro增加了许多新功能 首先 是控制播放 苹果在AirPods Pro中放弃了敲击手势 并用杆上的力传感器取代了它 控制音乐或视频只需要简单的短按即可 一次按压即可播放或暂停当前播放 两次按压将跳至下一曲目 而三次挤
  • 2019-07-11T09:15:41.000+0000类似时间转换

    let a 2019 07 11T09 15 41 000 0000 new Date a
  • (个人)AR电子书系统创新实训第一周(2)

    了解ZXing Net 想要在unity上实现下载资源的功能 我首先需要确认二维码扫描系统在unity上的可行性 如果要自行开发一套二维码扫描系统 不仅需要知道二维码生成和解码的原理 而且应该还需要用到一些图形学相关的代码库 如opencv
  • Android中为layout创建子文件夹

    在开发Android项目的时候 往往都有一大批java文件和layout文件 java文件分类比较简单 直接方法创建文件夹就行 但layout还需要多一步配置 看最后的文件结构图 实现步骤 1 创建相应的文件夹结构 需要注意的是 无论如何
  • ‘float‘ object has no attribute ‘decode‘

    错误代码 weibo df pd read csv Users dl Desktop 情感分析论文 词云图 微博文本数据 原始数据 原数据 表格 微博文本内容 csv print weibo df head 在读取csv或者excel文件时
  • Python基础—文件操作

    Python基础 文件操作 文件操作 文件是指为了重复使用或长期使用的目的 以文本或二进制形式存放于外部存储器 硬盘 U盘 光盘等 中的数据保存形式 文件是信息交换的重要途径 也是利用程序解决实际问题的重要媒介 程序对数据读取和处理都是在内
  • 单片机裸机环境下编写AT指令程序

    1 写在前面 AT指令在各种WIFI模块 2G 4G模块以及一些无线通讯模块中应用广泛 但是用过的朋友都知道 这种方式对于单片机编程来说 并不友好 本篇文章将以ESP8266 WIFI模块为例介绍在单片机裸机环境下编写AT指令程序的一种方式