跟着我完成一个简单的项目:物联网环境监测系统esp8266+stm32(持续更新中)
目录
概要
效果图展示
整体架构流程
esp8266模块初始化
ADC数据采集函数
DHT11 模块采集
stm32与esp8266上下行通信
esp8266_send_cmd
esp8266_config_network
esp8266_receive_msg
阿里云平台相关配置
系统功能解释
按键篇
技术细节
小结
概要
本题研究基于STM32f103c8t6开发板,设计一个集成温湿度、光照、烟雾、噪声等多种环境传感器的物联网智能仓库环境管理系统。传感器实时采集仓库环境中的关键数据,并通过WIFI模块(ESP8266)将数据传输至远程服务器或云平台,实现远程监控、数据存储与分析。当仓库环境数据超出设定的安全阈值时,系统自动发出报警或做出相应操作,提醒管理者采取措施。
核心内容包括:数据采集、数据传输、数据报警与处理、硬件电路搭建
使用到的软件:Keill5、STM32CubeMX、浏览器、ESP8266 Flash Download Tool工具、sscom串口工具
效果图展示



整体架构流程
如果你看到了这里,想必对本项目也有了 一定的了解,下面我来讲述一下本项目的实现原理。
本系统采用分层架构设计,其中STM32微控制器作为数据采集单元,负责从连接的传感器中周期性地收集环境参数,并将原始数据进行初步处理后,通过串行通信接口(UART)按照预定义的协议发送至网络传输单元——ESP8266 Wi-Fi模块。
ESP8266模块扮演着网关的角色,它接收来自STM32的数据包,对其进行解析并转换为符合JSON标准的数据格式,随后利用其内置的Wi-Fi功能将这些结构化的信息上传到指定的云服务平台。在此过程中,ESP8266确保了数据的安全性和完整性,并管理与云端的TCP/IP连接,实现可靠的数据传输。
esp8266模块初始化
首先启动ESP8266 Flash Download Tool工具进行 (1471)ESP8266-AT_MQTT-1M.bin固件的烧写,这个固件包含了预编程的AT指令集,允许用户通过发送简单的文本命令来配置和控制模块的功能。在使用之前烧写这样的固件文件是为了确保模块按照预期工作,并且能够满足项目的特定需求。
烧写完成之后就可以用串口工具对模块进行测试,以串口的形式传送at指令,测试esp8266模块的联网功能。
ADC数据采集函数
//ADC传感器的读取
{
lux_value = adc_read(); //5516光线传感器读值
ppm_value = adc_read(); //mq2气体传感器读值
sy01_value = adc_read(); //sy01噪声传感器读值
}
//上述代码中的adc_read()函数的解释,通过for循环,依次读取定义的三个adc输入端口
uint16_t adc_read()
{
int i;
for(i=0;i<3;i++)
{
HAL_ADC_Start(&hadc1);
HAL_ADC_PollForConversion(&hadc1, 10);
adc_value [i] = HAL_ADC_GetValue(&hadc1);
return adc_value[i];
}
}

DHT11 模块采集
由于DHT11传感器模块读取数据的方式较为特殊,因此单独列出其数据采集函数。
微控制器想要采集DHT11传感器数据,必须先将数据线拉低至少18毫秒以发送开始信号,然后将数据线拉高并等待DHT11响应。DHT11检测到主机发出的开始信号后,会拉低数据线大约80微秒作为应答信号,随后再将数据线拉高80微秒准备发送数据。DHT11会依次发送40位数据,每位数据由50微秒的低电平和不同长度的高电平组成。高电平的时间长度决定了该位是0还是1。40位数据包括湿度整数部分(8位)、湿度小数部分(8位)、温度整数部分(8位)、温度小数部分(8位)以及校验和(8位)。校验和是前四个字节的二进制加和的最低8位。如果接收到的数据中这五个字节的和的最低8位为0,那么说明数据传输无误;否则,可能存在错误。
//此处仅列举主要函数
uint8_t dht11_read_data(uint8_t *temp,uint8_t *humi)
{
uint8_t buf[5];
uint8_t i;
dht11_rst();//DHT11端口复位,发出起始信号
if(dht11_check()==0)
{ //等待DHT11回应
for(i=0;i<5;i++)
{//读取5位数据
buf[i]=dht11_read_byte(); //读出数据
}
if((buf[0]+buf[1]+buf[2]+buf[3])==buf[4])
{ //数据校验
*humi = buf[0]; //将湿度值放入指针1
*temp = buf[2]; //将温度值放入指针2
}
}
else
{
return 1;
}
return 0;
}
/**
* @brief DHT11端口复位,发出起始信号(IO发送)
* @param[in] none
* @retval none
*/
void dht11_rst (void)
{
dht11_io_out();
HAL_GPIO_WritePin(DHT11_GPIO_Port,DHT11_Pin, GPIO_PIN_RESET);
HAL_Delay(20); //拉低至少18ms
HAL_GPIO_WritePin(DHT11_GPIO_Port,DHT11_Pin, GPIO_PIN_SET);
delay_us(30); //主机拉高20~40us
}
**
* @brief 等待DHT11回应
* @param[in] none
* @retval 返回1:未检测到DHT11,返回0:成功(IO接收)
*/
uint8_t dht11_check(void)
{
uint8_t retry=0;
dht11_io_in();//IO到输入状态
while (HAL_GPIO_ReadPin(DHT11_GPIO_Port,DHT11_Pin)&&retry<100)
{//DHT11会拉低40~80us
retry++;
delay_us(1);
}
if(retry>=100)return 1; else retry=0;
while (!HAL_GPIO_ReadPin(DHT11_GPIO_Port,DHT11_Pin)&&retry<100)
{//DHT11拉低后会再次拉高40~80us
retry++;
delay_us(1);
}
if(retry>=100)return 1;
return 0;
}
/**
* @brief 从DHT11读取一个字节
* @param[in] none
* @retval 返回值:读到的数据
*/
uint8_t dht11_read_byte(void)
{
uint8_t i,dat;
dat=0;
for (i=0;i<8;i++){
dat<<=1;
dat|=dht11_read_bit();
}
return dat;
}
dht11_read_data函数使用方法
int main(void)
{
while(1)
{
dht11_read_data(&temp_value,&humi_value); //假设你已经定义温湿度数据接收对象
}
}
stm32与esp8266上下行通信
上传数据:通过格式化数据为JSON格式并使用AT+MQTTPUB
命令发布到指定的MQTT主题。
接收数据:通过订阅特定的MQTT主题,接收来自云端的消息,解析这些消息中的JSON数据,并更新设备状态
esp8266_send_cmd
esp8266_send_cmd
函数用于向ESP8266发送AT命令,并等待响应。它使用HAL_UART_Transmit
发送命令,并通过检查receive_start
标志位来判断是否收到响应。esp8266_send_msg
函数通过AT+MQTTPUB
命令将数据发布到指定的MQTT主题。/**
* @brief 向esp8266发送命令函数,成功返回0,失败返回1
* @param[in] cmd:发送的命令,len:命令的长度,rec_data:期望接收数据
* @retval none
*/
uint8_t esp8266_send_cmd(unsigned char *cmd,unsigned char len,char *rec_data)
{
unsigned char retval =0;
unsigned int count = 0;
HAL_UART_Transmit(&huart2, cmd, len, 1000);
while((receive_start == 0)&&(count<1000))
{
count++;
HAL_Delay(1);
}
if(count >= 1000)
{
retval = 1;
}
else
{
do
{
receive_finish++;
HAL_Delay(1);
}
while(receive_finish < 500);
retval = 2;
if(strstr((const char*)receive_buf, rec_data))
{
retval = 0;
}
}
uart2_receiver_clear(receive_count);
return retval;
}
esp8266_config_network
esp8266_config_network
函数通过发送AT+CWJAP
命令配置ESP8266连接到指定的Wi-Fi网络。
/**
* @brief esp8266配置wifi网络
* @param[in] none
* @retval 网络配置成功返回0,否则返回1
*/
uint8_t esp8266_config_network(void)
{
uint8_t retval =0;
uint16_t count = 0;
HAL_UART_Transmit(&huart2, (unsigned char *)"AT+CWJAP=\""WIFI_SSID"\",\""WIFI_PASSWD"\"\r\n",strlen("AT+CWJAP=\""WIFI_SSID"\",\""WIFI_PASSWD"\"\r\n"), 1000);
while((receive_start == 0)&&(count<1000))
{
count++;
HAL_Delay(1);
}
if(count >= 1000)
{
retval = 1;
}
else
{
HAL_Delay(8000);
if(strstr((const char*)receive_buf, "OK"))
{
retval = 0;
}
else
{
retval = 1;
}
}
uart2_receiver_clear(receive_count);
return retval;
}
esp8266_receive_msg
esp8266_receive_msg
函数处理从MQTT订阅的主题接收到的消息,解析JSON数据并更新设备状态。
/**
* @brief 通过esp8266接收数据 接收来自MQTT代理服务器的控制消息,并解析这些消息。
* @param[in] none
* @retval 返回0接收数据正常,返回1接收数据异常或无数据
*/
uint8_t esp8266_receive_msg(void)
{
uint8_t retval =0;
int msg_len=0;
uint8_t msg_body[128] = {0};
if(receive_start == 1)
{
do
{
receive_finish++;
HAL_Delay(1);
}
while(receive_finish < 5);
if(strstr((const char*)receive_buf,"+MQTTSUBRECV:"))
{
sscanf((const char *)receive_buf,"+MQTTSUBRECV:0,\""SUB_TOPIC"\",%d,%s",&msg_len,msg_body);
printf("len:%d,msg:%s\r\n",msg_len,msg_body);
if(strlen((const char*)msg_body)== msg_len)
{
retval = parse_json_msg(msg_body,msg_len);
}
else
{
retval = 2;
}
}
else
{
retval = 2;
}
}
else
{
retval = 2;
}
uart2_receiver_clear(receive_count);
return retval;
}
上述极端代码仅展示STM32如何通过UART与ESP8266模块进行串口通信,实现Wi-Fi连接和MQTT协议的应用。通过发送AT命令控制ESP8266的行为,接收ESP8266的响应,并处理MQTT消息,STM32能够实现远程控制和数据传输的功能。整个过程涉及到串口通信的配置、数据的发送与接收、以及对ESP8266响应的解析和处理。
最后放一张主函数程序图
阿里云平台相关配置
系统功能解释
按键篇
对于本项目暂时设置了四枚按键,在函数中的名称分别为button_mode、button_enter、button_up、button_down。
程序上电运行后首先运行在main_manual(手动模式),在本模式中,系统自动采集环境数据并且上传至云端,通过app可以进行数据读取或者进行灯光功能、舵机功能的控制,这些主动下发任务的功能都需要手动操作。
按下button_mode按键,程序将切换到main_auto(自动模式),此时系统将自行判定光照强度、温湿度、气体弄得等环境值,达到阈值后会自动打开或关闭led等一系列模块操作。
在main_auto模式中,如果按下button_enter按键,oled屏幕将依次显示温度最大值、温度最低值、湿度最大值……等环境数据,此时就可以按button_up或button_down按键进行阈值的设置。非常人性化
技术细节
小结
后续会继续补充文章内容
作者:Keenn4ss