From 71f14f69f9ae3d3ef85d97b30653db00abb26821 Mon Sep 17 00:00:00 2001 From: yuquanjun Date: Fri, 9 Oct 2026 17:28:15 +0800 Subject: [PATCH] fix(led): relight the key board after hot-plug or late insert TM1629 drops display-on when the board loses power, while key reads still work. Re-enable the display and rewrite the current pattern when the board is seen again. Co-authored-by: Cursor --- device/TM1629D/Drv_TM1629D_Key_Led.c | 78 +++++++++++++++++++++------- 1 file changed, 60 insertions(+), 18 deletions(-) diff --git a/device/TM1629D/Drv_TM1629D_Key_Led.c b/device/TM1629D/Drv_TM1629D_Key_Led.c index 811ecf9..7670815 100644 --- a/device/TM1629D/Drv_TM1629D_Key_Led.c +++ b/device/TM1629D/Drv_TM1629D_Key_Led.c @@ -36,17 +36,35 @@ static void TM1629D_DIO_Output(void) gpio_init(TM1629D_DIO_PORT, &g); } -/* DIO 引脚切换为输入模式(读按键) */ +/* DIO 引脚切换为输入模式(读按键)。上拉:板子拔掉时读到全 1,用来识别未插入。 */ static void TM1629D_DIO_Input(void) { gpio_init_type g; gpio_default_para_init(&g); g.gpio_mode = GPIO_MODE_INPUT; - g.gpio_pull = GPIO_PULL_NONE; + g.gpio_pull = GPIO_PULL_UP; g.gpio_pins = TM1629D_DIO_PIN; gpio_init(TM1629D_DIO_PORT, &g); } +/* 显示模式 + 开显示。芯片掉电(拔插/后插入)后必须重发,否则显存写了也不亮。 */ +static void TM1629D_DisplayOn(void) +{ + TM1629D_STB_L(); + TM1629D_Delay1us(); + TM1629D_SendByte(0x40); + TM1629D_STB_H(); + TM1629D_Delay1us(); + + TM1629D_STB_L(); + TM1629D_Delay1us(); + TM1629D_SendByte(0x8F); + TM1629D_STB_H(); + TM1629D_Delay1us(); +} + +static void TM1629D_OnKeySample(const uint8_t *keyBuf); + /* GPIO初始化 */ void TM1629D_Key_LED_Init(void) { @@ -74,23 +92,8 @@ void TM1629D_Key_LED_Init(void) TM1629D_CLK_H(); TM1629D_DIO_H(); - // 清寄存器 TM1629D_AllLedOff(); - // 配置TM1629D为“普通显示模式”(无译码,8个GRID) - TM1629D_STB_L(); - TM1629D_Delay1us(); - TM1629D_SendByte(0x40); // 普通模式命令(文档1-46) - TM1629D_STB_H(); - TM1629D_Delay1us(); - - // 配置亮度(示例:中亮度) - TM1629D_STB_L(); - TM1629D_Delay1us(); - TM1629D_SendByte(0x8F); // 0x88(最暗)~0x8F(最亮) - TM1629D_STB_H(); - TM1629D_Delay1us(); - - TM1629D_AllLedOn(COLOR_OTHER); + TM1629D_DisplayOn(); TM1629D_UpdateDisplay(0); } @@ -190,6 +193,13 @@ Key_TypeDef TM1629D_GetKey(void) { uint8_t keyBuf[4] = {0}; TM1629D_ReadKeyData(keyBuf); // 读取原始按键数据(与原逻辑一致) + TM1629D_OnKeySample(keyBuf); + /* 拔掉时上拉读到全 1,不能当成按键 */ + if (keyBuf[0] == 0xFF && keyBuf[1] == 0xFF && + keyBuf[2] == 0xFF && keyBuf[3] == 0xFF) + { + return KEY_NONE; + } // 遍历映射表匹配按键(C语言循环写法) for (uint8_t i = 0; i < KEY_MAP_LEN; i++) @@ -291,6 +301,8 @@ void TM1629D_SetGridSeg(uint8_t grid, uint8_t seg, uint8_t on) void TM1629D_UpdateDisplay(uint8_t u8LH) { uint8_t grid; + /* 每次刷灯都重开显示,后插入的板子不用等下一次拔插检测 */ + TM1629D_DisplayOn(); TM1629D_STB_L(); TM1629D_Delay1us(); @@ -310,6 +322,36 @@ void TM1629D_UpdateDisplay(uint8_t u8LH) TM1629D_Delay1us(); } +/* 连续全 0xFF 视为板子不在;重新读到键值后把当前灯态刷回去,闪烁逻辑不用重来。 */ +static uint8_t s_board_present; +static uint8_t s_absent_cnt; +static uint8_t s_present_cnt; + +static void TM1629D_OnKeySample(const uint8_t *keyBuf) +{ + int absent = (keyBuf[0] == 0xFF && keyBuf[1] == 0xFF && + keyBuf[2] == 0xFF && keyBuf[3] == 0xFF); + + if (absent) + { + s_present_cnt = 0; + if (s_absent_cnt < 8) + s_absent_cnt++; + if (s_absent_cnt >= 3) + s_board_present = 0; + return; + } + + s_absent_cnt = 0; + if (s_present_cnt < 8) + s_present_cnt++; + if (!s_board_present && s_present_cnt >= 2) + { + s_board_present = 1; + TM1629D_UpdateDisplay(0); + } +} + // 向指定地址写入1字节数据(单独调用调试用) void TM1629D_WriteDisplayByte(uint8_t addr, uint8_t data) {