课程大纲
【第一章】:物联网简介(什么是物联网)
【第二章】:物联网十大应用场景
【第三章】:什么是MCU?
【第四章】:MCU的应用范围
【第五章】:我们要怎么入门MCU开发?
【第六章】:如何使用STM32Cube MX进行STM32的快速开发
【第七章】:ESP8266+MQTT上阿里云物联网平台实践(附源码)
STM32CubeMX AT指令实现MQTT协议并接入阿里云IOT平台 源码解析
CSDN源代码下载
Github源代码下载
目录
- 课程大纲
- 7. 实践:STM32使用ESP8266+MQTT上阿里云物联网平台实践
- 7.1 项目整体介绍
- 7.1.1 硬件资源
- 7.1.2 软件资源
- 7.1.3 其它资源
- 7.2 新建工程
- 7.3 基础工程配置
- 7.3.1 时钟配置
- 7.3.2 下载接口设置,设置为串行下载
- 7.3.3 LED灯配置
- 7.3.4 按键输入中断设置
- 7.3.5 调试串口设置
- 7.3.6 ES8266串口设置
- 7.3.7 DHT11数据采集IO
- 7.3.8 工程概览
- 7.4 生成并验证工程
- 7.4.1 生成工程
- 7.4.2 编写USART2串口调试验证代码
- 7.4.3 编写三色灯测试代码
- 7.4.4 编写按键中断测试代码
- 7.5 移植DHT11温湿度传感器驱动程序
- 7.5.1 利用TIM1实现us级延时(编写DHT11驱动时会用)
- 7.5.2 添加DHT11驱动文件到工程中
- 7.5.3 修改驱动.c .h程序文件
- 7.6 移植ESP8266 AT指令WIFI驱动模块
- 7.6.1 连接硬件
- 7.6.2 添加ESP8266串口驱动文件到工程中
- 7.6.3 驱动程序分析
- 7.6.4 测试ESP8266驱动程序
- 7.7 移植MQTT驱动
- 7.7.1 添加驱动文件到工程中
- 7.7.2 使能USART1接收中断,添加接收函数
- 7.7.3 在main.c中引入头文件,测试代码
- 7.8 MQTT协议简单介绍
- 7.9 阿里云物联网平台介绍
- 7.9.1 创建产品
- 7.9.2 定义产品功能
- 7.9.3 添加具体设备
- 7.9.4 使用MQTT.fx模拟硬件进行连接
- 7.9.5 订阅消息调试
- 7.9.6 使用MQTT.fx模拟设备进行消息推送
- 7.10 STM32 使用MQTT接入阿里云平台过程详解
- 7.11 STM32传感器数据上传、平台数据下发效果展示
7. 实践:STM32使用ESP8266+MQTT上阿里云物联网平台实践
7.1 项目整体介绍
7.1.1 硬件资源
- STM32F429IGT6开发板:核心
- ST-Link下载器:下载程序用
- USB转232串口线:串口通信,调试用
- USB供电线:给开发板供电
- DHT11温湿度模块:采集环境温湿度
- ATK-ESP8266:联网上传数据
7.1.2 软件资源
- 串口调试助手(调试用)
7.1.3 其它资源
- STM32F429IGT6开发板原理图
- DHT11温湿度传感器编程手册
- ATK-ESP8266编程手册
- ESP8266样例程序
- 阿里云MQTT样例程序
7.2 新建工程
- 选择通过选择MCU创建工程
- 选择芯片
- 建立成功
7.3 基础工程配置
7.3.1 时钟配置
- 高速时钟:选择外部晶振
- 高速时钟选择Crystal/Ceramic Resonator
在用cube配置时钟时,有下面两个选项
BYPASS Clock Source(旁路时钟源)
Crystal/Ceramic Resonator(晶体/陶瓷晶振)
下面来解释一下:
所谓HSE旁路时钟源,是指无需使用外部晶体时所需的芯片内部时钟驱动组件,直接从外界导入时钟信号。犹如芯片内部的驱动组件被旁路了。
外部晶体/陶瓷谐振器(HSE晶体)模式该时钟源是由外部无源晶体与MCU内部时钟驱动电路共同配合形成,有一定的启动时间,精度较高。
- 配置时钟为180MHz
7.3.2 下载接口设置,设置为串行下载
7.3.3 LED灯配置
-
查看原理图
LED_R——PH10 红灯
LED_G——PH11 绿灯
LED_B——PH12 蓝灯
低电平有效,IO口要设置为推挽输出,上拉
-
工程配置
-
选择引脚设置为GPIO_Ooutput
-
配置标签 LED_R LED_G LED_B,方便工程直接调用
-
设置上下拉
-
7.3.4 按键输入中断设置
- 查看原理图
- 工程设置
- 设置中断等级,不能太高
7.3.5 调试串口设置
- 查看开发板原理图,找到RS232
- 修改跳帽方向
- 串口参数配置
- 修改PD5为USART2_TX
- 修改PD6为USART2_RX
- PA2 PA3自动取消定义
7.3.6 ES8266串口设置
7.3.7 DHT11数据采集IO
7.3.8 工程概览
7.4 生成并验证工程
7.4.1 生成工程
- 点击Project Manager并设置工程
- 勾选上单独生成.c.h文件
- 点击生成工程
- 查看工程
- 平台已经自动生成USART1、USART2驱动和GPIO驱动
- 用户只用专注于程序逻辑代码,实现快速开发
7.4.2 编写USART2串口调试验证代码
- 在文件usart.h中引入标准库stdio.h(里面包含printf)
#include "stdio.h"
- 在文件usart.c中添加printf重定向函数
// 重定向printf函数
int fputc(int ch,FILE *f)
{
uint8_t temp[1]={ch};
HAL_UART_Transmit(&huart2,temp,1,2);
return 0;
}
- 为了方便调试,在main.c中加入以下宏定义
#define USER_MAIN_DEBUG
#ifdef USER_MAIN_DEBUG
#define user_main_printf(format, ...) printf( format "\r\n",##__VA_ARGS__)
#define user_main_info(format, ...) printf("【main】info:" format "\r\n",##__VA_ARGS__)
#define user_main_debug(format, ...) printf("【main】debug:" format "\r\n",##__VA_ARGS__)
#define user_main_error(format, ...) printf("【main】error:" format "\r\n",##__VA_ARGS__)
#else
#define user_main_printf(format, ...)
#define user_main_info(format, ...)
#define user_main_debug(format, ...)
#define user_main_error(format, ...)
#endif
- 在主函数while(1)循环中添加以下测试代码
user_main_debug("我是USART2测试代码!\n");
HAL_Delay(1000);
- 设置下载后自动运行,编译运行,连接串口调试助手,观察现象
- 测试成功!!
7.4.3 编写三色灯测试代码
- 在main.c 主循环添加以下测试代码
//红灯亮,其它灭
HAL_GPIO_WritePin(LED_R_GPIO_Port,LED_R_Pin,GPIO_PIN_RESET);
HAL_GPIO_WritePin(LED_G_GPIO_Port,LED_G_Pin,GPIO_PIN_SET);
HAL_GPIO_WritePin(LED_B_GPIO_Port,LED_B_Pin,GPIO_PIN_SET);
HAL_Delay(500);
//绿灯亮,其它灭
HAL_GPIO_WritePin(LED_R_GPIO_Port,LED_R_Pin,GPIO_PIN_SET);
HAL_GPIO_WritePin(LED_G_GPIO_Port,LED_G_Pin,GPIO_PIN_RESET);
HAL_GPIO_WritePin(LED_B_GPIO_Port,LED_B_Pin,GPIO_PIN_SET);
HAL_Delay(500);
//蓝灯亮,其它灭
HAL_GPIO_WritePin(LED_R_GPIO_Port,LED_R_Pin,GPIO_PIN_SET);
HAL_GPIO_WritePin(LED_G_GPIO_Port,LED_G_Pin,GPIO_PIN_SET);
HAL_GPIO_WritePin(LED_B_GPIO_Port,LED_B_Pin,GPIO_PIN_RESET);
HAL_Delay(500);
- 观察LED灯,间隔500ms依次闪烁红、绿、蓝
图片!!
- 测试成功!!
7.4.4 编写按键中断测试代码
- 在main.c 底部添加以下测试代码
//KEY1按下动作执行函数
void KEY1_Pressed(void)
{
user_main_debug("我按下了KEY_1\r\n");
}
//KEY2按下动作执行函数
void KEY2_Pressed(void)
{
user_main_debug("我按下了KEY_2\r\n");
}
//按键中断处理函数
void HAL_GPIO_EXTI_Callback(uint16_t GPIO_Pin)
{
switch(GPIO_Pin)
{
case KEY_1_Pin:KEY1_Pressed();break;
case KEY_2_Pin:KEY2_Pressed();break;
default:break;
}
}
- 编译运行,分别按下按键,观察串口助手
- 测试成功!!
工程验证成功!!
7.5 移植DHT11温湿度传感器驱动程序
7.5.1 利用TIM1实现us级延时(编写DHT11驱动时会用)
-
首先去工程中设置定时器1
-
重新生成工程,来到tim.c,在中添加以下代码
//使用定时器1来做us级延时函数,温湿度传感器用,量程0-6553us
void TIM1_Delay_us(uint16_t n_us)
{
__HAL_TIM_SetCounter(&htim1, 0);//htim1
__HAL_TIM_ENABLE(&htim1);
while(__HAL_TIM_GetCounter(&htim1) < (10 * n_us));//计数频率10MHz,10次即为1us
__HAL_TIM_DISABLE(&htim1);
}
- 在tim.h中添加函数定义
void TIM1_Delay_us(uint16_t n_us);
- 到此,自定义us级延时函数添加完毕,在main.c 主循环中添加以下测试代码
// 自定义us级延时函数测试
static uint16_t tim1_test;
//延时1000个1ms
for(tim1_test = 0;tim1_test<1000;tim1_test++)
{
//延时1ms
TIM1_Delay_us(1000);
}
user_main_debug("我是us级延时函数测试代码,1s打印一次!\n");
- 观察串口打印,非常精确比自带的HAL_Delay还准!!
7.5.2 添加DHT11驱动文件到工程中
- 来到工程目录下,添加BSP文件夹
- 将事先准备好的DHT11驱动文件夹拷贝进去
- 里面包含这两个文件
- Keil工程添加工程文件
- 添加头文件地址
7.5.3 修改驱动.c .h程序文件
- 修改文件 “hal_temp_hum.c"
- 修改文件 “hal_temp_hum.h"
- 在main.c 中引入头文件"hal_temp_hum.h"
#include "hal_temp_hum.h"
- 在main.c KEY1_Pressed函数中添加以下测试代码
//KEY1按下动作执行函数
void KEY1_Pressed(void)
{
user_main_debug("按下KEY_1\r\n");
uint8_t temperature;
uint8_t humidity;
uint8_t get_times;
// 获取温湿度信息并用串口打印,获取十次,直到成功跳出
for(get_times=0;get_times<10;get_times++)
{
if(!dht11Read(&temperature, &humidity))//Read DHT11 Value
{
user_main_info("temperature=%d,humidity=%d \n",temperature,humidity);
break;
}
}
}
- 编译,下载运行,按下KEY_1,观察串口现象
- 成功!!
7.6 移植ESP8266 AT指令WIFI驱动模块
7.6.1 连接硬件
7.6.2 添加ESP8266串口驱动文件到工程中
- 与DHT11一样,将ESP8266驱动文件放到BSP目录下
- 工程中加入文件
- 添加头文件路径
- 在main.c中引入头文件
#include "esp8266_at.h"
7.6.3 驱动程序分析
- 直接看代码~
7.6.4 测试ESP8266驱动程序
- 添加WIFI热点宏定义
//此处根据自己的wifi作调整
#define WIFI_NAME "HappyOneDay"
#define WIFI_PASSWD "1234567890"
- 在KEY1_Pressed函数中添加测试代码
//KEY1按下动作执行函数
void KEY1_Pressed(void)
{
user_main_debug("我按下了KEY_1\r\n");
uint8_t status=0;
//初始化
if(ESP8266_Init())
{
user_main_info("ESP8266初始化成功!\r\n");
status++;
}
//连接热点
if(status==1)
{
if(ESP8266_ConnectAP(WIFI_NAME,WIFI_PASSWD))
{
user_main_info("ESP8266连接热点成功!\r\n");
status++;
}
}
}
- 编译,烧录运行,按下KEY_1 观察现象
- 测试成功!!
7.7 移植MQTT驱动
7.7.1 添加驱动文件到工程中
- 将驱动赋值到BSP文件目录下
- 将文件加入工程
- 添加头文件路径
7.7.2 使能USART1接收中断,添加接收函数
- 打开中断
- 优先级修改为3
- 生成工程,在main.c中处添加以下代码
//开启USART1接收中断
HAL_UART_Receive_IT(&huart1,usart1_rxone,1);
- 在在main.c中处添加以下代码(为了接收服务器的响应)
//USART1 ES8266驱动串口接收中断处理函数
void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart)
{
if(huart->Instance == USART1) // 判断是由哪个串口触发的中断
{
//将接收到的数据放入接收usart1接收数组
usart1_rxbuf[usart1_rxcounter] = usart1_rxone[0];
usart1_rxcounter++; //接收数量+1
//重新使能串口1接收中断
HAL_UART_Receive_IT(&huart1,usart1_rxone,1);
}
}
7.7.3 在main.c中引入头文件,测试代码
- 引入头文件
#include "esp8266_mqtt.h"
- 使用我一开始配置好的阿里云IOT进行测试,怎么配置稍后介绍
//此处是阿里云服务器的登陆配置
#define MQTT_BROKERADDRESS "a1lAoazdH1w.iot-as-mqtt.cn-shanghai.aliyuncs.com"
#define MQTT_CLIENTID "00001|securemode=3,signmethod=hmacsha1|"
#define MQTT_USARNAME "BZL01&a1lAoazdH1w"
#define MQTT_PASSWD "51A5BB10306E976D6C980F73037F2D9496D2813A"
#define MQTT_PUBLISH_TOPIC "/sys/a1lAoazdH1w/BZL01/thing/event/property/post"
#define MQTT_SUBSCRIBE_TOPIC "/sys/a1lAoazdH1w/BZL01/thing/service/property/set"
- 添加error报错函数
//进入错误模式等待手动重启
void Enter_ErrorMode(uint8_t mode)
{
HAL_GPIO_WritePin(LED_G_GPIO_Port,LED_G_Pin,GPIO_PIN_SET);
while(1)
{
switch(mode){
case 0:user_main_error("ESP8266初始化失败!\r\n");break;
case 1:user_main_error("ESP8266连接热点失败!\r\n");break;
case 2:user_main_error("ESP8266连接阿里云服务器失败!\r\n");break;
case 3:user_main_error("ESP8266阿里云MQTT登陆失败!\r\n");break;
case 4:user_main_error("ESP8266阿里云MQTT订阅主题失败!\r\n");break;
default:user_main_info("Nothing\r\n");break;
}
user_main_info("请重启开发板");
//HAL_GPIO_TogglePin(LED_R_GPIO_Port,LED_R_Pin);
HAL_Delay(200);
}
}
- 修改KEY1_Pressed函数
//KEY1按下动作执行函数
void KEY1_Pressed(void)
{
user_main_debug("我按下了KEY_1\r\n");
// uint8_t temperature;
// uint8_t humidity;
// uint8_t get_times;
// // 获取温湿度信息并用串口打印,获取十次,直到成功跳出
// for(get_times=0;get_times<10;get_times++)
// {
// if(!dht11Read(&temperature, &humidity))//Read DHT11 Value
// {
// user_main_info("temperature=%d,humidity=%d \n",temperature,humidity);
// break;
// }
// }
uint8_t status=0;
//初始化
if(ESP8266_Init())
{
user_main_info("ESP8266初始化成功!\r\n");
status++;
}
else Enter_ErrorMode(0);
//连接热点
if(status==1)
{
if(ESP8266_ConnectAP(WIFI_NAME,WIFI_PASSWD))
{
user_main_info("ESP8266连接热点成功!\r\n");
status++;
}
else Enter_ErrorMode(1);
}
//连接阿里云IOT服务器
if(status==2)
{
if(ESP8266_ConnectServer("TCP",MQTT_BROKERADDRESS,1883)!=0)
{
user_main_info("ESP8266连接阿里云服务器成功!\r\n");
status++;
}
else Enter_ErrorMode(2);
}
//登陆MQTT
if(status==3)
{
if(MQTT_Connect(MQTT_CLIENTID, MQTT_USARNAME, MQTT_PASSWD) != 0)
{
user_main_info("ESP8266阿里云MQTT登陆成功!\r\n");
status++;
}
else Enter_ErrorMode(3);
}
//订阅主题
if(status==4)
{
if(MQTT_SubscribeTopic(MQTT_SUBSCRIBE_TOPIC,0,1) != 0)
{
user_main_info("ESP8266阿里云MQTT订阅主题成功!\r\n");
}
else Enter_ErrorMode(4);
}
}
- 编译,下载运行,按下按键,观察串口打印
- 测试成功!!!
7.8 MQTT协议简单介绍
MQTT中文网:http://mqtt.p2hp.com/
7.9 阿里云物联网平台介绍
官网地址:https://help.aliyun.com/product/30520.html
7.9.1 创建产品
- 点击创建产品
- 按以下格式创建
- 查看产品详情
7.9.2 定义产品功能
- 编辑草稿
- 添加自定义功能
- 添加温度属性
- 添加湿度属性
- 添加红灯控制开关
- 添加绿灯控制开关
- 添加蓝灯控制开关
- 发布上线
7.9.3 添加具体设备
- 添加设备
- 查看设备属性
- 查看设备证书**(关键)**
7.9.4 使用MQTT.fx模拟硬件进行连接
- 使用MQTT.fx接入物联网平台:
https://help.aliyun.com/document_detail/140507.html?spm=a2c4g.11174283.6.565.3a8b16686rXYnj
- MQTT.fx官网:
https://mqttfx.jensd.de/index.php/download?spm=a2c4g.11186623.2.20.17b67908o3uJ8y
此处对应着官方文档进行讲解
参数 | 说明 |
---|---|
Profile Name | 输入您的自定义名称。 |
Profile Type | 选择为MQTT Broker。 |
Broker Address | 连接域名。格式:${YourProductKey}.iot-as-mqtt.${region}.aliyuncs.com 。其中,${region}需替换为您物联网平台服务所在地域的代码。地域代码,请参见地域和可用区。如:alxxxxxxxxx.iot-as-mqtt.cn-shanghai.aliyuncs.com 。 |
Broker Port | 设置为1883。 |
Client ID | 填写mqttClientId,用于MQTT的底层协议报文。格式固定:${clientId}|securemode=3,signmethod=hmacsha1| 。完整示例:12345|securemode=3,signmethod=hmacsha1| 。其中,${clientId}为设备的ID信息。可取任意值,长度在64字符以内。建议使用设备的MAC地址或SN码。securemode为安全模式,TCP直连模式设置为securemode=3 ,TLS直连为securemode=2 。signmethod为算法类型,支持hmacmd5和hmacsha1。说明 输入Client ID信息后,请勿单击Generate。 |
地域名称 | 所在城市 | Region ID | 可用区数量 |
---|---|---|---|
华北 1 | 青岛 | cn-qingdao | 2 |
华北 2 | 北京 | cn-beijing | 8 |
华北 3 | 张家口 | cn-zhangjiakou | 2 |
华北 5 | 呼和浩特 | cn-huhehaote | 2 |
华东 1 | 杭州 | cn-hangzhou | 8 |
华东 2 | 上海 | cn-shanghai | 6 |
华南 1 | 深圳 | cn-shenzhen | 5 |
华南 2 | 河源 | cn-heyuan | 2 |
西南 1 | 成都 | cn-chengdu | 2 |
- 示例:
Broker Address: a1kvAFB5siA.iot-as-mqtt.cn-shanghai.aliyuncs.com
Broker Port: 1883
Client ID: 00001|securemode=3,signmethod=hmacsha1|
参数 | 说明 |
---|---|
User Name | 由设备名DeviceName、符号(&)和产品ProductKey组成。固定格式:${YourDeviceName}&${YourPrductKey} 。完整示例如:device&alxxxxxxxxx 。 |
Password | 密码由参数值拼接加密而成。说明 如果您使用的MQTT.fx版本,在粘贴Password后不显示具体的字符串,只要光标已从输入框的前部移至了后部,则表示粘贴成功,请勿重复粘贴。您可以使用物联网平台提供的生成工具自动生成Password,也可以手动生成Password。单击下载Password生成小工具。解压缩下载包后,双击sign文件,即可使用。使用Password生成小工具的输入参数:productKey:设备所属产品Key。可在控制台设备详情页查看。deviceName:设备名称。可在控制台设备详情页查看。deviceSecret:设备密钥。可在控制台设备详情页查看。timestamp:(可选)时间戳。clientId:设备的ID信息,与Client ID中${clientId}一致。method:选择签名算法类型,与Client ID中signmethod确定的加密方法一致。手动生成方法如下:拼接参数。提交给服务器的clientId、deviceName、productKey和timestamp(timestamp为非必选参数)参数及参数值依次拼接。本例中,clientId值为12345,deviceName值为device,productKey值为alxxxxxxxxx,拼接结果为:clientId12345deviceNamedeviceproductKeyalxxxxxxxxx 加密。通过Client ID中确定的加密方法,使用设备deviceSecret,将拼接结果加密。假设设备的deviceSecret值为abc123,加密计算格式为hmacsha1(abc123,clientId12345deviceNamedeviceproductKeyalxxxxxxxxx) |
- password生成小工具(一个离线网页)
- 示例:
User Name: TESTDEVICE01&a1kvAFB5siA
Password: E18BFBEE7686EC3FBC5EAB10BEB101FD0913CF39
- 填入MQTT.fx,进行测试
- 点击connect
- 连接成功!!!
7.9.5 订阅消息调试
- 来到设备属性,物模型通信Topic
- MQTT.fx订阅
/sys/a1kvAFB5siA/TESTDEVICE01/thing/service/property/set
- 订阅消息成功,尝试平台下发消息
- 来到这里进行下发
- 设备成功收到消息
7.9.6 使用MQTT.fx模拟设备进行消息推送
-
推送地址:
/sys/a1kvAFB5siA/TESTDEVICE01/thing/event/property/post
-
推送以下json消息
- 温度:20.0摄氏度
- 湿度:60%
- 红灯:开
- 绿灯:开
- 蓝灯:关
{
"method":"thing.service.property.set",
"id":"354062502",
"params":{
"temperature":20.0,
"humidity":60.0,
"switch_led_r":1,
"switch_led_g":1,
"switch_led_b":0
},
"version":"1.0.0"
}
- 来看平台收到的消息日志
- 可视化查看设备上报的数据
- 至此,MQTT.fx调试完成!!!下一步,使用单片机进行该项工作
7.10 STM32 使用MQTT接入阿里云平台过程详解
直接看代码
7.11 STM32传感器数据上传、平台数据下发效果展示
真机演示