使用STM32F103C8T6和ESP8266链接阿里云

一、项目简介

基于 STM32F103C8T6 单片机和 ESP8266 Wi-Fi 模块,旨在实现通过 Wi-Fi 连接阿里云物联网平台,进行数据上传和远程控制

  • STM32F103C8T6:作为核心控制单元,负责系统的运算、数据处理和与外设的交互。STM32F103C8T6 具有强大的计算能力、丰富的外设接口和稳定的性能,适合嵌入式系统的开发。
  • ESP8266 Wi-Fi 模块:负责与阿里云物联网平台进行网络通信。ESP8266 是一个低功耗的 Wi-Fi 模块,通过 UART 与 STM32F103C8T6 进行连接,并通过 Wi-Fi 将数据传输到阿里云。
  • 外部传感器/执行器(可选):根据应用场景,用户可以选择连接温湿度传感器、光照传感器等,并通过 STM32F103C8T6 获取数据或控制执行器进行远程操作。
  • 串口通信(UART):STM32F103C8T6 与 ESP8266 通过 UART 接口进行数据传输。STM32 发送指令给 ESP8266,ESP8266 负责通过 Wi-Fi 网络与阿里云进行通信。
  • MQTT 协议:ESP8266 使用 MQTT 协议与阿里云物联网平台进行数据交互。通过 MQTT 协议,STM32 可以将传感器数据上传到阿里云,或接收来自阿里云的指令进行远程控制。

二、阿里云设置

1.通过百度搜索阿里云IOT

2.打开后进行注册登录,然后进入控制台界面

3.新建公共实例

新建一个公共实例,地区选择离自己近的地方即可其他默认,我这边选择的是华东2(上海)

4.然后选择新建一个产品

5.创建产品完成后再去添加一个设备

6.点击查看设备

然后查看三要素,把他们复制到文本文件中,后续需要使用。

7.点击产品进行查看

创建两个(根据自己的需求)自定义物模型

创建完成后记录下标识符后面需要用到,然后点击发布上线即可。

三、固件烧录

1.硬件连接

我这边使用的是ESP8266的nodemcu,自带CH340所以连接电源即可,如果只是最小的模块可以通过CH340连接到电脑上方式如下:

|-------|---------|
| CH340 | ESP8266 |
| 3.3V | VCC |
| RX | TX |
| TX | RX |
| GND | GND |

2.软件获取

烧录固件需要到烧录软件和一个固件,把链接放到下面自取即可。

烧录工具:通过网盘分享的文件:flash_download_tool_3.9.2_0.zip

链接: https://pan.baidu.com/s/1J93R1XedIUha_uL-9dx2pA 提取码: va4c

烧录固件:通过网盘分享的文件:1471_esp8266-at_mqtt-1m.zip

链接: https://pan.baidu.com/s/1GfZX8YfslurIw1rKer0JTw 提取码: y5yt

3.软件设置

1.解压完成后直接点击exe文件运行即可

2.选择ESP8266和develop

3.选择固件

选择刚才下载的固件,地址填0x0,具体设置如图所示,选择自己的串口,波特率选择最大即可

4.开始烧录

我用的nodemcu不需要按任何按键都可以下载,但有其他型号的板子下载起来可能比较复杂,如正点原子的开发板需要IO1接地才可以下载,以及一些板子需要一直按着BOOT0才可以下载。

正点原子的板子下载时IO1和GND以及VCC要连接在一个电源上不可以分开连接,否则会下载失败。

5.烧录完成

烧录完成后点击reset复位就可以进行 AT指令测试了

四、AT指令测试

AT指令集 这里列举了常用的AT指令集,具体指令的意思请自行查询。

打开XCOM或者其他的串口软件,发送AT指令

1.发送AT

复位后发送AT返回OK说明通讯没有问题

2.设置波特率

发送AT+UART=115200,8,1,0,0设置波特率

然后发送**AT+UART?**查看波特率是否设置成功

3.发送AT+RESTORE重新启动模块

4.发送AT+CWMODE=1配置WIFI模式

5.发送**AT+CWJAP="SSID","SSID_password"**连接wifi

输入自己WIFI的账号密码即可,用手机热点是注意使用2.4GHz的频段,现在的手机都是5G,但是该模块不支持5G,可能会导致连接失败。

例:AT+CWJAP="UFI-EB37","1234567890"

6.发送AT+MQTTUSERCFG=0,1,"NULL","name","password",0,0,""

这里的name就是之前复制下来的username,password就是passwd,复制粘贴过来即可

例:AT+MQTTUSERCFG=0,1,"NULL","Test&io5xsizC2D2","0620ed20f70f7bdf05637aa1b01292c2945760119bb7dd34da0aeacef84c7529",0,0,""

7.发送AT+MQTTCLIENTID=0,"ClienID"

设置MQTT ID,要在ID信息每一个","前加"\"进行转义 把之前复制的clientld拿过来使用

例:

原来的ClienID为:io5xsizC2D2.Test|securemode=2,signmethod=hmacsha256,timestamp=1736230153434|需要发送的AT指令为:AT+MQTTCLIENTID=0,"io5xsizC2D2.Test|securemode=2\,signmethod=hmacsha256\,timestamp=1736216781469|"

列出两个ID请注意查看区别,方便修改自己的ID

8.发送AT+MQTTCONN=0,"域名",1883,1

发送MQTT域名,域名获取 ,将之前的mqttHostUrl复制过来使用。

例:AT+MQTTCONN=0,"iot-06z00gjlxx4sqaa.mqtt.iothub.aliyuncs.com",1883,1

此时可以看到设备显示在线状态

9.发送AT+MQTTSUB=0,"订阅topic",1

订阅主题,根据如图所示步骤找到订阅的topic

/io5xsizC2D2/${deviceName}/user/get,此时我们看到还需要一个devicename

然后打开我们的设备界面就可以找到我们所需要的devicename了

例:AT+MQTTSUB=0,"/io5xsizC2D2/Test/user/get",1

发送完成后点击设备,查看设备中的topic列表一栏,就可以看到刚才订阅的topic出现在设备上了。

10.命令下发

点击设备的topic列表 ,点击发送消息,输入123456789,然后查看我们的xcom就可以看到已经成功接收到了。

11.数据上传

发送AT+MQTTPUB=0,"发布topic","AJson格式内容",1,0 发布主题

json数据格式,{\"params\":{\"temperature\":37.5}},其中temperature为属性的标识符

例:

AT+MQTTPUB=0,"/sys/io5xsizC2D2/Test/thing/event/property/post","{\"params\":{\"temperature\":37.5}}",1,0

发送完成后我们可以看到阿里云成功显示温度37.5℃

12.日志查看

选择日志服务我们可以看到所发的消息,以及可以看到发送失败时报错的代码,然后根据代码去阿里云手册中找到该错误的含义,便于排查错误。

五、串口测试

1.硬件连接

|---------------|---------|
| STM32F103C8T6 | ESP8266 |
| 5V | VCC |
| GND | GND |
| PA9 | RX |
| PA10 | TX |

使用这种小板子时记得外接电源,否则会因为电源不足而供不上电。

2. 串口文件

usart1.c

cpp 复制代码
#include "sys.h"
#include "usart.h"	  
  
#if 1
#pragma import(__use_no_semihosting)             
//标准库需要的支持函数                 
struct __FILE 
{ 
	int handle; 

}; 

FILE __stdout;       
//定义_sys_exit()以避免使用半主机模式    
void _sys_exit(int x) 
{ 
	x = x; 
} 
//重定义fputc函数 
int fputc(int ch, FILE *f)
{      
	while((USART1->SR&0X40)==0);//循环发送,直到发送完毕   
    USART1->DR = (u8) ch;      
	return ch;
}
#endif 

 
#if EN_USART1_RX   //如果使能了接收
//串口1中断服务程序
//注意,读取USARTx->SR能避免莫名其妙的错误   	
u8 USART_RX_BUF[USART_REC_LEN];     //接收缓冲,最大USART_REC_LEN个字节.
//接收状态
//bit15,	接收完成标志
//bit14,	接收到0x0d
//bit13~0,	接收到的有效字节数目
u16 USART_RX_STA=0;       //接收状态标记	  
  
void uart_init(u32 bound){
  //GPIO端口设置
  GPIO_InitTypeDef GPIO_InitStructure;
	USART_InitTypeDef USART_InitStructure;
	NVIC_InitTypeDef NVIC_InitStructure;
	 
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1|RCC_APB2Periph_GPIOA, ENABLE);	//使能USART1,GPIOA时钟
  
	//USART1_TX   GPIOA.9
  GPIO_InitStructure.GPIO_Pin = GPIO_Pin_9; //PA.9
  GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
  GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;	//复用推挽输出
  GPIO_Init(GPIOA, &GPIO_InitStructure);//初始化GPIOA.9
   
  //USART1_RX	  GPIOA.10初始化
  GPIO_InitStructure.GPIO_Pin = GPIO_Pin_10;//PA10
  GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;//浮空输入
  GPIO_Init(GPIOA, &GPIO_InitStructure);//初始化GPIOA.10  

  //Usart1 NVIC 配置
  NVIC_InitStructure.NVIC_IRQChannel = USART1_IRQn;
	NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority=3 ;//抢占优先级3
	NVIC_InitStructure.NVIC_IRQChannelSubPriority = 3;		//子优先级3
	NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;			//IRQ通道使能
	NVIC_Init(&NVIC_InitStructure);	//根据指定的参数初始化VIC寄存器
  
   //USART 初始化设置

	USART_InitStructure.USART_BaudRate = bound;//串口波特率
	USART_InitStructure.USART_WordLength = USART_WordLength_8b;//字长为8位数据格式
	USART_InitStructure.USART_StopBits = USART_StopBits_1;//一个停止位
	USART_InitStructure.USART_Parity = USART_Parity_No;//无奇偶校验位
	USART_InitStructure.USART_HardwareFlowControl = USART_HardwareFlowControl_None;//无硬件数据流控制
	USART_InitStructure.USART_Mode = USART_Mode_Rx | USART_Mode_Tx;	//收发模式

  USART_Init(USART1, &USART_InitStructure); //初始化串口1
  USART_ITConfig(USART1, USART_IT_RXNE, ENABLE);//开启串口接受中断
  USART_Cmd(USART1, ENABLE);                    //使能串口1 

}

void USART1_IRQHandler(void)                	//串口1中断服务程序
	{
	u8 Res;
	if(USART_GetITStatus(USART1, USART_IT_RXNE) != RESET)  //接收中断(接收到的数据必须是0x0d 0x0a结尾)
		{
		Res =USART_ReceiveData(USART1);	//读取接收到的数据
		
		if((USART_RX_STA&0x8000)==0)//接收未完成
			{
			if(USART_RX_STA&0x4000)//接收到了0x0d
				{
				if(Res!=0x0a)USART_RX_STA=0;//接收错误,重新开始
				else USART_RX_STA|=0x8000;	//接收完成了 
				}
			else //还没收到0X0D
				{	
				if(Res==0x0d)USART_RX_STA|=0x4000;
				else
					{
					USART_RX_BUF[USART_RX_STA&0X3FFF]=Res ;
					USART_RX_STA++;
					if(USART_RX_STA>(USART_REC_LEN-1))USART_RX_STA=0;//接收数据错误,重新开始接收	  
					}		 
				}
			}   		 
     } 
} 
#endif	

usart1.h

cpp 复制代码
#ifndef __USART_H
#define __USART_H
#include "stdio.h"	
#include "sys.h" 

#define USART_REC_LEN  			200  	//定义最大接收字节数 200
#define EN_USART1_RX 			1		//使能(1)/禁止(0)串口1接收
	  	
extern u8  USART_RX_BUF[USART_REC_LEN]; //接收缓冲,最大USART_REC_LEN个字节.末字节为换行符 
extern u16 USART_RX_STA;         		//接收状态标记	
//如果想串口中断接收,请不要注释以下宏定义
void uart_init(u32 bound);
#endif

3.ESP8266文件

esp8266.c

里面的wifi名称密码,以及MQTT三要素要根据自己的阿里云进行修改。

cpp 复制代码
#include "esp8266.h"
#include "usart.h"
#include "stm32f10x_usart.h"
#include "delay.h"
#include <stdio.h>
#include <string.h>
#include "esp8266.h"
void ESP8266_Init(void)
{
//	u16 t;  
//	u16 len;
//	u16 times=0;
	delay_init();       //延时函数初始化   
//NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2); //设置NVIC中断分组2:2位抢占优先级,2位响应优先级
//uart_init(115200); //串口初始化为11520
	
	//重启ESP
	printf("AT+RESTORE\r\n");
		delay_ms(1000);
		delay_ms(1000);
	//wifi模式设置
	printf("AT+CWMODE=1\r\n");
		delay_ms(1000);
		delay_ms(1000);
		delay_ms(1000);
	//wifi名称,WiFi密码
	printf("AT+CWJAP=\"UFI-EB37\",\"1234567890\"\r\n");
		delay_ms(1000);
		delay_ms(1000);
		delay_ms(1000);
		delay_ms(1000);
		delay_ms(1000);
		delay_ms(1000);
	//MQTT名称,MQTT密码
	printf("AT+MQTTUSERCFG=0,1,\"NULL\",\"ESP8266&io5xsNZLaxr\",\"ec2ac185df0828bd3d5f68fc840eed580ef660c88320010d71c049eeda719047\",0,0,\"\"\r\n");
		delay_ms(1000);
		delay_ms(1000);
		delay_ms(1000);
	//MQTTID
	printf("AT+MQTTCLIENTID=0,\"io5xsNZLaxr.ESP8266|securemode=2\\,signmethod=hmacsha256\\,timestamp=1735989723311|\"\r\n");
		delay_ms(1000);
		delay_ms(1000);
		delay_ms(1000);
	//MQTT域名
	printf("AT+MQTTCONN=0,\"iot-06z00gjlxx4sqaa.mqtt.iothub.aliyuncs.com\",1883,1\r\n");
		delay_ms(1000);
		delay_ms(1000);
		delay_ms(1000);
	//订阅消息
	printf("AT+MQTTSUB=0,\"/sys/io5xsNZLaxr/ESP8266/thing/deviceinfo/update\",1\r\n");
		delay_ms(1000);
		delay_ms(1000);
		delay_ms(1000);


    memset(USART_RX_BUF,0,500);
		USART_RX_STA=0;
}


	

esp8266.h

cpp 复制代码
#ifndef _ESP8266_H
#define _ESP8266_H
#include "stm32f10x.h"
#include "delay.h"
#include "usart.h"
	void ESP8266_Init(void);
#endif

4.主函数

我这边要做一个智能秤所以上传了一个称重传感器的数据,上述连接到阿里云后上传数据只需要这句话即可:printf("AT+MQTTPUB=0,\"/sys/io5xsNZLaxr/ESP8266/thing/event/property/post\",\"{\\\"params\\\":{\\\"Weight\\\":%d}}\",1,0\r\n",weight);

main.c

cpp 复制代码
int main(void)
{		
	NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);//设置中断优先级分组为组2:2位抢占优先级,2位响应优先级
	delay_init();
	HX711_GPIO_Init();
	uart_init(115200);
	ESP8266_Init();		  //ESP初始化
	Get_Tare();
	OLED_Init();
	OLED_Clear();
	OLED_ShowCH(2,0,"失重-智能迷你秤");
	OLED_ShowCH(20,4,"重量:   0g");
	while(1)
	{		
		Get_Weight();
		if(medleng == 0)                    //缓存的第1个元素,直接放入,不需要排序
		{ 
			buffer[0] = weight; medleng = 1; 
		}
		else                            	//插入排序算法,按从小到大的顺序排列 
		{  
			for(int i = 0; i < medleng; i ++)  
			{
				if( buffer[i] > weight) 	// 轮询到的当前元素>AD值,则交换它们的值,xd为中间变量存放位置
				{ 
					xd = weight; weight = buffer[i]; buffer[i] = xd;
				}
			}
			buffer[medleng] = weight; 	//把轮询出较大的数放入缓存的后面.
			medleng++;
		}		
		if(medleng >= MEDIAN_LEN) 		    //ADC采样的数据个数达到中值滤波要求的数据个数
		{
			weight = buffer[MEDIAN];	    //最终重量取中值滤波数组的中间值
			medleng = 0; 
			OLED_ShowNum(60,4,weight,4,0);
			printf("weight:%d g\r\n",weight);
			printf("AT+MQTTPUB=0,\"/sys/io5xsNZLaxr/ESP8266/thing/event/property/post\",\"{\\\"params\\\":{\\\"Weight\\\":%d}}\",1,0\r\n",weight);	
			delay_ms(500);
		}
	}
}

打开阿里云我们可以看到数据上传成功,都是0的原因是我还没有称重传感器~~

相关推荐
零下273°4 小时前
51单片机蜂鸣器铃声代码
单片机·嵌入式硬件·51单片机
猿~~~5 小时前
STM32的HAL库开发---高级定时器PWM输入模式实验
stm32·单片机·嵌入式硬件
鹿屿二向箔5 小时前
单片机上SPI和IIC的区别
单片机·嵌入式硬件
weixin_580382066 小时前
STC51 P0 口 与P1 口输出
单片机·嵌入式硬件
爱吃奶酪的松鼠丶6 小时前
51单片机之使用Keil uVision5创建工程以及使用stc-isp进行程序烧录步骤
嵌入式硬件·51单片机·接口隔离原则
一只搬砖的猹8 小时前
PCA9685舵机控制板使用
stm32·单片机·嵌入式硬件·mcu·pwm·舵机·舵机驱动
零下273°9 小时前
51单片机俄罗斯方块开机动画
单片机·嵌入式硬件·51单片机
浅陌pa9 小时前
04:定时器
c语言·单片机·嵌入式硬件·51单片机
╰⋛⋋⊱⋋翅膀⋌⊰⋌⋚╯9 小时前
STM32-启动文件
stm32·单片机