基于GD32E230与MAX7219的8位数码管模块驱动移植实战最近在做一个需要显示数字的小项目手头正好有立创的GD32E230C8T6开发板和一块MAX7219驱动的8位数码管模块。很多刚开始玩嵌入式的小伙伴可能会觉得驱动数码管有点复杂尤其是这种串行控制的芯片。其实只要搞懂它的通信时序移植起来并不难。今天我就带大家从硬件连接到软件编程一步步把这块数码管模块驱动起来让它在你的GD32工程里稳定显示。1. 认识我们的“队友”MAX7219数码管模块在动手写代码之前咱们先得了解要驱动的对象。你手里的这块8位数码管模块核心是一颗叫MAX7219的芯片。它是个“全能管家”专门负责驱动数码管或者LED点阵。MAX7219是干什么的简单说它就是一个串行输入/输出的显示驱动器。你的单片机比如GD32E230只需要用3个普通的IO口通过一种简单的串行协议告诉MAX7219要显示什么剩下的扫描、刷新、驱动电流这些杂活MAX7219全包了。这样一来单片机负担轻了显示还稳定无闪烁。模块关键特性抄自数据手册得记牢控制芯片MAX7219驱动能力能直接连接并驱动8位7段数码管共阴极或者64个独立的LED。核心优势只需要3个IO口DIN, CLK, CS就能控制8位数码管显示稳定不闪烁还支持多片级联扩展。工作电压4V - 5.5V注意GD32E230的IO是3.3V电平但模块是5V供电通信时需要确认电平兼容性通常3.3V输出可以驱动5V输入。通信协议单总线串行通信。提示模块资料和采购链接在原始文章里有提供如果需要可以查看。咱们这篇教程聚焦在如何把现成的驱动代码移植到你的GD32工程里。2. 核心原理MAX7219怎么“听话”想把模块用起来最关键的是搞懂怎么跟MAX7219芯片“对话”。它只听一种语言16位的串行数据包。2.1 通信时序三个引脚的分工模块引出5个引脚但我们驱动它只需要接其中3个DIN (Data In) 数据输入线。你要发送的数据就从这根线一位一位地传进去。CLK (Clock) 时钟线。它像指挥棒每个上升沿告诉MAX7219“注意现在DIN线上的数据位有效请收下。”CS (Chip Select) 片选线。拉低时表示“我要开始跟你说话了”拉高时表示“我说完了你可以处理了”。通信流程务必理解先把CS引脚拉低选中芯片。在CLK的每个上升沿MAX7219会读取一次DIN引脚上的电平0或1。这样连续读取16次就凑成了一个16位的数据包。16位数据发送完毕后在下一个CLK上升沿到来之前必须把CS拉高。这个上升沿会触发MAX7219把刚刚收到的16位数据锁存到内部寄存器。如果CS拉高晚了数据就丢了。2.2 数据包格式16位里说了啥发送的16位数据不是乱来的它有固定的格式位域 (Bit)D15-D12D11-D8D7-D0含义无效位寄存器地址数据说明忽略即可告诉MAX7219你要操作哪个寄存器你要写入这个寄存器的具体数据举个例子如果你想设置“译码方式寄存器”地址是0x09让所有数码管都按BCD码译码显示0-9那么需要写入的数据是0xFF。 那么组成的16位数据包就是地址(0x09) 数据(0xFF)。 在发送时先发高8位地址0x09再发低8位数据0xFF。3. 动手移植把代码“搬”到GD32工程理论懂了接下来就是实战。我们目标是在立创GD32E230C8T6的开发板工程里加入MAX7219的驱动代码。3.1 文件准备与工程添加首先我们需要创建两个文件bsp_max7219.c– 驱动函数的实现文件。bsp_max7219.h– 驱动函数的声明和引脚宏定义。怎么添加到工程里呢以常见的IDE如Keil为例在工程目录的Hardware文件夹或你自己存放外设驱动的文件夹里新建这两个文件。在IDE的工程管理窗口中右键点击源文件分组如User选择“添加现有文件到组...”然后选中bsp_max7219.c。头文件bsp_max7219.h通常不需要手动添加路径只要它和bsp_max7219.c在同一个目录或者该目录已被包含在工程的全局头文件路径中即可。注意根据原始文章提示立创的示例工程可能已经包含了Hardware文件夹的路径所以bsp_max7219.h会被自动找到。3.2 引脚配置与宏定义我们需要在bsp_max7219.h中定义单片机与模块连接的引脚。原文示例使用的是GPIOA的PIN1、2、3。// bsp_max7219.h 中的关键宏定义 #include gd32e23x.h // 引脚时钟定义 #define RCU_MAX7219_CLK RCU_GPIOA #define RCU_MAX7219_DIN RCU_GPIOA #define RCU_MAX7219_CS RCU_GPIOA // 引脚端口和编号定义 #define PORT_MAX7219_CLK GPIOA #define GPIO_MAX7219_CLK GPIO_PIN_3 #define PORT_MAX7219_DIN GPIOA #define GPIO_MAX7219_DIN GPIO_PIN_1 #define PORT_MAX7219_CS GPIOA #define GPIO_MAX7219_CS GPIO_PIN_2 // 操作引脚的便捷宏X为1则置高为0则置低 #define MAX7219_CLK(X) gpio_bit_write(PORT_MAX7219_CLK, GPIO_MAX7219_CLK, X?SET:RESET) #define MAX7219_DIN(X) gpio_bit_write(PORT_MAX7219_DIN, GPIO_MAX7219_DIN, X?SET:RESET) #define MAX7219_CS(X) gpio_bit_write(PORT_MAX7219_CS, GPIO_MAX7219_CS, X?SET:RESET)接着在bsp_max7219.c中实现引脚的初始化函数MAX7219_GPIO_Init。这个函数负责打开GPIO时钟并把三个引脚配置为推挽输出模式。// bsp_max7219.c 中的引脚初始化函数 void MAX7219_GPIO_Init(void) { /* 开启GPIOA的时钟 */ rcu_periph_clock_enable(RCU_MAX7219_CLK); rcu_periph_clock_enable(RCU_MAX7219_DIN); rcu_periph_clock_enable(RCU_MAX7219_CS); // 实际CLK/DIN/CS都用PA时钟这里调用三次是示例写法 /* 配置CLK引脚为输出模式上拉推挽输出速度50MHz */ gpio_mode_set(PORT_MAX7219_CLK, GPIO_MODE_OUTPUT, GPIO_PUPD_PULLUP, GPIO_MAX7219_CLK); gpio_output_options_set(PORT_MAX7219_CLK, GPIO_OTYPE_PP, GPIO_OSPEED_50MHZ, GPIO_MAX7219_CLK); gpio_bit_set(PORT_MAX7219_CLK, GPIO_MAX7219_CLK); // 初始化为高电平 /* 配置DIN引脚 (配置同上) */ gpio_mode_set(PORT_MAX7219_DIN, GPIO_MODE_OUTPUT, GPIO_PUPD_PULLUP, GPIO_MAX7219_DIN); gpio_output_options_set(PORT_MAX7219_DIN, GPIO_OTYPE_PP, GPIO_OSPEED_50MHZ, GPIO_MAX7219_DIN); gpio_bit_set(PORT_MAX7219_DIN, GPIO_MAX7219_DIN); /* 配置CS引脚 (配置同上) */ gpio_mode_set(PORT_MAX7219_CS, GPIO_MODE_OUTPUT, GPIO_PUPD_PULLUP, GPIO_MAX7219_CS); gpio_output_options_set(PORT_MAX7219_CS, GPIO_OTYPE_PP, GPIO_OSPEED_50MHZ, GPIO_MAX7219_CS); gpio_bit_set(PORT_MAX7219_CS, GPIO_MAX7219_CS); }3.3 核心驱动函数编写这是驱动层最核心的部分对应我们前面讲的时序。首先写一个发送一个字节8位的函数// 向MAX7219写入一个字节 void Write_Max7219_byte(uint8_t dat) { uint8_t i; MAX7219_CS(0); // 开始通信拉低CS for(i8; i1; i--) // 循环8次发送8个bit { MAX7219_CLK(0); // 先将时钟拉低 // 判断要发送的数据最高位bit7是1还是0 if(dat 0x80) { MAX7219_DIN(1); // 是1则DIN输出高电平 } else { MAX7219_DIN(0); // 是0则DIN输出低电平 } dat dat 1; // 将数据左移一位准备发送下一个bit MAX7219_CLK(1); // 将时钟拉高产生上升沿MAX7219在此时采样DIN数据 } }然后利用上面的函数实现发送16位数据包地址数据的函数// 向MAX7219写入数据地址数据 void Write_Max7219(uint8_t address, uint8_t dat) { MAX7219_CS(0); // 拉低CS开始传输 Write_Max7219_byte(address); // 先发送高8位寄存器地址 Write_Max7219_byte(dat); // 再发送低8位要写入的数据 MAX7219_CS(1); // 拉高CS结束传输数据在CS的上升沿被锁存 }这个Write_Max7219函数就是我们以后控制MAX7219最常用的工具。3.4 初始化MAX7219芯片芯片上电后需要一些配置才能正常工作。我们把这些配置集中在一个初始化函数里。void MAX7219_Init(void) { MAX7219_GPIO_Init(); // 1. 初始化GPIO引脚 // 2. 配置MAX7219内部寄存器 Write_Max7219(0x09, 0xff); // 设置译码方式0xFF表示所有8位数码管都使用BCD译码显示0-9,-,E,H,L,P,灭 Write_Max7219(0x0a, 0x03); // 设置亮度值范围0x00~0x0F0x0F最亮 Write_Max7219(0x0b, 0x07); // 设置扫描界限0x07表示扫描0-7共8个数码管 Write_Max7219(0x0c, 0x01); // 设置关机模式0x00-关机0x01-正常操作 Write_Max7219(0x0f, 0x01); // 开启显示测试所有段点亮。测试完后需关闭设为0x00 }这里有几个关键寄存器0x09 (译码模式) 告诉芯片哪些数码管需要把数字如‘3’自动译码成对应的段码a-g段哪些亮。0xFF表示全部需要。0x0B (扫描界限) 告诉芯片你实际接了几个数码管。0x07表示扫描8位0-7。0x0C (关机模式) 必须设置为0x01才能正常显示。0x0F (显示测试) 上电后可以先设为0x01让所有段全亮一下测试硬件是否正常然后再设为0x00进入正常模式。4. 实战演示让数码管动起来驱动都写好了现在我们在主函数里调用它们实现一个简单的显示效果。#include gd32e23x.h #include systick.h #include bsp_usart.h #include stdio.h #include bsp_max7219.h // 包含我们刚写的驱动头文件 int main(void) { int i 0; systick_config(); // 初始化系统滴答定时器用于延时 usart_gpio_config(115200U); // 初始化串口用于打印调试信息可选 MAX7219_Init(); // 初始化MAX7219 delay_1ms(1000); // 延时1秒 Write_Max7219(0x0f, 0x00); // 关闭显示测试进入正常显示模式 // 先让所有数码管熄灭可选地址1-8对应数码管1-8数据0x0F表示熄灭 for(i 1; i 9; i) { Write_Max7219(i, 0x0F); } delay_1ms(500); printf(MAX7219 Demo Start!\r\n); // 串口打印开始信息 while(1) { // 循环让第1个数码管显示1第2个显示2...第8个显示8 for(i 1; i 9; i) { Write_Max7219(i, i); // 地址i数据i。因为开启了BCD译码数据i会被译码成数字i显示。 delay_1ms(1000); // 每个数字显示1秒 } // 循环结束后会重新从1开始显示 } }上电后的现象应该是所有数码管全亮一下显示测试。所有数码管熄灭。从左边第一个数码管开始依次显示数字1, 2, 3, ..., 8每个数字停留1秒然后循环。5. 进阶与排错如何显示特定的数字在BCD译码模式下初始化时设置了0x09, 0xff向数码管写入0-9的数字它会自动显示。如果想显示小数点需要用到非译码模式直接控制段码那就要查7段数码管的段码表了这里先不展开。如果显示不正常怎么排查检查硬件连接 DIN, CLK, CS三根线是否接对模块供电5V和地线是否接好GD32的IO口是否和定义的一致检查时序 用逻辑分析仪或示波器抓一下DIN, CLK, CS的波形对照数据手册的时序图看CS是否在16个CLK周期后拉高。检查初始化序列 确保MAX7219_Init()函数里的几个寄存器配置命令都成功发送了。尤其是关机寄存器0x0C必须设为0x01。检查电平 GD32是3.3V系统模块是5V。虽然通常3.3V的IO高电平能被5V系统识别为高但如果不行可能需要电平转换电路。支持级联是的MAX7219支持级联。模块上留有DOUT引脚就是用来输出数据给下一片芯片的。驱动级联时需要发送更多位的数据16位 * 芯片数并且注意Write_Max7219_2函数里对前一片芯片的空操作指令。好了代码移植和基本使用的过程就是这样。整个过程的核心就是理解串行时序和数据包格式。一旦驱动调通你就可以用它来显示时间、温度、计数器等各种信息了。希望这篇教程能帮你顺利点亮你的数码管
基于GD32E230与MAX7219的8位数码管模块驱动移植实战
基于GD32E230与MAX7219的8位数码管模块驱动移植实战最近在做一个需要显示数字的小项目手头正好有立创的GD32E230C8T6开发板和一块MAX7219驱动的8位数码管模块。很多刚开始玩嵌入式的小伙伴可能会觉得驱动数码管有点复杂尤其是这种串行控制的芯片。其实只要搞懂它的通信时序移植起来并不难。今天我就带大家从硬件连接到软件编程一步步把这块数码管模块驱动起来让它在你的GD32工程里稳定显示。1. 认识我们的“队友”MAX7219数码管模块在动手写代码之前咱们先得了解要驱动的对象。你手里的这块8位数码管模块核心是一颗叫MAX7219的芯片。它是个“全能管家”专门负责驱动数码管或者LED点阵。MAX7219是干什么的简单说它就是一个串行输入/输出的显示驱动器。你的单片机比如GD32E230只需要用3个普通的IO口通过一种简单的串行协议告诉MAX7219要显示什么剩下的扫描、刷新、驱动电流这些杂活MAX7219全包了。这样一来单片机负担轻了显示还稳定无闪烁。模块关键特性抄自数据手册得记牢控制芯片MAX7219驱动能力能直接连接并驱动8位7段数码管共阴极或者64个独立的LED。核心优势只需要3个IO口DIN, CLK, CS就能控制8位数码管显示稳定不闪烁还支持多片级联扩展。工作电压4V - 5.5V注意GD32E230的IO是3.3V电平但模块是5V供电通信时需要确认电平兼容性通常3.3V输出可以驱动5V输入。通信协议单总线串行通信。提示模块资料和采购链接在原始文章里有提供如果需要可以查看。咱们这篇教程聚焦在如何把现成的驱动代码移植到你的GD32工程里。2. 核心原理MAX7219怎么“听话”想把模块用起来最关键的是搞懂怎么跟MAX7219芯片“对话”。它只听一种语言16位的串行数据包。2.1 通信时序三个引脚的分工模块引出5个引脚但我们驱动它只需要接其中3个DIN (Data In) 数据输入线。你要发送的数据就从这根线一位一位地传进去。CLK (Clock) 时钟线。它像指挥棒每个上升沿告诉MAX7219“注意现在DIN线上的数据位有效请收下。”CS (Chip Select) 片选线。拉低时表示“我要开始跟你说话了”拉高时表示“我说完了你可以处理了”。通信流程务必理解先把CS引脚拉低选中芯片。在CLK的每个上升沿MAX7219会读取一次DIN引脚上的电平0或1。这样连续读取16次就凑成了一个16位的数据包。16位数据发送完毕后在下一个CLK上升沿到来之前必须把CS拉高。这个上升沿会触发MAX7219把刚刚收到的16位数据锁存到内部寄存器。如果CS拉高晚了数据就丢了。2.2 数据包格式16位里说了啥发送的16位数据不是乱来的它有固定的格式位域 (Bit)D15-D12D11-D8D7-D0含义无效位寄存器地址数据说明忽略即可告诉MAX7219你要操作哪个寄存器你要写入这个寄存器的具体数据举个例子如果你想设置“译码方式寄存器”地址是0x09让所有数码管都按BCD码译码显示0-9那么需要写入的数据是0xFF。 那么组成的16位数据包就是地址(0x09) 数据(0xFF)。 在发送时先发高8位地址0x09再发低8位数据0xFF。3. 动手移植把代码“搬”到GD32工程理论懂了接下来就是实战。我们目标是在立创GD32E230C8T6的开发板工程里加入MAX7219的驱动代码。3.1 文件准备与工程添加首先我们需要创建两个文件bsp_max7219.c– 驱动函数的实现文件。bsp_max7219.h– 驱动函数的声明和引脚宏定义。怎么添加到工程里呢以常见的IDE如Keil为例在工程目录的Hardware文件夹或你自己存放外设驱动的文件夹里新建这两个文件。在IDE的工程管理窗口中右键点击源文件分组如User选择“添加现有文件到组...”然后选中bsp_max7219.c。头文件bsp_max7219.h通常不需要手动添加路径只要它和bsp_max7219.c在同一个目录或者该目录已被包含在工程的全局头文件路径中即可。注意根据原始文章提示立创的示例工程可能已经包含了Hardware文件夹的路径所以bsp_max7219.h会被自动找到。3.2 引脚配置与宏定义我们需要在bsp_max7219.h中定义单片机与模块连接的引脚。原文示例使用的是GPIOA的PIN1、2、3。// bsp_max7219.h 中的关键宏定义 #include gd32e23x.h // 引脚时钟定义 #define RCU_MAX7219_CLK RCU_GPIOA #define RCU_MAX7219_DIN RCU_GPIOA #define RCU_MAX7219_CS RCU_GPIOA // 引脚端口和编号定义 #define PORT_MAX7219_CLK GPIOA #define GPIO_MAX7219_CLK GPIO_PIN_3 #define PORT_MAX7219_DIN GPIOA #define GPIO_MAX7219_DIN GPIO_PIN_1 #define PORT_MAX7219_CS GPIOA #define GPIO_MAX7219_CS GPIO_PIN_2 // 操作引脚的便捷宏X为1则置高为0则置低 #define MAX7219_CLK(X) gpio_bit_write(PORT_MAX7219_CLK, GPIO_MAX7219_CLK, X?SET:RESET) #define MAX7219_DIN(X) gpio_bit_write(PORT_MAX7219_DIN, GPIO_MAX7219_DIN, X?SET:RESET) #define MAX7219_CS(X) gpio_bit_write(PORT_MAX7219_CS, GPIO_MAX7219_CS, X?SET:RESET)接着在bsp_max7219.c中实现引脚的初始化函数MAX7219_GPIO_Init。这个函数负责打开GPIO时钟并把三个引脚配置为推挽输出模式。// bsp_max7219.c 中的引脚初始化函数 void MAX7219_GPIO_Init(void) { /* 开启GPIOA的时钟 */ rcu_periph_clock_enable(RCU_MAX7219_CLK); rcu_periph_clock_enable(RCU_MAX7219_DIN); rcu_periph_clock_enable(RCU_MAX7219_CS); // 实际CLK/DIN/CS都用PA时钟这里调用三次是示例写法 /* 配置CLK引脚为输出模式上拉推挽输出速度50MHz */ gpio_mode_set(PORT_MAX7219_CLK, GPIO_MODE_OUTPUT, GPIO_PUPD_PULLUP, GPIO_MAX7219_CLK); gpio_output_options_set(PORT_MAX7219_CLK, GPIO_OTYPE_PP, GPIO_OSPEED_50MHZ, GPIO_MAX7219_CLK); gpio_bit_set(PORT_MAX7219_CLK, GPIO_MAX7219_CLK); // 初始化为高电平 /* 配置DIN引脚 (配置同上) */ gpio_mode_set(PORT_MAX7219_DIN, GPIO_MODE_OUTPUT, GPIO_PUPD_PULLUP, GPIO_MAX7219_DIN); gpio_output_options_set(PORT_MAX7219_DIN, GPIO_OTYPE_PP, GPIO_OSPEED_50MHZ, GPIO_MAX7219_DIN); gpio_bit_set(PORT_MAX7219_DIN, GPIO_MAX7219_DIN); /* 配置CS引脚 (配置同上) */ gpio_mode_set(PORT_MAX7219_CS, GPIO_MODE_OUTPUT, GPIO_PUPD_PULLUP, GPIO_MAX7219_CS); gpio_output_options_set(PORT_MAX7219_CS, GPIO_OTYPE_PP, GPIO_OSPEED_50MHZ, GPIO_MAX7219_CS); gpio_bit_set(PORT_MAX7219_CS, GPIO_MAX7219_CS); }3.3 核心驱动函数编写这是驱动层最核心的部分对应我们前面讲的时序。首先写一个发送一个字节8位的函数// 向MAX7219写入一个字节 void Write_Max7219_byte(uint8_t dat) { uint8_t i; MAX7219_CS(0); // 开始通信拉低CS for(i8; i1; i--) // 循环8次发送8个bit { MAX7219_CLK(0); // 先将时钟拉低 // 判断要发送的数据最高位bit7是1还是0 if(dat 0x80) { MAX7219_DIN(1); // 是1则DIN输出高电平 } else { MAX7219_DIN(0); // 是0则DIN输出低电平 } dat dat 1; // 将数据左移一位准备发送下一个bit MAX7219_CLK(1); // 将时钟拉高产生上升沿MAX7219在此时采样DIN数据 } }然后利用上面的函数实现发送16位数据包地址数据的函数// 向MAX7219写入数据地址数据 void Write_Max7219(uint8_t address, uint8_t dat) { MAX7219_CS(0); // 拉低CS开始传输 Write_Max7219_byte(address); // 先发送高8位寄存器地址 Write_Max7219_byte(dat); // 再发送低8位要写入的数据 MAX7219_CS(1); // 拉高CS结束传输数据在CS的上升沿被锁存 }这个Write_Max7219函数就是我们以后控制MAX7219最常用的工具。3.4 初始化MAX7219芯片芯片上电后需要一些配置才能正常工作。我们把这些配置集中在一个初始化函数里。void MAX7219_Init(void) { MAX7219_GPIO_Init(); // 1. 初始化GPIO引脚 // 2. 配置MAX7219内部寄存器 Write_Max7219(0x09, 0xff); // 设置译码方式0xFF表示所有8位数码管都使用BCD译码显示0-9,-,E,H,L,P,灭 Write_Max7219(0x0a, 0x03); // 设置亮度值范围0x00~0x0F0x0F最亮 Write_Max7219(0x0b, 0x07); // 设置扫描界限0x07表示扫描0-7共8个数码管 Write_Max7219(0x0c, 0x01); // 设置关机模式0x00-关机0x01-正常操作 Write_Max7219(0x0f, 0x01); // 开启显示测试所有段点亮。测试完后需关闭设为0x00 }这里有几个关键寄存器0x09 (译码模式) 告诉芯片哪些数码管需要把数字如‘3’自动译码成对应的段码a-g段哪些亮。0xFF表示全部需要。0x0B (扫描界限) 告诉芯片你实际接了几个数码管。0x07表示扫描8位0-7。0x0C (关机模式) 必须设置为0x01才能正常显示。0x0F (显示测试) 上电后可以先设为0x01让所有段全亮一下测试硬件是否正常然后再设为0x00进入正常模式。4. 实战演示让数码管动起来驱动都写好了现在我们在主函数里调用它们实现一个简单的显示效果。#include gd32e23x.h #include systick.h #include bsp_usart.h #include stdio.h #include bsp_max7219.h // 包含我们刚写的驱动头文件 int main(void) { int i 0; systick_config(); // 初始化系统滴答定时器用于延时 usart_gpio_config(115200U); // 初始化串口用于打印调试信息可选 MAX7219_Init(); // 初始化MAX7219 delay_1ms(1000); // 延时1秒 Write_Max7219(0x0f, 0x00); // 关闭显示测试进入正常显示模式 // 先让所有数码管熄灭可选地址1-8对应数码管1-8数据0x0F表示熄灭 for(i 1; i 9; i) { Write_Max7219(i, 0x0F); } delay_1ms(500); printf(MAX7219 Demo Start!\r\n); // 串口打印开始信息 while(1) { // 循环让第1个数码管显示1第2个显示2...第8个显示8 for(i 1; i 9; i) { Write_Max7219(i, i); // 地址i数据i。因为开启了BCD译码数据i会被译码成数字i显示。 delay_1ms(1000); // 每个数字显示1秒 } // 循环结束后会重新从1开始显示 } }上电后的现象应该是所有数码管全亮一下显示测试。所有数码管熄灭。从左边第一个数码管开始依次显示数字1, 2, 3, ..., 8每个数字停留1秒然后循环。5. 进阶与排错如何显示特定的数字在BCD译码模式下初始化时设置了0x09, 0xff向数码管写入0-9的数字它会自动显示。如果想显示小数点需要用到非译码模式直接控制段码那就要查7段数码管的段码表了这里先不展开。如果显示不正常怎么排查检查硬件连接 DIN, CLK, CS三根线是否接对模块供电5V和地线是否接好GD32的IO口是否和定义的一致检查时序 用逻辑分析仪或示波器抓一下DIN, CLK, CS的波形对照数据手册的时序图看CS是否在16个CLK周期后拉高。检查初始化序列 确保MAX7219_Init()函数里的几个寄存器配置命令都成功发送了。尤其是关机寄存器0x0C必须设为0x01。检查电平 GD32是3.3V系统模块是5V。虽然通常3.3V的IO高电平能被5V系统识别为高但如果不行可能需要电平转换电路。支持级联是的MAX7219支持级联。模块上留有DOUT引脚就是用来输出数据给下一片芯片的。驱动级联时需要发送更多位的数据16位 * 芯片数并且注意Write_Max7219_2函数里对前一片芯片的空操作指令。好了代码移植和基本使用的过程就是这样。整个过程的核心就是理解串行时序和数据包格式。一旦驱动调通你就可以用它来显示时间、温度、计数器等各种信息了。希望这篇教程能帮你顺利点亮你的数码管