STM32 ES8266上阿里云IOT MQTT实践【第七章】:ESP8266+MQTT上阿里云物联网平台实践

课程大纲

STM32 ES8266上阿里云IOT MQTT实践【第一章】:物联网简介(什么是物联网)
STM32 ES8266上阿里云IOT MQTT实践【第二章】:物联网十大应用场景
STM32 ES8266上阿里云IOT MQTT实践【第三章】:什么是MCU?
STM32 ES8266上阿里云IOT MQTT实践【第四章】:MCU的应用范围
STM32 ES8266上阿里云IOT MQTT实践【第五章】:我们要怎么入门MCU开发?
STM32 ES8266上阿里云IOT MQTT实践【第六章】:如何使用STM32Cube MX进行STM32的快速开发
STM32 ES8266上阿里云IOT MQTT实践【第七章】:ESP8266+MQTT上阿里云物联网平台实践(附源码)
STM32CubeMX通过ESP8266 AT指令MQTT上阿里云物联网平台实践源代码

7. 实践:STM32使用ESP8266+MQTT上阿里云物联网平台实践

7.1 项目整体介绍

7.1.1 硬件资源
  • STM32F429IGT6开发板:核心
  • ST-Link下载器:下载程序用
  • USB转232串口线:串口通信,调试用
  • USB供电线:给开发板供电
  • DHT11温湿度模块:采集环境温湿度
  • ATK-ESP8266:联网上传数据

image-20200504195716268

7.1.2 软件资源
  • 串口调试助手(调试用)

image-20200504200038516

7.1.3 其它资源
  • STM32F429IGT6开发板原理图
  • DHT11温湿度传感器编程手册
  • ATK-ESP8266编程手册
  • ESP8266样例程序
  • 阿里云MQTT样例程序

7.2 新建工程

  • 选择通过选择MCU创建工程

image-20200504200445596

  • 选择芯片

image-20200504200612470

  • 建立成功

image-20200504200759484

7.3 基础工程配置

7.3.1 时钟配置
  • 高速时钟:选择外部晶振

image-20200507105624694

  • 高速时钟选择Crystal/Ceramic Resonator

在用cube配置时钟时,有下面两个选项
BYPASS Clock Source(旁路时钟源)
Crystal/Ceramic Resonator(晶体/陶瓷晶振)
下面来解释一下:
所谓HSE旁路时钟源,是指无需使用外部晶体时所需的芯片内部时钟驱动组件,直接从外界导入时钟信号。犹如芯片内部的驱动组件被旁路了。
外部晶体/陶瓷谐振器(HSE晶体)模式该时钟源是由外部无源晶体与MCU内部时钟驱动电路共同配合形成,有一定的启动时间,精度较高。

image-20200507105818756

  • 配置时钟为180MHz

image-20200507110045846

7.3.2 下载接口设置,设置为串行下载

image-20200507110151989

7.3.3 LED灯配置
  • 查看原理图

    LED_R——PH10 红灯

    LED_G——PH11 绿灯

    LED_B——PH12 蓝灯

    低电平有效,IO口要设置为推挽输出,上拉

image-20200507110347395

  • 工程配置

    • 选择引脚设置为GPIO_Ooutput

    • 配置标签 LED_R LED_G LED_B,方便工程直接调用

    • image-20200507110609310

    • 设置上下拉

    • image-20200507110918931

7.3.4 按键输入中断设置
  • 查看原理图
  • image-20200507111139923
  • 工程设置
  • image-20200507111415830
  • image-20200507111426161
  • image-20200507111439585
  • 设置中断等级,不能太高
  • image-20200507111507573
  • image-20200507111541714
7.3.5 调试串口设置
  • 查看开发板原理图,找到RS232

image-20200504202324034

  • 修改跳帽方向

image-20200504202114680

  • 串口参数配置

image-20200504202531112

  • 修改PD5为USART2_TX

image-20200504202632483

  • 修改PD6为USART2_RX

image-20200504202705527

  • PA2 PA3自动取消定义

image-20200504202843344

image-20200507112042637

7.3.6 ES8266串口设置

image-20200507112200157

7.3.7 DHT11数据采集IO

image-20200507112422533

7.3.8 工程概览

image-20200507112914628

7.4 生成并验证工程

7.4.1 生成工程
  • 点击Project Manager并设置工程

image-20200507112544875

  • 勾选上单独生成.c.h文件

image-20200504203158452

  • 点击生成工程

image-20200504203313895

  • 查看工程
    • 平台已经自动生成USART1、USART2驱动和GPIO驱动
    • 用户只用专注于程序逻辑代码,实现快速开发

image-20200507121925003

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);
  • 设置下载后自动运行,编译运行,连接串口调试助手,观察现象

image-20200507123750198

image-20200507123848921

  • 测试成功!!
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;  
    }  
}
  • 编译运行,分别按下按键,观察串口助手

image-20200507125155015

  • 测试成功!!

工程验证成功!!

7.5 移植DHT11温湿度传感器驱动程序

7.5.1 利用TIM1实现us级延时(编写DHT11驱动时会用)
  • 首先去工程中设置定时器1

    image-20200507130101274

  • 重新生成工程,来到tim.c,在/* USER CODE BEGIN 1 */中添加以下代码

//使用定时器1来做us级延时函数,温湿度传感器用,量程0-6553us
void TIM1_Delay_us(uint16_t n_us)
{
	__HAL_TIM_SetCounter(&htim1, 0);//htim1

	/* 开启定时器1计数 */
	__HAL_TIM_ENABLE(&htim1);

	while(__HAL_TIM_GetCounter(&htim1) < (10 * n_us));//计数频率10MHz,10次即为1us
	/* Disable the Peripheral */
	__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还准!!

image-20200507131303080

7.5.2 添加DHT11驱动文件到工程中
  • 来到工程目录下,添加BSP文件夹

image-20200507131516946

  • 将事先准备好的DHT11驱动文件夹拷贝进去

image-20200507131620652

  • 里面包含这两个文件

image-20200507131641449

  • Keil工程添加工程文件

image-20200507131757306

  • 添加头文件地址

image-20200507131850975

7.5.3 修改驱动.c .h程序文件
  • 修改文件 “hal_temp_hum.c"

image-20200507132338750

  • 修改文件 “hal_temp_hum.h"

image-20200507133711271

  • 在main.c 中引入头文件"hal_temp_hum.h"
#include "hal_temp_hum.h"

image-20200507132539145

  • 在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,观察串口现象

image-20200507133812297

  • 成功!!

7.6 移植ESP8266 AT指令WIFI驱动模块

7.6.1 连接硬件

image-20200507140111603

7.6.2 添加ESP8266串口驱动文件到工程中
  • 与DHT11一样,将ESP8266驱动文件放到BSP目录下

image-20200507134337359

image-20200507134346098

  • 工程中加入文件

image-20200507134447790

  • 添加头文件路径

image-20200507134636295

  • 在main.c中引入头文件
#include "esp8266_at.h"

image-20200507134709421

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");

	/* ESP8266测试代码 */
	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 观察现象

image-20200507135513552

  • 测试成功!!

7.7 移植MQTT驱动

7.7.1 添加驱动文件到工程中
  • 将驱动赋值到BSP文件目录下

image-20200507135708766

image-20200507135724735

  • 将文件加入工程

image-20200507135820349

  • 添加头文件路径

image-20200507135853187

7.7.2 使能USART1接收中断,添加接收函数
  • 打开中断

image-20200507142128079

  • 优先级修改为3

image-20200507142213561

  • 生成工程,在main.c中/* USER CODE BEGIN 2 */处添加以下代码
//开启USART1接收中断
HAL_UART_Receive_IT(&huart1,usart1_rxone,1);
  • 在在main.c中/* USER CODE BEGIN 4 */处添加以下代码(为了接收服务器的响应)
//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"

image-20200507135946011

  • 使用我一开始配置好的阿里云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");
	
	/* DHT11温湿度传感器测试 */
//	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;
//		}
//	}
	
	/* ESP8266&MQTT测试代码 */
	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);
	}
}
  • 编译,下载运行,按下按键,观察串口打印

image-20200507142647550

  • 测试成功!!!

7.8 MQTT协议简单介绍

MQTT中文网:http://mqtt.p2hp.com/

image-20200507143425086

image-20200507143437970

7.9 阿里云物联网平台介绍

官网地址:https://help.aliyun.com/product/30520.html

7.9.1 创建产品
  • 点击创建产品

image-20200507143608350

  • 按以下格式创建

image-20200507143720005

  • 查看产品详情

image-20200507143821968

7.9.2 定义产品功能
  • 编辑草稿

image-20200507143857884

  • 添加自定义功能

image-20200507143946099

  • 添加温度属性

image-20200507144125329

  • 添加湿度属性

image-20200507144348668

  • 添加红灯控制开关

image-20200507144531497

  • 添加绿灯控制开关

image-20200507144540793

  • 添加蓝灯控制开关

image-20200507144549003

  • 发布上线

image-20200507144612140

7.9.3 添加具体设备
  • 添加设备

image-20200507144814845

image-20200507144834281

  • 查看设备属性

image-20200507144854827

  • 查看设备证书**(关键)**

image-20200507144924761

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确定的加密方法一致。手动生成方法如下:拼接参数。提交给服务器的clientIddeviceNameproductKeytimestamp(timestamp为非必选参数)参数及参数值依次拼接。本例中,clientId值为12345,deviceName值为device,productKey值为alxxxxxxxxx,拼接结果为:clientId12345deviceNamedeviceproductKeyalxxxxxxxxx加密。通过Client ID中确定的加密方法,使用设备deviceSecret,将拼接结果加密。假设设备的deviceSecret值为abc123,加密计算格式为hmacsha1(abc123,clientId12345deviceNamedeviceproductKeyalxxxxxxxxx)
  • password生成小工具(一个离线网页)

image-20200507150142511

  • 示例:
User Name:	TESTDEVICE01&a1kvAFB5siA
Password:	E18BFBEE7686EC3FBC5EAB10BEB101FD0913CF39
  • 填入MQTT.fx,进行测试

image-20200507150255329

  • 点击connect

image-20200507150320960

  • 连接成功!!!
7.9.5 订阅消息调试
  • 来到设备属性,物模型通信Topic

image-20200507150454316

  • MQTT.fx订阅/sys/a1kvAFB5siA/TESTDEVICE01/thing/service/property/set

image-20200507150544732

  • 订阅消息成功,尝试平台下发消息

image-20200507150614904

  • 来到这里进行下发

image-20200507150632532

  • 设备成功收到消息

image-20200507150714719

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"
}

image-20200507151023439

  • 来看平台收到的消息日志

image-20200507151109459

  • 可视化查看设备上报的数据

image-20200507151140341

  • 至此,MQTT.fx调试完成!!!下一步,使用单片机进行该项工作

7.10 STM32 使用MQTT接入阿里云平台过程详解

直接看代码

7.11 STM32传感器数据上传、平台数据下发效果展示

真机演示

猜你喜欢

转载自blog.csdn.net/u014779536/article/details/106328156