一、天威TM1640介绍
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驱动数码管时钟(带设置、加、减、确认按键功能)
- VCC:电源正,推荐3.3V或5V ———5V供电
- CLK:同步串行通信时钟信号输入引脚 ——–CLK=P2^1
- DIN:同步串行通信数据输入引脚 ——— DIN=P2^0
- GND:地
简易电路搭建如下图所示:
完整代码如下 :
/********************************************************************* 程序名称: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驱动数码管+任务矩阵按键调节
今天的文章
(51单片机)习题:TM1640驱动数码管并用任意矩阵键盘调节显示参数分享到此就结束了,感谢您的阅读。
版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。
如需转载请保留出处:https://bianchenghao.cn/80142.html