TM1640 是一种LED(发光二极管显示器)驱动控制专用电路,内部集成有MCU 数字接口、数据锁存器、LED 驱动等电路。主要应用于电子产品LED显示屏驱动。采用SOP28、SSOP28的封装形式。
• 采用CMOS 工艺
• 显示模式(8 段×16 位)
• 辉度调节电路(占空比8 级可调)
• 两线串行接口(SCLK,DIN)
• 振荡方式:内置RC 振荡
• 内置上电复位电路
• 封装形式:SSOP28、SOP28
(1).管脚定义:
(2).管脚功能定义:
(3).电气参数
(4).微处理器的数据通过两线总线接口和TM1640 通信,在输入数据时当 CLK 是高电平时,DIN 上的信号必须保持不变;只有 CLK 上的时钟信号为低电平时 DIN 上的信号才能改变。 数据的输入总是低位在前, 高位在后传输。 数据输入的开始条件是 CLK 为高电平时, DIN 由高变低;结束条件是 CLK 为高时, DIN 由低电平变为高电平。
指令数据传输过程如下图:
根据上面时序图,可以写出如下写一字节驱动代码:
- void TM1640_Write_Byte(uint8 TM1640_Dat)
- {
- uint8 i;
- for(i=0;i<8;i++)
- {
- CLK = 0;
- if((TM1640_Dat & 0X01)==0X01)
- DIN = 1;
- else
- DIN = 0;
- TM1640_Dat = TM1640_Dat >>1;
- //_nop_(); //延时 500ns
- CLK = 1;
- //_nop_(); //延时 500ns
- }
-
- //*********************************
- //写完一字节数据,必须要把DIN,SLK拉低,否则会导致固定地址模式不能显示“.”
- DIN = 0;
- CLK = 0;
- //*********************************
- }
(5).两种模式
写 SRAM 数据地址自动加 1 模式:
写 SRAM 数据固定地址模式:
- /两种写数据模式(固定地址模式、地址自动+1模式)
- typedef enum
- {
- Addr_Fix_Mode = 0X44, //固定地址模式
- Addr_Auto_Mod = 0X40, //地址自动增+1模式
- } Addr_Mode_t;
(6)显示控制命令
- //亮度调节
- typedef enum
- {
- Brightness_level_0 = 0X80, //亮度 0 熄灭
- Brightness_level_1 = 0X88, //亮度 1
- Brightness_level_2 = 0X89, //亮度 2
- Brightness_level_3 = 0X8A, //亮度 3
- Brightness_level_4 = 0X8B, //亮度 4
- Brightness_level_5 = 0X8C, //亮度 5
- Brightness_level_6 = 0X8D, //亮度 6
- Brightness_level_7 = 0X8E, //亮度 7
- Brightness_level_8 = 0X8F, //亮度 8
- } Brightness_level_t;
(7)地址命令设置
- //显示寄存器地址
- typedef enum
- {
- All_Place_Addr = 16, //TM1640 最大支持16位数码管
- Place_Addr_01 = 0XC0,
- Place_Addr_02 = 0XC1,
- Place_Addr_03 = 0XC2,
- Place_Addr_04 = 0XC3,
- Place_Addr_05 = 0XC4,
- Place_Addr_06 = 0XC5,
- Place_Addr_07 = 0XC6,
- Place_Addr_08 = 0XC7,
- Place_Addr_09 = 0XC8,
- Place_Addr_10 = 0XC9,
- Place_Addr_11 = 0XCA,
- Place_Addr_12 = 0XCB,
- Place_Addr_13 = 0XCC,
- Place_Addr_14 = 0XCD,
- Place_Addr_15 = 0XCE,
- Place_Addr_16 = 0XCF,
- } Place_Addr_t;
上电时,地址默认设为C0H。显示数据与芯片管脚以及显示地址之间的对应关系如下表所示:
注意:芯片显示寄存器在上电瞬间其内部保存的值可能是随机不确定的,此时客户直接发送开屏命令, 将有可能出现显示乱码。所以我司建议客户对显示寄存器进行一次上电清零操作,即上电后向16位显存地址 (C0H-CDH)中全部写入数据0x00。
TM1640初始化代码如下 :
- void TM1640_Init()
- {
- uint8 i =0;
-
- //地址自动增加 1 模式
- TM1640_Star();
- TM1640_Write_Byte(Addr_Auto_Mod);
- TM1640_End();
-
- //清除显示寄存器
- TM1640_Star();
- TM1640_Write_Byte(Place_Addr_01); //设置首地址
- for(i=0;i<All_Place_Addr;i++) //All_Place_Addr = 16, //TM1640 最大支持16位数码管
- TM1640_Write_Byte(0X00); //TM1640 初始化,数据清零 0x00
- TM1640_End();
-
- //显示亮度
- TM1640_Star();
- TM1640_Write_Byte(Brightness_level_5);
- TM1640_End();
- }
-
- void TM1640_Star()
- {
- //TM1640起始信号 ,SCL 高电平期间,DIN 由高变低
- CLK = 1; //时钟 高电平
- DIN = 1; //数据 IO
- _nop_();
-
- DIN = 0; //数据 IO
- _nop_();
- }
-
- void TM1640_End()
- {
- //TM1640起始信号 ,SCL 高电平期间,DIN 由低变高
- CLK = 1; //时钟 高电平
- DIN = 0; //数据 IO
-
- DIN = 1; //数据 IO
-
- }
习题要求:使用TM1640驱动数码管时钟(带设置、加、减、确认按键功能)
简易电路搭建如下图所示:
完整代码如下 :
- /*********************************************************************
- 程序名称:TM1640驱动数码管时钟(带设置、加、减、确认按键功能)
- 程序版本:V1.0
- 作 者: Attack BUG
- 编写时间:2023.09.01
- 硬件支持: TM1640、STC89C52RC、 16位矩阵键盘
- 接口说明:
- 修改日志:
- *********************************************************************/
- /*********************************************************************
- 头文件包含/SFR定义
- *********************************************************************/
- #include <reg52.h>
- #include <intrins.h>
- /*********************************************************************
- 宏定义
- *********************************************************************/
- typedef unsigned char uint8; //8位有符号字符型
- typedef unsigned int uint16; //16位有符号整型
- typedef unsigned long uint32; //32位有符号长整型
-
- #define SET 1 //设置键
- #define ADD 2 //加
- #define SUB 3 //减
- #define OK 4 //确认键
- /*********************************************************************
- 单片机IO口位定义
- *********************************************************************/
- sbit DIN=P2^0; //定义端口 3个位声明
- sbit CLK=P2^1;
- /*********************************************************************
- 函数原形声明
- *********************************************************************/
- uint8 code SMG[19]={0x3f,0x06,0x5b,0x4f,0x66,0x6d,0x7d,0x07,0x7f,0x6f,0x77,0x7c,0x39,0x5e,0x79,0x71,0x76,0x80,0x40}; //共阴数码管段码表
- uint8 key_scan();
- uint8 shi=12,fen=30,miao=0;
- void delay(uint16 x_ms);
- void TM1640_Init();
- void TM1640_Star();
- void TM1640_End();
- void TM1640_Write_Byte(uint8 TM1640_Dat);
- void TM1640_Display_time(uint8 address, uint8 shi, uint8 fen, uint8 miao);
- void TM1640_address_moshi(uint8 address_mode);
- void TM1640_liangdu(uint8 liangdu);
- void TM1640_Display_dian(uint8 address,uint8 set_mode);
- void TM1640_Display_liushui();
- //两种写数据模式(固定地址模式、地址自动+1模式)
- typedef enum
- {
- Addr_Fix_Mode = 0X44, //固定地址模式
- Addr_Auto_Mod = 0X40, //地址自动增+1模式
- } Addr_Mode_t;
-
- //亮度调节
- typedef enum
- {
- Brightness_level_0 = 0X80, //亮度 0 熄灭
- Brightness_level_1 = 0X88, //亮度 1
- Brightness_level_2 = 0X89, //亮度 2
- Brightness_level_3 = 0X8A, //亮度 3
- Brightness_level_4 = 0X8B, //亮度 4
- Brightness_level_5 = 0X8C, //亮度 5
- Brightness_level_6 = 0X8D, //亮度 6
- Brightness_level_7 = 0X8E, //亮度 7
- Brightness_level_8 = 0X8F, //亮度 8
- } Brightness_level_t;
-
- //显示寄存器地址
- typedef enum
- {
- All_Place_Addr = 16, //TM1640 最大支持16位数码管
- Place_Addr_01 = 0XC0,
- Place_Addr_02 = 0XC1,
- Place_Addr_03 = 0XC2,
- Place_Addr_04 = 0XC3,
- Place_Addr_05 = 0XC4,
- Place_Addr_06 = 0XC5,
- Place_Addr_07 = 0XC6,
- Place_Addr_08 = 0XC7,
- Place_Addr_09 = 0XC8,
- Place_Addr_10 = 0XC9,
- Place_Addr_11 = 0XCA,
- Place_Addr_12 = 0XCB,
- Place_Addr_13 = 0XCC,
- Place_Addr_14 = 0XCD,
- Place_Addr_15 = 0XCE,
- Place_Addr_16 = 0XCF,
- } Place_Addr_t;
- /*********************************************************************
- *函数名称:main
- *函数功能:主函数
- *函数调用:
- *参数列表:无
- *返 回 值:无
- *结 果:
- *备 注:
- *********************************************************************/
- void main()
- {
- bit smg_mode = 0; //数码管模式 0:时钟模式 1:设置模式
- uint8 set_mode = 0; //设置模式的3种情况,1:秒 2:分 3:时
- uint8 temp = 0; //缓存矩阵键盘键值
- uint16 count = 0; //秒精度调节参数
- TM1640_Init(); //初始化TM1640,必需进行初始化
-
- while(1)
- {
- if(smg_mode==0) // smg_mode = 0 默认上电时钟模式
- {
- count++; //秒精度调节参数
- TM1640_address_moshi(Addr_Auto_Mod); //选择地址模式 Addr_Auto_Mode:地址自动加1模式
- TM1640_Display_time(Place_Addr_01, shi, fen, miao); //在第一个数码管位置显示:时、分、秒
- //TM1640_Display_liushui(); //从第9位数码管(Place_Addr_09)开始显示 8个横杠“-“
- TM1640_liangdu(Brightness_level_5); //亮度选择:5级亮度
-
- if(count==800)
- {
- count=0;
- miao++;
- if(miao==60)
- {
- miao=0;
- fen++;
- if(fen==60)
- {
- fen=0;
- shi++;
- if(shi==24)
- {
- shi=0;
- }
- }
- }
- }
- }
-
- else //smg_mode = 1 设置模式
- {
- //TM1640_Display_liushui(); //从第9位数码管(Place_Addr_09)开始显示 8个横杠“-“
- TM1640_Display_time(Place_Addr_01, shi, fen, miao); //在第一个数码管位置显示:时、分、秒
- }
-
- //****************************************************************************
- temp = key_scan(); //缓存矩阵键盘键值,key_scan()有四种结果:SET、ADD、SUB、OK
- switch(temp)
- {
- case SET: //识别到设置键时(每按一次set_mode进行一次自加计数)
- {
- smg_mode = 1; //识别到设置键按下,进入设置模式
- set_mode++; //按一次设置键,切换一次设置模式
- if(set_mode >= 4)
- set_mode = 1;
- }
- break;
-
- case OK: //识别确认键时,退出,进入正常走时
- {
- smg_mode = 0; //返回时钟模式
- set_mode = 0; //退出模式设置
- }
- break;
-
- default:
- switch(set_mode) //基于设置模式下的三种情况(时、分、秒调节)
- {
- case 1: //模式一:设置秒钟 set_mode = 1
- {
- TM1640_Display_dian(Place_Addr_01,set_mode); //set_mode=1,秒钟个位显示"."
-
- if(temp==ADD) //识别 '加' 键
- {
- miao++; //秒+
- if(miao==60)
- miao = 0;
- }
- if(temp==SUB) //识别 '减' 键
- {
- miao--; //秒-
- if(miao==255)
- miao = 59;
- }
- }
- break;
-
- case 2: //模式二:设置分钟 set_mode = 2
- {
- TM1640_Display_dian(Place_Addr_01,set_mode); //set_mode=2,分钟个位显示"."
- if(temp==ADD) //识别 '加' 键
- {
- fen++; //分+
- if(fen==60)
- fen = 0;
- }
- if(temp==SUB) //识别 '减' 键
- {
- fen--; //分-
- if(fen==255)
- fen = 59;
- }
- }
- break;
-
- case 3: //模式三:设置时 set_mode = 3
- {
- TM1640_Display_dian(Place_Addr_01,set_mode); //set_mode=3,时个位显示"."
- if(temp==ADD) //识别 '加' 键
- {
- shi++; //时+
- if(shi==24)
- shi = 0;
- }
- if(temp==SUB) //识别 '减' 键
- {
- shi--; //时-
- if(shi==255)
- shi = 23;
- }
- }
- break;
- }
- break;
- }
-
- }
- }
-
- void TM1640_Init()
- {
- uint8 i =0;
-
- //地址自动增加 1 模式
- TM1640_Star();
- TM1640_Write_Byte(Addr_Auto_Mod);
- TM1640_End();
-
- //清除显示寄存器
- TM1640_Star();
- TM1640_Write_Byte(Place_Addr_01); //设置首地址
- for(i=0;i<All_Place_Addr;i++) //All_Place_Addr = 16, //TM1640 最大支持16位数码管
- TM1640_Write_Byte(0X00); //TM1640 初始化,数据清零 0x00
- TM1640_End();
-
- //显示亮度
- TM1640_Star();
- TM1640_Write_Byte(Brightness_level_5);
- TM1640_End();
- }
-
- void TM1640_Star()
- {
- //TM1640起始信号 ,SCL 高电平期间,DIN 由高变低
- CLK = 1; //时钟 高电平
- DIN = 1; //数据 IO
- _nop_();
-
- DIN = 0; //数据 IO
- _nop_();
- }
-
- void TM1640_End()
- {
- //TM1640起始信号 ,SCL 高电平期间,DIN 由低变高
- CLK = 1; //时钟 高电平
- DIN = 0; //数据 IO
-
- DIN = 1; //数据 IO
-
- }
-
- void TM1640_Write_Byte(uint8 TM1640_Dat)
- {
- uint8 i;
- for(i=0;i<8;i++)
- {
- CLK = 0;
- if((TM1640_Dat & 0X01)==0X01)
- DIN = 1;
- else
- DIN = 0;
- TM1640_Dat = TM1640_Dat >>1;
- //_nop_(); //延时 500ns
- CLK = 1;
- //_nop_(); //延时 500ns
- }
-
- //*********************************
- //写完一字节数据,必须要把DIN,SLK拉低,否则会导致固定地址模式不能显示“.”
- DIN = 0;
- CLK = 0;
- //*********************************
- }
-
- void TM1640_Display_liushui()
- {
- uint8 j;
- TM1640_Star(); //开始条件
- TM1640_Write_Byte(Place_Addr_09); //在第9个数码管位置写入地址
- for(j=0;j<8;j++)
- TM1640_Write_Byte(SMG_liushui[j]); //显示"-"
- TM1640_End(); //结束条件
- }
-
-
- void TM1640_Display_time(uint8 address, uint8 shi, uint8 fen, uint8 miao)
- {
- TM1640_Star(); //开始条件
- TM1640_Write_Byte(address); //写入地址
- TM1640_Write_Byte(SMG[shi%100/10]); //显示时的十位
- TM1640_Write_Byte(SMG[shi%10]); //显示时的个位
- TM1640_Write_Byte(SMG[18]); //显示"-"
- TM1640_Write_Byte(SMG[fen%100/10]); //显示分的十位
- TM1640_Write_Byte(SMG[fen%10]); //显示分的个位
- TM1640_Write_Byte(SMG[18]); //显示"-"
- TM1640_Write_Byte(SMG[miao%100/10]); //显示秒的十位
- TM1640_Write_Byte(SMG[miao%10]); //显示秒的个位
-
- TM1640_End(); //结束条件
- }
-
- void TM1640_Display_dian(uint8 address,uint8 set_mode) //小数点显示函数
- {
- TM1640_Star(); //开始条件
- TM1640_Write_Byte(address); //写入首地址
- //传输显示数据
- if(set_mode==3) //若为时钟,时钟个位显示“.”
- {
- TM1640_Write_Byte(SMG[shi%100/10]); //显示时 十位
- TM1640_Write_Byte(SMG[shi%10]|0X80); //显示时 个位,同时显示"."
- TM1640_Write_Byte(SMG[18]); //显示"-"
- TM1640_Write_Byte(SMG[fen%100/10]); //显示分 十位
- TM1640_Write_Byte(SMG[fen%10]); //显示分 个位
- TM1640_Write_Byte(SMG[18]); //显示"-"
- TM1640_Write_Byte(SMG[miao%100/10]); //显示秒 十位
- TM1640_Write_Byte(SMG[miao%10]); //显示秒 个位
- TM1640_End(); //结束条件
- }
-
- else if(set_mode==2) //若为分钟,分钟个位显示“.”
- {
- TM1640_Write_Byte(SMG[shi%100/10]); //显示时 十位
- TM1640_Write_Byte(SMG[shi%10]); //显示时 个位
- TM1640_Write_Byte(SMG[18]); //显示"-"
- TM1640_Write_Byte(SMG[fen%100/10]); //显示分 十位
- TM1640_Write_Byte(SMG[fen%10]|0X80); //显示分 个位,同时显示"."
- TM1640_Write_Byte(SMG[18]); //显示"-"
- TM1640_Write_Byte(SMG[miao%100/10]); //显示秒 十位
- TM1640_Write_Byte(SMG[miao%10]); //显示秒 个位
- TM1640_End(); //结束条件
- }
-
- else if(set_mode==1) //若为秒钟,秒钟个位显示“.”
- {
- TM1640_Write_Byte(SMG[shi%100/10]); //显示时 十位
- TM1640_Write_Byte(SMG[shi%10]); //显示时 个位
- TM1640_Write_Byte(SMG[18]); //显示"-"
- TM1640_Write_Byte(SMG[fen%100/10]); //显示分 十位
- TM1640_Write_Byte(SMG[fen%10]); //显示分 个位
- TM1640_Write_Byte(SMG[18]); //显示"-"
- TM1640_Write_Byte(SMG[miao%100/10]); //显示秒 十位
- TM1640_Write_Byte(SMG[miao%10]|0X80); //显示秒 个位,同时显示"."
- TM1640_End(); //结束条件
- }
-
- else //默认显示 shi-fen-miao
- {
- TM1640_Write_Byte(SMG[shi%100/10]); //显示时 十位
- TM1640_Write_Byte(SMG[shi%10]); //显示时 个位
- TM1640_Write_Byte(SMG[18]); //显示"-"
- TM1640_Write_Byte(SMG[fen%100/10]); //显示分 十位
- TM1640_Write_Byte(SMG[fen%10]); //显示分 个位
- TM1640_Write_Byte(SMG[18]); //显示"-"
- TM1640_Write_Byte(SMG[miao%100/10]); //显示秒 十位
- TM1640_Write_Byte(SMG[miao%10]); //显示秒 个位
- TM1640_End(); //结束条件
- }
- }
-
- void TM1640_address_moshi(uint8 address_mode) //模式选择函数
- {
- TM1640_Star(); //开始条件
- TM1640_Write_Byte(address_mode); //写数据模式 地址自动加1模式 or 固定地址模式
- TM1640_End(); //结束条件
- }
-
- void TM1640_liangdu(uint8 liangdu) //亮度调节
- {
- TM1640_Star(); //开始条件
- TM1640_Write_Byte(liangdu); //设置亮度级别
- TM1640_End(); //结束条件
- }
-
- uint8 key_scan()
- {
- uint8 keynum = 0; //矩阵键盘键值 1~16
- uint8 temp = 0; //按键按下时的P3数据缓存
- /**************************************************************************/
- // 扫描矩阵键盘第一行 0XFE 1111 1110
- P3 = 0XFE;
- if(P3 != 0XFE)
- {
- delay(10); //按键消抖 5~10ms
- if(P3 != 0XFE)
- {
- temp = P3; //缓存P3总线的数据状态
- while(P3 != 0XFE)
- {
- TM1640_Display_time(Place_Addr_01,shi,fen,miao); //在第1位数码管(Place_Addr_09)显示时间 xx-xx-xx
- }
- switch(temp)
- {
- case 0X7E: keynum = 1; break;
- case 0XBE: keynum = 2; break;
- case 0XDE: keynum = 3; break;
- case 0XEE: keynum = 4; break;
- default: keynum = 0; break;
- }
- }
- }
-
- /**************************************************************************/
- // 扫描矩阵键盘第二行 0XFD 1111 1101
- P3 = 0XFD;
- if(P3 != 0XFD)
- {
- delay(10); //按键消抖 5~10ms
- if(P3 != 0XFD)
- {
- temp = P3; //缓存P3总线的数据状态
- while(P3 != 0XFD)
- {
- TM1640_Display_time(Place_Addr_01,shi,fen,miao); //在第1位数码管(Place_Addr_09)显示时间 xx-xx-xx
- }
- switch(temp)
- {
- case 0X7D: keynum = 5; break;
- case 0XBD: keynum = 6; break;
- case 0XDD: keynum = 7; break;
- case 0XED: keynum = 8; break;
- default: keynum = 0; break;
- }
- }
- }
-
- /**************************************************************************/
- // 扫描矩阵键盘第三行 0XFB 1111 1011
- P3 = 0XFB;
- if(P3 != 0XFB)
- {
- delay(10); //按键消抖 5~10ms
- if(P3 != 0XFB)
- {
- temp = P3; //缓存P3总线的数据状态
- while(P3 != 0XFB)
- {
- TM1640_Display_time(Place_Addr_01,shi,fen,miao); //在第1位数码管(Place_Addr_09)显示时间 xx-xx-xx
- }
- switch(temp)
- {
- case 0X7B: keynum = 9; break;
- case 0XBB: keynum = 10; break;
- case 0XDB: keynum = 11; break;
- case 0XEB: keynum = 12; break;
- default: keynum = 0; break;
- }
- }
- }
- /**************************************************************************/
- // 扫描矩阵键盘第四行 0XF7 1111 0111
- P3 = 0XF7;
- if(P3 != 0XF7)
- {
- delay(10); //按键消抖 5~10ms
- if(P3 != 0XF7)
- {
- temp = P3; //缓存P3总线的数据状态
- while(P3 != 0XF7)
- {
- TM1640_Display_time(Place_Addr_01,shi,fen,miao); //在第1位数码管(Place_Addr_09)显示时间 xx-xx-xx
- }
- switch(temp)
- {
- case 0X77: keynum = 13; break;
- case 0XB7: keynum = 14; break;
- case 0XD7: keynum = 15; break;
- case 0XE7: keynum = 16; break;
- default: keynum = 0; break;
- }
- }
- }
- /**************************************************************************/
- return keynum;
- }
-
-
- /********************************延时函数***********************************/
- void delay(uint16 x_ms) //延迟 x_ms*1 毫秒
- {
- uint16 i,j;
- for(i=0;i<x_ms;i++)
- for(j=0;j<114;j++);
- }
最终视觉效果如下 :
TM1640驱动数码管+任务矩阵按键调节