资讯动态

STM32驱动MAX7219控制8x8点阵显示0-9:从GPIO模拟到SPI完整实战

发布时间:2026/10/14 19:02:37 来源:尧图企业网站定制
简介一套基于STM32微控制器与MAX7219驱动芯片的八乘八LED点阵显示工程面向嵌入式初学者实现数字0至9的点阵显示。项目通过串行外设接口完成主控芯片与显示驱动的通信覆盖时钟配置、引脚复用、显示数据生成与扫描刷新等环节可帮助读者理解同步串行协议和点阵控制原理。压缩包共一百二十一个文件大小约一点二兆以C语言源文件与头文件为主同时包含集成开发环境工程文件、编译生成的镜像文件及中间产物既可直接编译烧录也便于按需修改验证。目前已有四百二十人学习适合用于课程设计、电子竞赛或入门实践。包内除核心显示逻辑外还提供定时器、闪存、模数转换、集成电路总线、控制器局域网、通用异步收发器等标准外设库源码可作为微控制器基础驱动代码参考。1. 8x8点阵不是点亮就行先说清这份资源的边界STM32F103C8T6 驱动的 8x8LED点阵模块MAX7219 方案经常被当成入门外设但很多人把示例代码烧进去之后得到的是乱码、镜像、甚至是全暗屏幕——不是芯片坏了而是字模方向、译码模式、供电接线三件事没对齐。这份压缩包就是围绕“显示 0-9”这个课程设计级目标整理出来的完整工程里面包含驱动初始化、16 位串行写入函数、0-9 字模数组和主循环调用拿过来改改引脚就能跑。适合两类人一是想快速交差的学生二是手里有 8x8 模块但始终搞不清“行扫描、列扫描、镜像”关系的人。下面我会按协议、字模、代码、坑位、进阶五条线拆开讲每一步都能照着执行。2. MAX7219驱动8x8点阵从协议原理到引脚接线2.1 MAX7219的串行协议16位一帧别和标准SPI寄存器概念混MAX7219 不是 I2C也不是严格意义上的标准 SPI 外设它用一组由 DIN、CLK、CS/LOAD 组成的三线串行接口。每次传输固定为 16 位帧前 8 位是要操作的寄存器地址后 8 位是该寄存器的数据。所有位都按高位先出的顺序在每个 CLK 上升沿被芯片采样CS/LOAD 保持低电平等到 16 位全部移完再把 CS/LOAD 拉高这次写入才真正锁存进去。你可以理解成“CS 低电平期间不允许中途跳变否则芯片会认为这是一帧脏数据”。资源包里默认用 GPIO 模拟这套时序而不是直接开硬件 SPI这个选择在实际课程设计里很常见。原因有三个第一单个 MAX7219 模块只需要 DIN、CLK、CS 三根信号线GPIO 完全够用第二用 GPIO 模拟时对时钟极性和相位的理解最直观DS18B20、红外遥控这类外设以后也还会用到这个套路第三硬件 SPI 一次只能发 8 位你要连发两个字节中间还得手动控制 CS 线处理不当反而容易在帧边界处多出一个时钟沿。所以压缩包里给出的是 GPIO 模拟版本代码量不大却能把协议吃透。MAX7219 内部可操作寄存器主要有几个0x01 到 0x08 是 8 个显示数据寄存器对应 8 行或 8 列具体对应关系看模块 PCB 走线0x09 是译码模式寄存器点阵应用必须写 00x0A 是亮度控制取值 0x00 到 0x0F0x0B 是扫描限制控制扫描几行0x0C 是掉电/正常工作开关0x0F 是显示测试模式。后面初始化代码会逐个设置但你要先记住一个结论点阵显示 0-9 时写的主要是 0x01 到 0x08 这 8 个数据寄存器其他寄存器都只是辅助配置。2.2 接线表STM32F103C8T6最小系统板与MAX7219模块对号入座拿到一块“8x8 点阵 MAX7219 一体”模块时模块上一般有 5 个引脚VCC、GND、DIN、CS、CLK。下面这组接线是压缩包代码里默认的引脚方案也恰好是 F103C8T6 最小系统板上 SPI1 的复用引脚位置后续想切硬件 SPI 不用改板子模块引脚STM32F103C8T6 引脚说明VCC5V 电源引脚绝大多数模块需要 5V 供电3.3V 下点阵亮度明显偏低GNDGND必须和单片机系统共地DINPA7数据输入对应 SPI1_MOSICLKPA5时钟输入对应 SPI1_SCKCS/LOADPA6片选/锁存用普通 GPIO 控制你要注意这个接线表里 VCC 接的是 5V不是 3.3V。我见过不少人在最小系统板上找 3.3V 焊点结果模块能显示但亮度极暗、字迹发虚误以为是字模问题。原因是 MAX7219 内部是低压差恒流源结构输入电压不足时LED 段电流上不去。另外DIN、CLK、CS 三根线尽可能短面包板接线时不要跨过整个板子去绕线太长会带来串扰和压降后面做硬件 SPI 时会更容易出现花屏。如果手里不是一体模块而是那种矩阵屏和 MAX7219 分开卖的裸件接线逻辑一样但必须自己确认点阵的 16 个引脚哪个接 MAX7219 的 DIG 引脚、哪个接 SEG 段引脚。网购的很多 8x8 点阵屏本身没有标注行列这需要你用手头万用表或者一颗测试电阻逐针点亮不建议靠猜。用一体模块就省掉这一步这也是为什么大多数课程设计选一体板。2.3 模块选型一体板与级联板差别很大市面上的 MAX7219 点阵模块大致分两类。第一类是“单 8x8 点阵 单 MAX7219”排针通常按 VCC、GND、DIN、CS、CLK 排列偶尔也有 DOUT 引脚即级联输出。第二类是 FC-16 级联模块常见的是两个 8x8 拼成 8x16或四个 8x8 拼成 16x16板上有两颗或四颗 MAX7219信号通过 DIN 进 DOUT 出串联。压缩包里的驱动默认是针对单模块写的。如果插的是 FC-16 级联板你用默认代码只会看到第一颗芯片有反应后面的屏幕全暗或者出现错位数据。这不是程序没写对而是级联时同一帧数据会从第一颗芯片的 DOUT 移向下一颗芯片。正确方法是把要显示给“离单片机最远那块屏”的数据先发出去再发离单片机最近那块屏的数据并在最后一个字节后统一拉高 CS。课程设计如果只是“显示 0-9”这个要求直接用单模块最省事不要主动给自己找级联的麻烦。另外模块的 5V 供电电流要比你想的大。全亮状态下8x8 点阵满载电流往往到 250mA 以上便宜的开发板板载 LDO 根本拖不动。最稳的做法是独立的 5V 稳压模块给 MAX7219 供电F103C8T6 板子单独上电下载两者只要共地即可。项目包里给的初始化代码不处理电源问题但你在实际排线时必须先想清楚否则后面做亮度测试时数字 8 一亮单片机板子上的指示灯都跟着闪。3. 显示0-9的字模数据编码方式与字体细节3.1 先分清“段”和“位”字模是行编码还是列编码8x8 点阵里面有 8 行、8 列共 64 个 LED。MAX7219 的数据寄存器地址 0x01 到 0x08 对应的是芯片扫描的 8 个“位”每个数据字节的 8 个 bit 对应 8 个“段”。问题在于模块厂家把点阵的行和列接到 MAX7219 的 DIG 与 SEG 上时两种接法都有人用。一种常见接法是DIG0 到 DIG7 对应点阵的行SEG A 到 SEG G、DP 对应点阵的列。这时候你往 0x01 寄存器写一个字节实际显示的是点阵第一行的 8 个点。另一种接法会反过来DIG 对应列、SEG 对应行那寄存器地址就代表列而不是行。字模表直接拷过来经常出现数字整体旋转 90 度或者水平镜像。怎么判断你的模块是哪一种很简单写一段测试代码调用 MAX7219_Write(0x01, 0xFF)其余寄存器正常配置看屏幕上是亮了一行还是一列再写 MAX7219_Write(0x01, 0x01)看点亮的是不是这条线上最左边或最右边那一点。资源包里的字模如果上电后方向不对就按这个测试方法去对位而不是盲目改代码。源码包的注释通常会写“行扫描”或“列扫描”但新人最容易忽略的是即使同为行扫描字节内 bit0 对应左侧还是右侧 LED 也可能相反。这就导致字节层面的“镜像”需要做位反转。下面一节给的字模数组是我按常用一体模块整理出来的基准表实际使用前建议先烧一遍 0 到 9 循环看看镜像问题是否出现。3.2 0-9字模表源码包里的font数组就是这路子资源包里的字模数组在 font.h 文件中结构大概是这样每个数字占 8 个字节每个字节表示一行或一列static const uint8_t font_8x8[10][8] { {0x3C, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x3C}, /* 0 */ {0x08, 0x18, 0x08, 0x08, 0x08, 0x08, 0x08, 0x1C}, /* 1 */ {0x3E, 0x41, 0x01, 0x02, 0x0C, 0x10, 0x20, 0x7F}, /* 2 */ {0x3E, 0x41, 0x01, 0x0E, 0x01, 0x01, 0x41, 0x3E}, /* 3 */ {0x04, 0x0C, 0x14, 0x24, 0x44, 0x7F, 0x04, 0x04}, /* 4 */ {0x7F, 0x40, 0x40, 0x7E, 0x01, 0x01, 0x41, 0x3E}, /* 5 */ {0x1E, 0x20, 0x40, 0x7E, 0x42, 0x42, 0x42, 0x3C}, /* 6 */ {0x7F, 0x01, 0x02, 0x04, 0x08, 0x10, 0x10, 0x10}, /* 7 */ {0x3C, 0x42, 0x42, 0x3C, 0x42, 0x42, 0x42, 0x3C}, /* 8 */ {0x3C, 0x42, 0x42, 0x3E, 0x02, 0x02, 0x04, 0x38}, /* 9 */ };以上是一套按“行扫描、高比特对应左侧”的思路画的字模。可以看到数字 0 是第 1 行两侧亮、中间不亮第 2 到第 7 行两端亮、中间暗最后一行两侧再收拢。你可以把 0x3C 拆成二进制也就是 0b00111100四颗灯在中间两侧各留两个空位。逐字节核对就知道每个数字的 8 行是怎么拼出来的。这个表不要求你背关键是学会验证。压缩包里的字模可能和我列出的不完全一致因为不同模块的接法不同作者在整理时可能事先做过位反转。你拿到代码后第一件事不是改算法而是把数字 0 单独显示出来对照上面的二进制逻辑看左右是否反了。如果反了就用一个字节反转函数预处理后面会讲。3.3 译码模式必须关掉不然点阵画不出你要的形状MAX7219 最让人困惑的一个寄存器是 0x09 译码模式。它本来是给 7 段数码管用的芯片可以把数据字节直接解释成“0”到“9”对应的段码省掉软件查表。但在 8x8 点阵上打开译码模式会让点阵芯片把数据和内部 7 段译码表对应起来你原本按“每行一个字节”组织的点阵图案会变得完全不可控表现出来就是数字乱闪、无法还原字形。所以初始化代码里必须写 MAX7219_Write(0x09, 0x00)。这个 0x00 的含义是8 位显示数据全部不译码D7 到 D0 每一位都直接驱动对应段。资源包里的主函数如果有“数字依然乱码”的反馈记录十有八九是有人把 0x09 参数误写成 0xFF。写成 0xFF 在某些 7 段模块上会很好用但在 8x8 点阵场景就是翻车现场。另一个容易忽略的是 0x0C 关机寄存器。MAX7219 上电默认处于 shutdown 模式需要写 0x01 才进入正常工作。如果代码里只配了译码、扫描、亮度忘了最后把 0x0C 写成 0x01那屏幕就是全暗的而且你不会立刻怀疑到软件因为硬件看着没毛病。初始化顺序我一般建议先写 0x0C0x00 进入关机再配 0x09、0x0B、0x0A最后写 0x0C0x01 打开显示。这样能避免上电瞬间寄存器处于半配置状态把花屏概率降到最低。4. 完整工程解析初始化、写入函数与调用顺序4.1 初始化流程先关显示再配寄存器最后打开压缩包的主控制逻辑一般分两段第一段是 MAX7219 初始化第二段是主循环里循环显示 0-9。初始化代码如下面这样模块里用到的寄存器顺序在这里体现得很完整void MAX7219_Init(void) { MAX7219_Write(0x0C, 0x00); // 进入shutdown模式避免配置中途乱显示 MAX7219_Write(0x09, 0x00); // 关闭BCD译码点阵模式必须设为0 MAX7219_Write(0x0B, 0x07); // 扫描限制设为7即扫描全部8行 MAX7219_Write(0x0A, 0x06); // 亮度寄存器初始值取中间档 MAX7219_Write(0x0C, 0x01); // 退出shutdown恢复显示 }这段代码逻辑很清楚。第一句先写 0x0C 为 0相当于把芯片先关掉让后续寄存器配置过程在屏幕熄灭状态下完成。第二句关闭译码模式点阵才能接收你自定义的字模。第三句 0x0B 写 0x07 不是“只扫描 7 行”而是扫描限制值的含义是从 0 计数到 7也就是 8 行。第四句 0x0A 写 0x06亮度不是开最大初始给个中等亮度方便在调试时区分程序问题和硬件问题。最后一句再次写 0x0C 的 0x01芯片才开始正常扫描显示。这里要强调一个常见的错误把这五句顺序倒过来先打开显示再配置寄存器。上电瞬间 MAX7219 每个显示寄存器里可能是随机值如果你先开 0x0C屏幕会立刻把随机数据显示出来然后你再一行一行改寄存器就能看到“扫过去一行变一下”的怪像。虽然最终也能恢复正常但每次复位都会闪一下观感很差而且会让新手误以为硬件不稳定。4.2 逐字节写入函数CS拉低、16个CLK边沿、CS拉高GPIO 模拟的核心写入函数是这个工程里被调用最多次的函数。它的任务就是把“寄存器地址 数据”组成 16 位按高位先发最后锁存void MAX7219_Write(uint8_t reg, uint8_t data) { uint8_t i; CS_LOW(); // 拉低LOAD/CS开始一帧传输 for (i 0; i 8; i) { CLK_LOW(); // 时钟先拉低为上升沿做准备 if ((reg (7 - i)) 0x01) DIN_HIGH(); // 发送地址位从最高位开始 else DIN_LOW(); CLK_HIGH(); // 上升沿MAX7219采样当前DIN电平 } for (i 0; i 8; i) { CLK_LOW(); if ((data (7 - i)) 0x01) DIN_HIGH(); // 再发送8位数据 else DIN_LOW(); CLK_HIGH(); } CS_HIGH(); // 拉高CS整帧16位数据被锁存进MAX7219 }逻辑拆开看CS_LOW 之后第一个 for 循环依次发送 reg 的 bit7 到 bit0每次发送前 CLK 拉低设置完 DIN 电平后 CLK 拉高形成上升沿。MAX7219 就是在 CLK 上升沿把 DIN 读进去的。第二个 for 循环完全一样只是发送对象换成 data。最后 CS_HIGH 这步不能省如果不拉高前面 16 个时钟沿全部白费。参数上你只需要改两处reg 是寄存器地址比如 0x01 到 0x08 对应点阵第 1 行到第 8 行data 是你要显示的那一行字节。代码里的(reg (7 - i)) 0x01是一种标准写法它的效果是依次取出 reg 的最高位、次高位……直到最低位。如果你更喜欢直观写法也可以改成((reg i) 0x80)效果一样只是可读性差一点。4.3 压缩包内的文件结构烧录前先改这三个地方压缩包解开后通常包含这些文件我按最常见的结构列一下文件作用main.c时钟配置、引脚初始化、主循环调用显示MAX7219.c / MAX7219.h驱动主机代码font.h0-9 字模数组定义工程文件打开后直接编译烧录烧录前建议你先改三个地方。第一确认 main.c 里引脚的宏定义和你的接线一致尤其是 DIN、CLK、CS 这三个宏不要实际接 PA5/PA6/PA7代码里却写 PB5/PB6/PB7。第二确认 5V 供电确实到位用万用表量模块 VCC 和 GND 之间电压不要只看 USB 供电灯亮就默认模块也是 5V。第三确认字体方向烧进去之后先显示一个 0判断是否需要做位反转或数组转置。这个工程并不复杂main.c 里主循环一般就是不断调用ShowDigit(0)、延时、ShowDigit(1)这样循环。看清楚调用关系后你要改成“显示 0-9 循环一次后停留”或“按键切数字”都很容易。资源包覆盖的是完整流程剩下的灵活性完全在你自己手里。5. 常见问题排查不显示、镜像、花屏和亮度坑5.1 现象上电全亮或按复位时闪过正常字形平时全暗很多同学第一次烧录后点阵要么全亮没有变化要么按一下单片机复位键屏幕闪一下正确字形然后又暗掉。这个现象看起来像是程序没烧进去其实多半是 CS 引脚浮空导致帧数据无法稳定锁存。原因在于 STM32 上电复位瞬间PA6 如果没被配置成推挽输出输入模式下引脚电平不确定。MAX7219 在 CS 电平不稳定时会把移位寄存器里的数据随机锁存于是显示乱掉。复位一瞬间有一个低电平窗口恰好让单片机把正确数据写入进去看起来就“闪了一下正常字形”。解决方法是初始化引脚时先把 CS 配置为推挽输出并拉高再执行 MAX7219 初始化。如果你用的是某开发板还要检查 CS 引脚是否和调试器接口或板上 LED 共用了同一 GPIO。F103C8T6 最小系统板的 PA6 一般没复用但如果你把 PA6 插了杜邦线到模块杜邦线悬空或接触不良也会产生同样现象。重插一遍并确保共地能解决掉一半电源相关的玄学问题。5.2 现象数字能显示但看起来像照镜子左右完全相反这是点阵模块最经典的镜像问题。你心里想的“1”在最右边靠边屏幕上却出现在最左边或者数字“6”的圆弧方向相反。第一个反应不要是换模块或重新下载程序而是检查字模字节的位顺序。原因是 MAX7219 的数据字节 D7 到 D0 对应 SEG A 到 SEG G、DP但不同模块在布线时可能把 D7 接到点阵最左侧也可能把 D0 接到最左侧。同一个字模数组在两种模块上显示就互为镜像。解决的思路是写一个字节反转函数在显示前对每个字模字节做一次镜像翻转uint8_t ReverseByte(uint8_t value) { uint8_t result 0; uint8_t i; for (i 0; i 8; i) { result 1; result | (value 0x01); value 1; } return result; }然后在 ShowDigit 函数里把font_8x8[num][row]替换成ReverseByte(font_8x8[num][row])再调用 MAX7219_Write。注意反转的是字节内部位序不是数组行号。如果你发现数字旋转了 90 度那是行和列的概念对调了需要改变循环方式把第 row 行第 col 列点提出来重新组成新数组这就不是一次 ReverseByte 能解决的。建议先只对数字 0 做测试左右反了就用上面的函数上下反了就是寄存器地址与字模行序对应反了把 for 循环反过来即可。5.3 现象亮度调低没用0x0A 寄存器写 0x00 还是刺眼项目需求里可能会写“显示亮度可调”于是你在主循环里把 0x0A 寄存器从 0x00 到 0x0F 都试了一遍发现亮度变化不大甚至写 0x00 还是亮得刺眼。这个问题的根因不在程序逻辑而在硬件限流电阻。MAX7219 的 ISET 引脚到 VCC 之间会接一个电阻它决定了 LED 段电流的基准。很多一体模块出厂时为了达到足够亮度把限流电阻选得较小导致最小段电流也超过人眼舒适范围。0x0A 亮度寄存器控制的是扫描占空比相当于调节平均亮度但它的调节范围受硬件电流基准限制并不能把亮度压到熄灭级别。正确做法是先检查模块硬件上的电阻参数再通过代码把亮度寄存器设到 0x02 到 0x05 之间不要把希望全压在软件上。还有另一个容易被忽视的情况初始化函数如果在主循环里被反复调用每次都会把你设定的亮度重新覆盖掉。有人的代码在 while(1) 里先 ShowDigit 再 Init结果初始化每次都把 0x0A 写回中间值你在其他位置写多少都会被覆盖。我的习惯是初始化放到 main 函数上线开始处只执行一次主循环只负责刷新显示数据。5.4 现象显示 0 和 1 正常换到 2 或 3 出现毛刺、错位如果数字 0 和 1 清晰数字 2 和 3 偶尔出现多点亮或错行先不要怀疑字模数组。你可以在调试器里单步执行看写入 2 的字模数据是否正确通常数据是对的问题出在 GPIO 翻转速率与线缆质量。GPIO 模拟 SPI 时如果把 STM32 引脚输出速度配置成 50MHz翻转沿会非常陡峭。当杜邦线较长、且 CLK 和 DIN 并行走线时信号之间的串扰会让 MAX7219 在 CLK 上升沿采样到错误电平。这个现象不是每个数字都会出现因为不同数字在同一时刻的 DIN 翻转次数不同恰好翻转组合更容易触发串扰。解决方法是把 GPIO 速度降到 2MHz或者在每个 bit 写入后加一个短暂延时人为降低翻转速率。另一个有效手段是在 CLK 拉高后加一点 tCLK 保持时间代码里表现为CLK_HIGH(); delay_us(1);16 位走完后再 CS_HIGH 锁存。如果毛刺只在快速循环切换数字时出现还要检查刷新间隔。MAX7219 是动态扫描芯片它在内部不断轮流点亮 8 行如果在一次扫描周期中间连续写入 8 个寄存器某些行难免读到新旧数据混杂。我一般会在数字切换之间加一个消隐步骤先写 0x01 到 0x08 全 0延时一两毫秒再写入新的数字字模。这样一来人眼感觉不到熄灭但鬼影明显减少。6. 进阶用法切到硬件SPI让数字轮流刷起来6.1 硬件SPI1配置把GPIO模拟换成外设发送前面提到资源包默认用 GPIO 模拟但你如果想更接近工程化可以把发送部分换成 F103C8T6 的 SPI1 外设。接线不变仍是 PA5、PA6、PA7。初始化配置如下这里用的是常见库函数风格void SPI1_Init(void) { GPIO_InitTypeDef GPIO_InitStructure; SPI_InitTypeDef SPI_InitStructure; RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA | RCC_APB2Periph_SPI1, ENABLE); GPIO_InitStructure.GPIO_Pin GPIO_Pin_5 | GPIO_Pin_7; GPIO_InitStructure.GPIO_Mode GPIO_Mode_AF_PP; GPIO_InitStructure.GPIO_Speed GPIO_Speed_50MHz; GPIO_Init(GPIOA, GPIO_InitStructure); GPIO_InitStructure.GPIO_Pin GPIO_Pin_6; GPIO_InitStructure.GPIO_Mode GPIO_Mode_Out_PP; GPIO_InitStructure.GPIO_Speed GPIO_Speed_50MHz; GPIO_Init(GPIOA, GPIO_InitStructure); SPI_InitStructure.SPI_Direction SPI_Direction_1Line_Tx; SPI_InitStructure.SPI_Mode SPI_Mode_Master; SPI_InitStructure.SPI_DataSize SPI_DataSize_8b; SPI_InitStructure.SPI_CPOL SPI_CPOL_Low; SPI_InitStructure.SPI_CPHA SPI_CPHA_1Edge; SPI_InitStructure.SPI_NSS SPI_NSS_Soft; SPI_InitStructure.SPI_BaudRatePrescaler SPI_BaudRatePrescaler_16; SPI_InitStructure.SPI_FirstBit SPI_FirstBit_MSB; SPI_Init(SPI1, SPI_InitStructure); SPI_Cmd(SPI1, ENABLE); }这段配置里最关键的是时钟极性和相位CPOL 为低、CPHA 为 1Edge即 SPI 模式 0。MAX7219 在 CLK 上升沿采样数据模式 0 正好满足这个时隙要求。BaudRatePrescaler 选 16也就是 SPI 时钟为 72MHz/164.5MHz对 MAX7219 完全绰绰有余。PA6 要提前拉高否则 CS 默认低电平会让芯片认为一直有数据在进入。对应的写寄存器函数也要改但整体逻辑不变CS 拉低发一个字节地址发一个字节数据等待发送完成CS 拉高。所有操作都基于 SPI1 外设12 个寄存器的写入速度会比 GPIO 模拟快得多。6.2 轮播0-9清屏、显示、延时三步走硬件 SPI 写好后主循环可以做成“0 到 9 自动轮播”。我用的是最简单的三步逻辑void ShowDigit(uint8_t num) { uint8_t row; if (num 9) return; for (row 0; row 8; row) { MAX7219_Write(row 1, font_8x8[num][row]); } } void ClearScreen(void) { uint8_t row; for (row 0; row 8; row) { MAX7219_Write(row 1, 0x00); } } int main(void) { uint8_t num 0; SystemInit(); GPIO_Init(); SPI1_Init(); MAX7219_Init(); while (1) { ClearScreen(); delay_ms(2); ShowDigit(num); delay_ms(400); num; if (num 10) num 0; } }这里为什么要先 ClearScreen因为 MAX7219 的显示寄存器会被持续扫描旧字模不会自动消失。数字 0 和 1 差距很大时可能没感觉但 6 和 8 之间切换就会有亮度残留。先清屏两毫秒再写入新数据就能避免两个字模叠印。如果你觉得 400ms 的轮播速度偏慢可以改成 200ms如果项目要求“按键切换数字”把延时改成读按键状态即可。核心是保持刷新函数不阻塞太久MAX7219 本身会动态扫描你只需要在数据变化时重新写入不需要像数码管软件扫描那样一直刷 CPU。6.3 拿到新模块先做四步自检全亮、清屏、定位、数字分享一个我自己常用来验证新模块的流程也适合拿到这份资源后第一次烧录时执行。第一步让 MAX7219 进入测试模式写 0x0F 寄存器为 0x01屏幕会全部点亮如果扫描数据异常就说明硬件本身有问题。第二步退出测试模式并写 0x0F 为 0做一次清屏确认全灭。第三步单独写 0x01 寄存器一个字节确认第一行或第一列的位置背下模块的位序关系。第四步跑 0-9 轮播如果出现镜像或旋转回到第 5 章去改位序。这个四步流程能筛掉九成问题。有一次我把一整套代码移植到对手头的模组直接显示“0-9”全乱后来发现是该模块的 CS 引脚上电逻辑与代码默认相反必须先写低才能完成锁存查了很久才发现。从那以后我每次拿到新矩阵模块都会强制走一遍全亮、清屏、定位、数字自检再开始改功能这个习惯帮我在课程设计答辩前少踩了很多坑。希望帮到你。本文还有配套的精品资源点击获取

读完文章,也想定制专属网站?

尧图设计师 24 小时内与您沟通定制方案

免费获取报价 →
↑