STM32驱动16x16点阵全攻略:动态扫描、595级联与字模解析

发布时间:2026/9/9 4:25:20
STM32驱动16x16点阵全攻略:动态扫描、595级联与字模解析 简介这套基于STM32F103的16×16点阵显示源码包主要面向初学STM32与嵌入式开发的读者帮助理解LED点阵屏的扫描驱动原理以及用按键/定时器实现内容移动的处理方式。作者采用比较原始、直白的实现方法虽然没有炫技式优化但胜在逻辑清晰容易对照原理图逐段阅读适合作为入门阶段的练手参考。压缩包共335个文件大小约15.57MB除33个C源码和36个头文件外还包含完整的Keil工程配置、hex/axf烧录文件、编译中间文件以及PDF点阵原理图字库数组也已内置可自行替换或扩展字符内容。目前已有3978人学习这份资源说明这种基础的实现思路对不少新手有实际帮助。使用者下载后既可烧录hex直接观察效果也可基于工程修改移动速度、显示方向或字库内容快速验证自己的点阵控制想法。 16x16点阵这个项目几乎可以算是我入坑STM32后做的第一个真正有点“产品感”的东西。玩过8x8单色点阵的朋友都知道那东西模块便宜、接线简单随便用几根杜邦线连上就能让LED跑起来。但一旦从8x8升级到16x16事情就完全不一样了——IO口数量直接翻倍到32个驱动电流需求也上去了用之前那套直连GPIO的思路根本玩不转。这篇文章把我的完整实现过程、踩坑记录和优化思路整理出来给正准备做课设、竞赛或者单纯想折腾点阵屏的朋友一个可以直接抄作业的参考。1. 为什么16x16点阵必须用动态扫描而不是全部同时点亮先说结论16x16点阵理论上需要控制256个LED但实际硬件上不可能给每个LED单独拉一根线。点阵屏内部的行线和列线是复用的任意时刻只能通过“行列交叉选通”的方式点亮特定位置的LED。想同时点亮所有LED硬件上就不支持除非你重新设计驱动板。1.1 8x8模块的内部结构和引线逻辑市面上的8x8点阵模块不管是共阳还是共阴内部都是8行8列交叉排列的LED阵列。拿共阳模块举例每一行的8个LED阳极连在一起引出一个管脚每一列的8个LED阴极连在一起引出一个管脚。这样下来一个8x8模块总共16个引脚行8个、列8个。想点亮坐标(2,3)那个LED操作方式是给第2行的行引脚接高电平给第3列的列引脚接低电平电流从行引脚流入、经LED、从列引脚流出LED就亮了。若同时想让(5,6)位置也亮就得第5行给高、第6列给低。问题来了——如果两个点的行或列有冲突比如第2行和第5行同时高电平第3列和第6列同时低电平那么(2,6)和(5,3)这两个不需要亮的LED也会跟着亮专业术语叫“串扰”或“鬼影”。1.2 动态扫描用视觉暂留“骗”过人眼要解决串扰同时还要让整个屏显示出完整图案就只能用动态扫描的方式。原理很简单把16行分成16个时间片每个时间片内只让一行有效同时往这一行的16列写入要显示的数据亮完这一行立即切到下一行。举个例子显示一个“A”字。第1行扫描时把“A”第1行对应的列数据写进去第2行扫描时写第2行的列数据以此类推。16行全部扫完一遍人眼因为视觉暂留效应看到的是一帧完整的“A”。这个原理和CRT显示器一行行扫描成像是一回事只是点阵屏的“分辨率”低得多。扫描频率有讲究。我实测下来整屏刷新率低于30Hz时肉眼能明显看到闪烁盯久了眼睛特别累达到60Hz以上基本就稳定了感觉不到闪动。16行扫描意味着每行的周期是刷新周期的1/16比如60Hz刷新每行激活时间约为1/60/16也就是大约1毫秒级别。这个时间窗口非常短所以行选通信号必须足够利落不能拖泥带水。1.3 选共阴还是共阳直接影响驱动方案这是新手很容易忽略的坑。共阳模块在行扫描时行线输出高电平、列线输出低电平来点亮LED共阴模块正好相反。两种模块的扫描代码完全不同硬件驱动电路也不同。我自己的板子上用的是共阴模块搭配74HC595输出列数据行选通用一组三极管反相驱动。选共阴的原因是当时手头正好有PNP管低电平选通行比较顺手。如果你用的是成品的16x16点阵模块绝大多数厂家会把行和列的驱动电路直接做好你只需要按模块说明书的约定时序操作就行。但如果是自己买4块8x8拼16x16务必先在面包板上测清楚每块模块的引脚定义不同厂家同一标准的模块引脚顺序可能都不一样。2. 硬件连线策略IO口不够用时的几种方案对比16x16点阵需要16根行线和16根列线。STM32F103系列以ZET6为例GPIOA~GPIOE加起来最多80个IO理论上够用但工程上谁会为一块点阵屏把这么多IO全占掉尤其是还得留出串口下载、按键输入、传感器接口等后续扩展空间。所以我的方案是能少用IO就少用IO用串行转并行的方式扩展。2.1 方案一全直连——代码最简单但最不推荐直接用STM32的32个GPIO16个接行线、16个接列线。代码方面确实最简单初始化一堆GPIO扫描时直接对行和列寄存器操作就行不需要任何移位芯片。但坏处也明显占用的IO太多后续想接其他外设几乎不可能3.3V的GPIO直接驱动LED亮度上不去电流过大会损伤引脚走线在PCB上极其拥挤杜邦线连接时一团乱麻这个方案只适合纯验证性质、点亮一下就没打算长期用的测试场景。我第一版就是这么干的点亮一个心形图案用了2小时但想扩展显示内容时直接后悔——IO全占完了。2.2 方案二74HC595级联——性价比最高的主流方案74HC595是8位串行输入、并行输出的移位寄存器STM32只需3根线数据SER、移位时钟SRCLK、锁存时钟RCLK就能控制任意多片级联的595。16列数据需要2片595级联16行选通可以再用2片595或者用两片595直接搞定全部32路输出。总共只占3个GPIO这对stm32f103来说太划算了。595的工作原理不复杂SER引脚上的数据在SRCLK上升沿逐位移入内部8位寄存器全部移完后RCLK上升沿将数据一次性锁存到并行输出端。多片级联时把前一片的QH串行溢出脚接到下一片的SER数据就像流水线一样依次推进。这里有个重要的细节先送入的数据位会被推到更后面的芯片上所以发送数据的字节顺序要和硬件连接顺序对应我第一次就把这个顺序搞反了屏幕显示直接镜像了。2.3 方案三用STM32的硬件SPI驱动595——省CPU的进阶玩法如果你后续还想在扫描的同时跑点别的逻辑用硬件SPI替代GPIO模拟时序是更好的选择。STM32F103的SPI外设主频最高18MHz发送一个字节只需要一次写DR寄存器的操作数据移位的等待时间由硬件完成不占用CPU。我后来改用SPI1驱动595主循环里只负责准备每行的数据缓冲然后调用spi_send把16个字节丢进去CPU负载大幅下降。不过用SPI要注意SPI是高位先出的而你的字模数据可能是低位先出需要在上层转换一次比特顺序。此外SPI的SCK空闲电平、相位要和595的时序匹配STM32的SPI CPOL/CPHA参数默认状态就可以用但换其他芯片时要确认。2.4 行驱动别忘加三极管或专用驱动芯片直接拿GPIO或595输出驱动8个LED是很吃力的。如果每行16个LED同时亮按每个LED 20mA计算一行总电流320mA这个电流绝对不能从芯片引脚直接走。正确做法是列线用595输出数据提供LED的电流路径行线经三极管或MOS管做开关控制选通。推荐的简化电路行选信号接PNP三极管基极经限流电阻发射极接VCC集电极接行线。低电平选通时三极管导通行线被拉高高电平选通时断开。这样595输出的列低电平电流直接经LED流到地即可行选电流由VCC提供不会进芯片。3. 字模数据到底要怎么取为什么你取出来的字显示是乱的软件部分最容易翻车的就是字模取模方式。你以为从字模软件里导出了一串看起来合理的十六进制数组烧进单片机后屏幕却显示成一团乱码——十有八九是取模方向和你的扫描逻辑不一致。3.1 纵向取模和横向取模的区别常见的取模方式分纵向取模和横向取模。以16x16像素的汉字为例纵向取模每列从上到下填充8个像素作为1个字节16列共32字节因为16行需要2个字节/列横向取模每行从左到右填充8个像素作为1个字节16行共32字节如果你在取模软件里选择了“纵向取模”扫描代码却按“横向取模”的方式组织数据显示出来自然就是乱的。这不是代码BUG是数据格式不匹配。3.2 我的驱动代码和取模参数的对应关系我的扫描逻辑是对每一行从字模数组中取出该行对应的列数据然后经595发给列线。这种情况下取模方式应该选择“横向取模从左到右高位在前”。具体来说16列分成2个字节左8列是第一个字节右8列是第二个字节。数据位与列引脚的关系是字节的最低位对应第0列最左边最高位对应第7列。如果你用的595串行移位数据先送高位还是先送低位也要和这个对应上。我的代码统一采用“先送高字节、再送低字节”每个字节内部“高位先行”。3.3 取模软件推荐和参数配置技巧PCtoLCD2002是大家用得比较多的一款的取模软件输出格式模板可以自定义。我的配置参考如下点阵格式阴码1亮0灭配合扫描行低电平选通取模走向横向取模取模走向从左到右从上到下每行显示数16字节内位序高位在前为什么用阴码因为我的列驱动是595输出低电平点亮LED数据位为1时对应LED灭为0时对应LED亮。这个逻辑很多人对接不上建议在代码里写好注释避免过几天自己都看懵。3.4 自建ASCII字库的快速方法16x16点阵显示汉字GB2312全字库大概需要几百KB的FlashSTM32F103的Flash一般只有64KB或128KB塞全字库有点吃紧。实际项目中常用做法是只取用到的部分汉字把它们转成C数组。常见做法是做一个16x16汉字索引表按GB2312编码顺序存储用的时候根据汉字的区位码查表算出偏移量。这样哪怕只有一两百个常用字也足够做一个小型显示系统了。更省事的方式是直接用取模软件导出“C51格式”的数组但要注意不同编译器对数组元素个数和注释格式的兼容性。我习惯在生成后手动裁掉软件自带的注释头保留纯数据部分再包上自己定义的const数组避免编译时出现多余的符号。4. 代码结构设计从裸机循环到定时器中断扫描刚开始玩点阵屏的人容易把扫描放在主循环的delay里比如每次循环先扫描16行再延时一下。这种做法虽然可以实现功能但主循环被扫描函数占满后续想加按键、串口处理就非常困难。我的经验是把扫描放进定时器中断定时触发刷新主循环只负责更新显示缓冲区。4.1 显示缓冲区模型定义一个16字节的数组作为显示缓冲区每一行对应一个字节16列刚好一个字节不拆封值1代表LED亮、0代表灭。注意这里的数据位和595输出逻辑是反的因为阴码低电平点亮所以真正送入595前需要取反。void display_buffer[16];主循环只需要修改显示缓冲区的内容比如显示“A”就是把“A”的字模数据拷贝到display_buffer里至于什么时候扫描、怎么扫描完全交给中断处理。4.2 定时器中断扫描的核心实现使用TIM3产生中断中断频率为刷新率乘以16行。比如目标刷新率60Hz则TIM3中断频率为960Hz即每次中断扫描一行每16次中断完成一帧。void TIM3_IRQHandler(void){ static uint8_t row 0; uint8_t col_data[2]; col_data[0] display_buffer[row] 0xFF; col_data[1] (display_buffer[row] 8) 0xFF; // 发送两个字节给595同时把行选通切换到对应的row hc595_send_two_bytes(col_data[1], col_data[0]); // 注意字节顺序 select_row(row); row; if(row 16) row 0; TIM_ClearITPendingBit(TIM3, TIM_IT_Update); }这段代码的关键在于先关闭行选通、再发数据、最后开启行选通。否则你会看到上一行的余辉残留到下一行产生横向拖影。具体做法可以是用一个引脚控制行驱动的使能端595的OE脚也可以发送数据期间OE置高发送完成后OE置低。4.3 中断优先级和主循环的配合这类扫描中断对实时性要求不算苛刻960Hz的中断频率对STM32F103来说非常轻松。我建议把扫描中断设置为中等优先级同时注意在主循环里不要在临界区停留太长时间否则可能导致扫描中断被延迟屏幕偶尔闪一下。如果使用了DMA搬运显示数据加SPI发送还可以进一步降低中断频率负担。4.4 显示内容的动态修改如果想做滚动显示比如一条字幕从右向左滚动思路是维护一个更大的缓冲区比如64字节每次定时把内容整体移位一列再截取当前窗口对应的16列映射到display_buffer全屏刷新。这样做的好处是扫描逻辑完全不变只改主循环的数据更新部分。5. 实测中的常见坑亮度、刷新率、595数据错位等问题的排查过程这一节记几个我实际调试中踩过、并且排查了很久才解决的坑。看着都很基础但每一个都能让屏幕出现让人抓狂的现象。5.1 屏幕亮度不均匀靠近供电端更亮、远端偏暗发生这个现象的原因是PCB走线或者杜邦线的电阻太大越靠近供电端的LED分到的电流越多远端由于线阻压降导致亮度衰减。16x16点阵整屏电流很大最坏情况下所有LED全亮接近320mA如果使用普通杜邦线压降会比较明显。排查过程我用万用表测最远端LED的VCC引脚电压发现比电源端低了约0.4V基本确认是线阻问题。解决办法一是加粗供电走线二是给行驱动和595的工作电压用单独走线从电源端引出三是使用多点供电在PCB两端都接入电源。用了双端供电后亮度差异从肉眼可辨降到几乎看不出。5.2 595数据错位显示内容像被水平切成两半再左右交换这个问题的根因是多片595级联时的数据发送顺序。前面提到数据是先送出的位会被推到更后面的芯片所以如果你从第2片往第1片方向发送数据发送顺序必须是从最后一篇芯片的数据开始发。我最初发送16列数据时按第1片、第2片的顺序结果高8列和低8列正好互换。排查时用最简单的“单行全亮”测试图案就能轻松判断数据是否对位如果左侧8列亮而右侧不亮或者反过来基本就是595顺序问题。建议在调试阶段写一个测试函数依次点亮16列中的每一列用工装确认硬件连接无误。不要一上来就显示复杂图案否则根本分不清是硬件接错还是软件的取模问题。5.3 刷新率降下来之后图案出现“撕裂”或“闪烁”如果刷新率低于40Hz画面有闪烁如果扫描中断里除了发送数据还做了大量运算导致每行的激活时间不均匀画面会出现“撕裂”感——上半部分和下半部分的亮度或图案状态不一致。这个时候优先优化扫描中断的执行时间把列数据发送改成硬件SPIDMA模式中断服务函数里只做行选通和计数器累加靠DMA完成移位发送。我在升级成DMA模式前GPIO模拟时序发送2个字节大概需要几十微秒加上中断调度开销每行扫描周期偏长。改成SPIDMA后发送数据由外设完成主循环几乎零开销整屏刷新率轻松做到100Hz以上亮度也更均匀。这个改动对体验提升非常明显。5.4 供电不足导致的“亮一片、灭一片”当所有LED同时点亮时电流峰值很大。如果使用USB口直接供电电源能力不足会导致电压跌落引起595输出异常表现为屏幕随机乱闪。建议在电源端并联一个100uF电解电容和0.1uF陶瓷电容做去耦同时选择输出能力1A以上的稳压模块。如果是用面包板搭的电路这一点格外重要面包板自身的接触电阻加线材压降会让整块屏幕工作不稳定。5.5 行余辉和拖影的彻底解决即便用中断扫描有时也能看到上一行的微弱残影尤其在显示内容上下部分对比度很高的时候。原因是选通行切换时595的输出端在数据更新前仍保持着上一行的状态行开关没有完全关闭老信号泄漏了一拍到新行。解决方式有两个方式一硬件上给行驱动加OE使能控制数据更新期间关闭输出更新完再打开方式二软件上在扫描函数开头先把当前行选通断开再发送新数据最后打开新行选通。我实测中方式一更彻底。用595本身的OE脚做全局输出使能每次进入中断先置高OE等数据全部送入并锁存完再置低OE开启输出屏幕上残留彻底干净了。6. 从显示字符到实用系统串口改字、滚动动画和级联扩展思路当你的16x16点阵能稳定显示静态图案后下一步就是把它做成一个真正能用的系统。这里提几个我验证过的扩展方向。6.1 串口控制显示内容用STM32F103的USART接收上位机发来的指令比如用固定帧格式“AA 01 汉字编码 0D 0A”解析出要显示的汉字内码再查字库表更新显示缓冲区。这个思路非常实用我其中一个项目就是通过RS232接口接收Modbus RTU指令来切换显示屏内容调通了之后发现整个显示模块可以作为一个从机挂在总线上和上位机组态软件联动。做串口解析时要注意汉字内码是双字节不能按单字节处理串口中断接收时建议用环形缓冲区避免主循环处理数据和接收中断互相打乱。6.2 滚动字幕和简单动画的实现横向滚动字幕的代码逻辑不复杂维护一个32字节的“虚拟屏幕”缓冲区每隔一定时间比如30ms把虚拟屏幕内容向左移动一列然后把当前窗口的16列截取到display_buffer。虚拟屏幕的宽度可以任意想要多少字就拼接多少字模。纵向滚动或上下拉幕的动画类似把移位的方向从“列”换成“行”即可。这类动画的刷新速度设置我建议给用户提供参数接口实际测试发现横向滚动时每帧移动1列、间隔约30~50ms时观感最舒服太快会视觉疲劳太慢显得拖沓。6.3 级联更大尺寸或者改用RGB点阵16x16单色屏的升级路线无外乎两个方向横向级联用多组16x16组合成16x32、16x64的长条屏适合做跑马灯或信息条。级联时595数量增多注意发送数据长度同步增加DMA缓冲也要相应扩大。换RGB屏如果只是玩显示建议直接用WS2812等智能灯珠通过单总线控制每颗灯珠自带驱动IC对STM32的IO需求极低一颗GPIO就能控制几百颗灯珠做动效的能力远超传统扫描点阵。如果还是一定要做大尺寸的传统单色点阵建议看一下专门的LED驱动芯片比如CH451、MAX7219这类集成扫描逻辑的芯片软件工作量会大幅下降。MAX7219可以直接驱动8x8点阵多片级联后做16x16只需两片SPI接口和595不冲突代码更简洁只是显示灰度能力有限。6.4 一点关于工程管理的建议代码堆到一定程度文件结构要整理清楚。我的习惯是driver层放hc595、led_matrix、delay这些底层驱动app层放显示逻辑、字库查询、滚动动画main.c只负责初始化和主循环调度。这样后面想换芯片平台比如从F103换到F407底层驱动重写app层基本不动。用标准外设库的话记得把系统时钟配置放在最前面特别是工程配合stm32f103中文参考手册核对GPIO复用配置和AFIO时钟开启别漏了这一步导致引脚不工作。做这个项目的最大体会是点阵屏看起来是个简单外设但真正沉下心把刷新、亮度、扫描时序调明白对理解单片机的中断系统、外设时序、电源设计都有很大帮助。它不是那种跑通就扔的玩具而是能从硬件到软件完整锻炼一遍的小型系统。如果你刚开始接触这个项目建议先不要一次性上全功能按“点亮单点—扫描整屏—显示字模—中断刷新—串口控制”的顺序一步步来每一步都验证稳了再往下一步走。我现在手头这块16x16点阵板还在桌面角落亮着显示着今天的日期和温湿度看着它稳定跑了几百个小时确实比当初第一次点亮时那团乱码有成就感得多。本文还有配套的精品资源点击获取

关于本文作者

来自尧图内容编辑团队

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

尧图内容编辑团队

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

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

延伸阅读

相关资讯与近期热门内容

深度阅读推荐

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

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

网站改版的5个关键决策

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

获取专属建站方案

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

立即免费咨询