stm32通过wifi方式进行数据通信时通常采用ESP8266模块,最常用的方法就是通过AT指令与esp模块进行交互,本项目对常用的AT指令进行封装成协议,使用户调用简单的函数即可实现热点连接、服务器连接、开启热点、创建服务器等功能。并提供了两种数据发送模式,用户可根据项目需要选择101协议数据封装发送或无数据封装发送。数据解析也可以根据项目需要设置解析或不解析。协议具有很强的可扩展性,能够根据自己的项目需求对AT指令进行裁剪和扩展。
文章目录
- 项目说明
- 使用说明
- 客户端模式
- 服务器模式
- 移植方法
- AT指令扩展
- 添加方法
- 裁剪方法
- 数据封装与解析
项目说明
git仓库地址:https://github.com/redstarbrother/esp8266ATPackage
项目目录如图所示:
第一个文件夹是stm32f103c8t6板子的项目文件,第二个是NUCLEO-F103RB板子的项目文件,如果使用这两个板子的话可以直接下载对应的项目文件进行二次开发。如果是其他型号mcu则需要下载wifi.c和wifi.h文件进行项目移植,下面会有详细的移植方法。
项目是由博主断断续续半个多月写完的,代码量大约在500行左右,对CLIENT和SERVER模式(暂时还没加入SA模式)进行简单的测试,项目中必然还存在许多未发现的bug,如果在使用过程中遇到了bug请留言告知。
使用说明
客户端模式
将wifi模块作为CLIENT,可以连接wifi热点、连接指定服务器,和服务器进行数据交互。
-
在wifi.h文件中修改CLIENT_WIFI_NAME、CLIENT_WIFI_PWD、CLIENT_IP、CLIENT_PORT,分别为wifi热点名称、密码、服务器IP地址、端口号。
-
16、17行DISPLAY_AT_INFO、PASSTHROUGH 根据项目需求修改,开启数据回显时系统会将从wifi模块接收到的所有数据都通过串口打印,包括AT指令和用户接收到的数据,通常情况在调试bug时才开启。透传模式也是按需开启,如果项目对数据的实时性要求不高可以不开启,开启透传模式后建议两条数据的发送时间间隔不低于50ms。
-
在main.c文件while()循环上面有wifi初始化函数wifiInit(CLIENT)和dataAnalyzeFlag变量,dataAnalyzeFlag为接收数据解析变量,可以在任意位置修改它的值(TRUE|FALSE),作用是开启或关闭数据解析。
-
可调用的数据发送函数为sendData(uint8_t *userdata, uint16_t userLength)和sendData101(uint16_t con, uint16_t addr, uint8_t *data, uint16_t userLength)
- sendData函数直接将用户数据发送到服务器,传入变量分别为用户数据数组和发送长度,系统会发送userdata数组的前userLength个字节。
- sendData101函数接收四个变量,除了用户数据数组和发送长度之外还会接收con和addr数据,并且会对用户数据进行数据封装,封装方式见xxx
-
当用户接收到服务器端发来的数据时会调用wifi.c文件中的*userToDo(uint8_t *data, uint16_t length, uint16_t con, uint16_t addr)*函数,分别为接收到的数据、数据长度、con、addr。用户可以在此函数中执行相应操作,最好不要加延时可能会出错。
服务器模式
将wifi模块作为SERVER,可创建wifi热点、创建服务器、和客户端进行数据交互。
- 在wifi.h文件中修改SERVER_PORT、SERVER_TIMEOUT、SERVER_WIFI_NAME、SERVER_WIFI_PASSWORD、SERVER_CHANNEL、SERVER_ENCRYPTION,分别为服务器开启的端口号、服务器连接超时时间、wifi热点名称、密码、wifi热点信道、wifi热点加密方式。
- 16行DISPLAY_AT_INFO配置同上。
- 在main.c文件while()循环上面有wifi初始化函数wifiInit(SERVER)和dataAnalyzeFlag变量,同上。
- 服务器端发送函数暂时不可用,下个版本再加。
- userToDo()函数同上。
移植方法
如果mcu型号不是f103c8tx或F103RB可以参考移植方法进行mcu适配。
- 通过cubemx创建新项目
- 配置定时器,定时周期为1ms,这块根据自己的时钟主频进行修改我的mcu主频为72M,所以根据公式溢出时间=((1+TIM_Prescaler )/72M)*(1+TIM_Period ) TIM_Prescaler 和TIM_Period 分别为72-1、10000-1。
- 配置串口和DMA,一般来说配置两个串口,一个连接wifi模块、另一个用于调试。配置wifi串口的接收端为DMA方式
- 中断优先级,可根据项目需求进行修改,保证wifi串口中断优先级最高。
- 时钟树配置
- Code Generator中设置为每个外设生成独立的’.c/.h’文件。
- 将wifi.c和wifi.h分别复制到项目根目录的Src和Inc文件夹中,打开项目并添加两个文件。
- 在stm32f1xx_it.c文件中添加
- 添加#include “wifi.h”
- USARTx_IRHandler函数( wifi串口的IRHandler函数中)中添加 :
USER_UART_Handler(); HAL_UART_Receive_DMA(&huartx,Espdatatype.DMARecBuffer,DMA_REC_SIZE); //重新打开DMA接收
- 添加定时器中断回调函数:
void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim) { static uint8_t count = 0; if (htim == (&htimx)) { count++; if(count>=10) { // printf("timer interupt"); recDataHandle(); count = 0; } } }
- 在main.c文件中添加
- 添加#include “wifi.h”
- while循环前加入wifi初始化函数
wifiInit(CLIENT); // 需要以服务器模式工作则将传入参数更改为SERVER
- 在wifi.c文件中修改
- 第6行 UART_HandleTypeDef *wifiCom = &huartx; 将&huartx修改为wifi串口
- 第39行 HAL_TIM_Base_Start_IT(&htimx); 将&htimx修改为配置好的定时器
- 第53行 temp = hdma_usartx_rx.Instance->CNDTR; 将usartx修改为wifi串口
- 第457行 if(huart->Instance == USARTX) 将USARTX修改为wifi串口
- 第518、521行 while((USARTX->SR & 0x40) == 0);USARTX->DR = (uint8_t) ch; 将USATTX修改为测试串口,如果没有配置测试串口可以将整个函数删除
- 在wifi.h文件中第52行extern DMA_HandleTypeDef hdma_usartx_rx;将usartx修改为wifi串口
- Options for Target --> C/C++ --> Optimizztion 将代码优化等级设置为Level 0
- 编译项目、编写业务代码。
AT指令扩展
本协议支持AT指令扩展,目前只实现了常用的AT指令解析。用户可根据项目需要进行AT指令的添加和删除。
添加方法
例如添加AT+CWAUTOCONN指令,在ESP8266AT指令集页面找到对应的指令。
- 在wifi.c文件中添加布尔型Flag变量autoConnectAPFlag,默认为FALSE。
- 在recDataHandle(void)函数中添加解析语句
- 在clientStart()或serverStart()函数中添加相应的指令发送代码和具体操作。
部分AT指令可能需要其他的操作,根据具体指令修改。
裁剪方法
可根据添加方法步骤按需删除不需要的AT指令代码。
数据封装与解析
协议包含两种数据发送函数,一种是直接发送用户数据sendData(),这种方式适用于用户数据不需要封装或用户有自己的数据封装格式。另一种是将用户数据封装后发送sendData101(),这种方式将会对用户的数据进行封装再发送从而保证数据的准确性和有效性。
数据封装格式是在电网101规约的基础上精简得到,101规约解析可以参考文章:https://blog.csdn.net/ZhangYu971014/article/details/79841555
协议格式:
68H HL LL 68H HC LC HA LA DATA CS 16H
数据/字节 | 解析 |
---|---|
68H | 帧头 |
HL | 数据长度高8位 |
LL | 数据长度低8位 |
68H | 帧头 |
HC | 控制数据高8位 |
LC | 控制数据低8位 |
HA | 地址数据高8位 |
LA | 地址数据低8位 |
DATA(…) | 用户数据 |
CS | 数据校验 |
16H | 帧尾 |
控制、地址数据为16位数据,用户数据传入值为数组,但只发送指定长度的数据
数据长度 = 控制域到用户数据结尾的总字节长度
校验位CS = ~(控制域 + 地址域 + 用户数据)
校验位数据CS为8bit数据,从控制域一直加到用户数据结尾,将得到的值取反,那么接收端接收到的数据从控制域一直加到用户数据结尾再加校验位CS得到的值一定为0xff,否则说明数据不完整或接收出错。
举个栗子:
用户向服务器发送数据,控制数据为0x01,地址数据为0x02,DATA数组为{0x01, 0x02, 0x03, 0x04, 0x05},发送长度为5。帧头为0x68,数据长度为5+4=9,所以高8位为0x00,低8位为0x09,控制数据高8位、低8位分别为0x00、0x01,地址数据高8位、低8位分别为0x00、0x02,用户数据为DATA数组,CS为~(0x01+0x02+0x01+0x02+0x03+0x04+0x05)=0xED=11101101B,帧尾为0x16。所以最终的数据为【0x68 0x00 0x01 0x00 0x02 0x01 0x02 0x03 0x04 0x05 0xED 0x16】
函数解析就是数据封装的逆向过程,可以参考数据封装理解解析函数。
原文链接:https://www.jhxblog.cn/article/?articleid=24