
简介天津理工大学嵌入式实验报告2是一份面向嵌入式系统课程实验二嵌入式硬件接口实验的完整报告资源适用于需要完成Linux环境下I2C总线控制、Raspberry Pi开发板温湿度读取任务的高校学生。报告围绕实验目的、内容、步骤和考核标准展开详细涉及GCC编译、main.c/temperature.c/humidity.c模块化程序设计、LPS25H气压读取选做部分并记录了实验过程中遇到的gedit安装问题及解决思路能够为同类实验提供直接参考。资源包内共1个docx文件整体大小约955KB内容结构清晰包含实验考核表、实验报告正文、带注释的源代码和运行结果展示。目前已有544人学习下载适合嵌入式系统初学者或需要借鉴温湿度传感器编程思路的读者使用。1. 嵌入式实验报告2 考察的不是跑通而是讲清外设时序嵌入式的第二份实验通常不再满足于“点灯”LED 要由 delay 函数改用定时器中断按键要从轮询改成边沿触发调试信息要依赖 UART 的波特率、停止位和数据位。嵌入式实验报告2 的考察点是你能不能把芯片从“上电就跑”升级到“按外设时序工作”并在报告中回答时钟树怎么配、中断服务函数耗时多少、波特率误差来自哪里这类具体问题。天津理工大学嵌入式课程在这个阶段普遍使用 STM32F103 或 STM32F407 教学板配套 STM32CubeMX 与 Keil MDK 完成实验。下面直接按环境与工程模板、外设实验、数据采集、报告写作四个环节展开这份路径同样适用于嵌入式入门、嵌入式面试准备和蓝桥杯嵌入式备考。2. 嵌入式实验环境搭建与最小工程模板2.1 嵌入式开发用 HAL、LL 还是寄存器实验报告在“实验原理”部分放什么往往能直接看出你有没有真跑过代码。官方例程里大多是 HAL 库写法但照抄例程改几个引脚很难解释清楚为什么串口能发第一个字节、第二个字节却乱码。我一般建议开发方式这样选工程骨架用 STM32CubeMX 生成业务代码用 HAL 库原理分析用寄存器语言描述。例如写“TIM2-PSC 7199把 72 MHz 计数时钟分频到 10 kHz”就比贴一整段 htim2.Init 结构体更有信息量。不要把三种方式混在一个实验里。HAL 和 LL 混用虽然能编译但报告只能挑一种讲否则答辩时你自己都会绕进去。选型可以按实验目的来对照开发方式使用时机报告需要展示的内容容易踩的坑HAL 库课程实验、快速出效果初始化结构体、中断回调回调里忘记重新启动 UART 接收LL 库对时序敏感的驱动实验外设时钟使能、寄存器位操作漏使能 RCC 对应外设时钟直接寄存器解释底层原理、准备嵌入式面试外设基地址、中断向量不看参考手册导致位定义错误实验报告建议只写两种一种是你实际用的一种是你在原理分析里用来解释的。比如用 HAL 实现实验但在“实验原理”里写清 GPIOA 的 CRL/CRH 寄存器中第 0~3 位决定 PA0 的输入模式这属于嵌入式开发基本功不算冗余。2.2 STM32CubeMX 的最小工程配置与时钟树检查新建 CubeMX 工程时不要急着加外设按顺序检查四类配置调试接口、时钟源、GPIO、串口。调试接口选 Serial Wire选 JTAG 会占用 PA13~PA15 和 PB3/PB4几个常用引脚直接不能用。时钟源优先选外部晶振 HSE如果板子上没有晶振再退回 HSI但 72 MHz 主频的 STM32F103 必须通过 HSE 加 PLL 得到HSI 只能跑到 64 MHz 附近。CubeMX 的 Clock Configuration 页面生成之后记住三个值HCLK72 MHz、PCLK136 MHz、PCLK272 MHz。特别注意 STM32F1 的 APB1 预分频系数大于 1 时定时器时钟自动翻倍成 72 MHz这个翻倍规则写错后面定时器溢出时间就全错了。工程生成时可以选择 Toolchain我这里常用 Makefile原因是在报告里能展示完整的编译烧录命令而不必依赖图形界面。代码编译完成后最常用的烧录指令是STM32_Programmer_CLI.exe -c portSWD modeUR -w build/experiment2.bin -v -rstportSWD指定调试协议-w写入固件-v烧录后校验-rst复位运行。如果烧录后没现象先查 BOOT0 跳线是否拉高再把 SWD 引脚是否被重新映射为 GPIO 查一遍最后检查 HAL_MspInit 里对应外设的 GPIO 时钟有没有使能。按这个顺序排查大多数“烧录失败”都不是固件问题。嵌入式硬件上还有一个容易被忽略的点板载 ST-Link 和串口共用一块 USB 转接芯片时插上 USB 后先确认设备管理器里枚举出来的是什么设备枚举错了会报连接失败。2.3 main.c 初始化顺序与工程模板骨架嵌入式的裸机工程里初始化顺序本身就是一种规范。实验代码的 main 函数应该遵循固定顺序HAL_Init 先启动 SysTick 与 Flash 预取SystemClock_Config 配置 PLL 和总线分频MX_GPIO_Init 开 GPIO 时钟并设置引脚方向MX_TIM_Init 和 MX_USART1_UART_Init 再初始化定时器和串口最后启动中断并在 while(1) 里处理业务。定时器初始化放在串口前面还是后面没有绝对要求但必须放在 SystemClock_Config 之后因为定时器预分频值依赖总线时钟频率。一个典型的最小模板如下int main(void) { HAL_Init(); SystemClock_Config(); MX_GPIO_Init(); MX_TIM2_Init(); MX_USART1_UART_Init(); __HAL_UART_ENABLE_IT(huart1, UART_IT_RXNE); /* 打开发送接收中断 */ HAL_TIM_Base_Start_IT(htim2); /* 定时器中断开始 */ while (1) { if (uart_rx_flag) { uart_rx_flag 0; /* 主循环消费串口收到的字节 */ } } }这段代码里有两个容易被新手忽略的设计一是 __HAL_UART_ENABLE_IT 之后外设的 RXNE 事件只要发生就会进入中断无需在循环里反复开启接收二是 HAL_TIM_Base_Start_IT 只调用一次定时中断在后台持续触发。如果实验报告能声明“定时器中断在主循环外独立运行主循环只做非实时任务”后面的分析和代码可读性都会高很多。2.4 实验目录与报告素材的对应关系建议建一个固定目录把实验与报告素材分开。工程源码放 src日志放 logs截图放 captures报告正文引用相对路径避免交报告时找不到原始图片。工程里只保留必要文件CubeMX 自动生成的 Debug 目录和 build 目录不要提交压缩包体积会从几十 MB 变小到几百 KB。嵌入式实验报告常见的扣分项就是“源码能编译但没给 clear 步骤”或者“截图时间与源码修改时间对不上”目录结构规范一点这些都不是问题。3. 嵌入式实验核心外设实验GPIO 消抖、定时器中断与串口回显3.1 按键输入轮询消抖与外部中断的选择按键几乎出现在每份嵌入式实验报告里。常见要求是“按键按一下LED 翻转一次”。直接写判断加翻转运行时会出现按一次闪两下的情况这就是按键抖动。抖动时间通常在 5~10 ms 区间最简单的处理是延时跳过这个区间再判断一次if (HAL_GPIO_ReadPin(GPIOA, GPIO_PIN_0) GPIO_PIN_RESET) { HAL_Delay(20); /* 等待抖动结束 */ if (HAL_GPIO_ReadPin(GPIOA, GPIO_PIN_0) GPIO_PIN_RESET) { HAL_GPIO_TogglePin(GPIOC, GPIO_PIN_13); while (HAL_GPIO_ReadPin(GPIOA, GPIO_PIN_0) GPIO_PIN_RESET); } }20 ms 是经验值来自于机械按键的典型抖动区间。HAL_Delay 在主循环里用没问题但如果在外部中断服务里调用 HAL_Delay 就会卡死因为 HAL_Delay 依赖 SysTick 中断SysTick 优先级若低于当前中断计数器永远不更新。嵌入式面试真题里经常出现这一题实验报告里顺带写一句说明会显得有体系。外部中断方案要分清触发边沿。板载按键一端接 GND、另一端接 MCU 引脚时用 GPIO_MODE_IT_FALLING一端接 VCC 时用 GPIO_MODE_IT_RISING。大部分教学板用前者。中断回调里应只做标记void HAL_GPIO_EXTI_Callback(uint16_t GPIO_Pin) { if (GPIO_Pin GPIO_PIN_0) { key_flag 1; /* 只置标志 */ key_tick HAL_GetTick(); } }主循环检测到 key_flag 后再处理按键业务这种“中断置位、主循环处理”的模型比在中断里直接翻转 LED 更规范。原因有两个一是中断服务函数里做耗时操作会拉高整个系统的中断延迟二是如果同时有定时器中断在前嵌套处理容易丢状态。3.2 定时器中断实验PSC 与 ARR 的溢出时间计算定时器实验的目标通常是把延时改成定时器中断来实现 LED 闪烁。以 STM32F103 主频 72 MHz、TIM2 挂在 APB1 上为例APB1 分频为 2定时器内部自动倍频所以 TIM2 输入时钟是 72 MHz。想得到 1 s 溢出周期设 PSC7199、ARR9999htim2.Init.Prescaler 7199; /* 72 MHz / 7200 10 kHz */ htim2.Init.Period 9999; /* 10 kHz 下计 10000 次 1.0 s */ htim2.Init.CounterMode TIM_COUNTERMODE_UP; htim2.Init.AutoReloadPreload TIM_AUTORELOAD_PRELOAD_ENABLE;溢出周期 T (PSC1) × (ARR1) / f_TIM。代入后是 7200×10000/72 MHz 1.0 s。这个公式必须写进报告并把 f_TIM 的来源讲清楚PCLK1 是 36 MHz但 STM32 参考手册写明 APB1 预分频系数不为 1 时定时器时钟是 APB1 的两倍。把这个计算放进实验报告是区分“照抄例程”和“理解时序”的关键一步。配置好后要启动定时器中断并实现溢出回调HAL_TIM_Base_Start_IT(htim2); /* 使能 TIM2 更新中断 */ void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim) { if (htim-Instance TIM2) { HAL_GPIO_TogglePin(GPIOC, GPIO_PIN_13); } }注意回调里用 htim-Instance 判断是哪个定时器不要在回调里再次调用启动函数。HAL 库中所有定时器中断共用同一个回调函数如果后续加了 TIM3就加 else if 分支。报告里展示回调写法说明你对 HAL 库的中断分发机制已经有了基本认识。3.3 串口回环实验printf 重定向与中断接收串口实验的要求一般是“单片机收到什么就回发什么”同时把数据通过调试串口输出到 PC。先做 printf 重定向这样后续调试可以直接用 printf#include stdio.h int fputc(int ch, FILE *f) { HAL_UART_Transmit(huart1, (uint8_t *)ch, 1, 100); /* 100 ms 超时 */ return ch; }在裸机工程里printf 最终会调用 fputc 输出单个字符把它重定向到 UART 发送就可以用 printf 打印变量。注意超时参数不要给 HAL_MAX_DELAY给固定 100 ms避免发送阻塞时程序一直卡在那里。串口接收部分使用单字节中断接收static uint8_t rx_byte; void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart) { if (huart-Instance USART1) { HAL_UART_Transmit(huart1, rx_byte, 1, 100); /* 回显 */ HAL_UART_Receive_IT(huart1, rx_byte, 1); /* 续接 */ } }HAL_UART_Receive_IT 的行为是“启动一次接收接收完成进回调”。所以回调里回显后必须再次调用否则只收第一个字节。很多实验在这里出错程序跑起来只能回显一次。如果做多字节收发建议维护一个环形缓冲区中断里只把字节放入缓冲区并更新索引主循环再从缓冲区取字节处理。嵌入式开发里这就是典型的“生产者-消费者”模型报告里提一句是明显加分项。3.4 NVIC 优先级分配与中断嵌套边界三个外设实验同时跑起来之后优先级分配就变得关键。实验里一般只涉及 SysTick、EXTI0、TIM2、USART1 四个中断源需要明确谁抢占谁。建议按下面的优先级布局中断源抢占优先级子优先级说明SysTick00HAL_Delay 依赖优先级最高USART1 全局中断10串口接收尽量及时响应TIM2 全局中断20允许延迟几个 msEXTI030按键消抖后响应即可优先级的组合由 HAL_NVIC_SetPriorityGrouping 决定STM32 默认使用 NVIC_PRIORITYGROUP_4只有抢占优先级没有子优先级。如果把 SysTick 配置成最低优先级某个高优先级中断里调用 HAL_GetTick 或 HAL_Delay 就会死锁。这个表直接写进报告会显得实验设计在时序上是有考虑的。4. 嵌入式实验数据采集与误差分析把现象变成可复现数据4.1 用示波器和逻辑分析仪记录 GPIO 波形实验报告里只写“LED 闪烁正常”没有说服力。嵌入式硬件实验需要把你观测到的具体波形、周期值放进去读者才能复现。以定时器溢出实验为例用示波器直接夹 LED 引脚时基设 200 ms/div量两次翻转之间的时间差然后记录成表格。逻辑分析仪也可以采样率设到信号频率的 4 倍以上即可1 Hz 翻转信号用 1 MHz 采样完全够用。关键是夹地不要接到 3.3 V 引脚逻辑分析仪地线接开发板 GND信号线接被测引脚。建议以测量表的形式记录原始数据测量对象理论值实测值相对误差工具LED 翻转周期1.000 s0.997 s0.3%示波器 time 档 200 msUART 单 bit 宽度8.68 us8.71 us0.35%逻辑分析仪按键消抖总延时大于 20 ms约 23 ms手动延时 20 ms示波器触发把表格放到“实验数据”小节比一句“跑通了”强很多。记录里要写明探头接的引脚比如“示波器接 PC13 与 GND”。不同开发板的 LED 引脚不同标注清楚答辩时不会被问住。4.2 UART 波特率误差与纠错思路波特率误差是串口实验里最自然的数据分析点。115200 波特率下每一位宽度是 8.68 µs。用逻辑分析仪抓取 0x550x55 的二进制是 01010101起始位加上 8 个数据位在波形上是 8 个稳定宽度。量一个 bit 的实际宽度反推实际波特率为 1 除以实测单 bit 时间。如果实测位宽为 8.71 µs实际波特率约 114810误差 0.34%低于 UART 通信一般要求的 2% 误差线。如果误差超过 2%优先检查时钟源是否从 HSI 切换到 HSE。HSI 的出厂误差可能到 1%~3%且受温度影响高波特率连续收发会出现偶发错帧。这也是嵌入式开发中常问的面试题为什么 9600 波特率稳定改成 115200 就乱码答案就是两端时钟误差被放大了。报告里把两种配置下的位宽测量并排对比是很有说服力的分析。4.3 用 Python 记录长时串口数据与时间戳有些实验需要统计定时器中断溢出 N 次的总耗时或者验证串口长时间收发是否丢包。手工记录不可取串口助手自带的时间戳精度也不够。用 pyserial 记录时间戳是常见做法import serial import time ser serial.Serial(COM8, 115200, timeout0.1) start time.perf_counter() count 0 with open(uart_log.csv, w, encodingutf-8) as fp: while count 100: data ser.read(16) if data: count len(data) elapsed time.perf_counter() - start fp.write(f{elapsed:.6f},{data.hex()}\n) print(freceived {count} bytes in {time.perf_counter() - start:.3f}s) ser.close()time.perf_counter 在 Windows 和 Linux 上都提供高精度计时timeout 设为 0.1 s 是为了在没有数据时不阻塞。日志文件前三行可以作为原始数据贴进报告附录。这个脚本属于上位机PC 的系统调度会影响时间戳精度所以只用来验证长时间收发不参与核定时序本身。4.4 从 STM32 参考手册核对中断向量与寄存器位数据分析和排错时查参考手册比在网上搜零散答案可靠。中断向量表里 EXTI0_IRQn 和 TIM2_IRQn 的编号顺序影响 NVIC 优先级配置如果实验用到多个中断优先级分组要在 NVIC 初始化时一次性确定。参考手册的 RCC 章节会写明 GPIOA 时钟挂在 APB2ENR 的第 2 位USART1 也在 APB2 上而 USART2 和 TIM2 在 APB1 上。遇到“外设初始化看起来没问题却不工作”时先查 RCC 对应位是否使能。把寄存器位查证过程作为排错分支写进实验报告体现的是嵌入式开发的硬底子。5. 嵌入式实验报告写作结构编排、数据呈现与答辩要点5.1 报告结构按工程闭环组织实验报告建议分成七段实验目的、实验环境、实验原理、实验内容与步骤、实验现象与数据记录、结果分析、源代码附录。实验环境里不要只写“STM32 开发板”要写清芯片型号、主频、下载方式、编译器和库版本实验原理部分放时钟树和中断优先级表数据记录部分放波形截图和测量表结果分析回答“理论值怎么来的实测误差为什么是这样”。实验数据和源码修改时间要对得上避免答辩现场跑出的数据与报告不一致。5.2 答辩常见的三个嵌入式面试高频追问答辩时基本会围绕这几个问题追问中断服务函数里能不能调用 HAL_Delay串口回调里为什么还要重新启动接收定时器溢出公式里的 f_TIM 是从哪个寄存器得到的。这三个问题的答案都在前面实验里。把实验跑完只是完成了 60%把三个为什么写进报告才能拿到比较好的答辩评价。提示如果平时习惯用 VSCode 开发嵌入式可以把 Cortex-Debug 插件配置好这样在实验记录中可以同时提供寄存器和时序事件的快照比纯看串口日志更可靠。5.3 加分设计核心是“让别人能照着复现”最后的加分技巧是让报告可以被复现。附录里同时放固件版本号、串口日志的前 20 行和一张最小验证表标记每个实验条件的理论预期、实测现象和对应测量位置。定时器溢出时间、按键消抖延时、串口波特率误差这三组数据一定要实测并填写不要编。嵌入式实验报告2 本身就是一套待验证的系统开发板是运行环境代码是产物日志是输出报告是回放依据。下一步无论准备蓝桥杯嵌入式省赛、转向嵌入式 Linux 还是继续深入裸机驱动开发这套“跑通 → 记录 → 查表 → 回放”的习惯都能直接平移过去。本文还有配套的精品资源点击获取