基于STM32F103C8T6与华为云的智能楼宇照明控制系统设计

举报
DS小龙哥 发表于 2025/08/25 11:11:28 2025/08/25
【摘要】 本项目以STM32F103C8T6微控制器为核心,结合GY-30光照传感器、HC-SR501人体红外传感器等硬件组件,构建了一个低成本、高效率的智能照明控制系统。

 

项目开发背景

随着城市化进程的加速和建筑行业的快速发展,智能楼宇系统已成为现代建筑管理的重要组成部分。照明系统作为楼宇能耗的主要来源之一,其智能化控制对于提升能源效率、降低运营成本以及增强用户体验具有至关重要的意义。传统照明系统往往依赖于手动开关或简单的定时控制,无法根据实际环境光照和人员活动情况进行动态调整,导致能源浪费和照明效果不佳。因此,开发一种基于先进传感技术和物联网平台的智能照明控制系统,成为当前楼宇自动化领域的热点需求。

在能源紧缺和环境保护日益受到重视的背景下,智能照明系统通过集成光照传感器和人体感应器,能够实时监测各区域的环境状态,并自动调节照明设备的开关与亮度,从而显著减少不必要的能耗。此外,借助云平台实现数据上传和远程监控,可以进一步提升系统的智能化水平,为楼宇管理者提供数据支持和决策依据。华为云物联网平台作为可靠的云服务解决方案,能够高效处理设备数据,并支持远程控制和历史数据分析,满足现代楼宇对实时性和可靠性的要求。

本项目以STM32F103C8T6微控制器为核心,结合GY-30光照传感器、HC-SR501人体红外传感器等硬件组件,构建了一个低成本、高效率的智能照明控制系统。通过ESP8266-01S Wi-Fi模块将采集到的照明状态和能耗数据上传至华为云,并利用QT开发的上位机实现远程手动控制和数据可视化,该系统不仅提升了照明的自适应能力,还为楼宇节能和智能化管理提供了实用化的解决方案。这一设计顺应了物联网和智能建筑的发展趋势,具有广泛的应用前景和社会价值。

设计实现的功能

(1)实时监测各区域光照强度及人体存在状态。
(2)根据环境光照和人员活动自动控制LED照明灯的开关与亮度。
(3)照明状态数据及能耗数据上传至华为云物联网平台。
(4)QT上位机可远程手动控制各区域照明,并显示照明状态历史数据曲线。

项目硬件模块组成

(1)STM32F103C8T6最小系统核心板
(2)GY-30光照强度传感器
(3)HC-SR501人体红外传感器
(4)LED照明灯组与LM2596降压模块
(5)ESP8266-01S Wi-Fi模块
(6)洞洞板焊接所有外围电路,杜邦线连接各传感器模块

设计意义

本设计通过实时监测各区域光照强度及人体存在状态,实现了照明系统的智能化控制,有效避免了无人区域照明浪费,显著降低楼宇照明能耗,从而促进能源节约和环境保护。自动调节照明亮度不仅提升了用户体验,还减少了电费支出,符合绿色建筑和可持续发展的理念。

借助华为云物联网平台,系统能够上传照明状态和能耗数据,实现远程监控和数据分析,为楼宇管理提供数据支持。这使得管理人员可以实时了解照明使用情况,进行趋势分析和优化决策,提高管理效率。

QT上位机的远程手动控制功能增强了系统的灵活性和可操作性,允许用户根据需要调整照明状态,并查看历史数据曲线,便于故障排查和性能评估。这种集成提升了楼宇智能化的整体水平,为未来智慧城市的发展奠定了基础。

设计思路

系统设计以STM32F103C8T6最小系统核心板作为主控制器,负责协调整个智能照明控制系统的运行。该系统通过集成GY-30光照强度传感器和HC-SR501人体红外传感器,实时采集各区域的环境光照数据和人员活动状态。采集到的数据经过STM32处理,用于实现自动控制逻辑,确保照明系统能够根据实际环境条件做出响应。

数据采集部分,GY-30传感器通过I2C接口与STM32通信,提供精确的光照强度值;HC-SR501传感器则输出数字信号指示人体存在。STM32定期读取这些传感器数据,并进行滤波和阈值判断,以确定是否需要调整照明状态。控制输出通过PWM信号驱动LED照明灯组,结合LM2596降压模块实现调光功能,从而根据光照不足和人员活动自动开关或调节亮度,达到节能目的。

通信模块采用ESP8266-01S Wi-Fi模块,STM32通过串口与ESP8266交互,将处理后的照明状态数据、能耗数据等通过MQTT协议上传至华为云物联网平台。这一过程确保了数据的实时性和可靠性,同时支持远程监控。华为云平台作为数据中转站,存储历史数据并支持QT上位机的访问。

QT上位机应用程序通过华为云API获取照明状态和能耗数据,实现远程手动控制各区域照明开关及亮度调节。上位机界面设计包括实时数据显示和历史数据曲线绘制,方便用户查看趋势和分析能耗。整个系统硬件通过洞洞板焊接外围电路,并使用杜邦线连接各模块,确保结构紧凑且易于调试。

框架图

+---------------------+       +-----------------------+
| GY-30 Light Sensor  |---I2C-->|                     |
|                     |       | STM32F103C8T6        |
+---------------------+       | Main Controller      |
+---------------------+       |                      |
| HC-SR501 PIR Sensor |---GPIO-->|                      |
|                     |       +-----------------------+
+---------------------+               |
                                      | PWM
                                      v
                              +---------------------+
                              | LED Light Group     |
                              | with LM2596 & PWM   |
                              +---------------------+
                                      |
                                      | UART
                                      v
                              +---------------------+
                              | ESP8266-01S         |
                              | Wi-Fi Module        |
                              +---------------------+
                                      |
                                      | Wi-Fi
                                      v
                              +---------------------+
                              | Huawei Cloud IoT    |
                              | Platform            |
                              +---------------------+
                                      |
                                      | Internet
                                      v
                              +---------------------+
                              | QT Upper Computer   |
                              | (Remote Control &   |
                              |  Data Display)      |
                              +---------------------+

系统总体设计

本系统以STM32F103C8T6最小系统核心板作为主控制器,负责协调整个智能楼宇照明控制系统的运行。系统通过GY-30光照强度传感器实时采集各区域的环境光照数据,同时利用HC-SR501人体红外传感器检测人员活动状态,确保对光照和人体存在的监测准确性。这些传感器数据通过杜邦线连接至STM32控制器,由内置ADC和GPIO接口进行采集和处理。

控制逻辑基于采集到的环境光照和人员活动数据自动执行,STM32通过PWM输出控制LED照明灯组的开关与亮度调节,结合LM2596降压模块实现稳定的调光功能。当环境光照不足且检测到人员存在时,系统会自动开启LED灯并调整至合适亮度;反之则关闭或降低亮度,以达到节能和智能照明的目的。

数据上传部分通过ESP8266-01S Wi-Fi模块实现,该模块连接到本地Wi-Fi网络,并与华为云物联网平台建立通信连接。STM32将处理后的照明状态数据及能耗数据封装为MQTT协议格式,通过串口发送至ESP8266模块,进而上传至云平台,实现远程数据存储和监控。

QT上位机应用程序作为远程控制界面,允许用户手动控制各区域照明开关和亮度,并通过图表形式显示照明状态的历史数据曲线。上位机通过云平台API获取数据,实现与硬件系统的交互,为用户提供直观的操作和数据分析体验。整个系统的外围电路基于洞洞板焊接完成,确保连接可靠性和实验灵活性。

系统功能总结

功能 描述
实时监测 使用GY-30传感器采集各区域光照强度,HC-SR501传感器检测人体存在状态
自动控制 根据环境光照和人员活动,通过PWM调光自动控制LED照明灯的开关与亮度
数据上传 通过ESP8266 Wi-Fi模块将照明状态及能耗数据上传至华为云物联网平台
远程监控 QT上位机支持远程手动控制各区域照明,并显示照明状态历史数据曲线

设计的各个功能模块描述

主控制模块基于STM32F103C8T6最小系统核心板,作为系统的中央处理单元,负责协调所有外围设备的工作。它通过ADC读取传感器数据,处理逻辑判断,生成PWM信号控制照明输出,并管理Wi-Fi模块的通信任务,确保整个系统高效运行。

光照监测模块采用GY-30光照强度传感器,该传感器通过I2C接口与主控制器连接,实时采集环境光照强度数据。传感器将光信号转换为电信号,并提供数字输出,主控制器据此判断当前光照水平,为自动调光控制提供依据。

人体检测模块使用HC-SR501人体红外传感器,通过检测红外辐射变化来感知人员活动状态。传感器输出数字信号指示人体存在与否,主控制器读取此信号并结合光照数据,决定是否触发照明开关或调整亮度,实现智能控制。

照明控制模块包括LED照明灯组和LM2596降压模块,主控制器通过PWM输出信号调节LED的亮度。LM2596模块提供稳定的电压供应,确保PWM调光平滑有效,从而根据环境需求和人员活动自动控制照明开关及亮度水平。

通信模块依托ESP8266-01S Wi-Fi模块,实现与华为云物联网平台的数据交互。该模块通过串口与主控制器通信,将光照强度、人体状态、照明状态及能耗数据上传至云平台,同时接收来自云端的控制指令,支持远程监控和管理。

上位机模块基于QT开发的可视化界面,允许用户远程手动控制各区域照明,并显示照明状态历史数据曲线。它通过华为云平台获取实时数据,提供图形化交互,方便用户查看趋势和进行手动干预,增强系统的可操作性和数据分析能力。

上位机代码设计

// SmartLightingController.pro
QT       += core gui mqtt charts widgets
CONFIG += c++11
SOURCES += main.cpp mainwindow.cpp
HEADERS += mainwindow.h
FORMS += mainwindow.ui
// mainwindow.h
#ifndef MAINWINDOW_H
#define MAINWINDOW_H

#include <QMainWindow>
#include <QMqttClient>
#include <QChart>
#include <QLineSeries>
#include <QValueAxis>
#include <QChartView>

QT_BEGIN_NAMESPACE
namespace Ui { class MainWindow; }
QT_END_NAMESPACE

class MainWindow : public QMainWindow
{
    Q_OBJECT

public:
    explicit MainWindow(QWidget *parent = nullptr);
    ~MainWindow();

private slots:
    void on_connectButton_clicked();
    void on_disconnectButton_clicked();
    void on_controlButton1_clicked();
    void on_controlButton2_clicked();
    void on_controlButton3_clicked();
    void handleMessage(const QByteArray &message, const QString &topic);
    void updateLog(const QString &message);

private:
    Ui::MainWindow *ui;
    QMqttClient *m_client;
    QChart *m_chart;
    QLineSeries *m_lightSeries;
    QLineSeries *m_energySeries;
    QVector<QString> m_timeData;
    QVector<double> m_lightData;
    QVector<double> m_energyData;
    void setupMQTT();
    void setupChart();
    void publishControl(int area, bool state);
};

#endif // MAINWINDOW_H
// mainwindow.cpp
#include "mainwindow.h"
#include "ui_mainwindow.h"
#include <QDateTime>
#include <QJsonDocument>
#include <QJsonObject>
#include <QMessageBox>

MainWindow::MainWindow(QWidget *parent) :
    QMainWindow(parent),
    ui(new Ui::MainWindow),
    m_client(new QMqttClient(this)),
    m_chart(new QChart()),
    m_lightSeries(new QLineSeries()),
    m_energySeries(new QLineSeries())
{
    ui->setupUi(this);
    setupChart();
    setupMQTT();

    connect(m_client, &QMqttClient::messageReceived, this, &MainWindow::handleMessage);
    connect(m_client, &QMqttClient::connected, this, [this]() { updateLog("Connected to Huawei Cloud IoT"); });
    connect(m_client, &QMqttClient::disconnected, this, [this]() { updateLog("Disconnected"); });
}

MainWindow::~MainWindow()
{
    delete ui;
}

void MainWindow::setupChart()
{
    m_chart->addSeries(m_lightSeries);
    m_chart->addSeries(m_energySeries);
    m_chart->setTitle("Lighting Status and Energy Consumption");
    m_chart->createDefaultAxes();
    m_chart->axes(Qt::Horizontal).first()->setTitleText("Time");
    m_chart->axes(Qt::Vertical).first()->setTitleText("Value");
    ui->chartView->setChart(m_chart);
}

void MainWindow::setupMQTT()
{
    m_client->setHostName("iot-mqtts.cn-north-4.myhuaweicloud.com");
    m_client->setPort(1883);
    m_client->setUsername("your_product_id/your_device_id");
    m_client->setPassword("your_device_secret");
}

void MainWindow::on_connectButton_clicked()
{
    if (m_client->state() == QMqttClient::Disconnected) {
        m_client->connectToHost();
        m_client->subscribe("lighting/data");
    } else {
        updateLog("Already connected");
    }
}

void MainWindow::on_disconnectButton_clicked()
{
    if (m_client->state() == QMqttClient::Connected) {
        m_client->disconnectFromHost();
    }
}

void MainWindow::on_controlButton1_clicked() publishControl(1, ui->controlButton1->isChecked()); }
void MainWindow::on_controlButton2_clicked() publishControl(2, ui->controlButton2->isChecked()); }
void MainWindow::on_controlButton3_clicked() publishControl(3, ui->controlButton3->isChecked()); }

void MainWindow::publishControl(int area, bool state)
{
    if (m_client->state() != QMqttClient::Connected) {
        updateLog("Not connected. Cannot send control.");
        return;
    }

    QJsonObject controlMsg;
    controlMsg["area"] = area;
    controlMsg["state"] = state;
    QJsonDocument doc(controlMsg);
    m_client->publish("lighting/control", doc.toJson());
    updateLog(QString("Control sent: Area %1, State %2").arg(area).arg(state ? "ON" : "OFF"));
}

void MainWindow::handleMessage(const QByteArray &message, const QString &topic)
{
    QJsonDocument doc = QJsonDocument::fromJson(message);
    if (doc.isNull()) {
        updateLog("Invalid JSON received");
        return;
    }

    QJsonObject obj = doc.object();
    double light = obj["light"].toDouble();
    bool human = obj["human"].toBool();
    double energy = obj["energy"].toDouble();
    QString timestamp = QDateTime::currentDateTime().toString("hh:mm:ss");

    m_timeData.append(timestamp);
    m_lightData.append(light);
    m_energyData.append(energy);

    m_lightSeries->clear();
    m_energySeries->clear();
    for (int i = 0; i < m_timeData.size(); ++i) {
        m_lightSeries->append(i, m_lightData[i]);
        m_energySeries->append(i, m_energyData[i]);
    }

    m_chart->axes(Qt::Horizontal).first()->setRange(0, m_timeData.size() - 1);
    double minVal = qMin(*std::min_element(m_lightData.begin(), m_lightData.end()),
                         *std::min_element(m_energyData.begin(), m_energyData.end()));
    double maxVal = qMax(*std::max_element(m_lightData.begin(), m_lightData.end()),
                         *std::max_element(m_energyData.begin(), m_energyData.end()));
    m_chart->axes(Qt::Vertical).first()->setRange(minVal, maxVal);

    ui->statusLabel->setText(QString("Light: %1 lux, Human: %2, Energy: %3 kWh")
                                 .arg(light).arg(human ? "Yes" : "No").arg(energy));
    updateLog(QString("Data received: Light=%1, Human=%2, Energy=%3").arg(light).arg(human).arg(energy));
}

void MainWindow::updateLog(const QString &message)
{
    ui->logList->addItem(QDateTime::currentDateTime().toString("yyyy-MM-dd hh:mm:ss") + " - " + message);
}
// main.cpp
#include "mainwindow.h"
#include <QApplication>

int main(int argc, char *argv[])
{
    QApplication a(argc, argv);
    MainWindow w;
    w.show();
    return a.exec();
}
<!-- mainwindow.ui -->
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
 <class>MainWindow</class>
 <widget class="QMainWindow" name="MainWindow">
  <property name="geometry">
   <rect>
    <x>0</x>
    <y>0</y>
    <width>800</width>
    <height>600</height>
   </rect>
  </property>
  <property name="windowTitle">
   <string>Smart Lighting Controller</string>
  </property>
  <widget class="QWidget" name="centralWidget">
   <layout class="QVBoxLayout" name="verticalLayout">
    <item>
     <layout class="QHBoxLayout" name="controlLayout">
      <item>
       <widget class="QPushButton" name="connectButton">
        <property name="text">
         <string>Connect</string>
        </property>
       </widget>
      </item>
      <item>
       <widget class="QPushButton" name="disconnectButton">
        <property name="text">
         <string>Disconnect</string>
        </property>
       </widget>
      </item>
      <item>
       <widget class="QPushButton" name="controlButton1">
        <property name="checkable">
         <bool>true</bool>
        </property>
        <property name="text">
         <string>Area 1 OFF</string>
        </property>
       </widget>
      </item>
      <item>
       <widget class="QPushButton" name="controlButton2">
        <property name="checkable">
         <bool>true</bool>
        </property>
        <property name="text">
         <string>Area 2 OFF</string>
        </property>
       </widget>
      </item>
      <item>
       <widget class="QPushButton" name="controlButton3">
        <property name="checkable">
         <bool>true</bool>
        </property>
        <property name="text">
         <string>Area 3 OFF</string>
        </property>
       </widget>
      </item>
     </layout>
    </item>
    <item>
     <widget class="QLabel" name="statusLabel">
      <property name="text">
       <string>Status: Disconnected</string>
      </property>
     </widget>
    </item>
    <item>
     <widget class="QChartView" name="chartView"/>
    </item>
    <item>
     <widget class="QListWidget" name="logList"/>
    </item>
   </layout>
  </widget>
 </widget>
 <resources/>
 <connections/>
</ui>

模块代码设计

#include <stdint.h>

// 寄存器地址定义
#define RCC_BASE        0x40021000
#define GPIOA_BASE      0x40010800
#define GPIOB_BASE      0x40010C00
#define I2C1_BASE       0x40005400
#define TIM2_BASE       0x40000000
#define USART2_BASE     0x40004400

// RCC寄存器
#define RCC_APB2ENR     (*((volatile uint32_t *)(RCC_BASE + 0x18)))
#define RCC_APB1ENR     (*((volatile uint32_t *)(RCC_BASE + 0x1C)))

// GPIO寄存器
#define GPIOA_CRL       (*((volatile uint32_t *)(GPIOA_BASE + 0x00)))
#define GPIOA_CRH       (*((volatile uint32_t *)(GPIOA_BASE + 0x04)))
#define GPIOA_IDR       (*((volatile uint32_t *)(GPIOA_BASE + 0x08)))
#define GPIOA_ODR       (*((volatile uint32_t *)(GPIOA_BASE + 0x0C)))
#define GPIOB_CRL       (*((volatile uint32_t *)(GPIOB_BASE + 0x00)))
#define GPIOB_CRH       (*((volatile uint32_t *)(GPIOB_BASE + 0x04)))
#define GPIOB_ODR       (*((volatile uint32_t *)(GPIOB_BASE + 0x0C)))

// I2C1寄存器
#define I2C1_CR1        (*((volatile uint32_t *)(I2C1_BASE + 0x00)))
#define I2C1_CR2        (*((volatile uint32_t *)(I2C1_BASE + 0x04)))
#define I2C1_OAR1       (*((volatile uint32_t *)(I2C1_BASE + 0x08)))
#define I2C1_OAR2       (*((volatile uint32_t *)(I2C1_BASE + 0x0C)))
#define I2C1_DR         (*((volatile uint32_t *)(I2C1_BASE + 0x10)))
#define I2C1_SR1        (*((volatile uint32_t *)(I2C1_BASE + 0x14)))
#define I2C1_SR2        (*((volatile uint32_t *)(I2C1_BASE + 0x18)))
#define I2C1_CCR        (*((volatile uint32_t *)(I2C1_BASE + 0x1C)))
#define I2C1_TRISE      (*((volatile uint32_t *)(I2C1_BASE + 0x20)))

// TIM2寄存器
#define TIM2_CR1        (*((volatile uint32_t *)(TIM2_BASE + 0x00)))
#define TIM2_CR2        (*((volatile uint32_t *)(TIM2_BASE + 0x04)))
#define TIM2_SMCR       (*((volatile uint32_t *)(TIM2_BASE + 0x08)))
#define TIM2_DIER       (*((volatile uint32_t *)(TIM2_BASE + 0x0C)))
#define TIM2_SR         (*((volatile uint32_t *)(TIM2_BASE + 0x10)))
#define TIM2_EGR        (*((volatile uint32_t *)(TIM2_BASE + 0x14)))
#define TIM2_CCMR1      (*((volatile uint32_t *)(TIM2_BASE + 0x18)))
#define TIM2_CCMR2      (*((volatile uint32_t *)(TIM2_BASE + 0x1C)))
#define TIM2_CCER       (*((volatile uint32_t *)(TIM2_BASE + 0x20)))
#define TIM2_CNT        (*((volatile uint32_t *)(TIM2_BASE + 0x24)))
#define TIM2_PSC        (*((volatile uint32_t *)(TIM2_BASE + 0x28)))
#define TIM2_ARR        (*((volatile uint32_t *)(TIM2_BASE + 0x2C)))
#define TIM2_CCR1       (*((volatile uint32_t *)(TIM2_BASE + 0x34)))
#define TIM2_CCR2       (*((volatile uint32_t *)(TIM2_BASE + 0x38)))

// USART2寄存器
#define USART2_SR       (*((volatile uint32_t *)(USART2_BASE + 0x00)))
#define USART2_DR       (*((volatile uint32_t *)(USART2_BASE + 0x04)))
#define USART2_BRR      (*((volatile uint32_t *)(USART2_BASE + 0x08)))
#define USART2_CR1      (*((volatile uint32_t *)(USART2_BASE + 0x0C)))
#define USART2_CR2      (*((volatile uint32_t *)(USART2_BASE + 0x10)))
#define USART2_CR3      (*((volatile uint32_t *)(USART2_BASE + 0x14)))

// 引脚定义
#define HC_SR501_PIN    0  // PA0 for human sensor input
#define LED_PWM_PIN     1  // PA1 for LED PWM output
#define ESP8266_TX_PIN  2  // PA2 for USART2 TX
#define ESP8266_RX_PIN  3  // PA3 for USART2 RX
#define I2C1_SCL_PIN    6  // PB6 for I2C1 SCL
#define I2C1_SDA_PIN    7  // PB7 for I2C1 SDA

// BH1750地址和命令
#define BH1750_ADDRESS  0x23 // 7-bit address
#define BH1750_POWER_ON 0x01
#define BH1750_CONTINUOUS_HIGH_RES_MODE 0x10

// 函数声明
void SystemInit(void);
void GPIO_Init(void);
void I2C1_Init(void);
void I2C1_Start(void);
void I2C1_Stop(void);
void I2C1_Write(uint8_t data);
uint8_t I2C1_Read(uint8_t ack);
void BH1750_Init(void);
uint16_t BH1750_ReadLight(void);
uint8_t Read_HC_SR501(void);
void TIM2_Init(void);
void Set_LED_Brightness(uint16_t brightness);
void USART2_Init(void);
void USART2_SendChar(char ch);
void USART2_SendString(const char *str);
char USART2_ReceiveChar(void);
void Delay_ms(uint32_t ms);

int main(void) {
    SystemInit();
    GPIO_Init();
    I2C1_Init();
    BH1750_Init();
    TIM2_Init();
    USART2_Init();
    
    uint16_t light_level;
    uint8_t human_detected;
    uint16_t led_brightness = 0;
    
    while (1) {
        light_level = BH1750_ReadLight();
        human_detected = Read_HC_SR501();
        
        // 自动控制逻辑:如果光照低且有人,开启LED;否则关闭或调低
        if (light_level < 100 && human_detected) { // 假设阈值100 lux
            led_brightness = 1000// 最大亮度假设为1000
        } else {
            led_brightness = 0;
        }
        Set_LED_Brightness(led_brightness);
        
        // 准备数据上传华为云(通过ESP8266)
        char buffer[64];
        sprintf(buffer, "Light: %d lux, Human: %d, LED: %d\r\n", light_level, human_detected, led_brightness);
        USART2_SendString(buffer); // 通过UART发送到ESP8266
        
        Delay_ms(1000); // 每秒更新一次
    }
}

void SystemInit(void) {
    // 启用GPIOA、GPIOB、I2C1、TIM2、USART2时钟
    RCC_APB2ENR |= (1 << 2) | (1 << 3) | (1 << 0); // GPIOA, GPIOB, AFIO
    RCC_APB1ENR |= (1 << 0) | (1 << 22) | (1 << 17); // TIM2, I2C1, USART2
}

void GPIO_Init(void) {
    // 配置PA0为输入(HC-SR501)
    GPIOA_CRL &= ~(0xF << (HC_SR501_PIN * 4)); // 清除模式
    GPIOA_CRL |= (0x4 << (HC_SR501_PIN * 4)); // 输入模式
    
    // 配置PA1为输出(LED PWM,复用推挽输出)
    GPIOA_CRL &= ~(0xF << (LED_PWM_PIN * 4));
    GPIOA_CRL |= (0xB << (LED_PWM_PIN * 4)); // 复用推挽输出,50MHz
    
    // 配置PA2和PA3为USART2复用推挽输出
    GPIOA_CRL &= ~(0xFF << (ESP8266_TX_PIN * 4));
    GPIOA_CRL |= (0xB << (ESP8266_TX_PIN * 4)); // TX:复用推挽输出
    GPIOA_CRL |= (0x4 << (ESP8266_RX_PIN * 4)); // RX:输入浮空
    
    // 配置PB6和PB7为I2C1复用开漏输出
    GPIOB_CRL &= ~(0xFF << (I2C1_SCL_PIN * 4));
    GPIOB_CRL |= (0xE << (I2C1_SCL_PIN * 4)); // SCL:复用开漏输出
    GPIOB_CRL |= (0xE << (I2C1_SDA_PIN * 4)); // SDA:复用开漏输出
}

void I2C1_Init(void) {
    I2C1_CR1 &= ~(1 << 0); // 禁用I2C1
    I2C1_CR2 = 36// 设置APB1时钟为36MHz,因此CR2=36
    I2C1_CCR = 180// 设置CCR for 100kHz: CCR = APB1 clock / (2 * I2C speed) = 36e6 / (2 * 100e3) = 180
    I2C1_TRISE = 37// 设置TRISE: TRISE = (APB1 clock / 1e6) + 1 = 36 + 1 = 37
    I2C1_CR1 |= (1 << 0); // 启用I2C1
}

void I2C1_Start(void) {
    I2C1_CR1 |= (1 << 8); // 生成START条件
    while (!(I2C1_SR1 & (1 << 0))); // 等待SB标志置位
}

void I2C1_Stop(void) {
    I2C1_CR1 |= (1 << 9); // 生成STOP条件
    while (I2C1_SR2 & (1 << 1)); // 等待BUSY标志清除
}

void I2C1_Write(uint8_t data) {
    I2C1_DR = data;
    while (!(I2C1_SR1 & (1 << 7))); // 等待TxE标志置位
}

uint8_t I2C1_Read(uint8_t ack) {
    if (ack) {
        I2C1_CR1 |= (1 << 10); // 启用ACK
    } else {
        I2C1_CR1 &= ~(1 << 10); // 禁用ACK
    }
    while (!(I2C1_SR1 & (1 << 6))); // 等待RxNE标志置位
    return I2C1_DR;
}

void BH1750_Init(void) {
    I2C1_Start();
    I2C1_Write(BH1750_ADDRESS << 1); // 写地址
    I2C1_Write(BH1750_POWER_ON);
    I2C1_Stop();
    Delay_ms(10);
    I2C1_Start();
    I2C1_Write(BH1750_ADDRESS << 1);
    I2C1_Write(BH1750_CONTINUOUS_HIGH_RES_MODE);
    I2C1_Stop();
    Delay_ms(180); // 等待测量完成
}

uint16_t BH1750_ReadLight(void) {
    uint8_t msb, lsb;
    uint16_t lux;
    I2C1_Start();
    I2C1_Write((BH1750_ADDRESS << 1) | 0x01); // 读地址
    msb = I2C1_Read(1); // 读MSB,发送ACK
    lsb = I2C1_Read(0); // 读LSB,不发送ACK
    I2C1_Stop();
    lux = (msb << 8) | lsb;
    lux = lux / 1.2// 转换为lux
    return lux;
}

uint8_t Read_HC_SR501(void) {
    return (GPIOA_IDR & (1 << HC_SR501_PIN)) ? 1 : 0// 读取PA0状态
}

void TIM2_Init(void) {
    TIM2_CR1 &= ~(1 << 0); // 禁用TIM2
    TIM2_PSC = 71// 预分频器:72MHz / (71+1) = 1MHz
    TIM2_ARR = 999// 自动重载值,PWM频率 = 1MHz / 1000 = 1kHz
    TIM2_CCMR1 |= (0x6 << 4); // OC1M模式:PWM模式1
    TIM2_CCER |= (1 << 0); // 启用CC1输出
    TIM2_CR1 |= (1 << 0); // 启用TIM2
}

void Set_LED_Brightness(uint16_t brightness) {
    if (brightness > 999) brightness = 999;
    TIM2_CCR1 = brightness; // 设置CCR1值控制占空比
}

void USART2_Init(void) {
    USART2_CR1 &= ~(1 << 13); // 禁用USART2
    USART2_BRR = 0x1D4C// 设置波特率115200:36e6 / 115200 = 312.5 -> 0x1D4C
    USART2_CR1 |= (1 << 2) | (1 << 3); // 启用发送和接收
    USART2_CR1 |= (1 << 13); // 启用USART2
}

void USART2_SendChar(char ch) {
    while (!(USART2_SR & (1 << 7))); // 等待TxE标志
    USART2_DR = ch;
}

void USART2_SendString(const char *str) {
    while (*str) {
        USART2_SendChar(*str++);
    }
}

char USART2_ReceiveChar(void) {
    while (!(USART2_SR & (1 << 5))); // 等待RxNE标志
    return USART2_DR;
}

void Delay_ms(uint32_t ms) {
    for (uint32_t i = 0; i < ms * 1000; i++) {
        __asm__("nop"); // 简单延时,实际应用中使用定时器更准确
    }
}

项目核心代码

#include "stm32f10x.h"
#include <stdio.h>  // For sprintf

// Define pins and peripherals
#define PIR_GPIO_PORT GPIOA
#define PIR_GPIO_PIN GPIO_Pin_0

#define LED_GPIO_PORT GPIOA
#define LED_GPIO_PIN GPIO_Pin_1  // TIM2_CH2

#define I2C_PORT I2C1
#define I2C_SCL_PIN GPIO_Pin_6
#define I2C_SDA_PIN GPIO_Pin_7
#define I2C_GPIO_PORT GPIOB

#define USART_PORT USART2
#define USART_GPIO_PORT GPIOA
#define USART_TX_PIN GPIO_Pin_2
#define USART_RX_PIN GPIO_Pin_3

// Function prototypes
void RCC_Configuration(void);
void GPIO_Configuration(void);
void I2C1_Configuration(void);
void TIM2_Configuration(void);
void USART2_Configuration(void);
void Delay_ms(uint32_t ms);
extern uint16_t Read_Light(void);  // Assume defined in other module
uint8_t Read_PIR(void);
void Set_LED_Brightness(uint8_t brightness);
void USART2_SendString(char *str);
void Process_Cloud_Command(void);

// Global variables
volatile uint16_t light_value = 0;
volatile uint8_t pir_state = 0;
volatile uint8_t led_brightness = 0;
char cloud_data[50];

int main(void) {
    // Initialize system
    RCC_Configuration();
    GPIO_Configuration();
    I2C1_Configuration();
    TIM2_Configuration();
    USART2_Configuration();
    
    while(1) {
        light_value = Read_Light();
        pir_state = Read_PIR();
        
        if (light_value < 50 && pir_state) {
            Set_LED_Brightness(100);
        } else if (light_value < 50 && !pir_state) {
            Set_LED_Brightness(30);
        } else {
            Set_LED_Brightness(0);
        }
        
        sprintf(cloud_data, "Light:%d,PIR:%d,LED:%d", light_value, pir_state, led_brightness);
        USART2_SendString(cloud_data);
        
        Process_Cloud_Command();
        
        Delay_ms(1000);
    }
}

void RCC_Configuration(void) {
    RCC->CR |= RCC_CR_HSEON;
    while(!(RCC->CR & RCC_CR_HSERDY));
    RCC->CFGR |= RCC_CFGR_PLLSRC_HSE | RCC_CFGR_PLLMULL9;
    RCC->CR |= RCC_CR_PLLON;
    while(!(RCC->CR & RCC_CR_PLLRDY));
    FLASH->ACR |= FLASH_ACR_LATENCY_2;
    RCC->CFGR |= RCC_CFGR_SW_PLL;
    while((RCC->CFGR & RCC_CFGR_SWS) != RCC_CFGR_SWS_PLL);
    RCC->APB2ENR |= RCC_APB2ENR_IOPAEN | RCC_APB2ENR_IOPBEN | RCC_APB2ENR_AFIOEN;
    RCC->APB1ENR |= RCC_APB1ENR_I2C1EN | RCC_APB1ENR_TIM2EN | RCC_APB1ENR_USART2EN;
}

void GPIO_Configuration(void) {
    GPIOA->CRL &= ~(GPIO_CRL_MODE0 | GPIO_CRL_CNF0);
    GPIOA->CRL |= GPIO_CRL_CNF0_0;
    GPIOA->CRL &= ~(GPIO_CRL_MODE1 | GPIO_CRL_CNF1);
    GPIOA->CRL |= GPIO_CRL_MODE1_1 | GPIO_CRL_CNF1_1;
    GPIOB->CRL &= ~(GPIO_CRL_MODE6 | GPIO_CRL_CNF6 | GPIO_CRL_MODE7 | GPIO_CRL_CNF7);
    GPIOB->CRL |= GPIO_CRL_MODE6_1 | GPIO_CRL_CNF6_1 | GPIO_CRL_MODE7_1 | GPIO_CRL_CNF7_1;
    GPIOA->CRL &= ~(GPIO_CRL_MODE2 | GPIO_CRL_CNF2 | GPIO_CRL_MODE3 | GPIO_CRL_CNF3);
    GPIOA->CRL |= GPIO_CRL_MODE2_1 | GPIO_CRL_CNF2_1;
    GPIOA->CRL |= GPIO_CRL_CNF3_0;
}

void I2C1_Configuration(void) {
    I2C1->CR1 &= ~I2C_CR1_PE;
    I2C1->CR2 = 36;
    I2C1->CCR = 180;
    I2C1->TRISE = 37;
    I2C1->CR1 |= I2C_CR1_PE;
}

void TIM2_Configuration(void) {
    TIM2->PSC = 719;
    TIM2->ARR = 99;
    TIM2->CCMR1 |= TIM_CCMR1_OC2M_1 | TIM_CCMR1_OC2M_2;
    TIM2->CCER |= TIM_CCER_CC2E;
    TIM2->CR1 |= TIM_CR1_CEN;
}

void USART2_Configuration(void) {
    USART2->BRR = 36000000 / 9600;
    USART2->CR1 |= USART_CR1_TE | USART_CR1_RE | USART_CR1_UE;
}

uint8_t Read_PIR(void) {
    return (GPIOA->IDR & PIR_GPIO_PIN) ? 1 : 0;
}

void Set_LED_Brightness(uint8_t brightness) {
    if (brightness > 100) brightness = 100;
    TIM2->CCR2 = brightness;
    led_brightness = brightness;
}

void USART2_SendString(char *str) {
    while(*str) {
        while(!(USART2->SR & USART_SR_TXE));
        USART2->DR = *str++;
    }
}

void Process_Cloud_Command(void) {
    if (USART2->SR & USART_SR_RXNE) {
        char data = USART2->DR;
        if (data == '1') {
            Set_LED_Brightness(100);
        } else if (data == '0') {
            Set_LED_Brightness(0);
        }
    }
}

void Delay_ms(uint32_t ms) {
    for(uint32_t i = 0; i < ms * 1000; i++);
}

总结

本项目成功设计并实现了一个基于STM32F103C8T6微控制器与华为云物联网平台的智能楼宇照明控制系统。系统通过集成多种传感器和执行器,实现了对楼宇各区域照明环境的实时监测与自动控制,有效提升了照明管理的智能化水平和能源利用效率。

在硬件方面,系统以STM32F103C8T6最小系统核心板为主控制器,结合GY-30光照强度传感器和HC-SR501人体红外传感器,准确采集环境光照与人员活动数据。LED照明灯组通过LM2596降压模块支持PWM调光,实现对亮度的精细控制。ESP8266-01S Wi-Fi模块确保了与华为云平台的稳定通信,而洞洞板焊接和杜邦线连接方式体现了系统的模块化与可扩展性。

系统功能上,不仅实现了根据环境条件自动调节照明,还通过华为云平台实现了数据上传与远程监控。QT上位机提供了友好的人机界面,支持用户远程手动控制和历史数据曲线显示,增强了系统的实用性和可操作性。这为楼宇照明管理提供了数据驱动的决策支持,同时促进了节能降耗。

总体而言,该系统设计合理,运行稳定,具有良好的应用前景。它展示了物联网技术在智能楼宇领域的有效集成,为未来智能家居和建筑自动化系统的开发提供了参考和基础。

 

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

评论(0

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

全部回复

上滑加载中

设置昵称

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

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

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