大家好!今天我们要聊的是一位"数字世界的指挥家"——TM1620数码管驱动芯片。这位小个子可是控制数码管的行家,让我们一起来揭开它的神秘面纱。

一、TM1620:数码管背后的"大脑"

想象一下,你正在看一个电子钟,那些跳动的数字背后就有一位"隐形指挥家"在忙碌着。TM1620就是这样的角色,它是一款LED驱动控制专用电路,内置MCU数字接口、数据锁存、LED驱动等电路。

主要特点:

  • 工作电压范围宽:2.4V-5.2V(比变色龙还能适应环境)

  • 支持多种显示模式:8段×16位、7段×17位(数字界的变形金刚)

  • 内置256Hz的RC振荡器(自带节奏感)

  • 支持串行接口(SPI的三线制简化版)

二、硬件连接:与TM1620"握手"

单片机是赛元微的sc928361B的芯片(51单片机)。单片机用的哪一种都一样,万变不离其宗,我用的是官方封装好的库直接用的!!!!

让我们看看如何与这位数字指挥家建立联系:

// 引脚定义
#define TM1620_STB  GPIO_PIN_1  // P1.1
#define TM1620_CLK  GPIO_PIN_4  // P1.4
#define TM1620_DIO  GPIO_PIN_5  // P1.5

#define SEG_DP 0x80 // 小数点对应的段码
// 初始化TM1620引脚
void TM1620_init_pin(void)
{
    GPIO_Init(GPIO1, TM1620_STB, GPIO_MODE_OUT_PP);
    GPIO_Init(GPIO1, TM1620_CLK, GPIO_MODE_OUT_PP);
    GPIO_Init(GPIO1, TM1620_DIO, GPIO_MODE_OUT_PP);
    
    // 初始状态
    GPIO_WriteHigh(GPIO1, TM1620_STB);
    GPIO_WriteHigh(GPIO1, TM1620_CLK);
    GPIO_WriteHigh(GPIO1, TM1620_DIO);
	
}

三、通信协议:与TM1620"对话"

TM1620使用一种类似SPI的三线制通信方式,但比SPI更"话痨"一些。让我们看看如何与它交流:

void TM1620_Write_byte(uint8_t buff)
{
    uint8_t i;
    for (i = 0; i < 8; i++) 
    {
        if (buff & 0x01) 
        {
            GPIO_WriteHigh(GPIO1, TM1620_DIO);
        } 
        else 
        {
            GPIO_WriteLow(GPIO1, TM1620_DIO);
        }
        
        GPIO_WriteLow(GPIO1, TM1620_CLK);
        delay_us(2);
        GPIO_WriteHigh(GPIO1, TM1620_CLK);
        delay_us(2);
        buff >>= 1;
    }
}

四、初始化TM1620:唤醒数字指挥家

在开始表演前,我们需要先唤醒这位指挥家:

// 初始化 TM1620
void TM1620_Init(void)
{
    TM1620_init_pin();  // 初始化引脚
    TM1620_Write_cmd(0x40);  // 设置为数据写入模式,地址自动递增
    TM1620_Clear_All();  // 清除显示缓冲区
    TM1620_Set_Brightness(7); // 设置最大亮度
    TM1620_Write_cmd(0x8F);  // 开启显示
}

五、显示数字:让数码管"跳舞"

现在,让我们让数码管跳起来吧!首先需要一个段码表:

const uint8_t digitSegments_led[] = 
{
	0x01,//白色
	0x02,//蓝色
	0x04,//红色(左上)
	0x08,//红色(左下)
	0x10,//红色(右下)
	0x20,//红色(中间)
	0x40 //红色(右上)
	
};// 共阴极数码管段码表
// 带小数点的共阴极段码表
const uint8_t digitSegmentsDP[] = 
{
    0xBF, // 0. (10111111)
    0x86, // 1. (10000110)
    0xDB, // 2. (11011011)
    0xCF, // 3. (11001111)
    0xE6, // 4. (11100110)
    0xED, // 5. (11101101)
    0xFD, // 6. (11111101)
    0x87, // 7. (10000111)
    0xFF, // 8. (11111111)
    0xEF  // 9. (11101111)
};
/**
 * @brief 向 TM1620 指定地址写入数据(修正版)
 * @param addr 地址 (0x00~0x0F,对应数码管位)
 * @param seg_data 数据(段码,如 0x3F 显示 '0')
 */
void TM1620_Write_Data(uint8_t addr, uint8_t seg_data) 
{
    // 1. 首先发送数据写入模式命令(独立命令帧)
    GPIO_WriteLow(GPIO1, TM1620_STB);
    TM1620_Write_byte(0x44);  // 固定地址写入模式
    GPIO_WriteHigh(GPIO1, TM1620_STB);
    delay_us(2);
    // 2. 发送地址和数据(另一个独立帧)
    GPIO_WriteLow(GPIO1, TM1620_STB);
    TM1620_Write_byte(0xC0 | addr);  // 设置地址
    TM1620_Write_byte(seg_data);     // 写入数据
    GPIO_WriteHigh(GPIO1, TM1620_STB);
    delay_us(2);
}

// 清除所有显示
void TM1620_Clear_All(void)
{
    uint8_t i;
    for(i = 0; i < 16; i++)
    {
        TM1620_Write_Data(i, 0x00);  // 共阴极写入0x00关闭所有段
    }
}







六、进阶技巧:让显示更生动

1. 显示小数点:

只需要输入不同的段码表即可。

七、实战应用:制作一个电子时钟

让我们把这些知识整合起来,制作一个简单的电子时钟:是基于状态机写的代码基于一定c基础的能力才能理解在主函数内while(1)里调用TM1620_FSM_Update()。然后在你需要显示数码管的位置调用TM1620_Write_Data()即可,注意显存地址!!!!!!☆☆☆☆☆☆非常重要

头文件:

// 显示状态枚举
typedef enum 
{
    DISP_IDLE,
    DISP_WRITE_MIN_TENS,    // 分钟十位
    DISP_WRITE_MIN_UNITS,   // 分钟个位
    DISP_WRITE_SEC_TENS,    // 秒钟十位
    DISP_WRITE_SEC_UNITS,   // 秒钟个位
    DISP_COMPLETE
} DisplayState;

// 时间结构体
typedef struct 
{
    uint8_t minutes;
    uint8_t seconds;
} TimeType;

// 全局变量声明
extern volatile TimeType currentTime;
extern DisplayState dispState;
extern bit updateDisplay;

​

.c文件

// 全局变量定义
// 全局变量
volatile TimeType currentTime = {34, 56}; // 初始化时间34:56
DisplayState dispState = DISP_IDLE;
bit updateDisplay = 0;


// 状态机初始化
void TM1620_FSM_Init(void) 
{
    TM1620_Init();
    dispState = DISP_IDLE;
}

// 状态机更新函数(在主循环中调用)
// 状态机更新函数
void TM1620_FSM_Update(void) 
{
    if(!updateDisplay) return;
    switch(dispState) 
	{
        case DISP_IDLE:
            dispState = DISP_WRITE_MIN_TENS;
            break;
        case DISP_WRITE_MIN_TENS:
            TM1620_Write_Data(0, digitSegmentsDP[currentTime.minutes/10]); // 地址0:分钟十位
            dispState = DISP_WRITE_MIN_UNITS;
            break;
        case DISP_WRITE_MIN_UNITS:
            TM1620_Write_Data(2, digitSegmentsDP[currentTime.minutes%10]); // 地址1:分钟个位
            dispState = DISP_WRITE_SEC_TENS;
            break;
        case DISP_WRITE_SEC_TENS:
            TM1620_Write_Data(4, digitSegmentsDP[currentTime.seconds/10]); // 地址2:秒十位
            dispState = DISP_WRITE_SEC_UNITS;
            break;
        case DISP_WRITE_SEC_UNITS:
            TM1620_Write_Data(6, digitSegmentsDP[currentTime.seconds%10]); // 地址3:秒个位
            dispState = DISP_COMPLETE;
            break;
        case DISP_COMPLETE:
            updateDisplay = 0;
            dispState = DISP_IDLE;
            break;
    }
}


// 时间更新函数
void Time_Update(void) {
    static uint16_t counter = 0;
    
    if(++counter >= 100) 
	{      // 1秒计时
        counter = 0;
        if(++currentTime.seconds >= 60)
		{
            currentTime.seconds = 0;
            if(++currentTime.minutes >= 60) 
			{
                currentTime.minutes = 0;
            }
        }
        updateDisplay = 1;      // 请求显示更新
    }
}

八、调试技巧:当数码管不亮时

  1. 检查硬件连接:确认VCC、GND、CLK、DIO、STB连接正确

  2. 检查电压:确保供电电压在2.4V-5.2V之间

  3. 检查通信:用逻辑分析仪或示波器查看CLK、DIO信号

  4. 检查段码:确认数码管是共阴还是共阳,段码表是否正确

  5. 检查亮度设置:可能只是亮度调得太低了

九、TM1620的"小脾气"

  1. 时序要求严格:TM1620对时序比较敏感,延时不能太短

  2. 数据顺序:数据是LSB(最低位)先发送

  3. 显示地址:地址从0xC0开始,每个地址对应一个段

十、总结

TM1620就像一位严谨的乐队指挥,通过简单的三线制接口,就能控制多个数码管整齐划一地显示我们想要的数字和字符。掌握了它的使用方法,你就能轻松驾驭各种数码管显示需求,从简单的电子钟到复杂的仪器仪表显示都不在话下。

记住,每个伟大的数字显示背后,都有一位像TM1620这样默默付出的"指挥家"。现在,拿起你的开发板,开始你的数码管交响乐吧!

Logo

DAMO开发者矩阵,由阿里巴巴达摩院和中国互联网协会联合发起,致力于探讨最前沿的技术趋势与应用成果,搭建高质量的交流与分享平台,推动技术创新与产业应用链接,围绕“人工智能与新型计算”构建开放共享的开发者生态。

更多推荐