TM1629A
- TM1629A是一款专门用于驱动LED显示屏的驱动芯片。它集成了MCU、数据锁存器、LED高压驱动电路。
- 支持16段×8位的显示模式,总共可以驱动128个LED。
- 使用串行接口(CLK、STB、DIO)进行通讯。数据在CLK上升沿进行串行移位输入。 含有一个内部450KHz的RC振荡器。
- 支持通过调制占空比来调节8个级别的亮度。 通过串行接口可以发送控制命令来设置显示模式、亮度等。STB之后第一个字节是命令代码。
- 显示数据写入16个显示寄存器地址00h-0Fh,对应16个段。
- 段脚是PMOS开漏输出,连接LED阳极。位脚是NMOS开漏输出,连接LED阴极。 典型应用电路给出了驱动共阴共阳LED显示屏的连接。
典型硬件连接电路

读写时序

驱动代码
#ifndef _BSP_TM1629_H
#define _BSP_TM1629_H
#include "fm33lg0xx_fl_gpio.h"
#include "types.h"
typedef enum
{
LED_OFF = 0x00,
LED_ON = 0x01,
LED_BLINKING = 0x02
} LEDState;
typedef struct
{
u8 grid;
u8 seg;
} Position;
#define NUM_LEDS 32
#define TM1629_CMD_ADDRESS_INC_MODE 0x40
#define TM1629_CMD_ADDRESS_FIXED_MODE 0x44
#define TM1629_CMD_KEY_SCAN 0x42
#define TM1629_CMD_ADDRESS_START 0xC0
#define TM1629_CMD_DISPLAY_ON 0x88
#define TM1629_CMD_DISPLAY_OFF 0x80
#define TM1629_CMD_PULSE_1_16 0x00
#define TM1629_CMD_PULSE_2_16 0x01
#define TM1629_CMD_PULSE_4_16 0x02
#define TM1629_CMD_PULSE_10_16 0x03
#define TM1629_CMD_PULSE_11_16 0x04
#define TM1629_CMD_PULSE_12_16 0x05
#define TM1629_CMD_PULSE_13_16 0x06
#define TM1629_CMD_PULSE_14_16 0x07
#define TM1629_CMD_DEFAULT_BRIGHTNESS 0x03
#define GRID5 0x09
#define GRID6 0x0B
#define GRID7 0x0D
#define GRID8 0x0F
#define SEG9 0x01
#define SEG10 0x02
#define SEG11 0x04
#define SEG12 0x08
#define SEG13 0x10
#define SEG14 0x20
#define SEG15 0x40
#define SEG16 0x80
#define STB_TM_PIN FL_GPIO_PIN_11
#define STB_TM_PORT GPIOD
#define CLK_TM_PIN FL_GPIO_PIN_0
#define CLK_TM_PORT GPIOD
#define DIO_TM_PIN FL_GPIO_PIN_1
#define DIO_TM_PORT GPIOD
#define STB_HIGH() FL_GPIO_SetOutputPin(STB_TM_PORT, STB_TM_PIN)
#define STB_LOW() FL_GPIO_ResetOutputPin(STB_TM_PORT, STB_TM_PIN)
#define CLK_HIGH() FL_GPIO_SetOutputPin(CLK_TM_PORT, CLK_TM_PIN)
#define CLK_LOW() FL_GPIO_ResetOutputPin(CLK_TM_PORT, CLK_TM_PIN)
#define DIO_HIGH() FL_GPIO_SetOutputPin(DIO_TM_PORT, DIO_TM_PIN)
#define DIO_LOW() FL_GPIO_ResetOutputPin(DIO_TM_PORT, DIO_TM_PIN)
#define DIO_STA() FL_GPIO_GetInputPin(DIO_TM_PORT, DIO_TM_PIN)
u8 tm1629_read_byte(void);
void tm1629_write_byte(u8 dat);
void tm1629_set_brightness(u8 brightness);
void tm1629_send_data(u8 address, u8 data);
void tm1629_init(void);
void scan_key(u8 *buf);
bool is_keycode_changed(u8 *arr1, u8 *arr2);
void tm1629_update_leds(LEDState *data);
#endif
#include "bsp_tm1629.h"
#include "bsp.h"
#include "bsp_bstim.h"
#define CLK_WIDTH (2)
Position leds[NUM_LEDS] = {
{GRID5, SEG9}, {GRID5, SEG10}, {GRID5, SEG11}, {GRID5, SEG12}, {GRID5, SEG13}, {GRID5, SEG14}, {GRID5, SEG15},
{GRID5, SEG16}, {GRID6, SEG9}, {GRID6, SEG10}, {GRID6, SEG11}, {GRID6, SEG12}, {GRID6, SEG13}, {GRID6, SEG14},
{GRID6, SEG15}, {GRID6, SEG16}, {GRID7, SEG9}, {GRID7, SEG10}, {GRID7, SEG11}, {GRID7, SEG12}, {GRID7, SEG13},
{GRID7, SEG14}, {GRID7, SEG15}, {GRID7, SEG16}, {GRID8, SEG9}, {GRID8, SEG10}, {GRID8, SEG11}, {GRID8, SEG12},
{GRID8, SEG13}, {GRID8, SEG14}, {GRID8, SEG15}, {GRID8, SEG16}};
u8 GRID5_CACHE = 0x00;
u8 GRID6_CACHE = 0x00;
u8 GRID7_CACHE = 0x00;
u8 GRID8_CACHE = 0x00;
void DIO_SET_IN(void)
{
FL_GPIO_InitTypeDef cfg;
cfg.pin = DIO_TM_PIN;
cfg.mode = FL_GPIO_MODE_INPUT;
cfg.outputType = FL_GPIO_OUTPUT_OPENDRAIN;
cfg.pull = FL_DISABLE;
cfg.remapPin = FL_DISABLE;
FL_GPIO_Init(DIO_TM_PORT, &cfg);
}
void DIO_SET_OUT(void)
{
FL_GPIO_InitTypeDef cfg;
cfg.pin = DIO_TM_PIN;
cfg.mode = FL_GPIO_MODE_OUTPUT;
cfg.outputType = FL_GPIO_OUTPUT_OPENDRAIN;
cfg.pull = FL_DISABLE;
cfg.remapPin = FL_DISABLE;
FL_GPIO_Init(DIO_TM_PORT, &cfg);
}
u8 tm1629_read_byte(void)
{
DIO_SET_IN();
bsp_delayus(CLK_WIDTH);
u8 data = 0;
CLK_HIGH();
bsp_delayus(CLK_WIDTH);
for (u8 i = 0; i < 8; i++)
{
CLK_LOW();
bsp_delayus(CLK_WIDTH);
data >>= 1;
if (DIO_STA())
{
data |= 0x80;
}
else
{
data &= 0x7f;
}
CLK_HIGH();
bsp_delayus(CLK_WIDTH);
}
return data;
}
void tm1629_write_byte(u8 dat)
{
DIO_SET_OUT();
CLK_HIGH();
bsp_delayus(CLK_WIDTH);
for (u8 i = 0; i < 8; i++)
{
if (dat & 0x01)
{
DIO_HIGH();
}
else
{
DIO_LOW();
}
CLK_LOW();
bsp_delayus(CLK_WIDTH);
CLK_HIGH();
bsp_delayus(CLK_WIDTH);
dat >>= 1;
}
}
void tm1629_set_mode(u8 mode)
{
STB_LOW();
bsp_delayus(CLK_WIDTH);
tm1629_write_byte(mode);
STB_HIGH();
bsp_delayus(CLK_WIDTH);
}
void tm1629_send_data(u8 address, u8 data)
{
STB_LOW();
bsp_delayus(CLK_WIDTH);
tm1629_write_byte(TM1629_CMD_ADDRESS_START | address);
tm1629_write_byte(data);
STB_HIGH();
bsp_delayus(CLK_WIDTH);
}
void tm1629_set_brightness(u8 brightness)
{
STB_LOW();
bsp_delayus(CLK_WIDTH);
tm1629_write_byte(TM1629_CMD_DISPLAY_ON | brightness);
STB_HIGH();
bsp_delayus(CLK_WIDTH);
}
void tm1629_clear_display(void)
{
u8 i;
tm1629_set_mode(TM1629_CMD_ADDRESS_FIXED_MODE);
for (i = 0; i < 16; i++)
{
STB_LOW();
bsp_delayus(CLK_WIDTH);
tm1629_write_byte(TM1629_CMD_ADDRESS_START + i);
tm1629_write_byte(0x00);
STB_HIGH();
bsp_delayus(CLK_WIDTH);
}
tm1629_set_brightness(TM1629_CMD_DEFAULT_BRIGHTNESS);
}
void tm1629_led_on(u8 id)
{
switch (leds[id].grid)
{
case GRID5:
GRID5_CACHE |= (leds[id].seg);
tm1629_send_data(GRID5, GRID5_CACHE);
break;
case GRID6:
GRID6_CACHE |= (leds[id].seg);
tm1629_send_data(GRID6, GRID6_CACHE);
break;
case GRID7:
GRID7_CACHE |= (leds[id].seg);
tm1629_send_data(GRID7, GRID7_CACHE);
break;
case GRID8:
GRID8_CACHE |= (leds[id].seg);
tm1629_send_data(GRID8, GRID8_CACHE);
break;
default:
LOG("error grid!");
}
}
void tm1629_led_off(u8 id)
{
switch (leds[id].grid)
{
case GRID5:
GRID5_CACHE &= ~(leds[id].seg);
tm1629_send_data(GRID5, GRID5_CACHE);
break;
case GRID6:
GRID6_CACHE &= ~(leds[id].seg);
tm1629_send_data(GRID6, GRID6_CACHE);
break;
case GRID7:
GRID7_CACHE &= ~(leds[id].seg);
tm1629_send_data(GRID7, GRID7_CACHE);
break;
case GRID8:
GRID8_CACHE &= ~(leds[id].seg);
tm1629_send_data(GRID8, GRID8_CACHE);
break;
default:
LOG("error grid!");
}
}
void tm1629_update_leds(LEDState *led_status)
{
static u32 last = 0;
static u32 timeout = 200;
static u32 last_blink_on = 0;
u32 now = bsp_get_tick();
if (now - last < timeout)
{
return;
}
last_blink_on = !last_blink_on;
timeout = last_blink_on ? 800 : 200;
last = now;
for (u8 i = 0; i < 32; i++)
{
switch (led_status[i])
{
case LED_ON:
tm1629_led_on(i);
break;
case LED_OFF:
tm1629_led_off(i);
break;
case LED_BLINKING:
if (last_blink_on)
{
tm1629_led_on(i);
}
else
{
tm1629_led_off(i);
}
break;
default:
LOG("Invalid ID\n");
}
}
}
void scan_key(u8 *buf)
{
STB_LOW();
bsp_delayus(CLK_WIDTH);
tm1629_write_byte(TM1629_CMD_KEY_SCAN);
bsp_delayus(2);
for (u8 i = 0; i < 2; i++)
{
buf[i] = tm1629_read_byte();
}
STB_HIGH();
bsp_delayus(CLK_WIDTH);
}
bool is_keycode_changed(u8 *arr1, u8 *arr2)
{
if (memcmp(arr1, arr2, 2) == 0)
{
return false;
}
return true;
}
void tm1629_init()
{
tm1629_clear_display();
}```