恒美微站 Logo 恒美微站
  • 首页
  • 关于我们
  • 建站服务
  • 主题模板
  • 案例展示
  • 资讯中心
  • 联系我们

HK32F030M 软件模拟 I2C 驱动 TM1624 数码管实战

  • 首页
  • 资讯中心
  • /
  • HK32F030M 软件模拟 I2C 驱动 TM1624 数码管实战

相关资讯

LFSR加扰与解扰仿真:从原理到误码率验证的工程实践 2026/10/19 3:33:13
AI生成PPT全解析:智能排版与互动效果实战指南 2026/10/19 3:33:13
多内核混部下的快速内存弹性伸缩技术实战 2026/10/19 3:28:12

最新资讯

open-code-review:一套让代码审查告别形式主义的开源工具集
Transformer端到端车道形状预测:从图像到贝塞尔曲线的实时建模
AI降重工具实操拆解:书匠策AI如何有效降低论文查重率
70个OpenClaw案例:AI智能体如何自动化你的工作与生活
open-code-review:一套规则开放、数据可追踪的轻量级代码评审方案
Makefile构建实战:依赖规则、自动变量与通用模板

今日推荐

OpenCowork 实测:支持本地文件、飞书机器人的 Windows AI 助手(只需配置 Token)
GPT-6 Sol 与 Luna 怎么选?Chat、Work、Codex 版本差异与 TaoToken 接入实测
openclaw.net 集成 ElBruno.MempalaceNet 记忆系统:把 MCP 配置改到 TaoToken 的完整实践

本周热门

基于GMM的语音识别系统原理与MATLAB实现详解
数字图像处理入门:反白、灰度化、调色板修改与导出txt实践
机器人大脑技术盘点:具身智能的感知、决策与数据闭环

本月精选

我发现了一个新思路:用 Remotion + Claude Code 像写代码一样自动化生成短视频
Windows下 Codex 中 Chrome 和 Computer Use 插件不可用问题排查及解决参考方式:TaoToken 统一 Key 配置与验证
2026 大模型集体涨价:用 Python 做企业 Token 成本测算与选型避坑(附配置)

HK32F030M 软件模拟 I2C 驱动 TM1624 数码管实战

发布时间:2026/10/19 3:33:13
HK32F030M 软件模拟 I2C 驱动 TM1624 数码管实战 简介这份源码资源面向嵌入式开发初学者与需要快速搭建数码管显示方案的工程师提供基于HK32F030M微控制器驱动TM1624数码管的完整工程代码。HK32F030M基于ARM Cortex-M0内核具备SPI、GPIO等外设TM1624则集成译码、驱动与动态扫描功能二者通过SPI通信实现多位数码管显示。代码涵盖SPI接口初始化、数据编码、动态扫描切换、亮度与消隐控制以及通信错误处理等关键环节可直接用于工业控制、智能家居、仪器仪表等显示场景。资源包共380个文件约7.3MB以94个h头文件、62个c源文件为核心另含Keil工程文件、编译中间产物、hex烧录文件及说明文档工程结构完整便于直接编译与二次开发。目前已有484人学习下载适合希望掌握MCU与数码管驱动技术的开发者参考借鉴。1. 从一块“点不亮”的数码管说起HK32F030M 驱动 TM1624 到底解决了什么如果你手头有一块 HK32F030M 的最小系统板又刚好买了几片 TM1624 的数码管模块大概率会遇到一个很尴尬的局面引脚接好了上电之后数码管要么全亮、要么全灭、要么乱码调了两天怀疑人生。问题往往不在芯片本身而在于 TM1624 这类专用显示驱动芯片有一套自己的通信时序和寄存器映射裸写 GPIO 模拟时序很容易在起始条件、数据位采样、地址自动递增这几个环节翻车。这份源码就是冲着这个场景来的——它把 HK32F030M 作为主控用软件模拟 I2C 的方式驱动 TM1624封装好了初始化、写显存、调亮度、读按键这一整套流程。适合两类人一是刚接触 HK32 系列、想找个能直接跑的显示驱动参考的嵌入式新手二是手上有 TM1624 模块、想快速验证硬件是否正常的熟手。代码结构不复杂但该有的分层和注释都在拿来当模板改自己的项目完全够用。2. 项目定位与技术选型为什么是软件模拟 I2C 而不是硬件外设2.1 HK32F030M 的资源约束决定了实现方式HK32F030M 是一颗 Cortex-M0 内核的入门级 MCU主频通常跑到 48MHzFlash 和 RAM 都比较紧张。它虽然带硬件 I2C 外设但在实际项目里很多开发者更愿意用软件模拟的方式去驱动 TM1624原因有几个第一硬件 I2C 的引脚是固定的PCB 一旦画死就没法换脚而软件模拟可以任意指定 GPIO第二TM1624 的时序并不完全标准某些批次的芯片对时钟拉伸和重复起始条件的容忍度不一样硬件外设反而容易卡死第三软件模拟的代码可移植性强换到另一颗没有硬件 I2C 的 MCU 上改几个宏定义就能跑。这份源码走的就是软件模拟路线。它把 SCL 和 SDA 的引脚操作抽象成宏底层是TM1624_I2C_Start、TM1624_I2C_Stop、TM1624_I2C_WriteByte这几个函数上层再封装成TM1624_WriteCmd和TM1624_WriteData。这种分层的好处是如果你哪天要把主控换成 STM32 或者 GD32只需要改底层 GPIO 操作的宏上层逻辑一行都不用动。2.2 TM1624 的通信协议要点TM1624 的通信格式和标准 I2C 有区别它没有寄存器地址的概念而是靠命令字节来区分操作类型。一次完整的写操作流程是这样的起始条件 → 发送命令字节比如 0x40 表示写显存模式→ 发送显存地址 → 发送数据字节 → 停止条件。如果要连续写多个显存地址可以在发送完第一个数据字节后继续发送下一个数据字节地址会自动递增。这里有个容易踩坑的地方TM1624 的命令字节和显存地址是分开的两个阶段中间不能插入停止条件。很多新手会把它们当成两次独立的 I2C 传输来写结果就是数码管完全不响应。源码里把这两个阶段合并在一个TM1624_WriteData函数里用ack标志位来判断从机是否应答逻辑上是连贯的。2.3 目录结构一览源码包的目录结构比较扁平没有搞复杂的工程模板核心文件就几个HK32F030M_TM1624/ ├── CMSIS/ # 内核头文件 ├── Drivers/ │ ├── HK32F030M_HAL_Driver/ # 官方外设库 │ └── TM1624/ │ ├── tm1624.c # 驱动核心实现 │ └── tm1624.h # 引脚宏定义与函数声明 ├── User/ │ ├── main.c # 主循环与测试逻辑 │ └── hk32f030m_it.c # 中断服务函数 └── Project/ # 工程文件tm1624.h里最上面几行就是引脚配置用宏定义把 SCL 和 SDA 绑到具体的 GPIO 端口和引脚号上。改硬件的时候只动这里就行不用去翻.c文件。3. 核心模块拆解从 GPIO 翻转到一个完整显示帧的链路3.1 底层时序起始、停止与字节写入软件模拟 I2C 最怕的就是时序不对。HK32F030M 跑在 48MHz 的时候一个for循环的延时如果没算准SCL 的高电平时间可能只有几百纳秒TM1624 根本来不及采样。源码里用的是简单的空循环延时通过TM1624_DELAY宏来调节。这个值需要根据实际主频微调后面避坑章节会细说。先看起始和停止条件的实现// tm1624.c static void TM1624_I2C_Start(void) { TM1624_SDA_OUT(); // 确保 SDA 为输出模式 TM1624_SDA_HIGH(); // SDA 拉高 TM1624_SCL_HIGH(); // SCL 拉高 TM1624_DELAY(); TM1624_SDA_LOW(); // SCL 高电平期间 SDA 由高变低 起始条件 TM1624_DELAY(); TM1624_SCL_LOW(); // 钳住 SCL准备发送数据 TM1624_DELAY(); } static void TM1624_I2C_Stop(void) { TM1624_SDA_OUT(); TM1624_SCL_LOW(); // 先确保 SCL 为低 TM1624_DELAY(); TM1624_SDA_LOW(); // SDA 拉低 TM1624_DELAY(); TM1624_SCL_HIGH(); // SCL 拉高 TM1624_DELAY(); TM1624_SDA_HIGH(); // SCL 高电平期间 SDA 由低变高 停止条件 TM1624_DELAY(); }起始条件的核心是“SCL 为高时 SDA 产生下降沿”停止条件则是“SCL 为高时 SDA 产生上升沿”。这两个函数里每个操作后面都跟了TM1624_DELAY()目的是保证电平建立时间足够。如果你的主频比较高比如跑到 72MHz这个延时循环的次数要相应加大。字节写入函数负责把 8 位数据从高位到低位依次送到 SDA 上每送一位就翻转一次 SCLstatic uint8_t TM1624_I2C_WriteByte(uint8_t data) { uint8_t i, ack; TM1624_SDA_OUT(); for (i 0; i 8; i) { TM1624_SCL_LOW(); TM1624_DELAY(); if (data 0x80) { TM1624_SDA_HIGH(); } else { TM1624_SDA_LOW(); } data 1; TM1624_DELAY(); TM1624_SCL_HIGH(); // 拉高 SCL从机在这一刻采样 SDA TM1624_DELAY(); } TM1624_SCL_LOW(); TM1624_DELAY(); TM1624_SDA_IN(); // 切换为输入准备读取 ACK TM1624_SDA_HIGH(); // 释放 SDA让从机拉低 TM1624_DELAY(); TM1624_SCL_HIGH(); TM1624_DELAY(); ack TM1624_SDA_READ(); // 读取从机应答0 表示应答成功 TM1624_SCL_LOW(); TM1624_DELAY(); return ack; }这里有个细节发送完 8 位数据后主机必须释放 SDA 线并切换为输入模式否则从机拉低 SDA 表示 ACK 的时候会发生电平冲突。源码里用TM1624_SDA_IN()和TM1624_SDA_HIGH()配合完成这个动作返回的ack值在调用处会被检查如果为 1 说明从机没应答通常是硬件没接好或者地址不对。3.2 命令与显存写入TM1624_WriteCmd 和 TM1624_WriteData底层时序搞定之后上层就是拼命令字节了。TM1624 的命令集不算复杂常用的有这几个命令字节功能说明0x40写显存模式后续数据写入显存地址自动递增0x44固定地址模式后续数据写入指定地址不自动递增0x48测试模式一般不用0x88 ~ 0x8F显示控制低 3 位控制亮度第 4 位控制开关0xC0 ~ 0xCF地址设置设置显存起始地址源码里的TM1624_WriteCmd就是把这个命令字节通过 I2C 发出去void TM1624_WriteCmd(uint8_t cmd) { TM1624_I2C_Start(); TM1624_I2C_WriteByte(cmd); TM1624_I2C_Stop(); }而TM1624_WriteData稍微复杂一点它要处理“命令 地址 数据”的连续传输void TM1624_WriteData(uint8_t addr, uint8_t *buf, uint8_t len) { uint8_t i; TM1624_I2C_Start(); TM1624_I2C_WriteByte(0x40); // 写显存模式地址自动递增 TM1624_I2C_Stop(); TM1624_I2C_Start(); TM1624_I2C_WriteByte(0xC0 | addr); // 设置起始地址 for (i 0; i len; i) { TM1624_I2C_WriteByte(buf[i]); // 连续写入数据 } TM1624_I2C_Stop(); }注意这里分成了两次 I2C 传输第一次发 0x40 设置模式第二次发地址和数据。中间插入停止条件是 TM1624 允许的而且这样写逻辑更清晰。addr参数一般填 0x00表示从显存第一个字节开始写buf是显示数据的缓冲区len是要写入的字节数。对于 TM1624 来说显存地址和数码管的段位是对应的具体映射关系要看数码管模块的原理图。3.3 显示初始化与亮度调节上电之后第一件事是初始化 TM1624把显示打开、亮度设好、显存清零。源码里的TM1624_Init函数做了这几件事void TM1624_Init(void) { TM1624_GPIO_Init(); // 配置 SCL/SDA 引脚 TM1624_WriteCmd(0x40); // 写显存模式 TM1624_WriteCmd(0x88 | 0x07); // 显示开亮度设为最高0x07 TM1624_Clear(); // 显存全部写 0 }亮度控制是靠命令字节的低 3 位实现的范围从 0x00 到 0x07对应 1/16 到 14/16 的占空比。如果你觉得数码管太刺眼把0x07改成0x03或者0x04就行。TM1624_Clear函数就是往显存里连续写 0把之前残留的显示内容清掉。3.4 主循环里的显示刷新逻辑main.c里的逻辑很直白初始化系统时钟、初始化 TM1624、然后在一个while(1)里不断更新显示缓冲区并调用TM1624_WriteData。源码里给了一个简单的计数器示例每隔一段时间数字加一通过查表的方式把数字转换成段码const uint8_t seg_table[] {0x3F, 0x06, 0x5B, 0x4F, 0x66, 0x6D, 0x7D, 0x07, 0x7F, 0x6F}; int main(void) { uint8_t disp_buf[4] {0}; uint16_t counter 0; SystemInit(); TM1624_Init(); while (1) { disp_buf[0] seg_table[counter / 1000 % 10]; disp_buf[1] seg_table[counter / 100 % 10]; disp_buf[2] seg_table[counter / 10 % 10]; disp_buf[3] seg_table[counter % 10]; TM1624_WriteData(0x00, disp_buf, 4); counter; Delay_ms(500); } }seg_table是共阴极数码管的段码表如果你用的是共阳极模块把表里的值按位取反就行。TM1624_WriteData每次写 4 个字节对应 4 位数码管。实际项目中显示刷新一般放在定时器中断里保证刷新频率稳定不会因为主循环里其他任务阻塞而闪烁。4. 编译与烧录从零把工程跑起来的完整步骤4.1 开发环境准备这份源码的工程文件是基于 Keil MDK 的如果你用的是 IAR 或者 GCC需要自己建工程把文件加进去。Keil 的话安装好 HK32F030M 的器件支持包Pack之后直接打开Project目录下的.uvprojx文件就行。器件包一般从芯片厂商的官网或者代理渠道获取安装完之后在 Keil 的 Device 列表里能搜到 HK32F030M 系列。编译器版本建议用 AC5 或者 AC6 都行源码里没有用到太新的 C 标准特性兼容性没问题。如果编译时报错说找不到hk32f030m.h检查一下Options for Target→C/C→Include Paths里有没有把Drivers/HK32F030M_HAL_Driver/inc和Drivers/TM1624加进去。4.2 关键编译选项与宏定义源码里用了一些宏来区分不同的硬件配置在tm1624.h里能看到#define TM1624_SCL_PORT GPIOA #define TM1624_SCL_PIN GPIO_Pin_5 #define TM1624_SDA_PORT GPIOA #define TM1624_SDA_PIN GPIO_Pin_6 #define TM1624_DELAY_CNT 10TM1624_DELAY_CNT控制的是前面说的空循环延时次数。如果你的主频不是 48MHz或者换了编译器优化等级这个值需要重新调。调的方法很简单用示波器看 SCL 的频率TM1624 的数据手册里一般要求 SCL 不超过 400kHz实际跑在 100kHz 到 200kHz 之间比较稳。没有示波器的话就先用默认值如果数码管不亮或者闪烁再逐步加大这个值。4.3 烧录与上电验证烧录工具用 J-Link 或者 DAP-Link 都行接线就是标准的 SWDSWCLK、SWDIO、GND、3.3V 四根线。烧录之前确认一下 BOOT 引脚的状态HK32F030M 一般 BOOT0 拉低就是从 Flash 启动。上电之后如果一切正常数码管应该显示 0000 然后每 500ms 加一。如果数码管完全不亮先量一下 TM1624 的 VCC 和 GND 有没有电再量 SCL 和 SDA 上有没有波形。如果波形有但数码管还是没反应大概率是段码表搞反了把seg_table里的值取反试试。提示第一次上电建议先用万用表确认 TM1624 的供电电压有些模块标称 5V 供电但 HK32F030M 的 GPIO 是 3.3V 电平直接连可能会有电平匹配问题。稳妥的做法是在 SDA 和 SCL 上各串一个 1kΩ 电阻或者用电平转换芯片。5. 避坑与排查数码管不亮、闪烁、乱码的常见原因5.1 数码管完全不亮但 SCL/SDA 有波形现象用逻辑分析仪抓波形能看到起始条件和数据位但数码管一个段都不亮。原因TM1624 的显示控制命令没有发对。源码里TM1624_Init发的是0x88 | 0x07其中0x88是显示控制命令的基础值低 3 位是亮度。如果你不小心改成了0x80显示是关闭的数码管自然不亮。解决检查TM1624_Init里的命令字节确保第 4 位0x08是置 1 的。另外确认TM1624_WriteData里的地址字节是0xC0 | addr如果漏了0xC0TM1624 会把后面的数据当成命令解析显示肯定不对。5.2 数码管闪烁或者亮度不均匀现象显示的数字一直在抖或者某几位比另外几位亮。原因刷新频率太低或者TM1624_DELAY_CNT太小导致时序不稳定。TM1624 的显存是双缓冲结构如果两次写入之间的间隔太长中间会出现短暂的灭灯状态人眼就能察觉到闪烁。解决把显示刷新放到定时器中断里保证每 5ms 到 10ms 刷新一次。另外把TM1624_DELAY_CNT适当加大比如从 10 改成 20让 SCL 的频率降下来。如果是个别段位亮度不均检查一下限流电阻是不是焊错了或者数码管模块本身的质量问题。5.3 显示的数字和预期不符段位错乱现象想显示“1”结果亮的是“7”或者别的奇怪组合。原因段码表和硬件接线不匹配。共阴极和共阳极的段码是反的另外不同厂家对段位的定义顺序也可能不一样。源码里的seg_table是按标准共阴极接法写的如果你的模块是共阳极所有值都要按位取反。解决先确认数码管是共阴还是共阳共阳的话把seg_table里的每个值用~取反。如果取反之后还是不对拿一个已知的段码比如全亮 0xFF写进去看哪几个段亮然后对照原理图重新排段码表。5.4 编译通过但程序跑不起来卡在启动文件现象烧录之后 MCU 没有任何反应连主循环都没进。原因启动文件里的堆栈大小设置不够或者中断向量表偏移不对。HK32F030M 的 RAM 比较小如果工程里开了比较大的全局数组堆栈容易溢出。解决检查startup_hk32f030m.s里的Stack_Size和Heap_Size一般设成 0x400 和 0x200 就够了。如果用了 printf 重定向堆要再大一点。另外确认system_hk32f030m.c里的时钟配置和实际晶振匹配外部晶振没起振的话MCU 会跑在内部 RC 上主频不对会导致所有延时都不准。5.5 按键读取不稳定偶尔误触发现象如果 TM1624 模块上带了按键读按键的时候偶尔会读到错误的值。原因TM1624 的按键读取和显示写入共用一套 I2C 接口如果读按键的时候没有先发命令切换模式读回来的数据可能是显存的残留值。解决读按键之前先发0x42命令进入读按键模式然后再发起始条件读数据。源码里如果没实现按键读取可以自己补一个TM1624_ReadKey函数逻辑和写数据类似只是把写字节换成读字节注意在读取最后一个字节后发 NACK 再发停止条件。6. 二次开发改造把驱动移植到自己的项目里拿到这份源码之后最直接的改造就是把 TM1624 驱动从示例工程里剥离出来放到你自己的项目里。我的习惯是只保留tm1624.c和tm1624.h两个文件把TM1624_GPIO_Init里的引脚配置改成你实际用的端口然后根据你的主频重新标定TM1624_DELAY_CNT。如果你用的是硬件 I2C那就把底层的TM1624_I2C_Start、TM1624_I2C_Stop、TM1624_I2C_WriteByte三个函数替换成 HAL 库的HAL_I2C_Master_Transmit上层逻辑完全不用动。另一个常见的改造方向是支持多位数码管。源码里的例子是 4 位如果你要驱动 6 位或者 8 位只需要把disp_buf数组加大TM1624_WriteData的len参数改成对应的位数就行。TM1624 的显存地址是自动递增的所以连续写多个字节不需要额外处理地址。如果你想让显示更流畅可以把刷新逻辑放到 SysTick 中断里每 5ms 调用一次TM1624_WriteData。注意不要在中断里做太耗时的操作TM1624_WriteData本身执行时间大概几十微秒放在中断里是安全的。但如果你用的是软件模拟 I2C中断里调用的时候要确保没有其他中断打断时序必要的时候关一下全局中断。还有一个实用技巧把段码表做成const数组放到 Flash 里不要放到 RAM 里。HK32F030M 的 RAM 只有几 KB能省一点是一点。另外如果显示的数字范围固定比如只显示 0 到 9可以把段码表压缩成 10 个字节用查表的方式取段码比实时计算要快得多。最后说一个我踩过的坑有一次我把TM1624_WriteData放在主循环里调用同时又在定时器中断里调了一次结果数码管显示乱跳。原因是两次调用之间没有做互斥保护I2C 时序被打断了。后来我在TM1624_WriteData开头加了一个简单的标志位判断如果正在写入就直接返回避免重入。从那以后我每次把显示驱动放到中断里之前都强制走一遍重入检查确认没有并发调用才放心。希望这些经验能帮到你少走点弯路。本文还有配套的精品资源点击获取

关于恒美微站

恒美微站专注于为个体商户、工作室提供极简自助建站服务,让每个人都能轻松拥有专业网站。

快速链接

  • 关于我们
  • 建站服务
  • 主题模板
  • 案例展示
  • 资讯中心

服务项目

  • 可视化建站
  • 拖拽编辑
  • 主题定制
  • SEO 优化
  • 网站托管

联系方式

  • 📍 地址:北京市朝阳区建国路 88 号
  • 📞 电话:400-888-8888
  • ✉️ 邮箱:info@hmyw.cn
  • 🕐 时间:周一至周日 9:00-18:00

© 2024 恒美微站 hmyw.cn 版权所有 | 京 ICP 备 12345678 号