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
习题要求:使用TM1640驱动数码管时钟(带设置、加、减、确认按键功能)
简易电路搭建如下图所示:
完整代码如下 :
/*********************************************************************
程序名称:TM1640驱动数码管时钟(带设置、加、减、确认按键功能)
程序版本:V1.0
作 者: Attack BUG
编写时间:2023.09.01
硬件支持: TM1640、STC89C52RC、 16位矩阵键盘
接口说明:
修改日志:
*********************************************************************/
/*********************************************************************
头文件包含/SFR定义
*********************************************************************/
#include
#include
/*********************************************************************
宏定义
*********************************************************************/
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>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
最终视觉效果如下 :
TM1640驱动数码管+任务矩阵按键调节