核心目标:整合前 9 天所有知识点(GPIO、定时器、串口、I2C、DMA、FreeRTOS),开发一个 “智能温湿度报警器”—— 实时采集温湿度、通过按键设置阈值、超标时 LED + 蜂鸣器报警、支持串口查看数据和远程修改阈值,完成从 “知识点” 到 “产品级应用” 的闭环,体验嵌入式开发的完整流程。
一、项目需求与架构设计(20 分钟)
1. 核心功能
- 实时采集:通过 AHT10 传感器(I2C)采集温湿度,1 秒更新一次;
- 阈值设置:板载按键(GPIO 输入)设置温度上限(如 30℃)和湿度上限(如 60% RH);
- 报警功能:温湿度超限时,LED 闪烁 + 蜂鸣器鸣叫(GPIO 输出);
- 数据交互:串口(DMA)上传实时数据和报警信息,支持电脑发送指令修改阈值;
- 多任务管理:用 FreeRTOS 实现 “采集 + 按键检测 + 报警 + 串口通信”4 任务并行,互不阻塞。
2. 硬件清单
- STM32F103C8T6 开发板、AHT10 温湿度传感器(I2C);
- 按键 2 个(设置温度阈值 / 湿度阈值)、蜂鸣器 1 个(有源)、LED1 个;
- USB-TTL 模块(串口通信)、杜邦线、面包板。
3. 系统架构(FreeRTOS 任务分配)
| 任务名称 | 优先级 | 功能描述 | 核心外设 |
|---|---|---|---|
| 采集任务 | 2 | 1 秒采集一次温湿度,更新全局变量 | I2C、定时器 |
| 按键检测任务 | 3 | 检测按键按下,修改阈值(高优先级) | GPIO 输入 |
| 报警判断任务 | 2 | 对比实时数据与阈值,触发报警 | GPIO 输出(蜂鸣器、LED) |
| 串口通信任务 | 1 | DMA 发送数据,接收远程指令 | USART1、DMA |
二、硬件接线(10 分钟,关键!)
| 外设 | 引脚连接(STM32F103C8T6) | 备注 |
|---|---|---|
| AHT10 | VCC→3.3V,GND→GND,SCL→PB6,SDA→PB7 | I2C1 通信 |
| 按键 1(温度阈值) | 一端→PA0,另一端→GND | 下拉输入(按下时为低电平) |
| 按键 2(湿度阈值) | 一端→PA1,另一端→GND | 下拉输入(按下时为低电平) |
| 蜂鸣器 | VCC→3.3V,GND→PB8(通过三极管驱动) | 低电平触发鸣叫(GPIO 输出) |
| LED | 正极→PC13(串联 1k 电阻),负极→GND | 低电平点亮(GPIO 输出) |
| 串口(USB-TTL) | TX→PA10,RX→PA9,GND→GND | USART1 通信,DMA 发送 |
三、CubeIDE 配置(30 分钟,模块化配置)
1. 基础配置
- 芯片选择:STM32F103C8T6;
- 时钟配置:HSE=8MHz,系统时钟 = 72MHz,APB1=36MHz,APB2=72MHz。
2. 外设配置
- I2C1:Mode=I2C,时钟频率 = 100kHz,PB6=SCL,PB7=SDA(上拉);
- USART1:异步模式,波特率 = 9600,PA9=TX,PA10=RX;DMA 配置:添加 TX 方向(DMA1_Channel4,内存→外设,正常模式);
- GPIO:
- PA0、PA1:GPIO_Input(按键,下拉输入);
- PB8:GPIO_Output(蜂鸣器,推挽输出);
- PC13:GPIO_Output(LED,推挽输出);
- FreeRTOS:CMSIS_V1,创建 4 个任务(按架构设计配置优先级和栈大小);
- NVIC:使能 I2C、USART1、按键中断(若用中断检测按键)。
3. 生成代码
点击 “Project→Generate Code”,CubeIDE 自动生成初始化代码和 FreeRTOS 任务框架。
四、核心代码实现(60 分钟,分模块编写)
1. 全局变量定义(main.c头部,任务间共享数据)
c
/* USER CODE BEGIN 0 */
#include <string.h>
// 传感器数据
float temp = 0.0, humi = 0.0;
// 阈值(默认温度30℃,湿度60%RH)
float temp_threshold = 30.0, humi_threshold = 60.0;
// 报警状态(0=正常,1=温度超标,2=湿度超标,3=两者都超标)
uint8_t alarm_state = 0;
// 串口发送缓冲区
uint8_t uart_send_buf[100];
/* USER CODE END 0 */
2. AHT10 传感器驱动(复用第八天代码,略作修改)
c
/* USER CODE BEGIN 0 */
// AHT10初始化和数据读取函数(同第八天,确保返回温度和湿度)
uint8_t AHT10_Init(I2C_HandleTypeDef *hi2c) { ... }
uint8_t AHT10_ReadData(I2C_HandleTypeDef *hi2c, float *temp, float *humi) { ... }
/* USER CODE END 0 */
3. FreeRTOS 任务实现(main.c的 “USER CODE BEGIN 5”)
任务 1:温湿度采集任务(1 秒一次)
c
void TempHumi_Collect_Task(void const * argument)
{
AHT10_Init(&hi2c1); // 初始化传感器
for(;;)
{
// 读取温湿度(更新全局变量temp、humi)
AHT10_ReadData(&hi2c1, &temp, &humi);
vTaskDelay(1000); // 1秒采集一次
}
}
任务 2:按键检测任务(检测阈值设置)
c
void Key_Detect_Task(void const * argument)
{
uint8_t key1_state = 1, key2_state = 1; // 按键初始状态(高电平,未按下)
for(;;)
{
// 检测按键1(温度阈值+1℃,按下一次加1)
if (HAL_GPIO_ReadPin(GPIOA, GPIO_PIN_0) == 0) { // 按键按下(低电平)
if (key1_state == 1) { // 边沿检测(只触发一次)
temp_threshold += 1.0;
if (temp_threshold > 40.0) temp_threshold = 40.0; // 上限40℃
// 串口反馈阈值修改
sprintf((char*)uart_send_buf, "温度阈值已修改为:%.1f℃\r\n", temp_threshold);
HAL_UART_Transmit_DMA(&huart1, uart_send_buf, strlen((char*)uart_send_buf));
}
key1_state = 0;
} else {
key1_state = 1;
}
// 检测按键2(湿度阈值+5%RH,按下一次加5)
if (HAL_GPIO_ReadPin(GPIOA, GPIO_PIN_1) == 0) {
if (key2_state == 1) {
humi_threshold += 5.0;
if (humi_threshold > 90.0) humi_threshold = 90.0; // 上限90%RH
sprintf((char*)uart_send_buf, "湿度阈值已修改为:%.1f%%RH\r\n", humi_threshold);
HAL_UART_Transmit_DMA(&huart1, uart_send_buf, strlen((char*)uart_send_buf));
}
key2_state = 0;
} else {
key2_state = 1;
}
vTaskDelay(50); // 50ms检测一次,消抖
}
}
任务 3:报警判断任务(实时对比阈值)
c
void Alarm_Check_Task(void const * argument)
{
for(;;)
{
// 判断报警状态
alarm_state = 0;
if (temp > temp_threshold) alarm_state |= 1; // 温度超标
if (humi > humi_threshold) alarm_state |= 2; // 湿度超标
// 执行报警动作
if (alarm_state != 0) {
// 超标:LED闪烁+蜂鸣器鸣叫
HAL_GPIO_WritePin(GPIOB, GPIO_PIN_8, GPIO_PIN_RESET); // 蜂鸣器响
HAL_GPIO_WritePin(GPIOC, GPIO_PIN_13, GPIO_PIN_RESET); // LED亮
vTaskDelay(300);
HAL_GPIO_WritePin(GPIOC, GPIO_PIN_13, GPIO_PIN_SET); // LED灭
vTaskDelay(300);
} else {
// 正常:关闭报警
HAL_GPIO_WritePin(GPIOB, GPIO_PIN_8, GPIO_PIN_SET); // 蜂鸣器关
HAL_GPIO_WritePin(GPIOC, GPIO_PIN_13, GPIO_PIN_SET); // LED灭
vTaskDelay(100); // 100ms检测一次
}
}
}
任务 4:串口通信任务(数据上传 + 远程指令)
c
void UART_Comm_Task(void const * argument)
{
uint8_t uart_recv_buf[20] = {0};
for(;;)
{
// 1. 每2秒发送一次实时数据
sprintf((char*)uart_send_buf,
"实时数据:温度=%.1f℃(阈值=%.1f),湿度=%.1f%%RH(阈值=%.1f),状态:%s\r\n",
temp, temp_threshold, humi, humi_threshold,
(alarm_state == 0) ? "正常" : "超标报警");
HAL_UART_Transmit_DMA(&huart1, uart_send_buf, strlen((char*)uart_send_buf));
vTaskDelay(2000);
// 2. 接收电脑指令(格式:"T30"→温度阈值30℃,"H60"→湿度阈值60%RH)
HAL_UART_Receive(&huart1, uart_recv_buf, 4, 100); // 超时100ms
if (uart_recv_buf[0] == 'T') { // 修改温度阈值
temp_threshold = atof((char*)&uart_recv_buf[1]); // 字符串转浮点数
sprintf((char*)uart_send_buf, "远程修改温度阈值为:%.1f℃\r\n", temp_threshold);
HAL_UART_Transmit_DMA(&huart1, uart_send_buf, strlen((char*)uart_send_buf));
} else if (uart_recv_buf[0] == 'H') { // 修改湿度阈值
humi_threshold = atof((char*)&uart_recv_buf[1]);
sprintf((char*)uart_send_buf, "远程修改湿度阈值为:%.1f%%RH\r\n", humi_threshold);
HAL_UART_Transmit_DMA(&huart1, uart_send_buf, strlen((char*)uart_send_buf));
}
memset(uart_recv_buf, 0, sizeof(uart_recv_buf)); // 清空接收缓冲区
}
}
五、系统测试与调试(30 分钟,关键验证)
1. 基础功能测试
- 传感器采集:串口每 2 秒收到温湿度数据,数值随环境变化;
- 按键设置:按下按键 1,温度阈值 + 1℃并串口反馈;按下按键 2,湿度阈值 + 5% RH;
- 报警功能:用手捂住 AHT10(升温加湿),温湿度超限时,LED 闪烁 + 蜂鸣器鸣叫。
2. 远程控制测试
- 电脑串口助手发送指令 “T32”→ 温度阈值改为 32℃,串口反馈修改成功;
- 发送指令 “H65”→ 湿度阈值改为 65% RH,系统按新阈值判断报警。
3. 多任务并行验证
- 报警时,按键仍可修改阈值,串口仍能上传数据 —— 证明 4 个任务并行不阻塞。
六、第十天总结:嵌入式开发的完整流程(10 分钟)
通过这个实战项目,你已掌握嵌入式开发的核心流程:
- 需求分析:明确系统要实现什么功能;
- 硬件选型与接线:根据需求选外设,设计电路连接;
- 软件架构设计:拆分任务,分配资源(如 FreeRTOS 任务优先级);
- 模块化开发:分外设驱动(传感器、按键、串口)、业务逻辑(采集、报警)编写代码;
- 测试与调试:逐步验证功能,解决硬件接线错误、逻辑漏洞等问题。


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



