🗑️ STM32F407 智慧垃圾桶 · 嵌入式实训课程

从零开始,纯手敲标准库代码,10天掌握嵌入式开发核心技能,完成具有传感器感知、PWM控制、串口通信的智能垃圾桶项目。

⚙️ STM32F407ZET6 📚 标准库开发 🖊️ 纯手敲代码 🦾 舵机 SG90 📡 HC-SR04 超声波 🧍 PIR 人体感应 📶 USART 串口 ⚡ PWM 控制

🎯 课程目标

GPIO 数字输入输出

LED 驱动、按键消抖、模块化驱动架构

中断与定时器

EXTI 外部中断、TIM6 定时中断、NVIC 配置

串口通信

USART 收发、printf 重定向、命令解析

PWM 与执行器

硬件 PWM、舵机控制、蜂鸣器

传感器集成

PIR 人体感应、HC-SR04 超声波测距

📅 学习路径

Day1 GPIO · LED 入门基础
Day2 模块化驱动 · 延时基础
Day3 按键输入 · 消抖基础
Day4 密码锁 · SysTick进阶
Day5 EXTI 外部中断进阶
Day6 USART 串口通信进阶
Day7 定时器 TIM6核心
Day8 硬件PWM · 舵机核心
Day9 传感器 · 系统集成综合
Day10 项目答辩综合

🧰 硬件清单

模块用途
STM32F407ZET6主控芯片
LED × 4状态指示灯
轻触按键 × 4手动控制输入
SG90 舵机桶盖开关
HC-SR04超声波测距(满桶检测)
HC-SR501 PIR人体红外感应
蜂鸣器满桶报警
USB-TTL 模块串口调试

🔄 系统功能流程

🧍 PIR
人体感应
⚙️ STM32
判断状态
🦾 舵机
开盖 180°
⏱️ 等待
3 秒
🦾 舵机
关盖 0°
📡 超声波
测垃圾量
🔔 满桶
报警
💡 项目核心逻辑空闲时LED呼吸灯待机 → 检测到人自动开盖 → 关盖后超声波检测垃圾量 → 满桶时蜂鸣器报警并锁定(不响应人体感应)→ 按键手动清空解锁。串口实时输出垃圾桶状态。

📅 十天教学计划

Day 1 🎯 STM32 入门 · GPIO 输出 · LED 闪烁

📋 教学目标

  • 理解 STM32F407ZET6 芯片命名规则和核心参数
  • 完成 Keil MDK 工程创建(含标准库配置)
  • 理解 RCC 时钟使能的含义和必要性
  • 掌握 GPIO_InitTypeDef 三要素:Pin、Mode、OType
  • 独立编写 LED 闪烁程序并下载验证

⏰ 时间分配

时段内容
上午 2hSTM32 简介、芯片命名、Keil 工程创建全流程
上午 2hRCC 时钟系统、GPIO 工作模式讲解
下午 2h手敲 LED 闪烁代码、编译下载、排查错误
下午 2h课堂练习 + 讲解常见错误

🧩 核心知识点

芯片命名规则 AHB1 总线 RCC_AHB1PeriphClockCmd GPIO_Mode_OUT GPIO_OType_PP 推挽 GPIO_SetBits / ResetBits while(1) 主循环

✅ 课堂验收标准

下课前必须完成 ① LED1 以约 500ms 间隔规律闪烁
② 代码能重新编译、下载,板子重启后自动运行
③ 能说出:为什么使用 GPIO 前要先调用 RCC 函数?

⚠️ 常见错误提示

老师重点讲解 · 工程路径含中文 → 编译报奇怪错误
· 宏定义 STM32F40_41xxx 漏写 → 头文件找不到
· startup 文件选错型号 → 程序无法运行
· 忘记 RCC 时钟使能 → GPIO 配置无效

💡 教学建议

先演示老师已做好的完整效果(LED 闪烁),再倒回来讲原理。学生有了感性认识,听理论更专注。Keil 工程创建步骤投影到屏幕逐步操作,学生同步跟做。

✏️ 课堂练习 & 作业

基础
练习1:四灯同步 — 修改代码,让 LED1、2、3、4 同时亮灭,间隔 300ms
基础
练习2:快慢双灯 — LED1 每 200ms 闪一次,LED2 每 1000ms 闪一次(在一个 while 循环里实现,思考为什么难以精确?)
进阶
练习3:SOS 求救灯 — 用三短三长三短的闪烁模式模拟摩尔斯电码 SOS(· · · — — — · · ·)
挑战
思考题 — 如果要让 4 个 LED 以不同频率独立闪烁,只用 while(1) + delay 能实现吗?说说你的想法,这个问题在 Day 7 学定时器后会有答案。
Day 2 🎯 模块化驱动 · .c/.h 分层 · 延时函数

📋 教学目标

  • 理解 User / Drivers / System 三层工程架构
  • 掌握头文件防重复包含(ifndef / define / endif)
  • 用宏定义集中管理引脚信息(换板只改 .h 文件)
  • 编写 LED_init()、LED1(x) 操作宏
  • 实现流水灯、跑马灯效果函数

⏰ 时间分配

时段内容
上午 2h工程分层思想,创建 LED.c / LED.h 文件
上午 2h宏定义引脚、操作宏 LED1(x) 讲解
下午 2h流水灯函数实现,软件延时分析
下午 2h练习:跑马灯 + 讨论软件延时的缺点

🧩 核心知识点

#ifndef 防重复包含 #define 宏替换 函数声明 vs 定义 GPIO_ToggleBits 软件延时原理 三层架构思想

✅ 课堂验收标准

下课前必须完成 ① LED.c / LED.h 文件结构完整,能独立编译
② 流水灯效果在实物上运行正常
③ 能回答:为什么要把引脚定义写在 .h 文件里?
重点强调 宏定义 LED1(x) 是三目运算符的应用:x ? SetBits : ResetBits。调用时 LED1(1) 亮、LED1(0) 灭,像控制一个开关一样直观。
引导讨论 软件 delay 有什么问题?(答:精度差、阻塞 CPU、受编译优化影响)→ 埋下 Day4 学 SysTick 的伏笔。

✏️ 课堂练习 & 作业

基础
练习1:完善 LED 驱动 — 在 LED.c 中实现 LED_liushui()(流水灯)和 LED_paoma()(跑马灯)两个函数,在 main.c 中轮流调用
基础
练习2:全灭初始化 — LED_init() 结束后确保 4 个 LED 全部熄灭,这是良好的驱动设计习惯
进阶
练习3:换板验证 — 假设把 LED1 从 PG14 改到 PF10,你需要改几行代码、改哪个文件?动手实际修改并验证
挑战
练习4:心跳灯 — 实现"双闪"效果(快闪两次后长暗),模拟心跳节奏,并封装成 LED_heartbeat() 函数
Day 3 🎯 按键输入 · GPIO 输入模式 · 软件消抖

📋 教学目标

  • 理解 GPIO 输入模式与上拉电阻的作用
  • 理解机械按键抖动现象和危害
  • 掌握"判断→延时→再判断→等待释放"消抖模板
  • 实现 4 个按键分别控制 4 个 LED 翻转
  • 用 switch-case 简化多键处理逻辑

⏰ 时间分配

时段内容
上午 2hGPIO 输入模式、上拉/下拉原理、读引脚函数
上午 2h按键抖动演示(示波器/逻辑分析仪),消抖原理
下午 2hKEY_init() + KEY_scan() 驱动手敲
下午 2h4键4灯练习,排查接线问题

🧩 核心知识点

GPIO_Mode_IN GPIO_PuPd_UP 上拉 GPIO_ReadInputDataBit 按下=低电平(0) 消抖 10ms delay 等待释放 while(!KEY)

✅ 课堂验收标准

下课前必须完成 ① 按下 KEY1 → LED1 翻转,4 个按键各自控制对应 LED
② 快速按多次,只触发一次(消抖有效)
③ 能画出消抖流程图(5个步骤)
重点强调消抖 5 步套路 ① 检测低电平 → ② 等 10ms → ③ 再次确认 → ④ 执行动作 → ⑤ 等待松手 → ⑥ 再等 10ms。这个套路整个课程都在用,必须背下来!
接线注意 按键一端接 GPIO 引脚,另一端接 GND。GPIO 配置上拉输入,空闲时为高电平(1),按下后被 GND 拉低为(0)。接反则无法工作!

✏️ 课堂练习 & 作业

基础
练习1:4 键 4 灯 — KEY1~4 分别控制 LED1~4 翻转,每次按下必须消抖处理
基础
练习2:组合控制 — KEY1 控制 LED1/LED2,KEY2 控制 LED3/LED4,KEY3 熄灭所有 LED,KEY4 点亮所有 LED
进阶
练习3:长按短按 — 区分 KEY1 的短按(<500ms)和长按(≥500ms):短按翻转 LED1,长按让所有 LED 闪3次
挑战
练习4:计数器 — KEY1 每按一次,让 LED 用二进制方式显示按了几次(4个LED表示0~15,LED1=最低位),超过15后归零
Day 4 🎯 密码锁设计 · SysTick 精确延时

📋 教学目标

  • 理解 SysTick 定时器原理,实现 delay_us / delay_ms
  • 用数组存储 4 位按键密码序列
  • 实现密码正确→双闪解锁,密码错误→长亮报错
  • 理解状态机的基本概念(等待输入 / 验证 / 反馈)
  • 修复原课程密码逻辑 BUG(KEY3/4 未赋值问题)

⏰ 时间分配

时段内容
上午 2hSysTick 原理、delay_us / delay_ms 实现
上午 2h用数组存密码序列、逐位收集输入
下午 2h密码验证逻辑 + LED 反馈效果
下午 2h练习 + BUG 修复讨论

🧩 核心知识点

SysTick 24位递减计数 SystemCoreClock delay_us / delay_ms 数组存密码序列 if-else if 完整赋值 状态机初步

✅ 课堂验收标准

下课前必须完成 ① delay_ms(1000) 实测约 1 秒(手表计时验证)
② 按正确密码序列 → LED 双闪后解锁
③ 按错误密码 → LED 长亮 2 秒提示错误
④ KEY1/2/3/4 的值被正确存入 arr[i](0/1/2/3)
⚠️ 必须修正的 BUG 原课程密码代码只赋值了 KEY1→0,KEY2→1,KEY3 和 KEY4 按下时 arr[i] 未赋值,相当于都是 0,导致密码混乱。本次必须用 if-else if 把 4 个键都赋值!
知识延伸 SysTick 是 Cortex-M 内核自带的,不属于 STM32 外设,所以不需要 RCC 时钟使能。它每隔 1/SystemCoreClock 秒计数一次。

✏️ 课堂练习 & 作业

基础
练习1:密码验证 — 实现 4 位密码锁(KEY1=0, KEY2=1, KEY3=2, KEY4=3),默认密码为 1-0-1-0,正确双闪解锁,错误长亮报错
基础
练习2:SysTick 测时 — 用 delay_ms(500) 实现精确 500ms 闪烁,并和 Day1 的软件 delay 对比,说出差异
进阶
练习3:密码修改功能 — 解锁成功后,再按 KEY4 进入"设置新密码"模式,输入 4 位新密码并保存(存入全局数组),实现动态修改密码
挑战
练习4:3次错误锁定 — 密码连续输错 3 次后,LED 快闪 5 次并进入锁定状态,锁定期间按任何键无效,等待 10 秒后自动解除锁定
Day 5 🎯 EXTI 外部中断 · NVIC 优先级 · volatile

📋 教学目标

  • 理解轮询(Polling)vs 中断(Interrupt)的本质区别
  • 掌握 NVIC 优先级组的正确配置方式
  • 掌握 EXTI 四步配置法(GPIO→映射→EXTI参数→NVIC)
  • 理解 ISR 编写规范:确认→清除→动作
  • 用 volatile 全局变量实现 ISR 与主循环的安全通信

⏰ 时间分配

时段内容
上午 2h中断概念、NVIC 优先级组讲解
上午 2hEXTI 四步配置手敲
下午 2hISR 编写、volatile 关键字讲解
下午 2h练习:中断驱动 LED,对比轮询方式

🧩 核心知识点

NVIC_PriorityGroupConfig SYSCFG_EXTILineConfig EXTI_Trigger_Falling EXTI_GetITStatus EXTI_ClearITPendingBit volatile uint8_t flag

✅ 课堂验收标准

下课前必须完成 ① 按 KEY1 触发 EXTI2 中断,LED1 翻转
② ISR 中正确清除中断标志(否则反复触发)
③ 主循环同时做其他事(如流水灯),按键打断后继续
④ 能解释:为什么 ISR 中的变量必须加 volatile?
⚠️ 修正原课程的错误 原版 EXTI 代码 ISR 里的动作代码全被注释掉了,中断没有任何效果!本次必须在 ISR 里加入 g_flag = 1,并在 main 循环中检测 flag 响应。
必须在 main() 最开头调用一次 NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2),配置抢占优先级和子优先级各占 2 位。整个程序只能调用一次,且必须在所有中断配置之前!

✏️ 课堂练习 & 作业

基础
练习1:中断翻转灯 — KEY1 接 EXTI2,按下时 LED1 翻转。主循环同时让 LED2 以 200ms 慢闪,观察 LED2 不受按键影响
基础
练习2:双边沿检测 — 改成同时检测上升沿和下降沿(EXTI_Trigger_Rising_Falling),按下点亮 LED1,松开熄灭 LED1,实现"按住亮"效果
进阶
练习3:中断计数 — 用中断统计 KEY1 被按了多少次,每按 4 次,LED 全部闪烁 2 次庆祝;次数用 printf 输出到串口(串口初始化可参考 Day6)
挑战
练习4:中断优先级实验 — 配置两个 EXTI(KEY1 和 KEY2),分别设置不同抢占优先级。在 KEY1 的 ISR 里加入 2 秒延时,观察 KEY2 能否打断 KEY1 的处理
Day 6 🎯 USART 串口通信 · printf 重定向 · 命令解析

📋 教学目标

  • 理解 UART 协议:波特率、数据位、停止位、校验位
  • 掌握 GPIO 复用模式(AF)配置,重定向 printf
  • 实现 USART1 中断接收,字符串缓冲区管理
  • 用 '.' 或 '\n' 作结束符实现命令帧解析
  • 串口发送 "LED1." / "LED2." 控制对应 LED

⏰ 时间分配

时段内容
上午 2hUART 协议讲解,GPIO 复用模式,printf 重定向
上午 2hUsart1_init() 手敲,串口助手联调
下午 2hUSART 中断接收,缓冲区字符串收集
下午 2h命令解析函数,串口控制 LED 练习

🧩 核心知识点

波特率 115200 GPIO_Mode_AF GPIO_PinAFConfig fputc 重定向 USART_IT_RXNE strcmp 命令解析 Use MicroLIB

✅ 课堂验收标准

下课前必须完成 ① 开机串口打印 "系统启动成功"
② 串口助手发送 "LED1." → LED1 翻转
③ 发送 "LED2." → LED2 翻转,发送 "ALL." → 4灯全翻
④ 发送错误命令 → 串口回复 "未知命令: xxx"
⚠️ 修正原课程错误 原课程 USART1_IRQHandler() 函数体为空,学生看不到接收处理逻辑!本次必须完整演示:收到字符存入缓冲区数组,遇到 '.' 后置零并设 cmd_ready=1,主循环调用 parse() 解析。
Keil 配置提醒 Options → Target → 勾选 Use MicroLIB,否则 printf 无法重定向。这是最容易忘记的一步!

✏️ 课堂练习 & 作业

基础
练习1:串口控制 LED — 发送 "LED1." "LED2." "LED3." "LED4." 分别翻转对应 LED;发送 "ALL." 翻转全部
基础
练习2:状态查询 — 发送 "STATUS." 后,串口返回当前 4 个 LED 的亮灭状态(如 "LED:1010" 表示1亮2灭3亮4灭)
进阶
练习3:串口密码 — 通过串口发送 "PWD:1010." 来解锁(密码正确 LED 双闪,错误单闪)。结合 Day4 的密码锁功能
挑战
练习4:帮助菜单 — 发送 "HELP." 后,串口打印所有支持的命令列表及说明(格式整齐美观,用 \t 对齐),体验"命令行界面"的感觉
Day 7 🎯 定时器 TIM6 · 非阻塞定时 · 中断驱动

📋 教学目标

  • 理解定时器三要素:PSC 预分频、ARR 自动重装、CNT 计数
  • 掌握中断频率计算公式(必背!)
  • 配置 TIM6 实现 1Hz(每秒一次)更新中断
  • 用定时器中断驱动 LED,主循环同时处理其他逻辑
  • 理解"非阻塞"设计的重要性

⏰ 时间分配

时段内容
上午 2h定时器原理、PSC/ARR 计算公式推导
上午 2hTIM6_init() 手敲,NVIC 配置
下午 2hTIM6_DAC_IRQHandler 编写,1Hz LED 验证
下午 2h练习:非阻塞多任务(定时器灯 + 串口同时工作)

🧩 核心知识点

TIM6 在 APB1(84MHz) 频率 = 84M÷(PSC+1)÷(ARR+1) TIM_IT_Update TIM_GetITStatus TIM_ClearITPendingBit 非阻塞设计思想

✅ 课堂验收标准

下课前必须完成 ① LED1 以精确 1Hz 翻转(串口打印计数验证)
② 主循环同时处理串口命令,两者互不干扰
③ 能推导:PSC=8399, ARR=9999 时的中断频率
⭐ 关键公式(必须记住)
中断频率 = TIM时钟 ÷ (PSC+1) ÷ (ARR+1)
TIM6 时钟:APB1 = 42MHz,但定时器时钟 × 2 = 84MHz
84,000,000 ÷ 8400 ÷ 10000 = 1 Hz
与 Day1 的对比 Day1 用 delay 实现 LED 闪烁,主循环被卡死。今天用定时器中断,LED 由硬件定时翻转,主循环可以自由处理其他事情——这就是"非阻塞"设计!

✏️ 课堂练习 & 作业

基础
练习1:精准 1Hz — TIM6 产生 1Hz 中断,每次中断翻转 LED1,同时串口打印 "秒数: X"
基础
练习2:改变频率 — 修改 PSC 或 ARR,让 LED 以 2Hz(每秒闪2次)或 0.5Hz(2秒闪1次)闪烁,验证公式正确
进阶
练习3:定时流水灯 — 每次定时器中断,流水灯前进一格(LED1→2→3→4→1→…),不用任何 delay,主循环同时响应串口命令
挑战
练习4:秒表功能 — 串口发送 "START." 启动秒表计时,每秒打印当前秒数;发送 "STOP." 暂停;发送 "RESET." 清零。结合 TIM6 中断和串口命令
Day 8 🎯 硬件 PWM · SG90 舵机控制 · 蜂鸣器 ⭐新增

📋 教学目标

  • 理解 PWM 的三要素:频率、占空比、脉冲宽度
  • 掌握 TIM3 PWM 输出模式(OC 输出比较)配置
  • 计算 50Hz 舵机 PWM 参数,用 CCR 值控制角度
  • 实现舵机 0°(关盖)和 180°(开盖)两个位置切换
  • 用 PWM 控制蜂鸣器频率实现报警音

⏰ 时间分配

时段内容
上午 2hPWM 原理、TIM 输出比较模式讲解
上午 2h舵机参数计算、Servo_init() 手敲
下午 2h舵机角度控制验证,调 CCR 值看舵机转动
下午 2h蜂鸣器 PWM 配置,练习

🧩 核心知识点

PWM 占空比 TIM_OCMode_PWM1 TIM_OC1Init TIM_SetCompare1(CCR) SG90 50Hz = 20ms CCR:500=0°,1500=90°,2500=180°

✅ 课堂验收标准

下课前必须完成 ① 舵机 Servo_open() → 转到 180°(开盖位置)
② 舵机 Servo_close() → 转回 0°(关盖位置)
③ 按 KEY1 开盖,按 KEY2 关盖,动作平滑
④ 蜂鸣器能发出报警音(按 KEY3 触发)
⚠️ 为什么不能用软件PWM控制舵机 原课程呼吸灯用 delay_us 循环模拟 PWM,这是软件 PWM,频率不准且阻塞 CPU。舵机 SG90 需要精确 50Hz(20ms周期),只有硬件 PWM 才能保证,否则舵机会抖动或不响应!
SG90 角度与 CCR 对照(必背)
参数:TIM3,PSC=83,ARR=19999,TIM时钟=1MHz
0°(关盖)→ CCR = 500(0.5ms)
90°(半开)→ CCR = 1500(1.5ms)
180°(全开)→ CCR = 2500(2.5ms)
⚠️ 实际值可能因舵机个体差异需微调 ±100

✏️ 课堂练习 & 作业

基础
练习1:开盖关盖 — KEY1 按下 → 舵机转到 180°(开盖),等待 3 秒后自动转回 0°(关盖)
基础
练习2:报警音 — 蜂鸣器以 2000Hz 响起(有节奏的"嘟嘟嘟"),可用 TIM4 PWM 或 GPIO 快速翻转实现
进阶
练习3:渐进开盖 — 舵机不是瞬间跳到 180°,而是从 0° 逐渐增加到 180°(每次加 10°,间隔 20ms),模拟真实桶盖缓慢打开的效果
进阶
练习4:串口控制舵机 — 串口发送 "OPEN." 开盖,"CLOSE." 关盖,"ANGLE:90." 转到指定角度,结合 Day6 串口命令解析实现
挑战
练习5:PWM 呼吸灯 — 用硬件 PWM(TIM3 另一个通道)实现 LED 呼吸灯效果,在定时器中断里每次微调 CCR 值,不用任何 delay
Day 9 🎯 传感器集成 · 状态机设计 · 完整项目实现 ⭐新增

📋 教学目标

  • 掌握 PIR 人体传感器(HC-SR501)的读取方式
  • 掌握 HC-SR04 超声波测距时序,实现距离读取
  • 理解超声波距离公式(距离 = 时间 / 58 cm)
  • 设计并实现三状态垃圾桶状态机
  • 联调所有模块,完成完整项目代码

⏰ 时间分配

时段内容
上午 2hPIR 传感器讲解接线,超声波时序讲解
上午 2hHC-SR04 驱动实现,距离测试验证
下午 3h状态机设计 + 系统集成联调
下午 1h功能测试、BUG 修复、串口输出完善

🧩 核心知识点

PIR 高电平=检测到人 TRIG ≥10μs 脉冲触发 ECHO 高电平时间 距离 = 时间(μs) / 58 enum 枚举定义状态 switch-case 状态机

🔄 三状态机设计

IDLE
空闲待机
呼吸灯
→ 检测到人
或 KEY1
OPEN
已开盖
LED全亮
OPEN 等待3秒 →
CHECK
关盖测距
→ 距离<5cm
FULL
满桶报警
蜂鸣器响
验收标准 ① PIR 检测到人 → 舵机自动开盖
② 3 秒后关盖,超声波测距
③ 距离 < 5cm → 蜂鸣器报警 + LED 闪烁
④ 满桶时 PIR 不再触发开盖
⑤ KEY3 清空确认 → 解除报警
⑥ 串口实时输出状态和距离数据

✏️ 课堂练习 & 作业

基础
练习1:超声波测距 — HC-SR04 每 500ms 测一次距离,用串口打印 "距离: XX cm",用手在传感器前遮挡验证数据变化
基础
练习2:PIR 触发 — PIR 传感器检测到人时 LED1 亮,无人时 LED1 灭;同时串口打印 "人体检测: 有人 / 无人"
进阶
练习3:联调状态机 — 完整实现三状态机:IDLE→OPEN(PIR触发)→CHECK(关盖测距)→IDLE 或 FULL,所有模块协同工作
挑战
练习4:串口实时面板 — 在状态机运行时,每 1 秒通过串口打印一次完整状态面板,格式如:
[状态:IDLE] [距离:12cm] [LED:呼吸灯] [蜂鸣器:OFF]
Day 10 🎤 项目答辩 · 功能演示 · 代码讲解

📋 答辩流程

准备就绪(答辩前)

接好线、烧录程序、串口助手打开,确认系统正常启动

功能演示(5 分钟)

现场逐项演示:人感开盖→超声波测距→满桶报警→按键手动控制→串口输出

代码讲解(5 分钟)

选 2~3 个核心模块,讲清初始化逻辑、关键参数含义、状态机设计

问答环节(5 分钟)

每位同学至少回答 1 个问题(见右侧常见问题准备)

⏰ 时间安排

时段内容
上午各组自由调试,老师巡回指导
下午 1~5 点按组顺序答辩(每组约 15 分钟)

🎯 评分标准(100分)

功能完整性40分
40分
代码质量25分
25分
演示效果20分
20分
个人答辩15分
15分
答辩前一晚必做清单 ☐ 代码编译无报错
☐ 所有功能在实物验证通过
☐ 串口波特率 115200,输出正常
☐ 每人能讲清自己负责的模块
☐ 准备好回答下方 5 道常见问题

🔧 硬件连接总表

接线原则按照此表接线,如果板子上的引脚标注和表中不同,以实际板子丝印为准。所有 GND 共地!
模块模块引脚STM32 引脚说明
LED × 4LED1 阳极PG14阴极接 GND,串 330Ω 限流电阻
LED2 阳极PG13
LED3 阳极PG6
LED4 阳极PG11
按键 × 4KEY1 一端PG2另一端接 GND,GPIO 配置上拉输入
KEY2 一端PG3
KEY3 一端PG4
KEY4 一端PG5
SG90 舵机棕色(GND)GND信号线接 TIM3_CH1 复用引脚
红色(VCC)5V
橙色(信号)PA6(TIM3_CH1)
HC-SR04 超声波VCC5V⚠️ ECHO 输出 5V,需分压到 3.3V(2KΩ+1KΩ)再接 STM32
GNDGND
TRIG(触发)PB9(输出)
ECHO(回波)PB10(输入)⚠️分压!
HC-SR501 PIRVCC5VGPIO 配置下拉输入,HIGH = 检测到人
GNDGND
OUT(信号)PB8(输入)
蜂鸣器正极(+)PB6(TIM4_CH1)无源蜂鸣器用 PWM;有源蜂鸣器直接 GPIO 高电平
负极(-)GND
USB-TTL 串口TX(模块发)PA10(USART1_RX)波特率 115200,TX/RX 交叉连接
RX(模块收)PA9(USART1_TX)
GNDGND

⚠️ 关键注意事项

HC-SR04 ECHO 引脚 5V 电压!必须通过分压电阻降至 3.3V 后才能接 STM32 GPIO,否则可能损坏芯片。分压方案:ECHO → 2KΩ → PB10,同时 PB10 通过 1KΩ 下拉到 GND。
舵机电流需求SG90 工作电流约 150~300mA,空载峰值可达 600mA。建议使用独立 5V 电源为舵机供电,与开发板共 GND 即可,不要用开发板的 5V 引脚直接驱动多个舵机。
所有模块共 GND不同电源的模块(5V 模块和 3.3V STM32)之间必须共地,否则信号无法正常传输。

📁 推荐工程文件结构

文件夹文件职责
User/main.c主程序,状态机逻辑
Drivers/LED.c / LED.hLED 驱动
KEY.c / KEY.h按键驱动
USART.c / USART.h串口驱动
SERVO.c / SERVO.h舵机 PWM 驱动
PIR.c / PIR.h人体传感器
HCSR04.c / HCSR04.h超声波驱动
System/delay.c / delay.hSysTick 延时
TIM.c / TIM.hTIM6 定时中断

🗑️ 项目功能需求说明

3~4 人小组 实物 + 代码展示 必须实现 ≥ 4 项基础功能
#功能涉及技术难度分值
1🧍 人体感应自动开盖PIR 传感器 + 舵机 PWM基础8分
2📏 超声波满桶检测HC-SR04 时序测距基础8分
3🔔 满桶蜂鸣器报警GPIO / PWM 蜂鸣器基础6分
4💡 LED 状态指示GPIO 输出,多种模式基础6分
5🎮 按键手动控制GPIO 输入 + 消抖基础6分
6📡 串口实时状态输出USART printf进阶8分
7🌬️ LED 呼吸灯空闲效果硬件 PWM / 软件模拟进阶6分
8⌨️ 串口命令控制 LED 模式USART 接收 + 字符串解析挑战6分
9⏱️ 定时器驱动 LED 动效TIM6 中断,非阻塞挑战6分
10🔒 满桶时禁止人感开盖状态机逻辑设计挑战6分

🔄 完整系统状态机说明

状态条件(进入)执行动作条件(退出)
IDLE 空闲系统启动 / 垃圾清空后LED 呼吸灯效果,等待事件检测到人 或 KEY1 手动
OPEN 已开盖PIR 检测到人 或 KEY1舵机转 180°,LED 全亮等待 3 秒后自动
CHECKING 检测中OPEN 状态 3 秒后舵机关盖,超声波测距测距完成后进入 IDLE 或 FULL
FULL 满桶超声波距离 < 5cm蜂鸣器报警,LED 快闪,锁定开盖KEY3 按下确认清空
注意:满桶状态下,即使 PIR 检测到人也不会开盖!只有按下 KEY3(清空确认键)才能解除满桶锁定,恢复正常工作。这个逻辑必须通过状态机变量来实现,不能只靠 if-else。

🎤 答辩要求 & 评分标准

📊 评分细则

维度分值评分细则
功能完整性40分基础功能每项 6~8 分,进阶每项 6~8 分,满分 40
代码质量25分模块化架构 10 分,命名规范 5 分,注释 5 分,无明显 BUG 5 分
演示效果20分功能稳定运行 10 分,串口输出清晰 5 分,接线整洁 5 分
个人答辩15分能讲清自己负责模块 10 分,回答老师提问 5 分

🗣️ 答辩常见问题(提前准备!)

Q1:为什么 GPIO 要配置为 AF 模式才能用 USART?
USART 外设直接驱动引脚,配置 AF 后控制权交给 USART,GPIO 普通输出无法实现串口时序。
Q2:TIM6 的中断频率怎么计算?PSC 和 ARR 是什么?
频率 = TIM时钟 ÷ (PSC+1) ÷ (ARR+1)。PSC 是预分频降频,ARR 是计满多少次触发一次中断。
Q3:ISR 里的变量为什么要加 volatile?
防止编译器把变量缓存在寄存器,导致主循环读不到 ISR 修改后的值。
Q4:HC-SR04 超声波距离怎么计算?为什么除以 58?
声速 340m/s = 0.034cm/μs,往返÷2,所以距离(cm) = 时间(μs) × 0.034 / 2 ≈ 时间/58。
Q5:舵机 SG90 为什么需要 50Hz PWM?CCR=1500 是多少度?
SG90 标准要求 20ms 周期(50Hz)。CCR=1500 代表 1.5ms 脉冲,对应 90° 中间位置。

💡 互动教学建议

🏆 提升参与感的方法

积分排行榜

每天设置抢答和最快完成练习积分,黑板实时更新排名,前 3 名给予实物奖励

每日"点灯挑战"(5分钟)

开课前 5 分钟出一道用已学知识修改代码的小任务,比赛谁先在板子上跑通,第一名得积分

"BUG 医生"环节

下午拿出一段故意写错的代码投影,让全班找 BUG,第一个找到的得分。培养主动看代码的习惯

串口截图晒成果

每实现一个功能,让学生把串口输出截图发到群里。老师点评,好的截图被展示,形成正向竞争

功能解锁任务卡

设计任务卡:LED → 按键 → USART → PWM → 传感器,每解锁一个打印一张"勋章卡"发给学生

📝 教师备课建议

先演示效果,再讲原理 每个新模块,先把完整程序下载到板子,让学生看到舵机转动、串口输出、LED 效果,再倒回来讲"这是怎么实现的"。有了目标感,理论课更专注。
代码分"框架版"和"完整版" 课前准备好空白框架(函数签名已写,函数体为空),上课时现场手敲填充。框架版让学生明确每步写什么,完整版课后发给学生参考。
Day 8 舵机调试放下午 舵机 CCR 值调整(0°/90°/180°)让学生自己改数值观察效果,这个过程极有成就感。预留充足时间让每个人都动手试。
答辩前晚开放实验室 答辩前一天晚上开放实验室 2 小时,学生自由调试,老师轮流巡回指导,大幅降低答辩当天翻车概率。
结对编程 + 互审代码 两人一组,一人口述逻辑一人打代码,每天换角色。下午增加 5 分钟互相 review 代码,找出对方一个可改进的地方。