用STM32 HAL库驱动TM1638显示板:从点亮数码管到控制LED的完整流程(附代码)

张开发
2026/4/21 15:20:58 15 分钟阅读
用STM32 HAL库驱动TM1638显示板:从点亮数码管到控制LED的完整流程(附代码)
STM32 HAL库驱动TM1638显示模块实战指南1. 初识TM1638多功能显示控制芯片TM1638是天微电子推出的一款集成了数码管驱动、LED控制和按键扫描功能的专用芯片。这颗芯片最大的特点就是能用最少的IO口资源实现丰富的交互功能——仅需3个GPIO引脚就能同时控制8位数码管、8个独立LED和8个按键输入。对于资源有限的STM32项目来说这简直是性价比爆表的选择。市面上常见的TM1638模块通常采用以下配置8位7段共阴数码管带小数点8个独立彩色LED通常为红色或蓝色8个轻触按键标准2.54mm排针接口模块典型引脚定义引脚名称功能说明连接建议VCC5V电源输入接STM32 5V输出GND地线共地连接STB片选信号接任意GPIOCLK时钟信号接任意GPIODIO双向数据线接任意GPIO注意虽然模块标称5V工作电压但实际测试3.3V也能稳定工作与STM32直接连接时无需电平转换。2. 硬件连接与HAL库配置2.1 硬件连接方案以STM32F103C8T6蓝莓开发板为例推荐以下连接方式// 引脚定义根据实际电路修改 #define TM1638_STB_PIN GPIO_PIN_7 #define TM1638_STB_PORT GPIOB #define TM1638_CLK_PIN GPIO_PIN_8 #define TM1638_CLK_PORT GPIOB #define TM1638_DIO_PIN GPIO_PIN_9 #define TM1638_DIO_PORT GPIOB对应的硬件连接TM1638的VCC接开发板5V引脚GND接开发板GNDSTB接PB7CLK接PB8DIO接PB92.2 CubeMX配置打开STM32CubeMX选择对应型号配置PB7、PB8为GPIO_Output配置PB9为GPIO_Output初始状态生成代码时勾选Generate HAL library// 自动生成的GPIO初始化代码片段 GPIO_InitStruct.Pin GPIO_PIN_7|GPIO_PIN_8|GPIO_PIN_9; GPIO_InitStruct.Mode GPIO_MODE_OUTPUT_PP; GPIO_InitStruct.Pull GPIO_NOPULL; GPIO_InitStruct.Speed GPIO_SPEED_FREQ_HIGH; HAL_GPIO_Init(GPIOB, GPIO_InitStruct);3. TM1638通信协议深度解析3.1 模拟SPI时序实现TM1638使用类似SPI的同步串行协议但需要特别注意以下几点信号极性时钟上升沿采样数据字节顺序LSB最低位先传输时序要求STB信号在命令传输期间必须保持低电平典型写时序实现void TM1638_WriteByte(uint8_t data) { // 设置为输出模式 GPIO_InitStruct.Pin TM1638_DIO_PIN; GPIO_InitStruct.Mode GPIO_MODE_OUTPUT_PP; HAL_GPIO_Init(TM1638_DIO_PORT, GPIO_InitStruct); for(uint8_t i0; i8; i) { HAL_GPIO_WritePin(TM1638_CLK_PORT, TM1638_CLK_PIN, GPIO_PIN_RESET); HAL_Delay(1); // 适当延时保证时序稳定 // 输出数据位 if(data 0x01) { HAL_GPIO_WritePin(TM1638_DIO_PORT, TM1638_DIO_PIN, GPIO_PIN_SET); } else { HAL_GPIO_WritePin(TM1638_DIO_PORT, TM1638_DIO_PIN, GPIO_PIN_RESET); } data 1; HAL_GPIO_WritePin(TM1638_CLK_PORT, TM1638_CLK_PIN, GPIO_PIN_SET); HAL_Delay(1); } }3.2 核心命令集TM1638通过不同的命令字实现各种功能控制命令字功能描述参数说明0x40设置数据写入模式配合0x44使用0x44固定地址写入模式常用显示模式0x42读取按键数据需切换DIO为输入0x8X显示控制X为亮度0-70x80关显示0x88开启0xC0设置显示起始地址后跟数据字节4. 完整驱动实现与功能封装4.1 数码管显示功能数码管显示需要解决两个关键问题段码转换和地址映射。TM1638采用非标准的地址分配方式// 共阴数码管段码表0-9,A-F const uint8_t segmentMap[] { 0x3F, 0x06, 0x5B, 0x4F, 0x66, 0x6D, 0x7D, 0x07, 0x7F, 0x6F, 0x77, 0x7C, 0x39, 0x5E, 0x79, 0x71 }; // 数码管地址映射表 const uint8_t digitAddr[] {0xC0, 0xC2, 0xC4, 0xC6, 0xC8, 0xCA, 0xCC, 0xCE};显示函数封装示例void TM1638_DisplayDigit(uint8_t position, uint8_t value, bool showDot) { if(position 8) return; uint8_t segData segmentMap[value 0x0F]; if(showDot) segData | 0x80; TM1638_StartCommand(); TM1638_WriteByte(digitAddr[position]); TM1638_WriteByte(segData); TM1638_EndCommand(); }4.2 LED控制功能TM1638的LED控制地址与数码管地址交错排列// LED地址映射表 const uint8_t ledAddr[] {0xC1, 0xC3, 0xC5, 0xC7, 0xC9, 0xCB, 0xCD, 0xCF}; void TM1638_SetLED(uint8_t ledNum, bool state) { if(ledNum 8) return; TM1638_StartCommand(); TM1638_WriteByte(ledAddr[ledNum]); TM1638_WriteByte(state ? 1 : 0); TM1638_EndCommand(); }4.3 按键扫描实现按键扫描需要切换DIO为输入模式并解析返回的数据uint8_t TM1638_ReadKeys(void) { uint8_t keys 0; // 设置为输入模式 GPIO_InitStruct.Pin TM1638_DIO_PIN; GPIO_InitStruct.Mode GPIO_MODE_INPUT; GPIO_InitStruct.Pull GPIO_PULLUP; HAL_GPIO_Init(TM1638_DIO_PORT, GPIO_InitStruct); TM1638_StartCommand(); TM1638_WriteByte(0x42); // 读按键命令 for(uint8_t i0; i4; i) { uint8_t data TM1638_ReadByte(); if(data 0x01) keys | (1 (i*2)); if(data 0x10) keys | (1 (i*21)); } TM1638_EndCommand(); // 恢复输出模式 GPIO_InitStruct.Mode GPIO_MODE_OUTPUT_PP; HAL_GPIO_Init(TM1638_DIO_PORT, GPIO_InitStruct); return keys; }5. 高级应用与性能优化5.1 动态扫描优化默认情况下TM1638会自动进行动态扫描但我们可以通过调整扫描频率来优化显示效果void TM1638_SetScanMode(uint8_t mode) { // mode: 06位扫描, 17位扫描, 28位扫描 TM1638_WriteCommand(0x40 | (mode 0x03)); }5.2 亮度调节策略TM1638提供8级亮度控制实际项目中可以根据环境光自动调节void TM1638_SetBrightness(uint8_t level) { if(level 7) level 7; TM1638_WriteCommand(0x88 | level); }5.3 低功耗设计当系统进入休眠时可以完全关闭TM1638以节省功耗void TM1638_PowerDown(void) { TM1638_WriteCommand(0x80); // 关闭显示 HAL_GPIO_WritePin(TM1638_STB_PORT, TM1638_STB_PIN, GPIO_PIN_RESET); } void TM1638_PowerUp(void) { HAL_GPIO_WritePin(TM1638_STB_PORT, TM1638_STB_PIN, GPIO_PIN_SET); TM1638_WriteCommand(0x88); // 恢复显示 }6. 项目实战多功能显示面板结合前面封装的函数我们可以实现一个完整的显示控制系统typedef struct { uint8_t digits[8]; bool dots[8]; uint8_t leds; uint32_t lastUpdate; } DisplayPanel; void Display_Update(DisplayPanel *panel) { // 更新数码管显示 for(uint8_t i0; i8; i) { TM1638_DisplayDigit(i, panel-digits[i], panel-dots[i]); } // 更新LED状态 for(uint8_t i0; i8; i) { TM1638_SetLED(i, (panel-leds i) 0x01); } panel-lastUpdate HAL_GetTick(); } void Display_Clear(DisplayPanel *panel) { memset(panel-digits, 0, 8); memset(panel-dots, 0, 8); panel-leds 0; Display_Update(panel); }实际使用中发现TM1638的按键扫描需要约2ms的稳定时间建议在主循环中每50ms扫描一次即可获得良好的响应效果同时不会占用过多CPU资源。

更多文章