news 2026/8/19 3:05:05

利用STM32与视觉暂留效应,将旧风扇改造为悬浮时钟的完整实践

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
利用STM32与视觉暂留效应,将旧风扇改造为悬浮时钟的完整实践

1. 项目缘起:从废弃风扇到视觉暂留时钟的奇思妙想

不知道你有没有这样的经历:家里淘汰下来的旧电脑风扇,或者从某个废旧电器上拆下来的小风扇,总觉得丢了可惜,留着又占地方。我之前就攒了好几个,一直琢磨着怎么把它们“废物利用”起来。直到有一次,我在网上看到一个利用视觉暂留效应制作的LED摇棒,灵光一闪——风扇本身不就是一个高速旋转的“摇棒”吗?如果能在扇叶上安装LED,让它旋转起来显示图案,岂不是天然的POV显示平台?

这个想法让我兴奋了好一阵子。POV,全称Persistence of Vision,即视觉暂留效应。简单来说,就是当物体快速移动时,人眼看到的图像会在视网膜上短暂停留约0.1秒。利用这个原理,让一排高速移动的LED灯按特定时序点亮,我们就能在空中“画”出稳定的图案或文字。而一个高速旋转的风扇,其扇叶轨迹恰好形成了一个圆形的显示区域,简直是制作圆形POV时钟的绝佳载体。

那么,显示什么呢?时钟无疑是最实用、也最酷的选择。它既有实用价值,又能完美展示POV技术的魅力——一个看似空无一物的风扇,一旦转起来,时间便悬浮在空中。为了实现精准计时,我选择了经典的DS1307实时时钟芯片。它价格低廉、接口简单(I2C)、自带电池备份,即使主系统断电,时间也能继续走,是这类DIY项目的常客。整个项目的核心,就是让一个旧风扇“重生”,变成一个能悬浮显示时间的酷炫时钟。

2. 核心硬件选型与改造:风扇、主控与RTC的搭配逻辑

动手之前,得先把硬件家底摸清,并想清楚为什么选它们。这不是简单的零件堆砌,每个选择背后都有成本和性能的权衡。

2.1 风扇的“手术”:从散热器到显示载体

首先是最关键的显示载体——风扇。我手头有几个12V的机箱风扇,尺寸从8cm到12cm不等。我最终选择了一个9cm的旧CPU散热风扇。为什么是它?有几个考量:第一,尺寸适中,9cm的显示面积在桌面上既不显得笨重,信息量也足够;第二,大多数电脑风扇是无刷直流电机,由定子(线圈)和转子(磁铁+扇叶)构成,我们需要改造的是旋转的转子部分;第三,它的轴是通孔的,方便我们穿过导线。

改造风扇是第一步,也是最需要耐心的一步。我们的目标是在每个扇叶的尖端安装一颗LED。这样当风扇旋转时,这些LED就会形成一个圆环。我选择了常见的5mm雾状蓝色LED,亮度高,扩散效果好,在视觉暂留下线条更连续。拆下扇叶后,我在每个扇叶尖端用细钻头打一个小孔,刚好能紧密嵌入LED。这里有个关键细节:LED的引脚必须用极细的漆包线(比如AWG 38)连接,并且要从风扇中心轴的空洞穿出。粗线会增加旋转阻力并带来安全隐患。将漆包线沿着扇叶背面用耐高温胶带或少量热熔胶固定,最后所有LED的阴极(短脚)并联,阳极(长脚)则分别引出,为后续的单独控制做准备。

2.2 主控大脑:为什么是STM32而不是Arduino?

接下来是控制核心。很多人第一时间会想到Arduino,它确实简单易用。但我选择了STM32F103C8T6(即常说的“蓝色药丸”)。原因有三:第一,性能与实时性。POV显示对时序要求极其苛刻,STM32的72MHz主频远超Arduino UNO的16MHz,能提供更精准的定时中断来控制LED点亮瞬间,确保显示稳定不抖动。第二,外设与内存。STM32有丰富的定时器和DMA(直接存储器访问)资源,我们可以用高级定时器的PWM输出配合DMA,几乎不占用CPU资源就能生成复杂的LED控制信号。第三,功耗与扩展。本项目最终希望由电池供电,STM32的低功耗模式(如Standby模式配合RTC唤醒)能极大延长续航,这正是网络热词“stm32f103 standby rtc唤醒”所指向的应用场景。

2.3 时间之心:DS1307 RTC芯片的可靠性与局限

计时核心DS1307,这是一个老牌且经典的RTC芯片。它通过I2C接口与主控通信,自带56字节的NV SRAM,最关键的是,它有一个独立的电池备份引脚(VBAT)。当主电源(VCC)断开时,芯片会自动切换到纽扣电池供电,保证时钟持续运行。我选择它,一是因为其电路简单,只需外接一个32.768kHz的晶振和两个负载电容即可工作;二是因为资料丰富,任何问题基本都能找到答案。

但它也有缺点:精度一般(约±2分钟/月),且I2C通信速度较慢。对于时钟项目,精度可以通过软件定期校准来改善,而通信速度在每次读取时间(最多7字节)时的影响微乎其微,完全可接受。一个重要的实操心得:DS1307对晶振和电容的匹配比较敏感。务必按照数据手册推荐,使用负载电容为12.5pF的晶振,并且PCB布线时让晶振尽量靠近芯片引脚,走线对称,这样可以减少起振困难和频率偏差。

2.4 供电与信号传输:旋转部分的“生命线”

如何给旋转的扇叶上的LED供电和传输控制信号?这里有两个主流方案:滑环和无线供电(如电磁感应)。滑环可靠但会有磨损和噪音;无线供电电路稍复杂。为了追求静音和耐用性,我采用了简化版的电磁感应供电。在风扇底座固定一个初级线圈,通以高频交流电;在转子背面贴一个次级线圈和整流稳压电路,即可实现非接触供电。信号传输则采用红外对管:在底座安装一个红外发射管,在转子底部对应位置安装接收管。风扇每旋转一圈,接收管会收到一次脉冲,作为帧同步信号,告诉主控“新的一圈开始了”,这是保证显示内容不旋转错位的关键。

注意:改造风扇涉及电路和高速旋转物体,务必确保所有焊接牢固,导线固定稳妥,并在低压(如5V)下初步测试旋转平衡性,防止高速运行时零件脱落发生危险。

3. 系统架构与核心电路设计要点

硬件选型确定后,需要把它们有机地组合起来。整个系统可以分为旋转显示模块和固定主控模块两大部分,它们之间通过无线供电和红外信号进行能量与同步信息的交互。

3.1 旋转显示模块:简约而不简单

这个模块位于风扇转子上,随扇叶一起旋转。其核心是一个多通道的LED驱动电路。由于我们需要独立控制每个扇叶上的LED(以显示不同数字的笔画),所以不能简单地将所有LED并联。我使用了德州仪器的TLC5940这款LED驱动芯片。它是一款16通道的恒流驱动芯片,每个通道可以独立设置PWM灰度值。这意味着我们不仅可以控制LED亮灭,未来还能扩展为调节亮度,显示更丰富的效果。

旋转模块的电路板需要做得很小、很轻,并做好动平衡。PCB设计成圆形,中心开孔穿过风扇轴。上面集成TLC5940、红外接收管、稳压芯片(如AMS1117-3.3)以及接收线圈的整流滤波电路。TLC5940通过SPI接口接收来自主控的数据(经过电平转换和信号耦合)。这里的一个关键设计是电源管理:接收线圈感应到的电压先经过整流桥和滤波电容,然后输入一个低压差线性稳压器(LDO)得到稳定的3.3V。电容的容量要足够大,以储存能量,应对线圈感应电压瞬间波动的状况。

3.2 固定主控模块:控制与计算中枢

这个模块固定在风扇底座,不旋转。它以STM32F103为核心,周围环绕着几个关键电路:

  1. DS1307电路:包括DS1307芯片、32.768kHz晶振(Y1)、两个22pF的负载电容(C1, C2)、一个3V的纽扣电池座(BT1)以及I2C的上拉电阻(R1, R2 通常为4.7kΩ)。VBAT引脚直接接电池,VCC接系统3.3V。
  2. 红外同步电路:一个简单的红外发射管(IRED)串联一个限流电阻(如100Ω),由STM32的一个IO口控制。发射管对准旋转路径,确保每转一圈都能被转子底部的接收管检测到。
  3. 无线供电发射电路:这是一个由STM32定时器产生PWM方波驱动的H桥电路(如IRF7309),驱动初级线圈(L1)产生交变磁场。谐振电容(C3)与线圈电感形成LC谐振,能提高传输效率。调试心得:初级线圈的匝数和驱动频率需要匹配。通过测量线圈电感和计算谐振频率,将PWM频率设定在谐振点附近(通常在几百kHz),可以获得最佳的能量传输效果。
  4. 通信接口:STM32通过一个由光耦或电容耦合构成的简易隔离电路,将SPI数据发送给旋转模块上的TLC5940。这样做是为了隔离旋转与固定部分的地,避免噪声干扰。

3.3 同步机制:让时间“定格”在空中

POV显示稳定与否,关键在于同步。我们的同步机制是这样的:

  1. 硬同步(帧起始):风扇转子每旋转一圈,其底部的红外接收管会接收到一次底座发射管发出的信号,产生一个下降沿中断给STM32。这个中断被设置为最高优先级,它标志着“新的一帧显示开始”,STM32立即从显示缓冲区的起始位置开始发送LED数据。
  2. 软同步(时基分割):一圈360度,我们要显示60个刻度(秒)、12个小时刻度以及数字。STM32内部的一个高级定时器(如TIM1)被配置为向上计数模式,其溢出频率设置为风扇转速(RPS) * 每圈显示点数(N)。例如,风扇转速为1200 RPM(即20 RPS),我们希望每圈有360个显示点来保证圆环平滑,那么定时器频率应设为 20 * 360 = 7.2 kHz。每次定时器溢出中断,STM32就计算出当前角度对应的LED显示数据,并通过DMA发送给TLC5940。这样,就把时间(定时器中断)映射到了空间(旋转角度)上。

这种“硬同步复位+软同步插值”的方式,即使风扇转速有微小波动,显示的内容也不会扭曲或断裂,只是整体略微缩放,人眼几乎察觉不到。

4. 固件程序设计:从时间读取到空间绘制的全流程

软件是项目的灵魂,它需要高效地管理时间、处理同步信号、计算显示内容并驱动硬件。整个程序围绕中断和状态机展开。

4.1 底层驱动:初始化与时间接口

首先初始化所有外设:

// 伪代码示例 void Hardware_Init(void) { // 1. 系统时钟配置(72MHz) RCC_Configuration(); // 2. 初始化I2C1用于DS1307通信 I2C_Init(); // 3. 初始化SPI1用于TLC5940通信,并启用DMA SPI_DMA_Init(); // 4. 初始化高级定时器TIM1,用于生成显示时基中断 TIM1_Init(); // 设置ARR为 (72000000 / 7200) - 1 // 5. 初始化一个外部中断引脚(如EXTI0),用于红外同步信号下降沿触发 EXTI_Sync_Init(); // 6. 初始化另一个定时器(如TIM2)用于红外发射管调制(如38kHz载波) TIM2_Init(); // 7. 初始化RTC唤醒等相关低功耗功能(备用) PWR_RTC_Init(); }

DS1307的读写函数需要严格按照其时序编写。读时间时,先写入要读取的寄存器地址(0x00),然后重新发起读请求,连续读取7个字节(秒、分、时、星期、日、月、年)。

4.2 核心算法:将时间转换为LED点阵数据

这是最具挑战性的部分。我们需要一个“画布”——一个在内存中代表360度圆环的显示缓冲区DisplayBuffer[360][N_LED],其中360是角度分辨率,N_LED是LED数量(例如4个扇叶就是4)。每个元素是一个亮度值(0-4095,对应TLC5940的12位PWM)。

当从DS1307读取到当前时间(时、分、秒)后,需要将其绘制到这个圆形画布上:

  1. 计算角度
    • 秒针角度:second_angle = (seconds % 60) * 6(一圈360度,60秒,每秒6度)
    • 分针角度:minute_angle = (minutes % 60) * 6 + (seconds / 60.0) * 6(加上秒带来的偏移,更真实)
    • 时针角度:hour_angle = (hours % 12) * 30 + (minutes / 60.0) * 30(一圈360度,12小时,每小时30度)
  2. 绘制表盘:在缓冲区中,将所有60个秒刻度(每隔6度)、12个小时刻度的位置对应的LED亮度设为某个值。例如,在0度、90度、180度、270度位置绘制更粗的刻度。
  3. 绘制指针:这是一个反走样问题。指针不是一条完美的数学线,它占据一个角度范围。例如,绘制分针,我们可以在minute_angle ± 0.5度的范围内,将所有LED的亮度设为最大值。为了更平滑,甚至可以实现简单的线性反走样:角度差0.5度时亮度100%,角度差1度时亮度50%。
  4. 绘制数字:这是难点。需要在圆形坐标系上绘制“12”、“3”、“6”、“9”等数字。我预先定义了几个数字的矢量字体(用一系列角度和半径坐标表示笔画),然后根据当前角度,判断每个显示点(角度,半径)是否落在某个笔画的矩形区域内。如果是,则点亮该位置对应的LED。优化技巧:这些判断计算量较大,不要放在中断中进行。可以创建一个“脏标志”,当时间改变时,在主循环中重新计算整个显示缓冲区,中断服务程序只负责搬运已计算好的缓冲区数据。

4.3 中断服务程序:精准的时序控制

两个中断构成了显示引擎的核心:

// 红外同步中断(最高优先级) void EXTI0_IRQHandler(void) { if(EXTI_GetITStatus(EXTI_Line0) != RESET) { Display_Angle_Index = 0; // 重置角度索引 TIM_SetCounter(TIM1, 0); // 重置定时器计数器,确保严格同步 EXTI_ClearITPendingBit(EXTI_Line0); } } // 定时器中断(显示时基) void TIM1_UP_IRQHandler(void) { if(TIM_GetITStatus(TIM1, TIM_IT_Update) != RESET) { // 1. 根据当前 Display_Angle_Index,从 DisplayBuffer 中取出对应角度的LED数据 uint16_t led_data[4] = Get_LED_Data_At_Angle(Display_Angle_Index); // 2. 通过DMA将数据发送到SPI(非阻塞,高效) SPI_Send_Data_by_DMA(led_data); // 3. 角度索引递增,准备下一个点 Display_Angle_Index = (Display_Angle_Index + 1) % 360; TIM_ClearITPendingBit(TIM1, TIM_IT_Update); } }

通过DMA搬运SPI数据,CPU在中断服务程序中的负担极轻,大部分时间可以处于休眠状态,这对于电池供电至关重要。

4.4 低功耗策略:让时钟持续运行数月

如果希望用电池供电,低功耗设计必不可少。STM32的Standby模式功耗极低(约2μA),但在此模式下大部分外设都会关闭,包括定时器。然而,DS1307的SQW/OUT引脚可以输出方波信号(例如1Hz)。我们可以将这个信号连接到STM32的唤醒引脚(如WKUP)。配置DS1307输出1Hz方波,并使STM32进入Standby模式。每过1秒,DS1307的方波上升沿就会将STM32从Standby模式唤醒。唤醒后,STM32读取DS1307的时间,更新显示缓冲区,然后驱动风扇旋转显示几秒钟(比如10秒),随后再次进入Standby模式。这样,绝大部分时间系统都在“深度睡眠”,只有需要“刷新”显示时才短暂工作,可以极大地延长电池寿命。这正是“stm32f103 standby rtc唤醒”的经典应用。

5. 组装、调试与优化中的实战经验

把所有模块焊接好,代码编译下载,只是万里长征第一步。真正的挑战在于让整个系统稳定、可靠、美观地运行起来。

5.1 机械组装与动平衡调试

将改造好的扇叶组件重新安装到风扇电机上。确保所有导线从轴心穿出后,留有足够的松弛度,防止旋转时拉扯。固定主控板在风扇底座,调整红外发射管和初级线圈的位置,使其与转子上的接收部分对准。

动平衡是成败的关键。转子一侧增加了LED、线圈和小电路板,必然导致重心偏移,高速旋转时会产生剧烈震动和噪音。我的调试方法是:将风扇通电低速旋转,用手机慢动作视频拍摄,观察抖动情况。然后在偏轻的扇叶背面(非LED面)一点点粘贴配重(如小块电工胶带、焊锡),反复试验,直到在各个转速下都运行平稳。这个过程很枯燥,但必不可少。

5.2 电路调试:电源、同步与通信

  1. 无线供电调试:先不接旋转模块,用示波器或万用表测量初级线圈两端的电压波形,调整PWM频率,观察电压幅度变化,找到谐振点(电压幅度最大处)。然后接上旋转模块,在次级线圈输出端测量,应有稳定的3.3V左右电压。如果带载后电压跌落严重,可能需要增加初级驱动电流或优化线圈耦合距离(通常1-3mm为宜)。
  2. 红外同步调试:让风扇缓慢旋转(可用于拨动),用示波器观察红外接收管的输出信号。应该能看到一个清晰的、每转一圈出现一次的脉冲。如果信号杂乱,可能是环境光干扰,可以给接收管加上深色套管,或者调制发射管电流(用38kHz载波驱动),接收端使用带解调功能的接收头(如VS1838B)。
  3. SPI通信调试:这是最易出问题的地方。因为信号需要通过非接触方式传输,我采用了电容耦合。在固定端,SPI的MOSI信号通过一个100pF的电容连接到旋转端的接收电路。旋转端用一个施密特触发器(如74HC14)对耦合过来的信号进行整形,再送给TLC5940。调试时,先用杜邦线直连,确保TLC5940能被正常驱动。然后改用耦合电路,用示波器同时观察发送端和接收端的波形,调整耦合电容容量,直到接收端波形清晰、无严重畸变。

5.3 软件调试与显示优化

  1. 转速测量与自适应:理想情况下,我们希望显示内容大小固定,不受转速影响。这需要知道实时转速。我们可以利用红外同步中断,计算两个同步脉冲之间的时间间隔,从而得到实时转速(RPS = 1 / 间隔时间)。然后动态调整定时器TIM1的溢出频率(即转速 * 每圈点数),实现显示点密度的自适应,让时钟看起来大小恒定。
  2. 亮度与对比度:在光线较强的环境下,LED可能显得不够亮。可以通过提高TLC5940的驱动电流(调整IREF电阻)来解决。同时,由于POV效应,LED点亮时间极短(微秒级),实际视觉亮度与占空比(PWM值)不是线性关系,需要根据实际效果建立一个亮度伽马校正表,使亮度调节更符合人眼感知。
  3. 图形抗锯齿:直接绘制指针和数字会有明显的锯齿感。除了之前提到的角度反走样,对于数字,可以采用更高分辨率的虚拟画布进行计算,然后下采样到实际的LED网格上,能有效平滑边缘。

5.4 常见问题与排查清单

  • 问题:显示内容闪烁、断裂。
    • 排查:首先检查红外同步信号是否稳定。用示波器锁定同步脉冲,看其是否每圈一次且位置固定。其次,检查定时器中断是否被更高优先级的中断长时间阻塞。确保显示相关的中断优先级最高。
  • 问题:数字或指针显示位置漂移。
    • 排查:同步信号正常,但计算出的角度基准不对。检查Display_Angle_Index在同步中断中是否被正确重置为0。检查角度计算函数,确认没有整数溢出或浮点数精度问题。
  • 问题:旋转模块供电不稳定,时亮时灭。
    • 排查:测量次级线圈的整流输出电压。如果波动大,增加滤波电容的容值(如从100uF增加到470uF)。检查线圈对齐情况和距离,确保耦合良好。
  • 问题:电机发热严重或转速不稳。
    • 排查:动平衡没做好,导致负载不均。重新进行配平。也可能是驱动风扇的电压或电流不足,尝试提高供电电压(在电机额定电压内)。

完成所有这些调试后,一个由旧风扇改造的POV时钟就真正“活”了过来。看着它在空中清晰地显示着时间,那种成就感远超购买一个成品。这个项目融合了机械改造、模拟/数字电路设计、嵌入式编程和算法,是一个非常好的全栈式硬件学习实践。它教会我的不仅是技术,更是一种将想法一步步变为现实的能力。如果你手边也有闲置风扇,不妨试试,这个悬浮于空中的时间魔法,绝对能成为你工作台上最吸引眼球的装置。

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/8/19 3:00:49

基于Seeed XIAO RP2040的DIY键盘制作:从矩阵扫描到KMK固件实战

1. 从一块“小”板子到一把“大”键盘:我的DIY之旅最近几年,DIY客制化键盘的风潮越来越热,从轴体、键帽到PCB,玩家们追求极致的个性化和手感。但很多新手,包括之前的我,一看到复杂的电路设计、固件编译就望…

作者头像 李华
网站建设 2026/8/19 3:00:09

基于TinyML与CC1352的TI-RSLK机器人语音控制实战

1. 项目概述:当TI-RSLK机器人学会“听”话最近在捣鼓TI的机器人套件TI-RSLK,总感觉少了点什么。让它跑迷宫、循线都玩腻了,能不能让它更“智能”一点,比如,听我的指令行动?这个想法让我把目光投向了TinyML&…

作者头像 李华
网站建设 2026/8/19 2:56:12

齐纳二极管稳压原理、选型计算与电路设计实战指南

1. 从“反向击穿”到“稳压神器”:齐纳二极管的本质在电子设计的浩瀚世界里,二极管家族成员众多,从最基础的整流二极管,到发光的LED,再到快速开关的肖特基二极管,各有各的绝活。但如果说有哪一种二极管&…

作者头像 李华
网站建设 2026/8/19 2:56:08

音乐社交应用开发实战:从React+Node.js技术栈到智能推荐系统实现

1. 项目缘起:从课程作业到音乐应用的探索 最近刚结束了一门名为SE423的软件工程课程,这门课的期末大作业(Final Project)要求我们组队完成一个完整的软件项目。我们小组决定做一个音乐相关的应用,并给它起了个挺有意思…

作者头像 李华
网站建设 2026/8/19 2:54:55

基于树莓派与INA219的电流数据记录系统设计与实现

1. 项目概述:树莓派电流探针与数据记录系统最近在折腾一个嵌入式数据采集项目,核心需求是长时间、高精度地监测电路中的电流变化,并且能把数据完整地记录下来,方便后续分析。手头正好有闲置的树莓派,这玩意儿接口丰富、…

作者头像 李华
网站建设 2026/8/19 2:54:15

机械首饰盒设计:从蜗轮蜗轮到缓降开盖的工程实践

1. 项目概述:当机械工程遇上首饰收纳几年前,我还在学校带本科生做项目,一个机械工程专业的学生跑来问我:“老师,我们能不能做个不那么‘工业’的东西?比如,一个盒子?” 我当时的第一…

作者头像 李华