基于 STM32 的智能环境监测与控制系统

目录

通过网盘分享的文件:程序.zip
链接: https://pan.baidu.com/s/1j3hsaGV727QUCtE36cePSg?pwd=1234 提取码: 1234

基于 STM32 的智能环境监测与控制系统(代码实现与解析)

一、项目概述

二、硬件选型与引脚配置

2.1 硬件选型

2.2 引脚配置

三、软件设计与核心代码解析

3.1 整体框架

3.2 核心代码与解析

3.2.1 初始化函数(硬件外设启动)

3.2.2 核心数据与状态变量

3.2.3 自动控制逻辑

1. 风扇自动调速

2. 灯光自动调节(PWM 占空比)

3. 蜂鸣器报警逻辑

3.2.4OLED显示逻辑

3.2.5 定时器中断与按键处理(关键)

3.2.5 主循环逻辑

四、功能测试与现象说明


基于 STM32 的智能环境监测与控制系统(代码实现与解析)

一、项目概述

本文分享一个基于 STM32F103 的智能环境监测与控制系统,实现了以下功能:

  1. 环境参数采集:温湿度(DHT11)、光照强度(BH1750)
  2. 外设智能控制:LED 灯光(PWM 调节)、风扇(电机驱动)、蜂鸣器(异常报警)
  3. 工作模式切换:自动模式(根据环境参数自动调节)/ 手动模式(按键控制)
  4. 数据可视化:OLED 显示、串口打印,支持 MQTT 上传至 OneNet 平台

这个项目虽然简陋,但是也是做了好几天。

二、硬件选型与引脚配置

2.1 硬件选型

  1. 主控:STM32F103C8T6
  2. 传感器:DHT11(温湿度)、BH1750(光照)
  3. 外设:OLED12864、直流电机(风扇)、蜂鸣器、LED、独立按键 ×4
  4. 通信模块:ESP8266(WiFi,用于 MQTT 连接)

2.2 引脚配置

LED   PWM调光 PA6(TIM3_CH1)通过PWM_SetCompare1函数控制

DHT11  PA1

OLED   PB6  PB7 (分别为 SCL、SDA,借助 I2C 通信)

  1. MOTOR       P4  //正转
    1.                     P5  //反转
  2.      其中需要PA7(TIM3_CH2 )   通过PWM_SetCompare2函数控制电

UsartⅠ 9600    PA9  RXD      PA10 TXD  发送串口信息

UsartⅡ 115200    PA2 TXD        PA3 RXD  连接ESP01s

Buzzer   PA8

BH1750 用到I2C通信  PB6 CLK  PB7 SDA

ESP01S

烧录

用到UsartⅡ 115200  3.3V GND接板子的  RX接UsartⅡ TXD  TX接UsartⅡRXD   IO0接GND

下载时,先RST接地一下后拔开

测试时

VCC GND接VCC GND  R接T T接R 都接串口

正常工作时,

VCC GND接板子,R接T,T接R接板子

三、软件设计与核心代码解析

3.1 整体框架

程序采用模块化设计,主要分为以下模块:

  1. 初始化模块:硬件外设初始化(定时器、传感器、通信等)
  2. 数据采集模块:温湿度、光照数据读取
  3. 控制逻辑模块:自动 / 手动模式下的外设控制
  4. 交互模块:按键输入、OLED 显示、串口打印
  5. 通信模块:ESP8266 连接 OneNet 平台(MQTT 协议)

3.2 核心代码与解析

3.2.1 初始化函数(硬件外设启动)
void Init(void)

{

    delay_init();         

    Serial_Init();          // 串口1初始化(调试打印)

    Usart2_Init(115200);    // 串口2初始化(ESP8266通信)

    OLED_Init();            // OLED显示屏初始化

    ESP8266_Init();         // WiFi模块初始化

    DHT11_Init();           // 温湿度传感器初始化

    BH1750_Init();          // 光照传感器初始化

    Timer_Init();           // 定时器初始化(TIM2、TIM4)

    Pwm_Init();             // PWM初始化(LED亮度调节)

    buzzer_Init();          // 蜂鸣器初始化

    Motor_Init();           // 电机(风扇)初始化

    Key_Init();             // 按键初始化

    LED_Init();             // LED初始化

}

说明:初始化顺序需注意依赖关系(如定时器需在按键前初始化,确保中断正常)。

3.2.2 核心数据与状态变量
// 环境参数

float temperature, humidity;

u8 temp_int,temp_dec,humi_int,humi_dec;  // 温湿度整数/小数部分

float lux;                               // 光照强度(lx)

uint16_t pwm_duty;                       // LED PWM占空比

// 系统状态

u8 mode = 0;              // 0-自动模式,1-手动模式

u8 oled_page = 0;         // OLED显示页面(0-基本参数,1-扩展参数)

u8 light_state = 0;       // 手动模式下LED状态(0-关,1-开)

u8 fan_speed = 0;         // 风扇转速(0-99,对应占空比)

u8 key_press_flag[6] = {0};  // 按键触发标志(避免中断内耗时操作)
3.2.3 自动控制逻辑
1. 风扇自动调速
uint8_t AutoFanSpeed(void)

{

    if (temp_int >= 30 && temp_int < 50)

        return 99;   // 高温全速

    else if (temp_int >= 28 && temp_int < 30)

        return 50;   // 中温半速

    else if (temp_int >= 25 && temp_int < 28)

        return 25;   // 低温低速

    else if (temp_int >= 0 && temp_int < 25)

        return 0;    // 常温停止

    else

        return 0;

}
2. 灯光自动调节(PWM 占空比)
uint16_t AutoLight(void)

{
    uint16_t i; //记录线性

    if(mode)  // 手动模式:直接控制开关

    {

        return light_state ? 99 : 0;

    }

    else  // 自动模式:根据光照强度线性调节

    {

        if(lux < 100)      

            return 99;   // 昏暗环境全亮

        else if(lux > 1000)

            return 0;    // 强光环境关闭

        else

        {

            // 100-1000lx区间:占空比从99线性降至0

            i=(uint16_t)(99 - (lux - 100) * 99 / 900);

            return i;

        }

    }

}
3. 蜂鸣器报警逻辑
void buzzer_control(void)

{

    // 温度≥30℃或湿度≥80%时报警

    if(temp_int>=30 || humi_int>=80)

        buzzer_ON();

    else

        buzzer_OFF();

}
3.2.4OLED显示逻辑

可用通过按键5换页,一共两页。同时进行串口打印

void OLED_display(void)
{
    OLED_Clear();  // 清屏,避免上一帧数据残留
    if(oled_page==0)  // 第0页:基础环境参数页
    {
        // 显示当前工作模式(自动/手动)
        OLED_ShowString(1, 1, mode ? "Mode:Manual" : "Mode:Auto");  
        // 显示温度(整数+小数部分)
        OLED_ShowString(2, 1, "Temp:");
        OLED_ShowNum(2, 6, temp_int, 2);  // 温度整数位(2位显示)
        OLED_ShowChar(2, 8, '.');         // 小数点
        OLED_ShowNum(2, 9, temp_dec, 1);  // 温度小数位(1位显示)
        OLED_ShowChar(2, 11, 'C');        // 温度单位(摄氏度)

        // 显示湿度(整数+小数部分)
        OLED_ShowString(3, 1, "Humi:");
        OLED_ShowNum(3, 6, humi_int, 2);  // 湿度整数位(2位显示)
        OLED_ShowChar(3, 8, '.');         // 小数点
        OLED_ShowNum(3, 9, humi_dec, 1);  // 湿度小数位(1位显示)
        OLED_ShowChar(3, 11, '%');        // 湿度单位(百分比)

        // 页切换提示(引导用户按KEY5查看更多信息)
        OLED_ShowString(4, 1, "K5:More Info");
    }
    // 第1页:扩展设备状态页
    else if(oled_page==1)
    {
        // 显示光照强度(lx)
        OLED_ShowString(1, 1, "Lux:");
        OLED_ShowNum(1, 5, (uint16_t)lux, 4);  // 光照值(4位显示)
        OLED_ShowString(1, 9, "lx");           // 光照单位

        // 显示蜂鸣器状态(开/关)
        OLED_ShowString(2, 1, "Buzzer:");
        OLED_ShowString(2, 9, beep_state ? "OFF" : "ON");  // beep_state为1时显示OFF,0时显示ON

        // 显示风扇转速(0-99)
        OLED_ShowString(3, 1, "Speed:");
        OLED_ShowNum(3, 7, fan_speed, 2);  // 转速值(2位显示)

        // 显示LED状态(开/关,通过PWM占空比判断)
        OLED_ShowString(4, 1, "LED:");
        OLED_ShowString(4, 5, pwm_duty==0 ? "OFF" : "ON");  // 占空比为0时显示OFF,否则显示ON
    }

    // 串口打印:同步输出关键参数到上位机(如串口助手)
    Serial_Printf("当前模式:%s|温度:%.2f ℃|湿度: %.2f %|光照强度:%.1f lx| 蜂鸣器:%s \r\n", 
                  mode ? "Manual" : "Auto",  // 模式
                  temperature, humidity,     // 温湿度(浮点值)
                  lux,                       // 光照强度
                  beep_state ? "OFF" : "ON"); // 蜂鸣器状态
}
3.2.5 定时器中断与按键处理(关键)

采用双定时器分工:

  1. TIM2(1ms 周期):高频扫描按键,实现消抖,确保按键响应灵敏(无延迟感)
  2. TIM4(1s 周期):周期性触发数据更新与外设控制,降低 CPU 占用,避免资源浪费
  3. 用delay会一直占用cpu
// 1ms 周期定时器,负责按键扫描与消抖
void TIM2_IRQHandler(void)
{
    // 各按键消抖计数器(10ms 消抖:1ms×10)
    static uint8_t key1_counter = 0;
    static uint8_t key2_counter = 0;
    static uint8_t key4_counter = 0;
    static uint8_t key5_counter = 0;
    
    // 记录上一次按键状态(1-未按,0-按下)
    static uint8_t last_key1 = 1;
    static uint8_t last_key2 = 1;
    static uint8_t last_key4 = 1;
    static uint8_t last_key5 = 1;
    
    // 存储当前按键状态
    uint8_t current_key1, current_key2, current_key4, current_key5;

    // 检查中断标志(确保是更新中断)
    if (TIM_GetITStatus(TIM2, TIM_IT_Update) == SET)
    {
        // 读取当前按键状态
        current_key1 = KEY_GetPinState(KEY1);
        current_key2 = KEY_GetPinState(KEY2);
        current_key4 = KEY_GetPinState(KEY4);
        current_key5 = KEY_GetPinState(KEY5);
        
        // KEY1:切换自动/手动模式(无模式限制)
        if (current_key1 != last_key1) 
        {
            // 状态变化时,重置消抖计数器(10ms 后再判断)
            key1_counter = 10;
        } 
        else if (key1_counter > 0)  // 状态稳定时递减计数器
        {
            // 计数器减到0且按键仍按下,确认有效触发
            if (--key1_counter == 0 && current_key1 == 0)
            {
                mode = !mode;  // 翻转模式(0→1或1→0)
            }
        }
        
        // KEY2/KEY4:仅在手动模式(mode=1)下生效
        if (mode == 1)
        {
            // KEY2:控制LED开关
            if (current_key2 != last_key2) 
            {
                key2_counter = 10;  // 重置消抖计数器
            } 
            else if (key2_counter > 0)
            {
                if (--key2_counter == 0 && current_key2 == 0)
                {
                    light_state = !light_state;  // 翻转LED状态
                    key_press_flag[2] = 1;       // 标记主循环处理
                }
            }
            
            // KEY4:调节风扇转速(0→25→50→75→99→0循环)
            if (current_key4 != last_key4) 
            {
                key4_counter = 10;  // 重置消抖计数器
            } 
            else if (key4_counter > 0)
            {
                if (--key4_counter == 0 && current_key4 == 0)
                {
                    fan_speed += 25;
                    if (fan_speed > 99) fan_speed = 0;  // 溢出重置
                    key_press_flag[4] = 1;  // 标记主循环处理
                }
            }
        }
        
        // KEY5:切换OLED显示页面(无模式限制)
        if (current_key5 != last_key5) 
        {
            key5_counter = 10;  // 重置消抖计数器
        } 
        else if (key5_counter > 0)
        {
            if (--key5_counter == 0 && current_key5 == 0)
            {
                oled_page = !oled_page;  // 翻转页面(0→1或1→0)
                key_press_flag[5] = 1;   // 标记主循环处理
            }
        }
        
        // 更新上一次按键状态(为下一次判断做准备)
        last_key1 = current_key1;
        last_key2 = current_key2;
        last_key4 = current_key4;
        last_key5 = current_key5;
        
        // 清除中断标志(必须操作,否则会重复触发)
        TIM_ClearITPendingBit(TIM2, TIM_IT_Update);
    }
}
3.2.5 主循环逻辑
int main(void)
{
    unsigned char *dataPtr = NULL;  // 用于接收 ESP8266 数据(MQTT 指令)

    // 初始化温度默认值(调试用,实际由 DHT11 覆盖)
    temperature = 25;  

    // 关键初始化:定时器、传感器、通信等(需实现 Init 函数)
    Init();  

    // 连接 MQTT 平台(OneNet),实现数据上传与指令接收
    Link_MQTT();  

    // 主循环:持续执行环境监测与控制
    while(1)
    {
        // 1. 数据采集
        Read_light(&lux);  // 读取光照强度(BH1750)

        // 读取温湿度(DHT11)
        DHT11_Read_Data(&temp_int, &temp_dec, &humi_int, &humi_dec);  

        // 合并为浮点值
        temperature = temp_int + temp_dec / 10.0f;  
        humidity = humi_int + humi_dec / 10.0f; 
 

        // 2. 模式判断:手动/自动
        if(mode)  // 手动模式(mode=1)
        {
            // KEY2 触发:更新 LED PWM 占空比(手动调节)
            if (key_press_flag[2])  
            {
                pwm_duty = AutoLight();  // 获取目标占空比
                PWM_SetCompare1(pwm_duty);  // 输出 PWM 控制 LED
                key_press_flag[2] = 0;  
            }

            // KEY4 触发:更新风扇转速(手动调节)
            if (key_press_flag[4])  
            {
                Motor_Setspeed(fan_speed);  // 按设定转速控制风扇
                key_press_flag[4] = 0;  
            }

            // OLED 刷新
            if(oledUpdateFlag == 1)  
            {
                OLED_display();  // 显示手动模式页面
                oledUpdateFlag = 0;  
            }

            // 蜂鸣器控制
            if(buzzerUpdateFlag == 1)  
            {
                buzzer_control();  // 执行蜂鸣器控制
                buzzerUpdateFlag = 0;  
            }
        }
        else  // 自动模式(mode=0)
        {
            // OLED 刷新
            if(oledUpdateFlag == 1)  
            {
                OLED_display();  // 显示自动模式页面


                // MQTT 数据上传(需实现 OneNet_SendData 函数)
                OneNet_SendData();  
                // 清除 ESP8266 接收缓存,避免数据堆积
                ESP8266_Clear();  
                // 获取平台下发指令(超时 5ms)
                dataPtr = ESP8266_GetIPD(5);  
                if(dataPtr != NULL)
                {
                    // 解析并处理 MQTT 指令(需实现 OneNet_RevPro 函数)
                    OneNet_RevPro(dataPtr);  
                }

                oledUpdateFlag = 0;  
            }

            // 蜂鸣器控制
            if(buzzerUpdateFlag == 1)  
            {
                buzzer_control();  // 执行蜂鸣器逻辑(如异常报警)
                buzzerUpdateFlag = 0;  
            }

            // 设备状态更新
            if(MotorUpdateFlag == 1)  
            {
                // 自动调节 LED 亮度
                pwm_duty = AutoLight();  
                PWM_SetCompare1(pwm_duty);  

                // 自动调节风扇转速
                fan_speed = AutoFanSpeed();  
                Motor_Setspeed(fan_speed);  
                MotorUpdateFlag = 0; 
            }
        }
    }
}

四、功能测试与现象说明

  1. 按键响应
    1. KEY1:切换自动 / 手动模式(消抖 10ms,响应灵敏)
    2. KEY2(手动模式):控制 LED 开关
    3. KEY4(手动模式):循环调节风扇转速(0→25→50→75→99→0)
    4. KEY5:切换 OLED 显示页面(基础参数 / 扩展参数)
  2. 自动模式表现
    1. 风扇根据温度自动调速,光照≥30℃时全速运行
    2. LED 根据光照强度线性调节亮度(暗环境亮,亮环境灭)
    3. 温度≥30℃或湿度≥80% 时,蜂鸣器报警
  3. 数据上传: 每 1 秒向 OneNet 平台发送温湿度、光照等数据,支持远程查看。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值