接上篇4.门锁系统——卡片识别_only_print的博客-CSDN博客
ESP8266——真正进入物联网,虽然一开始说这个项目是物联网的项目,但是直到现在才算是真正进入物联网的领域,这次我们来学习WIFI模块,让我们的单片机联网。
目录
认识ESP8266
ESP8266为一个WiFi透传模块,和蓝牙透传模块具有主从两种工作模式一样,也具有两种工作模式:STA模式(Station)和AP模式(Access Point),一般WiFi模块还会有一个STA+AP模式,即可以在两种模式下切换的状态。
AP模式下,WiFi模块产生热点,提供无线接入服务,允许其它无线设备接入,提供数据访问,一般的无线路由/网桥工作在该模式下。该模式对应TCP传输协议中的服务端(TCP Server)。
STA模式下,WiFi模块为连接到无线网络的终端(站点),可以连接到AP,一般无线网卡工作在STA模式下。该模式对应TCP传输协议中的客户端(TCP Client)。
我们这次使用的ESP8266型号为ESP01s,其实只要是8266就都差不多:
ESP8266系列一般都具有两种开发方式,一种为AT指令开发方式,即厂家出厂时预先在ESP8266芯片烧入好固件,封装好WiFi的协议栈,内部已经实现透传,而用户只需要使用一个USB转TTL的模块或者单片机的串口就能实现与WiFi模块的通信,发送AT指令来对WiFi模块进行控制。
另外一种开发方式就是SDK开发,因为ESP8266本身即是可编程的芯片,可以把它视为一个带有无线通信的单片机,而用户需要在专门的IDE中编写对应的程序,然后通过烧写固件的方式将程序写入到芯片中,因此,此时想要实现WiFi通信,需要自定义WiFi协议栈,因此对用户掌握的相关知识要求更高。我们这个项目中使用AT模式。
既然使用的是AT模式,那么首先就得先烧录AT固件。一般出厂时会烧录进AT固件的。可以使用USB转TTL直接连接8266,然后打开串口调试助手(波特率为115200),发送AT(发送时要勾选发送新行!!!!),如果串口回复OK,说明有AT固件,如果没有回复,可能就是没有AT固件,不过不要慌张,烧录方式马上就来。
AT固件烧录
烧录之前需要先准备点准备工作:
AT固件汇总 | 安信可科技 (ai-thinker.com),在安可信官网有需要烧录的AT固件,直接下载解压即可。
还需要一个下载器:工具 | 乐鑫科技 (espressif.com.cn),乐鑫官网的下载器。
这两个东西都下载完成后,就可以进行烧录了(嫌寻找麻烦的话,我在本文末尾附上这两个工具)。
首先先连接USB转TTL和8266,连接方式如下:
注意:这个IO0一定要连接!!!否则会导致烧录不成功
连接好后如上图所示。
打开下载器,打开后是一个黑框(不用管那个黑框),中间有个白色的小框选择型号:
小白框中选择和图中一样即可。选择好后点击OK。
按图中步骤操作即可,最后点击开始等待完成即可。完成后即可进行WIFI操作了。
Stm32使用8266连接阿里云
CobeMX设置
因为8266是使用串口操作的,所以我们需要打开串口二,并将串口二和串口一的中断打开,再打开两者的接收DMA通道即可,接下来生成程序即可。
程序实现串口互通
因为我们需要对8266进行调试,所以我们想要看到我们给8266发送的AT指令和8266返回给我们的答复,就需要完成串口一和串口二的数据互通,这里还是和之前一样,为8266创建一个文件夹和对应的8266.c和8266.h文件,将它们添加到程序中。
然后进入8266.c中,在这里我们因为串口收发的数据长度都是不固定的,所以我们需要实现串口接收不定长数据。在实现之前需要定义一些变量:
extern DMA_HandleTypeDef hdma_usart1_rx;
extern DMA_HandleTypeDef hdma_usart2_rx;
uint8_t USART1_RX_BUF[USART1_MAX_RECV_LEN]; //接收缓冲,最大USART3_MAX_RECV_LEN个字节.
uint8_t USART1_RX_STA= 0;//串口是否接收到数据
uint8_t USART2_RX_BUF[USART1_MAX_RECV_LEN]; //接收缓冲,最大USART3_MAX_RECV_LEN个字节.
uint8_t USART2_RX_STA= 0;//串口是否接收到数据
这其中声明是在8266.h文件中定义的。接下来在8266的初始化中完成串口的初始化:
void ESP8266_Init(void)
{
HAL_UARTEx_ReceiveToIdle_DMA(&ESP8266_UART, USART2_RX_BUF, sizeof(USART2_RX_BUF));
HAL_UARTEx_ReceiveToIdle_DMA(&UART1, USART1_RX_BUF, sizeof(USART1_RX_BUF));
__HAL_DMA_DISABLE_IT(&hdma_usart1_rx,DMA_IT_HT);
__HAL_DMA_DISABLE_IT(&hdma_usart2_rx,DMA_IT_HT);
}
初始化完成后将其添加到主函数中。
接下来是对应的8266.h文件:
#include "main.h"
#include "usart.h"
#define USART1_MAX_RECV_LEN 400 //最大接收缓存字节数
#define USART2_MAX_RECV_LEN 400 //最大接收缓存字节数
#define ESP8266_UART huart2
#define UART1 huart1
extern uint8_t USART1_RX_BUF[USART1_MAX_RECV_LEN];
extern uint8_t USART2_RX_BUF[USART1_MAX_RECV_LEN];
extern uint8_t USART1_RX_STA;
extern uint8_t USART2_RX_STA;
void ESP8266_Init(void);
然后回到main.c文件中,在这里重新实现串口接收中断回调函数,来实现串口一和二在接收到信息后分别发送给二和一:
// 重新实现中断回调函数
void HAL_UARTEx_RxEventCallback(UART_HandleTypeDef *huart, uint16_t Size)
{
if(huart == &huart1)
{
HAL_UART_Transmit_IT(&ESP8266_UART,USART1_RX_BUF,Size);
HAL_UARTEx_ReceiveToIdle_DMA(&UART1, USART1_RX_BUF, sizeof(USART1_RX_BUF));
__HAL_DMA_DISABLE_IT(&hdma_usart1_rx,DMA_IT_HT);
}
if(huart == &huart2)
{
HAL_UART_Transmit_IT(&UART1,USART2_RX_BUF,Size);
HAL_UARTEx_ReceiveToIdle_DMA(&ESP8266_UART, USART2_RX_BUF, sizeof(USART2_RX_BUF));
__HAL_DMA_DISABLE_IT(&hdma_usart2_rx,DMA_IT_HT);
}
}
接下来连接8266和stm32,这时只需要连接rx、tx(连接在开发板的tx和rx)、GND和VCC即可,不需要连接IO0。连接完成后烧录程序,在串口处发送AT,看是否有OK的回复。如果回复OK就说明完成了串口的连接。
阿里云的创建
在网页搜索阿里云,登录后选择物联网中的物联网平台(可以试用一个月):
点击公共实例,进入后选择产品,创建产品:
选择自定义产品,自己填写产品名称,完成后点击确认。
完成后在产品栏找到刚才创建的产品,点击查看:
然后点击功能定义,然后选择编辑草稿:
进入后点击添加标准功能:
选择添加其他类型,搜索当前温度,在出来的选项中随便选一个,要问为什么在门禁的后台中选择温度?没有为什么,就是没找到门禁的,反正又不是不能用(哼)。
选择完成后点击确定,然后在编辑草稿页面点击发布上线。完成后就可以在设备处看到刚才创建的产品了,点击查看。
查看MQTT连接参数:
接下来就需要完成8266连接阿里云了。
8266连接阿里云的步骤
这里我不再赘述AT指令的参数了,需要的可以查AT指令的手册
1):确认AT正常;
AT+CWMODE=1
2):连接路由器;
AT+CWJAP="66","1234abcd"
第一个””中是要连接的WIFI的名称,第二个是密码。
3):使能 SNTP 服务器,设置中国时区 (UTC+08:00);
AT+CIPSNTPCFG=1,8,"ntp1.aliyun.com"
这个直接复制即可
5):设置阿里云上的用户命和密码,由网页生成;
AT+MQTTUSERCFG=0,1,"NULL","only_print&iwjauHr3P6U","
cc33ff98eeaeccf73472711896ee91f7cb941d1ba12dd99c8c62502ed9ff6965",0,0,""
6):设置阿里云clientId,由网页生成;
AT+MQTTCLIENTID=0,"
iwjauHr3P6U.only_print|securemode=2,signmethod=hmacsha256,timestamp=1686661884208|"
7):连接阿里云
AT+MQTTCONN=0,"iot-06z00fhtpniomkb.mqtt.iothub.aliyuncs.com",1883,1
这步完成后就可以点击设备,可以看到设备已经显示在线状态了。
8):订阅主题
AT+MQTTSUB=0,"/iwjauHr3P6U/only_print/user/get",1
订阅完成后就可以看到已订阅的设备了,从这里点击发布消息可以向8266发送消息。
到这里就完成了和stm32的连接。
9):上报数据
AT+MQTTPUB=0,"/sys/iwjauHr3P6U/only_print/thing/event/property/post","{params:{\"CurrentTemperature\":32}}",0,0
在之前产品的功能定义处有之前的功能的标识符,只要修改这个就可以了。
上报数据之后在设备的物理型数据中可以看到数据:
这样整个连接和数据传输都完成了,接下来就是将这些封装到之前的函数就好了:
//注意:
//末尾记得加\r\n
//字符串里面的 " 需要转义所以前面需要加 \才能得到正确的"
//字符串里面的一个\在字符串中需要使用\\
extern DMA_HandleTypeDef hdma_usart1_rx;
extern DMA_HandleTypeDef hdma_usart2_rx;
uint8_t USART1_RX_BUF[USART1_MAX_RECV_LEN]; //接收缓冲,最大USART3_MAX_RECV_LEN个字节.
uint8_t USART1_RX_STA= 0;//串口是否接收到数据
uint8_t USART2_RX_BUF[USART1_MAX_RECV_LEN]; //接收缓冲,最大USART3_MAX_RECV_LEN个字节.
uint8_t USART2_RX_STA= 0;//串口是否接收到数据
// 设置Wi-Fi模式
uint8_t cwmode[] = "AT+CWMODE=1\r\n";
// 连接路由器
uint8_t cwjap[] = "AT+CWJAP=\"123123123\",\"12345679\"\r\n";
// 使能 SNTP 服务器,设置中国时区
uint8_t cipsntpcfg[] = "AT+CIPSNTPCFG=1,8,\"ntp1.aliyun.com\"\r\n";
// 设置登录密码
uint8_t mqttusercfg[] = "AT+MQTTUSERCFG=0,1,\"NULL\",\"only_print&iwjauHr3P6U\",\"d38974e0373d5e2cc683d0cd05b0dc5cec7cc9eb77f9ded0edfe0dea73feb9e9\",0,0,\"\"\r\n";
// 配置 MQTT 用户属性
uint8_t mqttclientid[] = "AT+MQTTCLIENTID=0,\"iwjauHr3P6U.only_print|securemode=2\\,signmethod=hmacsha256\\,timestamp=1686622748083|\"\r\n";
// 连接 MQTT Broker
uint8_t mqttconn[] = "AT+MQTTCONN=0,\"iot-06z00fhtpniomkb.mqtt.iothub.aliyuncs.com\",1883,1\r\n";
// 订阅Topic
uint8_t mqttsub[] = "AT+MQTTSUB=0,\"/iwjauHr3P6U/only_print/user/get\",1\r\n";
uint8_t b[] = "123123123\r\n";
void ESP8266_Init(void)
{
HAL_UARTEx_ReceiveToIdle_DMA(&ESP8266_UART, USART2_RX_BUF, sizeof(USART2_RX_BUF));
HAL_UARTEx_ReceiveToIdle_DMA(&UART1, USART1_RX_BUF, sizeof(USART1_RX_BUF));
// 关闭DMA半完成中断
__HAL_DMA_DISABLE_IT(&hdma_usart1_rx,DMA_IT_HT);
__HAL_DMA_DISABLE_IT(&hdma_usart2_rx,DMA_IT_HT);
// HAL_UART_Transmit_IT(&ESP8266_UART,cwmode,sizeof(cwmode));
// while(__HAL_UART_GET_FLAG(&ESP8266_UART,UART_FLAG_TC)==RESET);//等待发送完成
// HAL_Delay(10);
// HAL_UART_Transmit_IT(&ESP8266_UART,cwjap,sizeof(cwjap));
// while(__HAL_UART_GET_FLAG(&ESP8266_UART,UART_FLAG_TC)==RESET);//等待发送完成
// HAL_Delay(10);
HAL_UART_Transmit_IT(&ESP8266_UART,cipsntpcfg,sizeof(cipsntpcfg));
while(__HAL_UART_GET_FLAG(&ESP8266_UART,UART_FLAG_TC)==RESET);//等待发送完成
HAL_Delay(1000);
HAL_UART_Transmit_IT(&ESP8266_UART,mqttusercfg,sizeof(mqttusercfg));
while(__HAL_UART_GET_FLAG(&ESP8266_UART,UART_FLAG_TC)==RESET);//等待发送完成
HAL_Delay(1000);
HAL_UART_Transmit_IT(&ESP8266_UART,mqttclientid,sizeof(mqttclientid));
while(__HAL_UART_GET_FLAG(&ESP8266_UART,UART_FLAG_TC)==RESET);//等待发送完成
HAL_Delay(1000);
HAL_UART_Transmit_IT(&ESP8266_UART,mqttconn,sizeof(mqttconn));
while(__HAL_UART_GET_FLAG(&ESP8266_UART,UART_FLAG_TC)==RESET);//等待发送完成
HAL_Delay(1000);
HAL_UART_Transmit_IT(&ESP8266_UART,mqttsub,sizeof(mqttsub));
while(__HAL_UART_GET_FLAG(&ESP8266_UART,UART_FLAG_TC)==RESET);//等待发送完成
HAL_Delay(1000);
}
还有最后的数据上报需要在之前定义的每个开锁方式中完成,实现方法和上边的一样。可以修改每次上报的数据,以达到识别不同的开锁方式:
到这里整个WIFI模块就开发完成了。