一、项目概述
在现代高速公路的隧道照明系统中,实时监控环境参数(如照度、温度和湿度)是确保安全与高效运营的重要环节。本项目旨在设计一个多通道数据采集器,能够实时采集隧道内的照明及环境数据,并通过工业标准的 Modbus 协议将数据传输到上位机进行监控和分析。
技术栈关键词
-
单片机: STM32
-
传感器: BH1750(照度传感器),DHT11(温度湿度传感器)
-
通信协议: Modbus
-
数据传输: I²C(用于BH1750),单总线(用于DHT11)
二、系统架构
设计系统架构
系统架构的设计旨在满足数据采集的实时性和准确性需求。整体架构包括数据采集模块、数据处理模块和数据传输模块。STM32作为主控制器,负责协调各个模块的工作。
选择的硬件组件
-
STM32: 作为主控制器,具备强大的处理能力和丰富的外设接口。
-
BH1750: 精确的数字光照传感器,通过 I²C 协议进行通信。
-
DHT11: 低成本的温湿度传感器,通过单总线协议进行通信。
系统架构图
以下是系统架构图,清晰展示了各组件之间的关系和通信方式。
三、环境搭建和注意事项
环境搭建
-
硬件准备:
-
STM32开发板(如STM32F103C8T6)
-
BH1750传感器模块
-
DHT11传感器模块
-
jumper线、面包板等
-
-
软件环境:
-
开发环境: STM32CubeIDE
-
库文件: STM32 HAL库、Modbus库、I²C库
-
-
注意事项:
-
确保各传感器的电源电压符合要求。
-
在连接传感器时注意I²C和单总线的引脚配置。
-
使用外部上拉电阻确保数据传输的可靠性。
四、代码实现过程
在本节中,我们将详细介绍基于 STM32 和 Modbus 协议的公路隧道照明多通道数据采集器的代码实现过程。整个实现过程包括多个功能模块的设计与集成,我们将对每个模块的代码逻辑、工作流程、时序图等进行深入分析和说明。
1. 照度采集模块
1.1 模块概述
照度采集模块主要负责从 BH1750 传感器读取光照强度数据。BH1750 是一款高精度的数字光照传感器,支持 I²C 通信协议,具备快速响应能力,适合用于隧道照明的实时监控。
1.2 硬件连接
-
I²C 引脚配置:
-
SCL (时钟线) 连接到 STM32 的 I²C1_SCL
-
SDA (数据线) 连接到 STM32 的 I²C1_SDA
-
VCC 连接到 STM32 的 3.3V
-
GND 连接到 STM32 的 GND
1.3 代码实现
I²C 初始化
首先,我们需要初始化 I²C 总线,以便与 BH1750 进行通信。以下是 I²C 初始化的代码示例:
#include "stm32f1xx_hal.h"
I2C_HandleTypeDef hi2c1;
void MX_I2C1_Init(void) {
hi2c1.Instance = I2C1;
hi2c1.Init.ClockSpeed = 100000; // I²C 时钟频率
hi2c1.Init.DutyCycle = I2C_DUTYCYCLE_2;
hi2c1.Init.OwnAddress1 = 0;
hi2c1.Init.AddressingMode = I2C_ADDRESSINGMODE_7BIT;
hi2c1.Init.DualAddressMode = I2C_DUALADDRESS_DISABLE;
hi2c1.Init.OwnAddress2 = 0;
hi2c1.Init.GeneralCallMode = I2C_GENERALCALL_DISABLE;
HAL_I2C_Init(&hi2c1);
}
读取照度数据
接下来,我们实现读取照度数据的函数。该函数会向 BH1750 发送读取命令,然后读取并返回光照强度值。
#define BH1750_ADDRESS 0x23 // BH1750 设备地址
float Read_Lux(void) {
uint8_t cmd = 0x01; // 启动测量
uint8_t data[2];
// 发送启动命令
HAL_I2C_Master_Transmit(&hi2c1, BH1750_ADDRESS, &cmd, 1, HAL_MAX_DELAY);
// 延时等待转换
HAL_Delay(180);
// 读取数据
HAL_I2C_Master_Receive(&hi2c1, BH1750_ADDRESS, data, 2, HAL_MAX_DELAY);
// 计算照度值
uint16_t lux = (data[0] << 8) | data[1];
return (float)(lux / 1.2); // 转换为 lux
}
2. 温湿度采集模块
2.1 模块概述
温湿度采集模块主要负责与 DHT11 传感器进行通信,获取环境温度和湿度数据。DHT11 是一种低成本的数字温湿度传感器,适合用于环境监测。
2.2 硬件连接
-
单总线连接:
-
DHT11 的 DATA 引脚连接到 STM32 的 GPIO 引脚(如 PA0),需要配置为输入输出模式。
-
VCC 连接到 STM32 的 3.3V
-
GND 连接到 STM32 的 GND
-
2.3 代码实现
DHT11 读取函数
以下是 DHT11 读取温度和湿度的函数实现,采用单总线协议进行通信。
#include "dht11.h"
// DHT11 读取温度和湿度
void Read_Temp_Humidity(float* temperature, float* humidity) {
uint8_t data[5] = {0}; // 存储数据的数组
GPIO_InitTypeDef GPIO_InitStruct = {0};
// 初始化 GPIO
__HAL_RCC_GPIOA_CLK_ENABLE();
GPIO_InitStruct.Pin = GPIO_PIN_0; // 假设 DATA 引脚连接到 PA0
GPIO_InitStruct.Pull = GPIO_NOPULL;
GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_HIGH;
HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);
// 向 DHT11 发送起始信号
HAL_GPIO_WritePin(GPIOA, GPIO_PIN_0, GPIO_PIN_RESET); // 拉低信号线
HAL_Delay(18); // 保持低电平18ms
HAL_GPIO_WritePin(GPIOA, GPIO_PIN_0, GPIO_PIN_SET); // 拉高信号线
HAL_Delay(20); // 等待 DHT11 反应
// 设置信号线为输入
GPIO_InitStruct.Mode = GPIO_MODE_INPUT;
HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);
// DHT11 响应信号
while (HAL_GPIO_ReadPin(GPIOA, GPIO_PIN_0)); // 等待连接
while (!HAL_GPIO_ReadPin(GPIOA, GPIO_PIN_0)); // 等待 DHT11 拉低信号
while (HAL_GPIO_ReadPin(GPIOA, GPIO_PIN_0)); // 等待 DHT11 拉高信号
// 读取 40 位数据
for (int i = 0; i < 5; i++) {
for (int j = 0; j < 8; j++) {
while (!HAL_GPIO_ReadPin(GPIOA, GPIO_PIN_0)); // 等待拉高
HAL_Delay(30); // 等待 30us
if (HAL_GPIO_ReadPin(GPIOA, GPIO_PIN_0)) {
data[i] |= (1 << (7 - j)); // 记录数据
}
while (HAL_GPIO_ReadPin(GPIOA, GPIO_PIN_0)); // 等待拉低
}
}
// 数据验证
if (data[4] == (data[0] + data[1] + data[2] + data[3])) {
*humidity = data[0]; // 湿度
*temperature = data[2]; // 温度
} else {
*humidity = -1; // 错误
*temperature = -1; // 错误
}
}
3. 数据传输模块
3.1 模块概述
数据传输模块负责将采集到的照度、温度和湿度数据通过 Modbus 协议发送到上位机。Modbus 是一种广泛使用的通信协议,适用于工业设备之间的数据交换。
3.2 硬件连接
-
串口连接:
-
使用 STM32 的 USART 接口(如 USART1)连接到 Modbus 上位机。
-
TX 引脚连接到上位机的 RX,引脚连接为 RX。
-
3.3 代码实现
Modbus 初始化
首先,我们需要初始化 USART 以便进行数据传输。
#include "usart.h"
UART_HandleTypeDef huart1;
void MX_USART1_UART_Init(void) {
huart1.Instance = USART1;
huart1.Init.BaudRate = 9600;
huart1.Init.WordLength = UART_WORDLENGTH_8B;
huart1.Init.StopBits = UART_STOPBITS_1;
huart1.Init.Parity = UART_PARITY_NONE;
huart1.Init.Mode = UART_MODE_TX_RX;
huart1.Init.HwFlowCtl = UART_HWCONTROL_NONE;
huart1.Init.OverSampling = UART_OVERSAMPLING_16;
HAL_UART_Init(&huart1);
}
Modbus 数据发送
接下来,我们实现一个函数,用于通过 Modbus 协议发送数据。
#include "modbus.h"
// 发送 Modbus 数据
void Send_Data(float lux, float temperature, float humidity) {
uint8_t buffer[32];
int length = snprintf((char*)buffer, sizeof(buffer),
"Lux: %.2f, Temperature: %.2f, Humidity: %.2f\n", lux, temperature, humidity);
// 通过 USART 发送数据
HAL_UART_Transmit(&huart1, buffer, length, HAL_MAX_DELAY);
}
4. 主程序逻辑
在主程序中,我们将整合以上模块,实现数据的周期性采集和传输。
#include "main.h"
int main(void) {
HAL_Init(); // 初始化 HAL 库
SystemClock_Config(); // 配置系统时钟
// 初始化 I2C 和 USART
MX_I2C1_Init();
MX_USART1_UART_Init();
// 主循环
while (1) {
float lux = Read_Lux(); // 读取照度
float temperature, humidity;
Read_Temp_Humidity(&temperature, &humidity); // 读取温湿度
// 发送数据到上位机
Send_Data(lux, temperature, humidity);
// 延时一段时间(例如 1 秒)
HAL_Delay(1000);
}
}
标签:STM32,HAL,Modbus,采集,Init,GPIO,DHT11
From: https://blog.csdn.net/qq_40431685/article/details/142530542