1. 无源矩阵和有源矩阵:这两个驱动名称里藏着什么
咱们聊LED显示,绕不开两个词:PM驱动和AM驱动。说得直白一点,这是两种完全不同的点亮灯的方式,直接决定了一块屏的亮度、刷新率、功耗、成本,甚至能决定某些产品形态能不能做出来。PM是无源矩阵驱动的缩写,AM是有源矩阵驱动的缩写。我刚接触点阵LED屏那会儿也懵:PWM我熟,PM又是什么?后来发现,这类缩写如果不放在整个驱动架构里去理解,确实容易被绕进去。
1.1 “主动”和“被动”到底指谁
很多人第一次看到PM和AM,第一反应是“被动驱动肯定比主动驱动低端”,其实这是最大的误解。
PM无源矩阵里的“无源”,说的是交叉点的像素本身没有独立的控制元器件,单纯靠行线和列线的交叉点来点亮。通俗点讲,就像老式教学楼里的电铃系统:值班室按一下,全校响铃;哪一楼层要响,靠的就是那一层的开关接到总线上。LED点阵屏的行扫描也是这个逻辑:行线负责逐行选通,列线负责给这一行里某些LED送电流,每行排队被“翻牌”,翻得快,人眼就觉得全亮了。
AM有源矩阵里的“有源”,是指每个像素旁边给它单独配了一个晶体管,也就是TFT,甚至还会配一个存储电容。这个晶体管像一个“站岗”的守卫,行选通信号告诉它“这一行该工作了”,它就把源极送过来的电压/电流锁在像素上;行选结束,其他行开始扫描了,它依然守着这个像素继续供电,直到下一帧刷新才更新数据。
所以PM和AM的划分,核心不在“驱动芯片好不好的”,而在像素这一层有没有自主持流能力。
1.2 这套概念不止用在LED屏上
聊LED显示时,这套架构概念其实是从LCD面板那边传承过来的。早期液晶屏用无源矩阵,扫描慢、响应差、视角窄,后来手机屏、显示器全面转向了AM TFT-LCD,每个子像素都有薄膜晶体管,画质才有了质的飞跃。到了OLED时代,AMOLED更是绝对主流,OLED本身是自发光,配上TFT背板做电流驱动,才能保证每个子像素的亮度基本一致。
咱们常说的LED显示屏,尤其是户外广告屏、室内全彩屏、点阵模块,绝大多数走的是PM路线,也就是行扫描+列恒流驱动芯片。每颗灯珠并不需要自己有晶体管,而是通过信号驱动程序按行快速点亮。13级扫描屏:一行一行扫过去,扫描频率达到几十赫兹以上,图案在人眼里就是稳定的画面。像16×16点阵屏,原理上也完全一样,只是规模小很多,非常适合拿来理解PM驱动到底是怎么工作的。
搞清楚这个背景,再往下拆原理,就不会被一堆术语带偏了。
2. 驱动原理拆解:PM的行扫描和AM的像素自持是怎么跑起来的
2.1 PM驱动的工作过程:分时复用点亮
PM驱动最核心的动作就是“分时”。一个16×16点阵,说到底就是256个LED。如果有256根线分别控制每一个LED,那接口规模、驱动芯片数量都没法接受。PM的做法是把LED排列成16行×16列,同行LED共一根行线,同列LED共一根列线,总共只需要32根线就能寻址到全部256个LED。
具体工作时:
- 主控先送出第0行的16位列数据,锁存到列驱动器的输出端。
- 打开第0行的行选通,第0行需要的LED按列数据点亮。
- 保持一小段时间,让这一行稳定显示。
- 关闭第0行,送出第1行数据,选通第1行,点亮。
- 依次循环到第15行,扫完一帧,再从第0行开始。
在PM扫描下,每一行LED的点亮时间只占整个扫描周期的1/16,这个比例叫“占空比”。以60Hz刷新率为例,一帧16.7ms,每行只有大约1.04ms的导通时间。因为人眼有视觉暂留,只要扫描频率足够高,就不会感觉到闪烁。但这也带来了一个问题:LED的“平均亮度”大约是“峰值亮度”的1/16。为了补偿亮度,PM驱动通常会把每行点亮时的电流提高,或者人为提高瞬间亮度来等效拉回平均亮度。
这就像轮班值岗,每人每天只值1小时班,但值班时必须把1整天的工作量集中干完。时间短没关系,效率高就行。
如果用74HC595、HT16K33、MAX7219这类芯片搭点阵,本质上都是在搞PM扫描。MAX7219的优势是它内部自己完成了8×8的扫描,主控只需要告诉它“这个点要亮”,它自己负责挨行扫;74HC595则需要主控自己扛扫描时序,虽然麻烦,但更容易把PM的原理看穿。
2.2 AM驱动的工作过程:每个像素都有“私人的供电员”
AM驱动则完全是另一套逻辑。每个像素由2个或更多的TFT构成,常见的有开关管和驱动管,再加上一个存储电容。开关管负责响应行选信号,行选通时,源极驱动电路把灰阶数据对应的电压写到像素电容上;行选结束后,驱动管依靠电容上的电压继续保持像素导通,让LED维持稳定的电流输出。
还是用16×16的屏幕来对比:如果做PM,必须有16根行线和16根列线;如果做AM,逻辑行线和列线依然存在,但每一个交叉点多了TFT和电容,等于给每个像素都配了一个独立开关。行扫到哪一行,哪一行的像素就接收新数据;没扫到的行,像素由电容里的电荷继续“撑住”,不熄灭。
AM最大的变化是LED的工作占空比接近100%。像素在整帧时间内都保持点亮,亮度和电流是连续的,因此不需要靠瞬间拉高电流来补偿亮度。这也让AM屏幕的刷新率上限做得更高,灰阶过渡更细腻。
2.3 灰度实现的差别
灰度这块,PM和AM的思路也不一样。
PM因为LED点亮时间被压缩到1/N,要表现灰阶,一般通过子场时间或者脉宽调制来实现。比如一行的导通周期被细分成若干个“位时间”,按二进制位加权分配,位数越高开启时间越长,亮度的层级就靠这个堆出来。好处是方案成熟,LED大屏上广泛使用;缺点是位数越多,对扫描频率、芯片建立时间要求越高,低灰度时容易产生视觉上的“颗粒感”或者“低灰偏色”。
AM的灰度控制则可以直接用模拟电压或者高速PWM写入每个像素的存储电容,像素一直保持导通,通过控制流过LED的电流大小来体现不同亮度。加上TFT电容有保持作用,刷新时新数据会直接替换旧数据,灰阶衔接更平滑。这也是AMOLED屏幕拿来做手机屏、穿戴设备屏时色彩过渡自然的原因之一。
3. 亮度、刷新率、鬼影、功耗:实际表现到底差在哪
PM和AM的区别不能只看一张原理图,具体到屏幕表现,差异非常直观。
3.1 核心表现对照
| 对比项 | PM无源矩阵 | AM有源矩阵 |
|---|---|---|
| 像素控制器件 | 无,行线和列线直接驱动 | 每像素有TFT开关/驱动管 |
| LED点亮占空比 | 平均约为1/行数 | 接近100% |
| 峰值电流需求 | 高,需要补偿占空比损失 | 低,平均电流即工作电流 |
| 亮度均匀性 | 受线路压降、扫描时序影响 | 受TFT一致性影响,整体更稳 |
| 刷新率 | 受行数限制,可做高但时序压力大 | 轻松做到高刷新,保持像素持续亮 |
| 鬼影/拖影风险 | 高,低灰和高速变化时容易出现 | 低,除非像素保持异常 |
| 布线复杂度 | 低,行数+列数即可 | 高,每个像素都要TFT电路 |
| 面板工艺难度 | 低,适合点阵、户外大屏 | 高,适合高密度小屏 |
| 典型成本 | 低,驱动芯片简单 | 高,需要半导体背板工艺 |
| 常见应用 | LED点阵、户外广告/LED显示屏 | AMOLED手机屏、MicroLED显示屏 |
对比里最直观的是占空比。一个16×16的PM点阵,理想情况下每个LED的占空比就是1/16。同样的屏幕亮度要求下,LED的峰值电流可能是平均电流的十几倍,这意味着电源和驱动芯片都要能扛住瞬时大电流。而AM屏幕没这个补偿需求,TFT和像素工作在相对温和的电流下,整个驱动链路的热压力小很多。
3.2 为什么户外LED大屏还是PM的天下
既然AM看着更高级,为什么现在还满大街的户外LED广告屏、门头屏、点阵屏,全是PM方案?原因其实很现实:像素密度决定成本。
户外LED大屏的像素间距大,几十毫米一个灯珠,如果需要给每个像素都配一个TFT背板和驱动电容,相当于要在一张大玻璃或者PCB上做半导体薄膜工艺,成本高到离谱,良率也不现实。PM方案只需要在PCB上布好行线和列线,再用恒流驱动芯片做扫描,工程上成熟、成本可控。这也是为什么LED显示屏行业里几乎很少直接听到“AM”这个词,大家更多听到的是“扫描屏”“1/16扫”“恒流驱动”等说法。
而AM的优势要在像素间距很小、像素密度极高的场景里才会体现。手机屏幕、智能手表的AMOLED屏,光电都挤在几英寸到十几英寸里,分辨率动辄1.5K、2K,这个时候PM根本做不了:行线列线会多到布线空间不够,占空比小到亮度彻底崩溃,扫描串扰也会让画面没法看。只有依靠每像素TFT持续驱动,才能在巴掌大的地方塞下几百万个子像素还保持亮度均匀。
所以严格说,PM和AM是两套适配不同物理尺度的驱动方案,不存在谁绝对碾压谁。
4. 用STM32做一个16×16点阵贪吃蛇,把PM驱动的每个环节验证一遍
光讲理论不够,真正理解PM驱动最好的方式,是亲手把一个16×16点阵屏跑起来。我前段时间拿STM32F103C8T6做了一个点阵贪吃蛇,方案不复杂,但涉及到了PM驱动的全部关键点:行扫描、列数据、坐标映射、刷新时序、视觉残留。
4.1 硬件方案选型:MAX7219还是74HC595
16×16点阵有一种最省事的接法,就是4片MAX7219。MAX7219是8×8 LED驱动芯片,片内自己完成行扫描,4片拼起来刚好组成16×16。SPI协议通信,占IO少、程序简单,适合快速出效果。它内部还有亮度寄存器可以调节,整体亮度的一致性不错。
另一种是74HC595做法,大概需要3片HC595:2片组成16位列数据,1片做行译码或行选通,扫描时序全部由STM32主控控制。这种做法程序量翻倍,但能最大限度还原PM驱动的本质,方便理解行与列是怎么配合工作的。我最终选的是“接近工业大屏”的做法:列数据用两片74HC595级联,16列对应16位数据;行选通用一片74HC595加PNP三极管阵列,一次性选通某一行。
实际做的时候需要注意:16×16点阵模块有共阳和共阴两种接法。如果选择共阳,那么行线接阳极做选通,列线接阴极做电流灌入;列数据通过595输出,外部还要加限流电阻。推荐把限流电阻放在列线上,因为同一列在不同行会被轮流选通,电阻放在列线才能保证所有LED电流路径都有限流保护。这个细节一开始没注意,结果点亮时电流极不均匀,有些LED亮到刺眼,有些暗到看不见。
4.2 坐标映射与扫描时序代码
贪吃蛇的画面本质是一个16×16的二值位图:1表示点亮,0表示熄灭。我在STM32里建了一个二维数组作为显示缓冲区:
uint8_t frame[16][16]; // frame[row][col],值为1时点亮对应LED每个循环负责把这一帧的所有行扫一遍。扫描函数的核心逻辑如下:
void scan_all_rows(void) { for (uint8_t row = 0; row < 16; row++) { uint16_t col_data = 0; // 把第row行16列的数据拼成一个16位整数 for (uint8_t col = 0; col < 16; col++) { if (frame[row][col]) col_data |= (uint16_t)(1U << (15 - col)); } // 先关闭所有行,避免移位过程中产生残影 driver_set_row(0xFF); // 把列数据移位到级联的74HC595 shift_out_16bit(col_data); // 锁存列数据,让595并行输出 LATCH_HIGH(); LATCH_LOW(); // 选通当前行 driver_set_row(row); // 保持行导通时间,形成视觉占空比 delay_us(400); // 关闭当前行 driver_set_row(0xFF); } }我用的列数据移位函数是两个595串联,高8位先发,低8位后发,这个顺序要和实际接线一一对上,否则会出现画面左右颠倒或者上下颠倒。行选通过一个3-8译码器加三极管阵列实现,一次只允许一路输出有效。
扫描循环跑在main主循环里,16行乘400微秒约等于6.4毫秒扫完一帧,刷新率接近150Hz。这个刷新率下肉眼看不到闪烁,也比普通60Hz点阵稳定很多。
4.3 贪吃蛇逻辑实现要点
有了显示缓冲区和扫描函数,贪吃蛇的核心逻辑就变得非常纯粹了。蛇身用数组保存每节的坐标:
typedef struct { uint8_t x; uint8_t y; } Point; Point snake[256]; uint8_t snake_len; uint8_t dir_x = 1, dir_y = 0; uint8_t food_x, food_y; uint32_t last_move_time;蛇的移动逻辑:每隔一段时间,把蛇尾的一节移走,再根据当前方向在蛇头位置新增一节。吃到了食物就不移尾,同时蛇身长度增加,并重新随机生成食物。判断撞墙或者撞到自己身体就结束游戏。
void update_snake(void) { // 先把所有点标记为熄灭 memset(frame, 0, sizeof(frame)); // 计算新蛇头位置 uint8_t new_x = snake[0].x + dir_x; uint8_t new_y = snake[0].y + dir_y; // 撞墙检测 if (new_x >= 16 || new_y >= 16) { game_over = 1; return; } // 把新蛇头插入数组最前面,舍弃蛇尾 for (uint8_t i = snake_len; i > 0; i--) snake[i] = snake[i - 1]; snake[0].x = new_x; snake[0].y = new_y; // 判断是否吃到食物 if (new_x == food_x && new_y == food_y) { snake_len++; food_x = rand() % 16; food_y = rand() % 16; } // 尾部越长,就越要防止它自己咬到自己 // 更新显示缓冲区 for (uint8_t i = 0; i < snake_len; i++) frame[snake[i].y][snake[i].x] = 1; frame[food_y][food_x] = 1; }整个游戏刷新放在主循环里,用HAL_GetTick()做非阻塞定时,每200ms调用一次update_snake()。扫描循环保持高速运行,游戏逻辑每200ms慢速推进,两者互不干扰。DO: 食物生成后要和蛇身坐标做一次碰撞检查,避免生成到蛇身上。
4.4 实机调试中遇到的鬼影和闪烁
做一个点阵屏,最常遇到的就是“鬼影”问题。我一开始在扫描函数里先移位、再选通行,结果画面边缘总会出现淡淡的残留点,尤其是蛇移动的时候,蛇身后拖出一串很淡的余晖。原因很典型:往595移位新数据的过程中,上一行的行选通还没完全关闭,新数据已经开始进入移位缓存,595输出引脚上的状态出现中间态,导致不该亮的灯被瞬间点亮。
解决办法是在行扫描前先做“整体消隐”,也就是把所有行选通全部关闭,再进行移位和锁存。这个消隐时间虽然只有几微秒,但效果立竿见影。我最后把扫描顺序固定为:关行 → 移列数据 → 锁存 → 开行 → 延时保持 → 关行。
还有一个坑是亮度跳动。因为每行只亮400微秒,16行扫描完6.4ms,如果每次主循环里偶尔被别的代码卡住,某一行的保持时间就会忽长忽短,表现就是画面亮度不稳定、闪烁。解决思路是让扫描循环不能被游戏逻辑阻断,游戏逻辑只在两次扫描间隙里执行,或者干脆把扫描放到定时器中断里跑。我这里用了一个简单办法:主循环只做扫描,游戏逻辑放在SysTick中断状态驱动下执行。实测下来扫描稳定性非常好。
5. 选型不看参数高低,要看像素密度和场景需求
5.1 PM和AM的选型建议
做LED显示相关项目时,选型不是“谁强选谁”,而是“谁合适选谁”。根据我的项目经验,可以给几类典型场景做个直接判断:
| 需求场景 | 推荐架构 | 理由 |
|---|---|---|
| 16×16、32×32点阵模块/桌面装饰 | PM | 成本低、硬件简单、驱动成熟 |
| 户外LED全彩屏/广告屏 | PM扫描 | 像素间距大,TFT背板成本不可接受 |
| 手机OLED屏/穿戴设备屏 | AM | 像素密度高,需要紧凑背板和低功耗保持 |
| MicroLED高密度显示 | AM | 必须逐像素驱动才能做高分辨率和亮度均一 |
| 大尺寸律动LED装饰墙 | PM | 刷新要求不高,布线和稳定性优先 |
选PM方案时,我比较关注驱动芯片的恒流精度。LED大屏行业常用MBI5024、ICN2038S这类恒流驱动芯片配合扫描。恒流芯片的通道间电流误差如果超过3%,屏幕上就会出现明显的亮度不均匀,低灰度下尤其明显。选型时不能只看芯片便宜,通道一致性才是决定观感的关键。
选AM方案时,要重点考虑TFT的阈值电压一致性。AMOLED面板厂经常提到“补偿电路”,就是为了解决TFT阈值电压漂移导致的亮度不均问题,这也是AM屏驱动难度的主要来源。普通爱好者自制AM类屏幕基本不现实,更多是直接买现成的AMOLED模组来做系统集成。
5.2 常见误区与踩坑经验
大部分人第一次接触PM和AM,都会有几个固定误区。
第一个误区是“PM就等于PWM”。两者完全不是一回事。PM是矩阵驱动架构,指的是无源矩阵;PWM是脉宽调制,是调光/调灰阶的手段。PM驱动里可以用PWM方式来表现灰阶,AM驱动里也同样可以用PWM方式。当年我在一个群里面说自己的点阵用的是PM扫描,有人立刻接话“哦,那你是用PWM调光”,这完全是两码事。记住:PM回答的是“像素怎么被选通点亮”,PWM回答的是“亮度怎么控制”。
第二个误区是“AM一定比PM省电”。很多人看到AM占空比接近100%,认为维持电流小就省电,却忽略了AM面板的TFT背板本身也是耗电大户,而且背板制造工艺复杂。真正要比,必须在同等分辨率、同等亮度、同等刷新率下测整屏功耗,脱离这些谈省电都是耍流氓。在低密度大屏上,成熟PM扫描方案的整体功耗反而容易控制得更好,因为布线和电路简单,线路损耗小,电源效率高。
第三个常见坑是直接把点阵模块的行列极性接反。拿常见的8×8点阵模块来说,引脚顺序并不总是按行排列整齐的,不同厂家的丝印不一样。我以前遇到一块16×16点阵,行列标号和厂家手册正好相反,结果按照默认映射写代码,画面显示的是镜像翻转加转置的“艺术效果”。排查这种问题,最有效的方式不是看代码,而是用一根线直接把某个LED的正负极短接测试,确定行线和列线的真实对应关系,再回头核对程序。
第四个坑和限流电阻有关。很多初学者做16×16点阵时,只在一组公共端上放限流电阻,结果不同行LED亮度不一致。正确做法是让列电流路径都有稳定的限流电阻,或者使用恒流驱动芯片,避免因为LED正向压降差异导致电流全看心情走。恒流芯片的本质就是强制每一路输出电流恒定,亮度才可能均匀。
回到PM和AM的选型反思上,我个人这几年做点阵项目的最大体会是:先想清楚“我要控多少像素、像素间距多大、刷新要求多高”,再决定用PM扫描还是AM背板。LED点阵、广告大屏、全彩显示屏,你在模块商那里看到的绝大多数都是PM架构;而手机屏、平板、智能手表和未来的MicroLED高密度屏,才需要AM架构去兜底。理解PM的扫描原理,不仅能让16×16贪吃蛇这类项目跑得顺,还能帮你把后续看所有LED驱动方案的眼力都练出来。先把扫描吃透,再去研究TFT补偿,整个人对显示的认知框架就不会乱。