基于App控制的STM32温湿度控制系统(WIFI模块)
ESP8266WIFI模块
在这个项目中我选用的正点原子的WIFI模块(ATK-ESP8266),这个模块采用串口(LVTTL)与MCU(或其他串口设备)通信,内置了TCP/IP的协议栈,可以实现串口与WIFI直接的转换,通过ATK-SEP8266模块,传统的串口设备只是需要简单的串口配置,即可通过网络(WIFI)传输自己的数据。
模块使用说明
其实挺简单的,拿出你的模块看,VCC就接3.3V或者5V,GND就接GND啦,然后WIFI模块与串口设备TX接RX,RX接TX,RST的复位是低电平有效。IO-0适用于固件烧写的,低电平就是烧写模式,高电平时运行模式(默认态)

RST和IO-0一般是不用接的(一般使用只用接前4个就好了)!
常用AT指令
| 指令 | 描述 |
|---|---|
| AT+CWMODE | 选择 WIFI 应用模式 |
| AT+CWJAP | 加入 AP |
| AT+CWLAP | 列出当前可用 AP |
| AT+CWQAP | 退出与 AP 的连接 |
| AT+CWSAP | 设置 AP 模式下的参数 |
| AT+CWLIF | 查看已接入设备的 IP |
| AT+CWDHCP | 设置 DHCP 开关 |
| AT+CWAUTOCONN | 设置 STA 开机自动连接到 wifi |
| AT+CIPSTAMAC | 设置 STA 的 MAC 地址 |
| AT+CIPAPMAC | 设置 AP 的 MAC 地址 |
| AT+CIPSTA | 设置 STA 的 IP 地址 |
| AT+CIPAP | 设置 AP 的 IP 地址 |
| AT+CWSTARTSMART | 启动智能连接 |
| AT+CWSTOPSMART | 停止智能连接 |
| AT+WPS | 设置 WPS 功能 |
| AT+MDNS | 设置 MDNS 功能 |
| AT+CWHOSTNAME | 设置 ATK-ESP-01 Station 的主机名字 |
具体AT指令的使用还是得去看下模块的用户手册,这里就不做过多的赘述了。
DHT11温湿度传感器
简介

| 参数 | Value |
|---|---|
| 工作电压 | 3.3V~5V |
| 湿度测量范围 | 20%~95% |
| 温度测量范围 | 0°~50° |
传感器数据输出的是未编码的二进制数据。数据(湿度、温度、整数、小数)之间应该分开处理。(如下图所示)

模块数据的发送流程

首先主机发送开始信号,即:拉低数据线,保持t1(至少18ms)时间,然后拉高数据线t2(20-40us)时间,然后读取DHT11的响应,正常的话,DHT11会拉低数据线,保持t3(40-50us)时间,作为响应信号,然后DHT11拉高数据线,保持t4(40-50us)时间后,开始输出数据。
代码实现
/*更改IO模式的封装函数*/
void DHT11_PIN_MODE(uint8_t mode)
{
GPIO_InitTypeDef GPIO_InitStruct = {
0};
if(mode==Intput)
{
GPIO_InitStruct.Pin = DHT11_DATA_Pin;
GPIO_InitStruct.Mode = GPIO_MODE_INPUT;
GPIO_InitStruct.Pull = GPIO_PULLUP;
GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_HIGH;
HAL_GPIO_Init(DHT11_DATA_GPIO_Port, &GPIO_InitStruct);
}else
{
GPIO_InitStruct.Pin = DHT11_DATA_Pin;
GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;
GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_HIGH;
HAL_GPIO_Init(DHT11_DATA_GPIO_Port, &GPIO_InitStruct);
}
}
static uint8_t DHT11_ReadByte ( void )
{
DHT11_PIN_MODE(Intput);
uint8_t i, temp=0;
for(i=0;i<8;i++)
{
/*每bit以50us低电平标置开始,轮询直到从机发出的50us低电平结束*/
while(Read_DHT11_DATA()==GPIO_PIN_RESET);
/*DHT11 以26~28us的高电平表示“0”,以70us高电平表示“1”,
*通过检测 x us后的电平即可区别这两个状 ,x 即下面的延时 */
HAL_Delay_us(40); //延时x us 这个延时需要大于数据0持续的时间即可
if(Read_DHT11_DATA()==GPIO_PIN_SET)/* x us后仍为高电平表示数据“1” */
{
/* 等待数据1的高电平结束 */
while(Read_DHT11_DATA()==GPIO_PIN_SET){
}
temp|=(uint8_t)(0x01<<(7-i)); //把第7-i位置1,MSB先行
}else // x us后为低电平表示数据“0”
{
temp&=(uint8_t)~(0x01<<(7-i)); //把第7-i位置0,MSB先行
}
}
return temp;
}
uint8_t DHT11_Read_TempAndHumidity(DHT11_Data_TypeDef *DHT11_Data)
{
if(Frame_Flag.dht11flag++ >= 1000 )
Frame_Flag.dht11flag = 0;
uint8_t temp;
uint16_t humi_temp;
/*输出模式*/
DHT11_PIN_MODE(Output);
/*主机拉低*/
DHT11_DATA_RESET();
/*延时18ms*/
Delay_ms(18);
/*总线拉高 主机延时30us*/
DHT11_DATA_SET();
HAL_Delay_us(30); //延时30us
/*主机设为输入 判断从机响应信号*/
DHT11_PIN_MODE(Intput);
/*判断从机是否有低电平响应信号 如不响应则跳出,响应则向下运行*/
if(Read_DHT11_DATA()==GPIO_PIN_RESET)
{
/*轮询直到从机发出 的80us 低电平 响应信号结束*/
while(Read_DHT11_DATA()==GPIO_PIN_RESET);
/*轮询直到从机发出的 80us 高电平 标置信号结束*/
while(Read_DHT11_DATA()==GPIO_PIN_SET);
/*开始接收数据*/
DHT11_Data->humi_high8Bit= DHT11_ReadByte();
DHT11_Data->humi_low8bit = DHT11_ReadByte();
DHT11_Data->temp_high8bit= DHT11_ReadByte();
DHT11_Data->temp_low8bit = DHT11_ReadByte();
DHT11_Data->check_sum = DHT11_ReadByte();
/*读取结束,引脚改为输出模式*/
DHT11_PIN_MODE(Output);
/*主机拉高*/
DHT11_DATA_SET();
/* 对数据进行处理 */
humi_temp=DHT11_Data->humi_high8Bit*100+DHT11_Data->humi_low8bit;
DHT11_Data->humidity =(float)humi_temp/100;
humi_temp=DHT11_Data->temp_high8bit*100+DHT11_Data->temp_low8bit;
DHT11_Data->temperature=(float)humi_temp/100;
/*检查读取的数据是否正确*/
temp = DHT11_Data->humi_high8Bit + DHT11_Data->humi_low8bit +
DHT11_Data->temp_high8bit+ DHT11_Data->temp_low8bit;
if(DHT11_Data->check_sum==temp)
{
return SUCCESS;
}else
{
return ERROR;
}
}else
{
return ERROR;
}
}
这里需要说明的是,如果用的是FreeRTOS的话就需要开多一个定时器用来进行μs级别的计时,同时不能放在任务中跑,这样任务很容易阻塞导致系统的暂停运行。但是实际上测量温度可以通过开关中断的方式进行读取,将读取速率放在一个任务里面也可以,主要是检测的时候用的us级的上拉下拉要注意下。
μs级的延时配置
这里选用的TIM6用来做计时器
HAL库配置
由于TIM6是挂载在APB1上的,所以要APB1的值

因为我APB1Timer clocks是90MHz
所以89+1/90=1MHz,也就是1μs计数一次。
代码实现
void HAL_Delay_us(uint16_t us)
{
// uint16_t startCount = __HAL_TIM_GET_COUNTER(&htim6);
//
// while((__HAL_TIM_GET_COUNTER(&htim6) - startCount) <= us);
uint16_t differ = 0xffff-us-5;
HAL_TIM_Base_Start(&htim6);
__HAL_TIM_SetCounter(&htim6,differ);
while(differ < 0xffff-5)
{
differ = __HAL_TIM_GetCounter(&htim6);
}
HAL_TIM_Base_Stop(&htim6);
}
项目总框架
讲完这个项目所用的两个外设了,现在来说一下整个项目的总体设计思路。
总框架图

如上图所示,首先我们利用AT指令初始化WIFI模块,然后WIFI模块等待APP建立TCP连接。建立完连接之后,便利用TCP间客户机与服务机之间的通信进行数据的传输。DHT11模块接收到温湿度信号后发送脉冲给单片机的IO口,IO口读取电平后将其转化成数字,再由单片机的串口发送到WIFI模块回显在APP上面。
单片机控制流程图

单片机首先初始化板上的资源(IO口、串口、WIFI模块),然后开启了串口中断,DMA传输,以及创建控制任务。开启了串口中断后就开始接收数据。如果没有接收到数据,则返回重新接收,如果有,就把数据存进缓冲区,存进缓冲区之后,程序会对缓冲区的数据进行解包处理后存进结构体对应的成员变量内,然后通过读取温度与湿度的成员变量,通过串口发送给WIFI模块,APP对数据进行回显。
APP控制流程图

在打开APP的时候,在界面中输入服务器IP地址和端口号,点击CONNECT按钮就会跟服务器建立TCP连接。然后在控制界面有开灯、关灯、播放音乐的按钮,点击可以触发对应的事件然后向WIFI模块发送信息。WIFI模块收到信息之后通过AT指令会发送数据给APP,APP处理之后可以回显到界面上。
项目代码实现
WIFI模块
首先需要利用单片机给WIFI模块通过串口传输发送以下AT指令进行初始化:
char rst[] = "AT+RESTORE\r\n";//WIFI模块重置
char cipmode[] = "AT+CIPMODE=0\r\n";//退出透传模式(因为WIFI模块在AP模式下是不需要透传的)
char mux[] = "AT+CIPMUX=1\r\n";//设置多连接
char server[] = "AT+CIPSERVER=1\r\n";//设置服务器模式
当APP(从机)与WIFI模块(主机建立连接后)需要发送如下指令:
char cipsend[] = "AT+CIPSEND=0,30\r\n";//其中的0代表连接号,30代表需要发送的数据 根据自己需求定
STM32单片机(主机)
初始化WIFI模块
/*给大延时是为了等待模块反应*/
HAL_UART_Transmit(&huart7,(uint8_t *)rst,strlen(rst),0xFFFF);
HAL_Delay(5000);
memset(ReceiveBuff,'\0',PackSize);
HAL_Delay(1000)

本文详细介绍了基于STM32单片机和ESP8266WIFI模块构建的温湿度控制系统,通过DHT11传感器获取数据,并使用AT指令配置WIFI模块与APP进行TCP通信。项目涵盖了硬件初始化、AT指令使用、DHT11传感器读取、μs级延时配置以及APP控制流程。在APP端,用户可以查看并控制温湿度数据和设备状态。
最低0.47元/天 解锁文章
2837

被折叠的 条评论
为什么被折叠?



