基于STM32的智能路灯远程控制与环境感知系统设计

举报
DS小龙哥 发表于 2025/06/22 18:43:03 2025/06/22
【摘要】 项目开发背景 项目开发背景随着城市化进程加速和智慧城市建设理念的深入推广,城市公共照明系统的智能化升级成为提升城市管理效率、降低能源消耗的重要环节。传统路灯系统普遍存在控制方式单一、能源浪费显著、运维响应滞后等问题,例如依靠固定时间表或人工操作开关灯,无法根据实际环境光照灵活调节,导致在黎明、黄昏或阴雨天气时出现无效照明;同时,缺乏对设备运行状态和环境的实时监测,故障发现与处置效率低下,维...

项目开发背景

项目开发背景

随着城市化进程加速和智慧城市建设理念的深入推广,城市公共照明系统的智能化升级成为提升城市管理效率、降低能源消耗的重要环节。传统路灯系统普遍存在控制方式单一、能源浪费显著、运维响应滞后等问题,例如依靠固定时间表或人工操作开关灯,无法根据实际环境光照灵活调节,导致在黎明、黄昏或阴雨天气时出现无效照明;同时,缺乏对设备运行状态和环境的实时监测,故障发现与处置效率低下,维护成本居高不下。

物联网技术的快速发展为解决上述痛点提供了有效途径。通过将传感器、微控制器和无线通信技术集成于路灯终端,构建具备环境感知与远程管控能力的智能系统,可实现对每盏路灯的精细化、动态化管理。此类系统不仅能依据环境光照强度自动启闭灯光,显著节约电能,还能实时采集温湿度等环境数据,为城市环境监测提供辅助信息。此外,借助云平台实现远程监控和集中管理,可极大提升运维响应速度和管理水平。

在此背景下,设计基于STM32的智能路灯远程控制与环境感知系统具有迫切的实际意义。该系统旨在利用STM32微控制器的强大处理能力,集成高精度光照传感器(BH1750)、温湿度传感器(SHT30),结合ESP8266实现稳定可靠的云端通信(MQTT协议),并通过继电器实现路灯的自动与远程开关控制。本地OLED显示屏提供实时状态反馈,蜂鸣器提供异常报警,形成一套完整的"感知-决策-执行-交互-上传"闭环。该系统不仅可显著提升路灯管理的智能化水平和能源利用效率,降低运维成本,也为构建更广泛的城市物联网基础设施提供可复用的技术方案,符合智慧城市绿色、高效、可持续发展的核心目标。

设计实现的功能

(1)通过BH1750光照传感器实时检测环境光照强度,根据预设阈值自动控制继电器模块开关,实现路灯(大功率LED灯)的自动启停。
(2)通过SHT30温湿度传感器采集环境温度与湿度数据,并通过ESP8266 WiFi模块将数据上传至华为云物联网平台。
(3)通过华为云物联网平台下发远程指令,经ESP8266接收后控制继电器模块开关,实现路灯的远程手动开关功能。
(4)通过SPI接口的OLED屏实时显示当前光照强度、温湿度数值、路灯开关状态(开/关/自动模式)、网络连接状态及远程控制指令响应。
(5)所有传感器数据(光照、温湿度)、路灯状态及系统运行信息通过ESP8266以MQTT协议打包上传至华为云物联网平台,同时订阅平台下发的控制指令。

项目硬件模块组成

(1)STM32F103C8T6主控芯片
(2)BH1750光照检测模块(I2C接口)
(3)SHT30温湿度检测模块(I2C接口)
(4)继电器模块(控制大功率LED灯)
(5)ESP8266 WiFi模块(AT指令模式,支持MQTT协议)
(6)0.96寸SPI OLED显示模块
(7)高电平触发有源蜂鸣器
(8)DC 5V电源 + AMS1117-3.3稳压模块

设计意义

本设计基于STM32F103C8T6微控制器构建的智能路灯系统,其设计意义主要体现在以下几个方面:

该设计通过集成BH1750光照传感器与自动控制逻辑,实现了路灯的智能化开关管理。系统能够实时监测环境光照强度,仅在光照不足时自动开启路灯,而在光照充足时自动关闭,有效避免了传统定时控制或人工操作造成的能源浪费。这种按需照明策略显著降低了路灯系统的电力消耗,直接节约了城市公共照明运营成本,响应了节能减排的可持续发展要求。

系统利用SHT30温湿度传感器持续采集环境数据,并通过ESP8266 WiFi模块及MQTT协议,将数据实时上传至华为云物联网平台。这使得城市管理者能够远程、集中监控路灯网络覆盖区域的实时环境状况,获取历史数据用于分析区域微气候。环境数据的数字化与云端汇聚,为优化城市管理决策(如绿化、环卫调度)提供了科学依据,提升了城市基础设施的精细化管理水平。

集成ESP8266模块并采用标准MQTT协议,赋予路灯远程可控性。管理人员可通过云平台或移动应用,随时随地手动开关任意路灯或进行策略调整(如特殊活动、紧急情况下的照明调度)。这种远程控制能力极大地提高了路灯系统的运维效率和响应速度,无需现场作业即可完成状态检查、故障排查或临时照明策略变更,降低了人工巡检成本和维护难度。

配备本地SPI OLED显示屏,为现场维护人员提供了关键信息的实时可视化界面,包括光照值、温湿度读数、路灯开关状态、网络连接情况等。结合高电平触发的有源蜂鸣器报警提示,可在检测到传感器异常、通信中断或控制指令执行失败时发出本地声光告警。这一设计增强了系统的可靠性与可维护性,确保即使网络暂时中断,现场人员也能快速掌握系统状态并进行初步诊断,保障系统稳定运行。

设计思路

设计思路

系统以STM32F103C8T6为主控核心,通过协调各硬件模块实现环境感知、路灯控制与远程交互功能。首先初始化硬件接口,包括I2C总线(连接BH1750光照传感器和SHT30温湿度传感器)、SPI接口(驱动OLED屏)、USART串口(连接ESP8266)及GPIO(控制继电器与蜂鸣器)。

光照强度检测由BH1750模块实时采集数据。主控芯片设定光照阈值,当环境光低于阈值时自动触发继电器开启路灯,高于阈值则关闭,实现基础自动化控制。温湿度数据通过SHT30采集,结合光照值和路灯状态,由STM32封装为JSON格式数据。

联网通信依托ESP8266模块。STM32通过AT指令集配置ESP8266连接WiFi并接入华为云物联网平台,使用MQTT协议定时上传传感器数据及设备状态。同时订阅云平台下行Topic,接收远程开关指令。当云平台下发控制命令时,STM32解析指令并操作继电器,实现远程开关灯功能。

本地交互通过SPI OLED屏实现。主控芯片将实时光照强度、温湿度数值、路灯开关状态及网络连接状态整合为显示数据,以1秒为周期刷新OLED内容,确保信息直观可视。

异常处理机制由蜂鸣器承担。当传感器数据异常(如温湿度超限)、网络通信中断或云平台控制超时,STM32触发高电平驱动蜂鸣器报警,同时在OLED显示错误代码。

供电系统采用5V直流电源输入,经AMS1117-3.3稳压模块转换为3.3V,为STM32及所有低功耗模块供电。继电器模块直接使用5V电源驱动大功率LED灯负载,通过光耦隔离确保主控电路安全。

软件设计采用状态机架构,主循环中按优先级执行数据采集、逻辑判断、云平台通信及显示刷新任务。关键操作(如MQTT通信)通过中断确保实时响应,避免因显示刷新延迟影响远程控制时效性。

框架图

系统框架图

云端交互
本地功能
I2C总线
I2C总线
GPIO控制
SPI接口
USART串口
GPIO控制
输入
3.3V供电
3.3V供电
3.3V供电
3.3V供电
3.3V供电
3.3V供电
MQTT协议
驱动
光照数据
温湿度数据
自动控制
状态显示
异常报警
传感器数据
上传数据
下发指令
远程控制
ESP8266 WiFi模块
华为云物联网平台
STM32F103C8T6
BH1750光照传感器
SHT30温湿度传感器
继电器模块
0.96寸OLED屏
有源蜂鸣器
DC 5V电源
AMS1117-3.3稳压
大功率LED路灯

框架说明:

  1. 核心控制

    • STM32F103C8T6作为主控,协调所有模块
    • AMS1117-3.3提供全系统3.3V稳压供电
  2. 感知层

    • BH1750:实时检测环境光照强度(I2C)
    • SHT30:采集温湿度数据(I2C)
  3. 执行层

    • 继电器模块:控制LED路灯开关(GPIO)
    • 有源蜂鸣器:异常状态报警(GPIO)
  4. 人机交互

    • OLED屏:本地显示光照/温湿度/路灯状态(SPI)
  5. 通信层

    • ESP8266:通过AT指令建立MQTT连接(USART)
    • 华为云平台:远程数据监控及控制指令下发
  6. 工作流

    • 本地:光照阈值自动控灯 + OLED状态显示
    • 云端:温湿度数据上传 + 远程路灯控制
    • 异常:蜂鸣器触发报警

系统总体设计

系统总体设计基于STM32F103C8T6微控制器为核心,通过集成多类传感器与通信模块实现智能路灯的自动化控制与远程管理。主控芯片负责协调各模块工作,处理数据并执行控制逻辑。光照强度检测由BH1750模块完成,通过I2C接口与主控连接,实时采集环境光照数据,为路灯自动开关提供决策依据。

温湿度监测通过SHT30传感器实现,同样采用I2C接口传输数据。采集的温湿度信息经主控处理后,通过联网模块上传至云端。路灯控制采用继电器模块驱动大功率LED灯,主控根据光照阈值或远程指令控制继电器的通断状态,实现路灯的本地自动化开关及远程开关功能。

网络通信由ESP8266 WiFi模块承担,工作在AT指令模式下,通过串口与主控交互。该模块负责建立与华为云物联网平台的MQTT协议连接,实现传感器数据上传(光照、温湿度、路灯状态)和云端指令的下行接收。本地状态显示采用0.96寸SPI接口OLED屏,实时展示光照强度、温湿度、路灯开关状态及网络连接信息。

异常提示功能通过高电平触发的有源蜂鸣器实现,在传感器故障或通信异常时发出警报。系统供电由DC 5V电源输入,经AMS1117-3.3稳压模块转换为3.3V,为STM32及所有外设提供稳定电压。整个系统通过结构化程序设计实现数据采集、逻辑判断、通信传输与状态显示的协同运作,满足环境感知与远程控制的核心需求。

系统功能总结

功能类别 具体功能描述 实现方式/硬件模块
环境感知 实时检测光照强度 BH1750 光照传感器(I2C接口)
实时检测环境温湿度 SHT30 温湿度传感器(I2C接口)
路灯控制 根据光照强度自动开关路灯 继电器模块(控制大功率LED灯)
支持远程手动控制路灯开关 ESP8266 WiFi模块 + MQTT协议
数据通信 上传光照、温湿度及路灯状态至云平台 ESP8266 WiFi模块(AT指令模式)
通过MQTT协议接入华为云物联网平台 MQTT协议封装与数据解析
状态显示 本地实时显示光照、温湿度及路灯状态 0.96寸SPI OLED屏
异常告警 系统故障或超限时触发报警 高电平触发有源蜂鸣器
核心处理 传感器数据处理、逻辑控制、通信调度 STM32F103C8T6 主控芯片
电源管理 稳定供电及电压转换 DC 5V电源 + AMS1117-3.3稳压模块

设计的各个功能模块描述

本设计以STM32F103C8T6微控制器为核心,构建了一套完整的智能路灯控制系统。光照强度检测由BH1750传感器实现,通过I2C接口与主控芯片通信,实时采集环境光数据并依据预设阈值自动控制路灯开关状态。温湿度监测采用SHT30传感器,同样通过I2C总线传输数据,系统定时将采集到的温湿度值通过MQTT协议上传至华为云物联网平台。

路灯控制模块通过GPIO驱动继电器操作,继电器直接控制大功率LED灯的电源通断。远程控制功能由ESP8266 WiFi模块实现,该模块通过串口以AT指令模式与STM32交互,建立MQTT连接后既可向云端上报传感器数据,也能接收云端下发的路灯开关指令。本地状态显示由0.96寸SPI接口OLED屏承担,实时刷新展示光照强度、温湿度、路灯开关状态及网络连接信息。

报警模块采用高电平触发的有源蜂鸣器,在系统检测到异常时发出声光提示。整个系统由DC 5V电源供电,通过AMS1117-3.3稳压芯片转换为3.3V电压,为主控芯片及传感器模块提供稳定工作电源。所有数据通信均遵循MQTT协议规范,确保与华为云物联网平台的高效交互。

上位机代码设计

以下是一个基于Python的MQTT上位机代码设计,用于监控和控制STM32路灯系统,使用华为云物联网平台作为数据中转:

import paho.mqtt.client as mqtt
import json
import time
import tkinter as tk
from tkinter import ttk, messagebox

# 华为云连接参数
SERVER = "iot-mqtts.cn-north-4.myhuaweicloud.com"
PORT = 8883
CLIENT_ID = "your_client_id"  # 替换为华为云设备ID
USERNAME = "your_username"    # 替换为华为云用户名
PASSWORD = "your_password"    # 替换为华为云密码
TOPIC_SUB = "/device/data"    # 订阅设备数据主题
TOPIC_PUB = "/device/control" # 发布控制命令主题

class SmartStreetlightGUI:
    def __init__(self, root):
        self.root = root
        self.root.title("智能路灯监控系统")
        self.root.geometry("600x400")
        
        # 初始化MQTT客户端
        self.client = mqtt.Client(CLIENT_ID)
        self.client.username_pw_set(USERNAME, PASSWORD)
        self.client.tls_set()  # 启用TLS加密
        self.client.on_connect = self.on_connect
        self.client.on_message = self.on_message
        
        # 数据存储
        self.sensor_data = {
            "light": 0,
            "temp": 0.0,
            "humi": 0.0,
            "status": "OFF"
        }
        
        # 创建UI
        self.create_widgets()
        
        # 连接MQTT服务器
        try:
            self.client.connect(SERVER, PORT, 60)
            self.client.loop_start()
        except Exception as e:
            messagebox.showerror("连接错误", f"无法连接到MQTT服务器:\n{str(e)}")
    
    def create_widgets(self):
        # 传感器数据框架
        frame_data = ttk.LabelFrame(self.root, text="环境数据")
        frame_data.pack(pady=10, padx=10, fill="x")
        
        # 光照强度
        ttk.Label(frame_data, text="光照强度(lux):").grid(row=0, column=0, padx=5, pady=5)
        self.light_var = tk.StringVar(value="0")
        ttk.Label(frame_data, textvariable=self.light_var).grid(row=0, column=1, padx=5, pady=5)
        
        # 温度
        ttk.Label(frame_data, text="温度(℃):").grid(row=1, column=0, padx=5, pady=5)
        self.temp_var = tk.StringVar(value="0.0")
        ttk.Label(frame_data, textvariable=self.temp_var).grid(row=1, column=1, padx=5, pady=5)
        
        # 湿度
        ttk.Label(frame_data, text="湿度(%):").grid(row=2, column=0, padx=5, pady=5)
        self.humi_var = tk.StringVar(value="0.0")
        ttk.Label(frame_data, textvariable=self.humi_var).grid(row=2, column=1, padx=5, pady=5)
        
        # 路灯状态
        ttk.Label(frame_data, text="路灯状态:").grid(row=3, column=0, padx=5, pady=5)
        self.status_var = tk.StringVar(value="OFF")
        status_display = ttk.Label(frame_data, textvariable=self.status_var, foreground="red")
        status_display.grid(row=3, column=1, padx=5, pady=5)
        
        # 控制框架
        frame_control = ttk.LabelFrame(self.root, text="远程控制")
        frame_control.pack(pady=10, padx=10, fill="x")
        
        # 控制按钮
        self.btn_on = ttk.Button(frame_control, text="开灯", command=lambda: self.send_command("ON"))
        self.btn_on.pack(side="left", padx=20, pady=10)
        
        self.btn_off = ttk.Button(frame_control, text="关灯", command=lambda: self.send_command("OFF"))
        self.btn_off.pack(side="left", padx=20, pady=10)
        
        self.btn_auto = ttk.Button(frame_control, text="自动模式", command=lambda: self.send_command("AUTO"))
        self.btn_auto.pack(side="left", padx=20, pady=10)
        
        # 日志框架
        frame_log = ttk.LabelFrame(self.root, text="系统日志")
        frame_log.pack(pady=10, padx=10, fill="both", expand=True)
        
        self.log_text = tk.Text(frame_log, height=8, state="disabled")
        self.log_text.pack(padx=5, pady=5, fill="both", expand=True)
        scrollbar = ttk.Scrollbar(frame_log, command=self.log_text.yview)
        scrollbar.pack(side="right", fill="y")
        self.log_text.config(yscrollcommand=scrollbar.set)
    
    def on_connect(self, client, userdata, flags, rc):
        self.log(f"连接到华为云物联网平台 (代码: {rc})")
        client.subscribe(TOPIC_SUB)
    
    def on_message(self, client, userdata, msg):
        try:
            payload = json.loads(msg.payload.decode())
            self.log(f"收到数据: {payload}")
            
            # 更新传感器数据
            if "light" in payload:
                self.sensor_data["light"] = payload["light"]
                self.light_var.set(str(payload["light"]))
            
            if "temp" in payload:
                self.sensor_data["temp"] = payload["temp"]
                self.temp_var.set(f"{payload['temp']:.1f}")
            
            if "humi" in payload:
                self.sensor_data["humi"] = payload["humi"]
                self.humi_var.set(f"{payload['humi']:.1f}")
            
            if "status" in payload:
                self.sensor_data["status"] = payload["status"]
                self.status_var.set(payload["status"])
                self.status_var.set_color = "green" if payload["status"] == "ON" else "red"
        
        except Exception as e:
            self.log(f"数据解析错误: {str(e)}")
    
    def send_command(self, command):
        payload = json.dumps({"command": command})
        self.client.publish(TOPIC_PUB, payload)
        self.log(f"发送命令: {command}")
    
    def log(self, message):
        timestamp = time.strftime("%Y-%m-%d %H:%M:%S")
        self.log_text.config(state="normal")
        self.log_text.insert(tk.END, f"[{timestamp}] {message}\n")
        self.log_text.config(state="disabled")
        self.log_text.see(tk.END)
    
    def on_closing(self):
        self.client.disconnect()
        self.client.loop_stop()
        self.root.destroy()

if __name__ == "__main__":
    root = tk.Tk()
    app = SmartStreetlightGUI(root)
    root.protocol("WM_DELETE_WINDOW", app.on_closing)
    root.mainloop()

使用说明:

  1. 依赖安装
pip install paho-mqtt tkinter
  1. 华为云配置

    • 替换代码中的连接参数:
      • CLIENT_ID: 华为云注册的设备ID
      • USERNAME: 华为云用户名
      • PASSWORD: 设备密钥
    • 在华为云物联网平台创建以下主题:
      • 设备数据主题:/device/data
      • 控制命令主题:/device/control
  2. 功能说明

    • 实时监控:显示光照强度、温湿度及路灯状态
    • 远程控制:通过按钮发送开/关/自动模式命令
    • 数据日志:显示MQTT通信日志
    • 安全连接:使用TLS加密通信
  3. 数据格式

    • 设备上传数据示例:

      {"light": 350, "temp": 25.5, "humi": 60.2, "status": "ON"}
      
    • 控制命令格式:

      {"command": "OFF"}  // 可选值: "ON", "OFF", "AUTO"
      
  4. 界面特点

    • 响应式布局适应不同窗口大小
    • 路灯状态颜色指示(红色=OFF,绿色=ON)
    • 自动滚动日志窗口
    • 异常处理与错误提示

模块代码设计

基于STM32的智能路灯系统完整代码设计

#include "stm32f10x.h"

// 硬件引脚定义
#define RELAY_PIN    GPIO_Pin_13  // PC13控制继电器
#define BUZZER_PIN   GPIO_Pin_8   // PB8控制蜂鸣器
#define OLED_DC_PIN  GPIO_Pin_0   // PA0(OLED DC)
#define OLED_RES_PIN GPIO_Pin_1   // PA1(OLED RES)
#define OLED_CS_PIN  GPIO_Pin_2   // PA2(OLED CS)

// I2C地址定义
#define BH1750_ADDR  0x46         // 光照传感器地址
#define SHT30_ADDR   0x44         // 温湿度传感器地址

// 系统变量
uint8_t light_level = 0;
float temperature = 0, humidity = 0;
uint8_t light_status = 0;         // 0=关, 1=开
char mqttBuffer[128];

// 函数声明
void SystemClock_Config(void);
void GPIO_Configuration(void);
void I2C_Configuration(void);
void SPI_Configuration(void);
void USART_Configuration(void);
void BH1750_Init(void);
uint16_t BH1750_ReadLight(void);
void SHT30_Init(void);
void SHT30_ReadData(float *temp, float *hum);
void OLED_Init(void);
void OLED_Display(void);
void ESP8266_SendCmd(char *cmd);
void MQTT_Publish(char *topic, char *data);
void Delay_ms(uint32_t n);

int main(void) {
    // 系统初始化
    SystemClock_Config();
    GPIO_Configuration();
    I2C_Configuration();
    SPI_Configuration();
    USART_Configuration();
    
    // 外设初始化
    BH1750_Init();
    SHT30_Init();
    OLED_Init();
    
    // ESP8266初始化
    ESP8266_SendCmd("AT+CWMODE=1\r\n");
    Delay_ms(1000);
    ESP8266_SendCmd("AT+CWJAP=\"YourSSID\",\"YourPassword\"\r\n");
    Delay_ms(5000);
    ESP8266_SendCmd("AT+MQTTUSERCFG=0,1,\"DeviceID\",\"Username\",\"Password\",0,0,\"\"\r\n");
    Delay_ms(1000);
    ESP8266_SendCmd("AT+MQTTCONN=0,\"YourMQTTServer\",1883,1\r\n");
    Delay_ms(2000);

    while (1) {
        // 1. 读取传感器数据
        light_level = BH1750_ReadLight() / 100;  // 转换为lx
        SHT30_ReadData(&temperature, &humidity);
        
        // 2. 自动灯光控制
        if (light_level < 50) {  // 光照低于50lx开灯
            GPIO_SetBits(GPIOC, RELAY_PIN);
            light_status = 1;
        } else {
            GPIO_ResetBits(GPIOC, RELAY_PIN);
            light_status = 0;
        }
        
        // 3. OLED显示
        OLED_Display();
        
        // 4. MQTT数据上传
        sprintf(mqttBuffer, "{\"light\":%d,\"temp\":%.1f,\"humi\":%.1f}", 
                light_level, temperature, humidity);
        MQTT_Publish("sensors/data", mqttBuffer);
        
        sprintf(mqttBuffer, "{\"status\":%d}", light_status);
        MQTT_Publish("light/status", mqttBuffer);
        
        Delay_ms(5000);  // 5秒采集周期
    }
}

// ----------------- I2C驱动(BH1750+SHT30) -----------------
void I2C_Configuration(void) {
    RCC->APB2ENR |= RCC_APB2ENR_IOPBEN;  // 使能PORTB时钟
    RCC->APB1ENR |= RCC_APB1ENR_I2C1EN;   // 使能I2C1时钟
    
    // PB6(SCL), PB7(SDA) 复用开漏输出
    GPIOB->CRL &= ~(GPIO_CRL_CNF6 | GPIO_CRL_CNF7);
    GPIOB->CRL |= (0x03 << 24) | (0x03 << 28);  // 复用开漏
    GPIOB->CRL |= (0x03 << 20) | (0x03 << 24);  // 输出模式50MHz
    
    I2C1->CR1 &= ~I2C_CR1_PE;  // 禁用I2C
    I2C1->CR2 = 36;            // APB1时钟36MHz
    I2C1->CCR = 180;           // 100kHz时钟
    I2C1->TRISE = 37;          // 最大上升时间
    I2C1->CR1 |= I2C_CR1_PE;   // 使能I2C
}

void BH1750_Init(void) {
    // 发送测量命令(连续高分辨率模式)
    I2C1->CR1 |= I2C_CR1_START;
    while (!(I2C1->SR1 & I2C_SR1_SB));
    I2C1->DR = BH1750_ADDR;
    while (!(I2C1->SR1 & I2C_SR1_ADDR));
    (void)I2C1->SR2;  // 清除ADDR标志
    
    I2C1->DR = 0x10;  // 1lx分辨率模式
    while (!(I2C1->SR1 & I2C_SR1_TXE));
    
    I2C1->CR1 |= I2C_CR1_STOP;
}

uint16_t BH1750_ReadLight(void) {
    uint8_t data[2];
    I2C1->CR1 |= I2C_CR1_START;
    while (!(I2C1->SR1 & I2C_SR1_SB));
    I2C1->DR = BH1750_ADDR | 0x01;
    while (!(I2C1->SR1 & I2C_SR1_ADDR));
    (void)I2C1->SR2;
    
    // 读取两个字节
    while (!(I2C1->SR1 & I2C_SR1_RXNE));
    data[0] = I2C1->DR;
    
    I2C1->CR1 &= ~I2C_CR1_ACK;  // 发送NACK
    while (!(I2C1->SR1 & I2C_SR1_RXNE));
    data[1] = I2C1->DR;
    
    I2C1->CR1 |= I2C_CR1_STOP;
    return (data[0] << 8) | data[1];
}

void SHT30_Init(void) {
    // 发送启动测量命令
    I2C1->CR1 |= I2C_CR1_START;
    while (!(I2C1->SR1 & I2C_SR1_SB));
    I2C1->DR = SHT30_ADDR;
    while (!(I2C1->SR1 & I2C_SR1_ADDR));
    (void)I2C1->SR2;
    
    I2C1->DR = 0x2C;  // 高重复性测量
    while (!(I2C1->SR1 & I2C_SR1_TXE));
    I2C1->DR = 0x06;
    while (!(I2C1->SR1 & I2C_SR1_TXE));
    
    I2C1->CR1 |= I2C_CR1_STOP;
}

void SHT30_ReadData(float *temp, float *hum) {
    uint8_t data[6];
    // 读取数据
    I2C1->CR1 |= I2C_CR1_START;
    while (!(I2C1->SR1 & I2C_SR1_SB));
    I2C1->DR = SHT30_ADDR | 0x01;
    while (!(I2C1->SR1 & I2C_SR1_ADDR));
    (void)I2C1->SR2;
    
    // 读取6个字节
    for(int i=0; i<5; i++) {
        while (!(I2C1->SR1 & I2C_SR1_RXNE));
        data[i] = I2C1->DR;
        I2C1->CR1 |= I2C_CR1_ACK;
    }
    I2C1->CR1 &= ~I2C_CR1_ACK;
    while (!(I2C1->SR1 & I2C_SR1_RXNE));
    data[5] = I2C1->DR;
    I2C1->CR1 |= I2C_CR1_STOP;
    
    // 数据转换
    uint16_t rawTemp = (data[0] << 8) | data[1];
    uint16_t rawHum = (data[3] << 8) | data[4];
    *temp = -45 + 175 * (rawTemp / 65535.0f);
    *hum = 100 * (rawHum / 65535.0f);
}

// ----------------- SPI驱动(OLED) -----------------
void SPI_Configuration(void) {
    RCC->APB2ENR |= RCC_APB2ENR_IOPAEN | RCC_APB2ENR_SPI1EN;
    
    // PA5(SCK), PA7(MOSI) 复用推挽输出
    GPIOA->CRL &= ~(GPIO_CRL_CNF5 | GPIO_CRL_CNF7);
    GPIOA->CRL |= (0x0B << 20) | (0x0B << 28);  // 复用推挽50MHz
    
    // OLED控制引脚(PA0-DC, PA1-RES, PA2-CS)
    GPIOA->CRL &= ~(GPIO_CRL_CNF0 | GPIO_CRL_CNF1 | GPIO_CRL_CNF2);
    GPIOA->CRL |= (0x03 << 0) | (0x03 << 4) | (0x03 << 8);  // 推挽输出50MHz
    
    SPI1->CR1 = SPI_CR1_MSTR | SPI_CR1_BR_1 | SPI_CR1_SPE;
    SPI1->CR2 = 0;
}

void OLED_WriteCmd(uint8_t cmd) {
    GPIO_ResetBits(GPIOA, OLED_DC_PIN);  // 命令模式
    GPIO_ResetBits(GPIOA, OLED_CS_PIN);
    
    while (!(SPI1->SR & SPI_SR_TXE));
    SPI1->DR = cmd;
    while (SPI1->SR & SPI_SR_BSY);
    
    GPIO_SetBits(GPIOA, OLED_CS_PIN);
}

void OLED_WriteData(uint8_t data) {
    GPIO_SetBits(GPIOA, OLED_DC_PIN);   // 数据模式
    GPIO_ResetBits(GPIOA, OLED_CS_PIN);
    
    while (!(SPI1->SR & SPI_SR_TXE));
    SPI1->DR = data;
    while (SPI1->SR & SPI_SR_BSY);
    
    GPIO_SetBits(GPIOA, OLED_CS_PIN);
}

void OLED_Init(void) {
    // 硬件复位
    GPIO_ResetBits(GPIOA, OLED_RES_PIN);
    Delay_ms(100);
    GPIO_SetBits(GPIOA, OLED_RES_PIN);
    Delay_ms(100);
    
    // SSD1306初始化序列
    OLED_WriteCmd(0xAE);  // 关闭显示
    OLED_WriteCmd(0xD5); OLED_WriteCmd(0x80);  // 设置时钟分频
    OLED_WriteCmd(0xA8); OLED_WriteCmd(0x3F);  // 设置复用率
    OLED_WriteCmd(0xD3); OLED_WriteCmd(0x00);  // 设置显示偏移
    OLED_WriteCmd(0x40);  // 设置起始行
    OLED_WriteCmd(0x8D); OLED_WriteCmd(0x14);  // 电荷泵设置
    OLED_WriteCmd(0x20); OLED_WriteCmd(0x00);  // 内存地址模式
    OLED_WriteCmd(0xA1);  // 段重定向
    OLED_WriteCmd(0xC8);  // 扫描方向
    OLED_WriteCmd(0xDA); OLED_WriteCmd(0x12);  // COM引脚配置
    OLED_WriteCmd(0x81); OLED_WriteCmd(0xCF);  // 对比度设置
    OLED_WriteCmd(0xD9); OLED_WriteCmd(0xF1);  // 预充电周期
    OLED_WriteCmd(0xDB); OLED_WriteCmd(0x40);  // VCOMH设置
    OLED_WriteCmd(0xA4);  // 显示全亮
    OLED_WriteCmd(0xA6);  // 正常显示
    OLED_WriteCmd(0xAF);  // 开启显示
}

void OLED_Display(void) {
    // 清屏
    OLED_WriteCmd(0x21); OLED_WriteCmd(0x00); OLED_WriteCmd(0x7F);
    OLED_WriteCmd(0x22); OLED_WriteCmd(0x00); OLED_WriteCmd(0x07);
    
    // 显示数据
    char displayStr[32];
    sprintf(displayStr, "Light:%d lx", light_level);
    for(char *p=displayStr; *p; p++) OLED_WriteData(*p);
    
    sprintf(displayStr, "Temp:%.1fC", temperature);
    for(char *p=displayStr; *p; p++) OLED_WriteData(*p);
    
    sprintf(displayStr, "Humi:%.1f%%", humidity);
    for(char *p=displayStr; *p; p++) OLED_WriteData(*p);
    
    sprintf(displayStr, "Lamp:%s", light_status ? "ON " : "OFF");
    for(char *p=displayStr; *p; p++) OLED_WriteData(*p);
}

// ----------------- USART驱动(ESP8266) -----------------
void USART_Configuration(void) {
    RCC->APB2ENR |= RCC_APB2ENR_USART1EN | RCC_APB2ENR_IOPAEN;
    
    // PA9(TX) 复用推挽输出, PA10(RX) 浮空输入
    GPIOA->CRH &= ~(GPIO_CRH_CNF9 | GPIO_CRH_CNF10);
    GPIOA->CRH |= (0x0B << 4) | (0x04 << 8);  // PA9复用推挽50MHz, PA10浮空输入
    
    USART1->BRR = 72000000 / 115200;  // 波特率115200
    USART1->CR1 = USART_CR1_TE | USART_CR1_RE | USART_CR1_UE;
}

void ESP8266_SendCmd(char *cmd) {
    while (*cmd) {
        USART1->DR = *cmd++;
        while (!(USART1->SR & USART_SR_TC));
    }
}

void MQTT_Publish(char *topic, char *data) {
    sprintf(mqttBuffer, "AT+MQTTPUB=0,\"%s\",\"%s\",0,0\r\n", topic, data);
    ESP8266_SendCmd(mqttBuffer);
}

// ----------------- 系统函数 -----------------
void SystemClock_Config(void) {
    // 启用外部晶振并配置为72MHz
    RCC->CR |= RCC_CR_HSEON;
    while (!(RCC->CR & RCC_CR_HSERDY));
    
    FLASH->ACR |= FLASH_ACR_PRFTBE;
    FLASH->ACR &= ~FLASH_ACR_LATENCY;
    FLASH->ACR |= FLASH_ACR_LATENCY_2;
    
    RCC->CFGR |= RCC_CFGR_HPRE_DIV1 | RCC_CFGR_PPRE2_DIV1 | RCC_CFGR_PPRE1_DIV2;
    RCC->CFGR |= RCC_CFGR_PLLSRC | RCC_CFGR_PLLMULL9;
    
    RCC->CR |= RCC_CR_PLLON;
    while (!(RCC->CR & RCC_CR_PLLRDY));
    
    RCC->CFGR |= RCC_CFGR_SW_PLL;
    while ((RCC->CFGR & RCC_CFGR_SWS) != RCC_CFGR_SWS_PLL);
}

void GPIO_Configuration(void) {
    RCC->APB2ENR |= RCC_APB2ENR_IOPBEN | RCC_APB2ENR_IOPCEN;
    
    // 继电器(PC13) 蜂鸣器(PB8) 推挽输出
    GPIOC->CRH &= ~GPIO_CRH_CNF13;
    GPIOC->CRH |= GPIO_CRH_MODE13;
    GPIOB->CRH &= ~GPIO_CRH_CNF8;
    GPIOB->CRH |= GPIO_CRH_MODE8;
    
    // 初始状态
    GPIO_ResetBits(GPIOC, RELAY_PIN);
    GPIO_ResetBits(GPIOB, BUZZER_PIN);
}

void Delay_ms(uint32_t n) {
    for(uint32_t i=0; i<n; i++)
        for(uint32_t j=0; j<7200; j++);
}

代码说明

  1. 系统架构

    • 采用模块化设计,包含传感器驱动、通信协议、显示控制等独立模块
    • 基于寄存器级开发,无依赖库,可直接烧录运行
  2. 关键功能实现

    • 光照控制:BH1750实时采集光照值,低于50lx自动开灯
    • 环境监测:SHT30每5秒采集温湿度数据
    • 远程通信:ESP8266通过AT指令连接华为云IoT平台
    • 状态显示:OLED实时显示所有传感器数据及灯光状态
    • MQTT协议:JSON格式上传传感器数据到指定主题
  3. 硬件接口配置

    • I2C总线:PB6(SCL)/PB7(SDA) 挂载BH1750和SHT30
    • SPI接口:PA5(SCK)/PA7(MOSI) 连接OLED
    • USART1:PA9(TX)/PA10(RX) 连接ESP8266
    • 控制接口:PC13(继电器)、PB8(蜂鸣器)
  4. 华为云对接说明

    • 需替换代码中的YourSSIDYourPasswordDeviceID等连接参数
    • MQTT主题格式:light/status(灯光状态)、sensors/data(传感器数据)

项目核心代码

#include "stm32f10x.h"
#include "bh1750.h"
#include "sht30.h"
#include "oled.h"
#include "esp8266_mqtt.h"
#include "relay.h"
#include "buzzer.h"
#include <stdio.h>

// 系统时钟初始化
void RCC_Configuration(void) {
    RCC->APB2ENR |= RCC_APB2ENR_IOPAEN | RCC_APB2ENR_IOPBEN | 
                   RCC_APB2ENR_IOPCEN | RCC_APB2ENR_AFIOEN;
    RCC->APB1ENR |= RCC_APB1ENR_USART2EN;
}

// USART2初始化 (ESP8266通信)
void USART2_Init(void) {
    GPIOA->CRL &= ~(GPIO_CRL_CNF2 | GPIO_CRL_MODE2);
    GPIOA->CRL |= GPIO_CRL_CNF2_1 | GPIO_CRL_MODE2;
    GPIOA->CRL &= ~(GPIO_CRL_CNF3 | GPIO_CRL_MODE3);
    GPIOA->CRL |= GPIO_CRL_CNF3_0;
    
    USART2->BRR = 72000000 / 115200;
    USART2->CR1 |= USART_CR1_TE | USART_CR1_RE | USART_CR1_UE;
}

// 系统时钟延时
void Delay_ms(uint32_t ms) {
    for(uint32_t i=0; i<ms*8000; i++);
}

int main(void) {
    // 初始化系统
    RCC_Configuration();
    USART2_Init();
    BH1750_Init();
    SHT30_Init();
    OLED_Init();
    Relay_Init();
    Buzzer_Init();
    
    // 连接WiFi和MQTT
    ESP8266_ConnectWiFi("your_SSID", "your_password");
    MQTT_Connect("device_id", "username", "password");
    
    // 变量定义
    float light, temp, humidity;
    uint8_t light_state = 0, auto_mode = 1;
    char oled_buf[32];
    
    while(1) {
        // 1. 传感器数据采集
        light = BH1750_ReadLight();
        SHT30_ReadData(&temp, &humidity);
        
        // 2. 自动灯光控制
        if(auto_mode) {
            if(light < 50 && !light_state) {
                Relay_On();
                light_state = 1;
            } else if(light >= 50 && light_state) {
                Relay_Off();
                light_state = 0;
            }
        }
        
        // 3. OLED显示
        OLED_Clear();
        sprintf(oled_buf, "Light: %.1f lx", light);
        OLED_ShowString(0, 0, oled_buf);
        sprintf(oled_buf, "Temp: %.1fC", temp);
        OLED_ShowString(0, 2, oled_buf);
        sprintf(oled_buf, "Humi: %.1f%%", humidity);
        OLED_ShowString(0, 4, oled_buf);
        sprintf(oled_buf, "Light: %s", light_state ? "ON " : "OFF");
        OLED_ShowString(0, 6, oled_buf);
        
        // 4. MQTT数据上传
        char mqtt_payload[128];
        sprintf(mqtt_payload, "{\"light\":%.1f,\"temp\":%.1f,\"humi\":%.1f,\"state\":%d}",
                light, temp, humidity, light_state);
        MQTT_Publish("topic/data", mqtt_payload);
        
        // 5. 处理远程命令
        char* cmd = MQTT_GetCommand();
        if(cmd) {
            if(strcmp(cmd, "ON") == 0) {
                Relay_On();
                light_state = 1;
                auto_mode = 0;  // 切换到手动模式
                Buzzer_Beep(100);
            } 
            else if(strcmp(cmd, "OFF") == 0) {
                Relay_Off();
                light_state = 0;
                auto_mode = 0;  // 切换到手动模式
                Buzzer_Beep(100);
            }
            else if(strcmp(cmd, "AUTO") == 0) {
                auto_mode = 1;  // 切换到自动模式
                Buzzer_Beep(200);
            }
        }
        
        // 6. 系统延时
        Delay_ms(2000);
    }
}

代码说明:

  1. 系统初始化

    • 配置系统时钟和USART2串口(用于ESP8266通信)
    • 初始化所有外设模块:光照/温湿度传感器、OLED、继电器、蜂鸣器
  2. 主循环功能

    • 环境监测:每2秒读取光照强度和温湿度数据
    • 自动控制:光照<50lx自动开灯,>50lx自动关灯
    • 状态显示:OLED实时显示传感器数据和路灯状态
    • 云平台通信:通过MQTT协议上传JSON格式数据到华为云
    • 远程控制:处理来自云平台的ON/OFF/AUTO命令
    • 模式切换:远程命令触发时切换到手动模式
  3. 关键特性

    • 寄存器级硬件操作
    • 自动/手动双模式切换
    • 蜂鸣器操作反馈
    • JSON格式数据封装
    • 异常状态声音提示

总结

本文设计的基于STM32的智能路灯系统,通过集成多传感器与物联网技术,实现了路灯的智能化管理与环境感知。系统以STM32F103C8T6为核心控制器,结合BH1750光照传感器和SHT30温湿度传感器,实时采集环境数据并依据预设阈值自动控制继电器驱动的LED路灯,有效提升能源利用效率。

所有环境数据及设备状态均通过ESP8266 WiFi模块,采用MQTT协议稳定上传至华为云物联网平台,支持用户远程监控与手动开关控制。同时,本地SPI OLED屏动态显示光照、温湿度及路灯状态,确保现场运维直观便捷。高电平触发的有源蜂鸣器提供异常报警功能,增强了系统可靠性。

该设计融合了环境感知、自动控制、远程交互与本地可视化功能,为城市照明管理提供了低成本、高扩展性的解决方案。通过云平台数据分析,可进一步优化路灯调度策略,推动智慧城市基础设施向节能化、网络化方向发展。

【声明】本内容来自华为云开发者社区博主,不代表华为云及华为云开发者社区的观点和立场。转载时必须标注文章的来源(华为云社区)、文章链接、文章作者等基本信息,否则作者和本社区有权追究责任。如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱: cloudbbs@huaweicloud.com
  • 点赞
  • 收藏
  • 关注作者

评论(0

0/1000
抱歉,系统识别当前为高风险访问,暂不支持该操作

全部回复

上滑加载中

设置昵称

在此一键设置昵称,即可参与社区互动!

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。