这些小活动你都参加了吗?快来围观一下吧!>>
电子产品世界 » 论坛首页 » DIY与开源设计 » 电子DIY » 【EEPW-let's design】STM32F103RBT6(NUCLEO-

共1条 1/1 1 跳转至页

【EEPW-let's design】STM32F103RBT6(NUCLEO-F103RB)开发板评测:板载外设与串口实验

菜鸟
2026-11-03 12:43:56     打赏

NUCLEO-F103RB 评测:硬件接口与板载外设实测

F103 的开发板有很多,Nucleo-F103RB 吸引我的地方,是上面那半块 ST-LINK。给 MCU 下载程序、打断点、看串口日志,这些写代码时天天要做的事,一根 USB 线就接齐了。选开发板时,这一点在我心里的分量,比多焊几颗传感器还大。

这块板的设计取舍很明确:把下载、调试和串口观察放在 ST-LINK 这一侧,把完整的 MCU 引脚留给外部电路。它适合从 GPIO、串口开始,逐步加入定时器、DMA、SPI 和 RTOS,项目变复杂以后,原来的调试器和扩展接口仍然派得上用场。

这次我只接一根 USB 数据线,用板载 LED、USER 按键和虚拟串口写了一个综合实验:定时器控制闪烁,按键切换周期或暂停,电脑通过串口修改参数、读取运行统计。文章后半部分给出了实际下载记录、按键事件和定时采样结果,代码也一并保留。

front.jpg

板卡正面。上方的 Mini-B USB 接口属于 ST-LINK,中间的开槽把调试器和目标板分成了两个区域。

板卡布局与硬件组成

照片上能看到 NUCLEO-F103RB 的型号贴纸,PCB 标着 MB1136 rev C。上面是 ST-LINK/V2-1,下面是 STM32F103RB;蓝色的是 USER 按键,黑色的是 RESET。两侧排针里,靠内的一组采用 Arduino Uno V3 接口布局,外侧长长的双排针则是 ST morpho。

这种布局看一眼就能明白大概怎么用。还没接外设时,板上的 LED 和按键就能做输入输出实验;要接现成的扩展板,先看 Arduino 接口;需要更多引脚,再从 Morpho 引出来。主控周围没有挤满显示屏和传感器,杜邦线接上去以后,仍然比较容易找到自己用的引脚。

Nucleo-64 里的“64”对应目标 MCU 的引脚数。主控丝印分成两行,上面是 STM32F103R,下面接着 BT6,完整型号就是 STM32F103RBT6。

siyin.jpg

STM32F103RBT6,LQFP64 封装。F103 常见的外设,在这颗芯片上都能找到对应的练手机会。

把和日常开发有关的规格列出来,大致是这样:

项目STM32F103RB 的配置



内核、主频Arm Cortex-M3,最高 72 MHz
存储128 KB Flash、20 KB SRAM
模拟采样两个 12 位 ADC
串行通信三路 USART、两路 SPI、两路 I2C
其他接口USB Full Speed、CAN,以及多组定时器、PWM、DMA
板载开发工具ST-LINK/V2-1,支持 SWD 下载、调试和虚拟串口

这些资源可以组合成一个完整的小控制系统:定时器给出采样节拍,ADC 采集数据,DMA 负责搬运,USART 输出结果,再接上 SPI 屏幕或 I2C 传感器。各个外设之间的配合关系,在这块板上比较容易逐步验证。

ST-LINK/V2-1 功能与串口连接

在 Linux 下接入这块板时,系统识别到的 USB ID 是 0483:374B,产品名为 STM32 STLink,同时出现 /dev/ttyACM0 和卷标为 NOD_F103RB 的存储盘。调试、串口、存储三个接口,来自同一个 USB 复合设备。

sc0_device-plugin.png

连接 ST-LINK 的 USB 接口后,系统出现 NOD_F103RB 存储卷,里面有 DETAILS.TXT 和 MBED.HTM。

这里的存储盘其实是 ST-LINK 提供的编程入口,支持拖入编译好的 BIN 或 HEX 文件。它看起来像一个小 U 盘,但用途是把固件送进目标 MCU。卷容量约 156 KiB,里面的 DETAILS.TXT 显示固件版本 0221,构建时间为 2019 年 1 月 7 日。NOD_F103RB 只是这次枚举出的卷标,认板卡型号还是看 PCB 和贴纸更直接。

下载之外,板载调试器也适合用来定位程序问题。程序停在断点上以后,可以沿着调用过程单步走,查看变量、寄存器和内存。比如按键中断没有按预期触发,可以先确认中断函数有没有进来,再去查引脚、触发沿和中断配置,不必靠不停加延时来猜。

虚拟串口则负责程序运行时的观察。F103RB 在默认焊桥配置下,把 USART2 的 PA2、PA3 接到了 ST-LINK。打开串口终端,目标程序通过 USART2 发出的日志就能从同一根 USB 线送到电脑。

这两个引脚值得提前记住。很多 F103 工程用的是 USART1,发送和接收脚常写成 PA9、PA10;把那份代码原样搬过来,电脑虽然能看到 ST-LINK 串口,日志却不会自动从这里出来。工程使用 USART2 时,少接一个 USB 转串口模块,也少了一组 TX、RX 交叉接线。

Linux 下如果要给日志脚本固定设备名,还可以用之前生成的序列号路径:

/dev/serial/by-id/usb-STMicroelectronics_STM32_STLink_066CFF485753667187155936-if02

ttyACM0 的编号会随设备插拔变化,这种路径更适合放进自己的脚本里。

还有一个很容易混淆的地方:板上的 USB 插座连着 ST-LINK,目标 F103 自己的 USB 外设则使用 PA11、PA12。写 USB 键盘、鼠标或自定义设备时,需要为目标芯片另外处理 USB 接口电路。板载虚拟串口已经替普通日志做好了连接,开发目标 USB 功能时,再把两条链路分开看就很清楚。

用户 LED、按键与 GPIO 映射

F103 的入门项目通常从闪灯开始,这块板上对应的是 PA5 上的绿色 LD2。蓝色 USER 按键 B1 接 PC13,黑色 B2 则负责复位。三个名字对上以后,板上现成的输入输出就够写一个小程序了。

这次实验把它们放进了同一个程序:TIM2 控制 LD2,PC13 负责用户输入,USART2 接收命令并输出日志。按键处理和串口解析都在主循环里完成,中断只负责计时、翻转输出和搬运字节。

PA5 同时还对应 Arduino 接口的 D13,也可复用为 SPI1 的时钟脚。所以接 SPI 外设前,要记得检查原来的 LED 程序有没有继续操作它。类似的引脚共用关系,在开发板上看得见、查得到,很适合拿来熟悉 STM32 的复用配置。

工具方面,可以先用 STM32CubeIDE 配合 CubeMX 的图形配置建立工程,再顺着初始化代码去看时钟和外设寄存器。熟悉流程后,换成 Makefile、GCC 或其他编辑器也不难,板载 ST-LINK 的下载和调试方式不受影响。

定时器、按键与串口综合实验

实验配置与程序结构

实验使用前面这块 MB1136 rev C 板卡,保留默认跳线和焊桥连接,USB 线接板载 ST-LINK。电脑运行 Linux,通过 OpenOCD 下载,串口配置为 115200 bit/s、8N1、无流控。LED、按键和串口都使用板上的现成连接,不需要另接模块。

固件采用 C 和寄存器配置,不依赖 HAL 或 RTOS。主要功能如下:

功能实现方式



LED 闪烁TIM2 每半个周期触发一次更新中断,翻转 PA5
按键消抖主循环采样,输入连续稳定 20 ms 后确认变化
短按在 200、1000、2000 ms 三档完整周期之间切换
长按消抖后的按下时间达到 1000 ms,切换暂停或闪烁状态
串口交互USART2 中断收发,主循环按行解析命令
运行统计记录中断、按键事件、收发字节、队列溢出和错误计数

默认完整周期是 1000 ms,点亮和熄灭各约 500 ms。短按从当前档位切换到下一档,所以从默认状态开始,第一次短按会变为 2000 ms。长按触发后只产生一次事件,松开时不再补发短按。

串口接收队列为 256 字节,发送队列为 1024 字节,环形队列各保留一个空槽。中断里不做命令解析,也不等待一整行日志发完;队列满时记录丢字节数。主循环每轮最多处理 32 个接收字节,给按键采样留出执行机会:

void app_poll(void)
{
    button_poll();
    char ch;
    for (unsigned n = 0; n < 32u && hw_rx(&ch); ++n) {
        input(ch);
    }
}

这一轮处理结束后,主循环执行 WFI,等待 SysTick 或外设中断唤醒。TIM2 的中断优先级高于 EXTI、SysTick 和 USART2,LED 节拍不依赖串口命令的处理速度。

时钟与定时器配置

STM32F103RB 支持最高 72 MHz,本实验使用 64 MHz:内部 HSI 8 MHz 经二分频后,再由 PLL 倍频 16 倍。这样可以直接使用芯片内部时钟,不依赖板卡的 HSE、ST-LINK MCO 或相关焊桥接法。

AHB 为 64 MHz,APB1 为 32 MHz。由于 APB1 配置了分频,其定时器时钟倍频,TIM2 仍使用 64 MHz。预分频器 PSC=6399,计数频率就是 10 kHz,每个计数为 0.1 ms。

程序中的 period_ms 表示一次完整亮灭周期,每次中断只推进半个周期,因此自动重装载值为:

TIM2 计数频率 = 64000000 / (6399 + 1) = 10000 Hz
ARR = period_ms × 5 - 1

设置 1000 ms 时,ARR=4999,每 500 ms 更新一次。允许的完整周期范围是 20~10000 ms,且必须为偶数;最大 ARR=49999,在 TIM2 的 16 位计数范围内。修改周期时先停止定时器,更新 ARR 和计数器,通过 UG 装载配置,再清除更新标志及挂起中断,最后从 LED 点亮状态重新开始。

编译、下载与命令验证

工程源码、构建说明和测试用例已放在 GitHub 公开仓库。编译器使用 GNU Arm GCC 13.2.1,优化等级为 -Os,通过 Makefile 生成 ELF、BIN 和 HEX:

git clone https://github.com/NyaRu-Kiss/nucleo-f103rb-lab.git
cd nucleo-f103rb-lab
make -j2 all size
make test
make backup
make flash

下载前,我先用 ST-LINK 读取了原程序的全部 128 KiB 主 Flash。随后通过 OpenOCD 写入新固件、执行校验并复位,日志中的关键结果是:

** Programming Finished **
** Verify Started **
** Verified OK **
** Resetting Target **

sc1_makeFlash.png

下载终端截图:识别到 128 KiB Flash,写入后返回 Verified OK,随后复位运行程序。

打开控制台后,可以直接输入命令:

python3 tools/board_tool.py console

命令操作结果



status查看模式、周期、LED 输出状态和运行计数
period 200将完整亮灭周期设置为 200 ms
led on / led off停止闪烁,设置常亮或熄灭
led blink按当前周期恢复闪烁
stats reset清空统计,保留运行时间、周期和模式
help查看命令列表

除了正常设置,我也检查了错误输入。period 19、period 21、period 10002、负数、带字母的参数和过长数字均返回错误,原设置保持不变。20 ms 和 10000 ms 两个边界值可以正常接受。一行超过 63 个字符时,程序丢弃该行,换行后可以继续接收 status。

这些检查由配套脚本执行,正常使用不需要逐条手动输入:

python3 tools/board_tool.py verify

最终复测的 13 项检查全部通过,包括参数检查、超长行恢复、LED 命令状态、暂停后定时器停止计数,以及两档周期的计数与间隔检查。每次运行都保存原始串口日志和 JSON 报告,方便把终端输出与设备状态对起来。

定时统计与中断耗时

我分别设置 200 ms、1000 ms 完整周期,在每组采样前清空统计。设备记录的结果如下:

完整亮灭周期设备时基观察窗口TIM2 中断增量相邻中断间隔(最近/最小/最大)RX/TX 丢字节串口错误







200 ms1235 ms12100 / 100 / 100 ms0 / 00
1000 ms2235 ms4500 / 500 / 500 ms0 / 00

200 ms 档每 100 ms 翻转一次,1235 ms 的窗口内记录到 12 次中断;1000 ms 档每 500 ms 翻转一次,2235 ms 内记录到 4 次。观察窗口不一定从定时器更新沿开始,也不一定在更新沿结束,所以计数比较要留出一个中断的边界差异,不能只做除法后要求完全相等。

例如,200 ms 档采样结束时,status 中与本组实验有关的字段如下。这里从原始状态行摘取并分行显示:

period_ms=200 timer_irqs=12 edges=12
last_interval_ms=100 min_interval_ms=100 max_interval_ms=100
last_isr_cycles=90 min_isr_cycles=79 max_isr_cycles=90
rx_dropped=0 tx_dropped=0 uart_errors=0

edges 是中断内执行 LED 翻转的次数,这两组采样中都与中断数一致。间隔由 SysTick 的毫秒计数记录,与 TIM2 共用 HSI 时钟参考,反映的是固件内部定时是否吻合;绝对频率精度还取决于 HSI 本身的误差。

此外,我用 Cortex-M3 的 DWT 周期计数器记录了 TIM2 中断内一段代码的耗时,两组结果均为最小 79、最近及最大 90 个 CPU 周期。按标称 64 MHz 换算约为 1.23~1.41 μs,覆盖标志处理、间隔统计和 LED 翻转等取样范围内的操作。这个数值不包含完整的异常入栈、出栈及取样后的统计开销,因此不能直接当成完整中断响应时间。

实体按键与异常处理

实际短按蓝色 USER 后,状态记录为 presses=1 short=1 long=0 period_ms=2000 button_irqs=2,与默认 1000 ms 档切到 2000 ms 一致。button_irqs=2 对应这次操作记录到的原始边沿中断;应用层则只确认一次短按。

随后长按按键,串口收到:

EVENT button=long uptime_ms=188156 period_ms=1000 mode=paused

后续状态中,long=1、mode=paused、led=0,程序已经暂停定时翻转并关闭 LED 输出。这次长按恰好落在自动采样期间,采样窗口内的中断数少于预期,脚本也因此报出计数不匹配。停止按键操作后重新采样,两档定时检查都通过了。做计数测试时,需要把手动操作与自动采样分开,否则测到的会是操作前后两种状态的混合结果。

下面是另一次手动复测的终端截图,与前面的自动采样记录分开。先设置 200 ms 完整周期并查询状态,再设置 1000 ms、清空统计,依次操作短按和长按。短按将周期切到 2000 ms,随后长按暂停;最终状态为 short=1 long=1 mode=paused led=0。

sc2_runtime.png

手动复测截图:200 ms 档的最近、最小和最大中断间隔均为 100 ms;下方记录了短按切换周期、长按暂停及最终状态。计数随本次操作和等待时间变化。

串口初次连接还出现过一次输入错误,后续会话开始同步时也收到过 ERR line too long or invalid character。目前工具在连接后先发送空行,结束可能残留的半行输入,再开始正式命令检查。错误原因还没有定位,日志仍保留;清空统计后的两档定时采样中,UART 硬件错误和收发队列丢字节数均为零。

固件资源占用

这一版固件的链接结果如下:

项目占用占板载资源的比例




Flash4204 B约 3.21%
静态 SRAM1476 B约 7.21%
预留栈空间2048 B10%
RAM 链接预算合计3528 B约 17.23%

RAM 合计还包含 4 字节对齐空间。这里的 2 KiB 栈是链接脚本预留的预算,没有测量运行时栈峰值。默认 size 输出会把 .stack 算入 bss,因此看到 bss=3528 时,要结合分节结果解释,不能全部算成全局变量。

应用逻辑另外在电脑上通过了 44 项检查,串口工具通过了 11 项 Python 测试。它们覆盖命令解析、消抖状态机、计时回绕、串口分段读取和超时等情况;板上运行记录则用于确认实际下载、通信和外设行为。具体实现见 工程说明、应用逻辑、STM32 外设驱动、主机测试和串口工具。

做完这组实验,ST-LINK 的便利就比较具体了:下载、串口命令和运行日志都走同一根线,PA5、PC13 和 USART2 可以直接组成一个能交互、能查询状态的小程序。后面增加传感器或显示器时,可以继续沿用这套命令和统计接口。

MAX7219 点阵扩展示例

板载实验之后,还可以增加 MAX7219 驱动的 8×8 LED 点阵,在上面运行康威生命游戏。Electronut 的这个参考项目同时使用 HAL、C++ 和 FreeRTOS,适合继续研究通信、任务和显示的组织方式。下面的接法与任务代码用于说明扩展方案,本次板载实验运行的是上一节的寄存器工程。

生命游戏很适合这样的小显示器:每个格子只有亮和灭两种状态,下一代的状态由周围格子决定。程序持续计算,点阵上就能看到图案变化。它有实际的计算任务,也有可见的输出,比单独翻转一个 GPIO 更容易让人想继续改。

接口分配如下,SPI2 负责显示数据,USART2 留作输出日志:

NUCLEO-F103RB 引脚连接或用途



PB13 / SPI2_SCKMAX7219 CLK,串行时钟
PB15 / SPI2_MOSIMAX7219 DIN,显示数据输入
PB14 / GPIO 输出MAX7219 LOAD/CS,软件控制片选
GND与点阵电源共地
PA2、PA3 / USART2通过板载 ST-LINK 输出日志、接收命令

MAX7219 只接收数据,这里不需要 MISO,PB14 可以配置为普通 GPIO。点阵另用 5 V 供电;模块的输入电平要求也要核对,必要时在 STM32 与模块之间加电平转换。

软件里,一个任务翻转板载 LED,并发信号给生命游戏任务;后者平时等待信号,收到后推进一代状态,再把显示数据发给 MAX7219。计算和刷新由同一个任务按顺序完成,避免显示驱动读到只更新了一半的图像。

采用 CMSIS-RTOS v1 信号接口时,显示任务的结构可以简化为下面这样。代码为任务逻辑示意,省略外设初始化和驱动实现;节拍任务通过 osSignalSet(displayTaskHandle, 0x01) 触发一次更新。

void DisplayTask(void const *argument)
{
    for (;;) {
        osEvent event = osSignalWait(0x01, osWaitForever);
        if (event.status == osEventSignal) {
            conway_next_frame();       /* 计算下一代状态 */
            max7219_write_frame();     /* 通过 SPI2 更新显示 */
        }
    }
}

MAX7219 每条写入命令包含 1 字节寄存器地址和 1 字节数据。更新一幅 8×8 图像,需要依次写入 8 个显示数据寄存器,共发送 16 字节;每条命令发送前拉低 LOAD/CS,16 位数据发送完成后再拉高,锁存本次写入。驱动层按这个顺序组织后,应用层只需要提交图像缓冲区。

8×8 的亮灭状态一共只有 64 bit,用 8 字节就能表示一张图。如果分别保存当前状态和下一代状态,两份图像缓冲区合计 16 字节。任务栈、邻居计数等临时变量、驱动对象和 RTOS 内核还要另外占用内存,不能把图像大小当成整个工程的 RAM 占用。

这样的项目适合用来熟悉 F103RB 的进阶用法。入门时先用主循环把功能写出来,后面可以加中断、DMA,或者改成几个任务协作。硬件和调试器继续使用,注意力可以集中在程序本身。相关的完整代码也可以作为实现参考。

Arduino 与 ST morpho 扩展接口

3f2cf70811da0b105e0f0b5e58d3be57.jpg

板卡背面,贴纸标着 MB1136-F103RB-C05。排针焊点之间,还能看到不少用于调整信号连接的焊桥。

两套接口面向的使用方式不同:Arduino 布局方便利用现成扩展板,Morpho 则把更多芯片引脚交给开发者。F103RB 把这两种方式都留了下来。

刚开始可以接一块 I2C 传感器,通过虚拟串口看读数;想做得完整些,再接显示器、按键或存储器。等外围电路多起来,也可以做一块自己的转接板,把分散的杜邦线收起来。板子中间留得比较清爽,接口又分布在两侧,适合按项目需要一点点往上加东西。

Nucleo 系列共用的接口布局,也让扩展硬件比较容易复用。以后换另一款 Nucleo-64,已有的扩展板有机会继续用,只需重新核对该型号的引脚功能、电源和软件配置。对想接触不同 STM32 型号的人来说,这比每次都从散线接起舒服。

背面那些标着 SB 的小焊桥,也解释了这块板为什么能有几种不同的连接方式。例如 SB13、SB14 管着目标 MCU 与 ST-LINK 之间的串口连接,SB62、SB63 则关系到 PA2、PA3 是否连向扩展排针。平时不用动它们,等项目确实需要换接法时,手册里有图可查。

接 Arduino 扩展板时,电平也要一起看。F103 使用 3.3 V 逻辑,部分数字引脚具有 5 V 容忍能力,模拟输入等引脚仍要按数据手册的条件来接。默认接到 ST-LINK 的 USART2,也不等于已经接通了 Arduino 的 D0、D1。接口形状熟悉,具体信号还得按 F103RB 的图来认。

芯片内置 CAN 控制器,做总线实验时再加一颗 CAN 收发器即可。USB、CAN、SPI 屏幕这些功能,都可以从同一块板子上继续扩展,不必在点亮 LED 之后马上换硬件。

功耗测量与供电配置

板子中部有个标着 IDD 的 JP6,这个小跳线很值得认识。移除跳线、串入电流表,就可以测目标 MCU 的电流。开发板把这个位置留出来,比自己割线找测量点方便得多。

做电源预算时,可以先看数据手册给出的典型值。在 3.3 V、25 °C、外部 8 MHz 时钟经 PLL 倍频、HCLK 为 72 MHz 的条件下,STM32F103RB 的典型电流如下:

工作状态所有外设使能所有外设关闭




Run,代码从 Flash 运行36 mA27 mA
Sleep14.4 mA5.5 mA

表中 ADC 的模拟部分还需按每个 ADC 约 0.8 mA 另计。这些数字只对应 MCU,不是 USB 端整板电流;ST-LINK、指示灯、稳压器以及外接模块都有各自的消耗,JP6 正好把关注点收到了目标芯片这一侧。

按 Run 模式的 36 mA 算,3.3 V 下对应约 0.12 W 的 MCU 供电功率。这组参数适合估算电源容量;上面的实验使用 64 MHz HSI PLL,主循环还会进入 WFI,工作条件不同,不能直接套用为该程序的电流。要做电池项目,我会优先研究哪些时钟能关、什么时候能睡眠,再通过 JP6 比较改动前后的电流。

供电扩展也有章可循。JP1 断开时,USB 枚举后的板卡及扩展板总电流上限为 300 mA;JP1 接通对应 100 mA 配置。接小传感器可以按这个预算安排,电机、继电器或多块亮度较高的显示模块,则更适合规划独立供电。外接 VIN、5 V 或 3.3 V 时,需要选择相应跳线,别只看接口旁边有一个电压标记就往上接。

ST-LINK 外接调试与项目迁移

Nucleo 上下两部分之间的开槽挺有辨识度,但我更在意旁边的 CN2 和 CN4。CN2 的两个跳线接通时,ST-LINK 连着板载 MCU;取下这两个跳线,就可以从 CN4 把 SWD 引到另一块目标板上。复位信号和 SB12 的连接关系,也要随目标接法一起核对。

这样,Nucleo 的用途就能延续到自己画 PCB 之后。先在 F103RB 上把传感器驱动、串口协议和控制逻辑理顺,换成自己的板子以后,仍然能用这块 ST-LINK 下载和调试。目标硬件变了,熟悉的断点、变量窗口和下载工具还能继续用。

从开发板迁移到自制板时,软件通常不需要全部推倒重来。需要重新确认的是时钟来源、供电方式、复位电路和每个外设的引脚复用。比如 USART2 在 Nucleo 上已经接到 ST-LINK,换到自制板后就要决定它是接 USB 转串口、无线模块,还是改用另一组 USART。把这些差异集中在板级初始化文件里,驱动和业务代码就能保持独立。

这种迁移方式也适合验证通信协议。先在 Nucleo 上接传感器或执行器,把数据格式、超时和错误处理跑通,再换成自己的接口板,问题会更容易定位。遇到异常时,ST-LINK 仍然可以读取寄存器和内存,串口日志也能继续保留,调试工具不会因为换了 PCB 就中断。

这次只用板载资源,我已经完成了定时翻转、实体按键输入、串口交互和运行统计,工程的 Flash 占用为 4204 B。NUCLEO-F103RB 适合作为这类控制程序的开发起点:先把交互和调试接口搭好,再通过两侧排针接入项目外设。等程序迁移到自制 PCB,板上的 ST-LINK 还可以继续使用。

参考资料

文中涉及的板卡规格、接口连接和示例工程,可通过下面的资料继续查阅。





关键词: STM32F103RBT6     NUCLEO-F103    

共1条 1/1 1 跳转至页

回复

匿名不能发帖!请先 [ 登陆 注册 ]