FindStar星图计划:02 多路 LED 流水灯:位操作,以及直接写寄存器有多快

发布时间:2026/11/5 4:00:18
FindStar星图计划:02 多路 LED 流水灯:位操作,以及直接写寄存器有多快 星图计划 · C8T6 卷 02上一篇点亮一颗灯这一篇让我们来把多个灯跑起来上一篇只点亮一颗 LED代码四行。这一篇要点亮六颗让它们依次亮过去看起来像水在流。你大概会觉得这不就是把上一篇的代码复制六遍吗确实可以而且我第一版就是这么写的。12 行每颗灯两行写完手臂发酸但灯确实跑了。逻辑分析仪上六个通道依次错开周期 1.202 秒和理论值几乎一致。问题不在灯亮不亮。问题在于——第 7 颗灯的时候你打算怎么办先搞清楚这颗灯是高电平亮还是低电平亮上一篇有个让人别扭的地方PC13 是拉低才亮代码里写GPIO_PIN_RESET才是开。这一篇的代码反过来HAL_GPIO_WritePin(GPIOA,GPIO_PIN_0,GPIO_PIN_SET);//开SET才是开。同一块板子同样的 LED极性怎么反了不是代码写错了是接法不一样接法电流路径点亮条件典型场景阳极接 3.3V阴极接引脚3.3V → LED → 引脚 → 内部到地引脚输出低电平蓝色药丸板的板载 PC13引脚 → 限流电阻 → LED → 地引脚 → 电阻 → LED → 地引脚输出高电平自己外接的 LED所以每次换硬件第一件事不是写代码是确认极性。判断方法很简单CubeMX 里把初始电平设成LOW下载后如果上电就亮说明是低电平点亮如果上电全灭、写SET才亮就是高电平点亮。这篇用 PA0–PA5 接六颗 LED高电平点亮每颗串一个 330Ω 限流电阻。顺便算一下电流红色 LED 正向压降约 1.9V(3.3−1.9)/330 ≈ 4.2mA。六颗全亮 25mA对 STM32 来说很安全。如果你图省事不接电阻或者用 100Ω六颗加起来可能超过 100mA那就不是能不能亮的问题是能亮多久的问题了。CubeMX 配置工具链和上一篇一样CubeMX HAL只有 GPIO 部分变了所以只列会出错的项位置配置项值说明SYS → DebugDebugSerial Wire不配这项第二次下载就失联PinoutPA0–PA5GPIO_Output六颗灯GPIOGPIO output levelLow上电全灭避免一上电就闪一下GPIOGPIO modeOutput Push Pull推挽能主动输出高低电平GPIOMaximum output speedLow驱动 LED 用最低档就够边沿慢一点反而干扰小让我们先看看效果吧这是纯 GPIO 的项目丢进 Proteus 跑一遍最快——GPIO 的仿真模型是可靠的等到后面的 CAN、USB 就不是了它能在半分钟内告诉你逻辑到底写没写错同一时刻只有一颗亮六颗轮流过去和预期一致。第一版老老实实复制六遍while(1){/* USER CODE BEGIN 3 */// LED1 开和关HAL_GPIO_WritePin(GPIOA,GPIO_PIN_0,GPIO_PIN_SET);HAL_Delay(200);HAL_GPIO_WritePin(GPIOA,GPIO_PIN_0,GPIO_PIN_RESET);// LED2 开和关HAL_GPIO_WritePin(GPIOA,GPIO_PIN_1,GPIO_PIN_SET);HAL_Delay(200);HAL_GPIO_WritePin(GPIOA,GPIO_PIN_1,GPIO_PIN_RESET);// ...LED3 到 LED6 同理}十二行六组每组只差一个数字。让我们上逻辑分析仪六个通道依次错开 200ms单个通道脉宽 W 0.2004 s周期 T 1.202 s频率 f 0.8321 Hz理论值每颗亮 200ms六颗轮一遍 1.2s频率 0.8333Hz。实测差 2ms这 2ms 就是六次函数调用和六次HAL_Delay的累积。灯是对的代码是脏的。第二版一行管一颗把重复的部分交给循环把第几颗交给位移while(1){/* USER CODE BEGIN 3 */for(inti0;i6;i){HAL_GPIO_WritePin(GPIOA,(uint16_t)(1ui),GPIO_PIN_SET);HAL_Delay(200);HAL_GPIO_WritePin(GPIOA,(uint16_t)(1ui),GPIO_PIN_RESET);}}代码从 12 行变成 5 行而且第 7 颗灯只需要把6改成7。关键是这个1u ii二进制十六进制对应引脚00000 00010x0001PA010000 00100x0002PA120000 01000x0004PA250010 00000x0020PA5所谓点亮第 i 颗灯在硬件层面就是把一个 1 挪到第 i 位。HAL 库里所有GPIO_PIN_x宏本质上就是这些数的别名——GPIO_PIN_0是0x0001GPIO_PIN_5是0x0020。所以1u i和GPIO_PIN_0~5完全等价只是前者能算出来。那个u不能省。写成1 i时1是int有符号。这里i最大是 5不会出事但如果你写1 31在有符号整数上左移到符号位是未定义行为不同编译器给你不同结果。养成写1u的习惯成本是一个字符。读数W 0.2sT 1.2sf 0.8333Hz。比第一版短了 2ms。这 2ms 是性能提升吗不是。在这个量程的逻辑分析仪上2ms 大概是一个像素宽——那是我用鼠标放光标的手抖。第三版直接写寄存器HAL 库写得再顺本质还是函数调用。想跳过中间层就直接改ODR寄存器uint8_tpattern0x01;// 注意必须在 while 外面初始化while(1){/* USER CODE BEGIN 3 */GPIOA-ODR(GPIOA-ODR0xFFC0)|(pattern0x3F);HAL_Delay(200);pattern((pattern1)|(pattern5))0x3F;// 6 位循环左移}这段只有三行但每一处都值得看 0x3F—— 0x3F 是0011 1111正好覆盖 PA0–PA5 六位。pattern 0x3F—— 保证写进去的只有低六位。GPIOA-ODR 0xFFC0—— 这一项最容易漏。ODR 是 16 位寄存器管着 PA0–PA15。如果你直接写GPIOA-ODR patternPA6–PA15 会被全部清零。今天这六个引脚没接东西看不出问题等你哪天在 PA8 上接了蜂鸣器就会发现流水灯一跑蜂鸣器就哑了然后花一晚上找原因。(pattern 1) | (pattern 5)—— 六位循环左移。 1把整体左移最高位bit5被挤出去 5把那个 bit5 捡回来放到 bit0。两次操作拼起来正好转一圈。读数还是 W 0.2sT 1.2s。三张图放在一起肉眼几乎找不出区别。所以直接写寄存器到底快多少答案是这个项目里测不出来。算一下就明白72MHz 主频一个时钟周期约 13.9ns。一次HAL_GPIO_WritePin包含函数调用、参数入栈、if/else分支判断、写 BSRR大约十几个到几十个周期算它 0.3µs。顺带说明库函数里那句assert_param在默认配置下是空宏不产生任何指令——它只在打开USE_FULL_ASSERT时才真正检查参数。六个 LED 一轮HAL 版比直写版多花的时间量级在1–2µs。而一个周期是1.2s。1.2 秒里有 2 微秒占比 0.00017%。逻辑分析仪 6 秒量程、屏幕一千像素宽一像素约等于 6 毫秒。这点差异连一个像素的万分之三都不到。所以网上那些直写寄存器快 10 倍的说法在你现在这个场景里是完全正确的废话——快 10 倍的确实是一个 0.3µs 的操作但你的瓶颈是HAL_Delay(200)它才是那 200,000µs。那什么时候这种差异会咬人场景时序要求为什么 HAL 版本会出问题WS2812 灯带0.4µs 与 0.8µs 区分 0 和 1函数调用开销正好在这个量级时序直接跑飞软件 SPI 刷屏SCK 周期几微秒每个边沿都走一次函数调用刷新率被拖垮软件 PWM 调光中断里翻转引脚中断服务函数里每一微秒都要抢到这三个场景函数调用从无关紧要变成主要矛盾。那时候不是优化是不这么做根本做不出来。所以这一篇真正的收获不是寄存器更快而是你知道有这么一条路并且知道它什么时候才值得走。在 200ms 的尺度上纠结那几个时钟周期是典型的过早优化。踩过的坑1.pattern没有初始化第一版直写寄存器的代码里如果漏了初始化那么上电第一帧是随机图案——这是因为pattern是局部变量初值来自栈上的残留数据。必须在while外面写uint8_t pattern 0x01;。2.PA2 / PA3 可能与串口打架Blue Pill 上 USART2 的 TX 是 PA2、RX 是 PA3正好落在这六个引脚里。这一篇还没用串口所以没事但如果你的 CubeMX 工程里提前开了 USART2PA2/PA3 会被外设占用LED 就不受你控制。遇到这两颗灯怎么都不亮先去看 Pinout 视图里这两个脚是不是变绿了。下一步灯会跑了但它只会自己跑——你没有任何办法在中途改变它。下一篇03 按键控制 LED解决这件事让板子第一次听见你的操作。听起来简单但按键是嵌入式里第一个真正会骗人的东西——你按下一次它可能报好几次。星图计划 · C8T6 卷 · FindStar 寻星工作室 · 基于 STM32F103C8T6 最小系统板工具链为 STM32CubeMX HAL 库所有代码与波形均在实机上验证。

关于本文作者

来自尧图内容编辑团队

尧图内容编辑团队 内容团队

尧图内容编辑团队

本文由尧图网络内容编辑团队执笔。团队由资深项目经理、前端工程师与设计师组成,所有内容均来自亲手交付的真实项目,先讲清问题、再给出可落地的解法。尧图深耕北京网站建设十年,服务过京华建材集团、智造科技等各行业客户,把一线经验沉淀为可复用的行业观察。

  • 十年建站经验,覆盖建材、制造、服务、文创等
  • 项目经理把关选题与事实准确性
  • 工程师与设计师联合撰写专业细节
  • 统一编辑规范,保证文风与排版一致
  • 每月复盘转化数据,迭代选题方向

延伸阅读

相关资讯与近期热门内容

深度阅读推荐

建站决策前值得细读的三篇

网站改版的5个关键决策
2024-08-12

网站改版的5个关键决策

什么时候该改版、改到什么程度、如何避免流量掉光,京华建材集团改版复盘给出答案。

获取专属建站方案

看完文章,把您的行业与预算告诉我们,免费获取一份量身定制的官网建设方案与报价。

立即免费咨询