首先,作为四年前就有的LED段码控制芯片,相关的资料及样例程序少的可怜。硬件驱动 作为固定使用的 软件资源,其共享性远低于软件领域的驱动库。人的才智不应浪费在这种不具创造性的重复实验上。
要点总结:
TM1652概述:
数据:
TM1652是一款共阴LED(发光二极管、数码管、点阵屏)驱动控制专用芯片。内部集成了数字通讯电路、震荡器、LED驱动电路等。显示模式(7段×6位,8段×5位),可调节屏幕亮度(位占空比16级可调、段驱动电流8级可调)。
供电:
供电电压3V~6V;数据接口电压可5V或3.3V(不同供电系统可对接,但尽量避免)。
功能:
支持共阴数码管显示;7段×6位,8段×5位数码管显示;辉度调节电路(位占空比16级可调、段驱动电流8级可调);内置上电复位电路;内置针对暗亮问题的优化电路。
连接:
采用单线SDA控制,可使用UART的TX端口控制,也可使用普通GPIO模拟UART的TX端口控制,支持波特率19200bps(即,每位数据52us)。
TM1652引脚说明:
TM1652电气特性:
TM1652 MCU连接:
连接时确定好各段的abcd…的位置连接,方便进行代码控制。(SG1连a;SG2连b;…)
7段x6位电路接法
8段x5位电路接法
应用时请在芯片 VDD 与 GND 加一个 104(100nf) 去耦电容。去耦电容与芯片 VDD 和 GND 之间的连线越短,去耦效果就越好,芯片工作就越稳定。
TM1652通信协议
通讯帧结构:
采用异步串口通信(UART)协议,工作原理是将传输数据的每个字符以串行方式一位接一位
的传输。工作模式:
1、每一位时间为52us
2、起始位(1bit):表示传输数据的开始,由高变低进行表示
3、数据位(8bit):8位数据位,低位在前,二进制数据为1设高,为0设低
4、校验位(1bit):统计数据位中1的个数,为奇数个设低(0),为偶数个设高(1)–(奇校验)
5、停止位(1bit):设高,发送完一个字符数据的结束标志
6、空闲位(1bit):设高,空闲位置高的时间大于 3ms,TM1652 就认为本次数据帧结束,本次数据从暂存器打入相应寄存器开始控制芯片输出。如果一帧数据传输没有结束,那么建议设置空闲位时间范围在
0-0.5ms 以内。
注意:提前说明一个概念,TM1652的数据帧包含两部分,显示帧数据和控制帧数据,空闲位在这两个数据帧之间发挥作用。在测试时,如果数据发送是正常的,不能点亮,一般是数据帧异常导致的。包括(1、数据帧不完整;2、数据帧空闲位时间长度不够;)
==波特率:==是衡量数据传输速率的指针。表示为每秒钟传送的二进制位数(bit 数)。TM1652 支持波特率范围为:17500bps~21200bps,这里我们建议用 19200bps 即每位的时间为:1s(秒)/19200≈ 52us(微秒)。TM1652 支持的每位的时间范围为:47us~57us。在用 IO 模拟 UART 通讯时候,SDA 数据的位宽应该满足提供的位宽范围即47us~57us。
TM1652帧数据结构:
注意:TM1652帧数据并非普通意义的数据帧,而是TM1652控制命令的最小单元,它包含两种形式
⑴ 显示地址命令+显示数据;(显示帧数据)
⑵ 显示控制命令+显示控制调节命令;(控制帧数据)
要想把TM1652点亮,据需要完整的发送显示帧数据和控制帧数据。
显示地址命令级显示控制命令格式:(显示地址命令控制显示的位号,显示控制命令控制显示的亮度和显示模式)
具体位号对应命令:
显示数据格式:(控制从显示地址命令设定的位开始显示的该位的a、b、c…段号的亮灭)
显示控制调节命令格式:(控制命令+控制调节命令组成控制帧数据,控制数据用于调节显示亮度与显示方式每一次显示帧数据的发送,都要跟上控制帧数据才能生效)
TM1652显示控制
帧数据发送顺序:
首先如果先发控制帧数据(开显示),显示寄存器没有清零,此时就会输出显示寄存器里面的随机数据,导致数码管显示乱码。因此要先发显示帧数据,再发控制帧数据(开显示)避免乱码。
由于数码管有多位,因此一个显示地址命令可以跟多个byte显示数据。后续 byte数据按地址累加 1 放入相应暂存器中。数据超出地址的部分无效。
显示数据:
上图给出共阴数码管的连接示意图,如果让该数码管显示“0”,则需要在GR1为低电平时置SG1,
SG2,SG3,SG4,SG5,SG6为高电平,置SG7,SG8为低电平
即显示数据为0b00111111=0x3f
数据包传输方式:(显示帧数据+控制帧数据=数据包)
1、地址自动加1模式(上面介绍了多个显示数据会自动放入地址加1的寄存器中)
这就是一条完整的TM1652命令了,可以控制TM1652显示。
Command1:选择显示地址命令(0x08)
Data1~Data n:发送显示数据(1byte数据为1位,最多支持6位)
Time:数据线置高时间(最小时间为3ms)就是上面的空闲位,分割显示帧数据和控制帧数据
CommandX:选择显示控制命令(0x18)
CommandY:发送显示控制调节命令(包括位占空比、段驱动电流以及显示模式设置)
2、固定地址模式(对每一个数据发送一个地址)
这也是一条完整的TM1652命令,可以控制TM1652显示。
Command1–Command n:选择显示地址命令(0x08:位号1;0x88:位号2…)
Data1~Data n:发送显示数据(最多6 bytes)
Time:数据线置高时间(最小时间为3ms)就是上面的空闲位,分割显示帧数据和控制帧数据
CommandX:发送显示控制命令(0x18)
CommandY:发送显示控制调节命令(包括位占空比、段驱动电流以及显示模式设置)
可以看到固定地址模式每个显示帧数据都需要至少间隔3ms,不推荐(官方说明芯片严格来说只有一种地
址自动加1模式,间隔只是分离了操作)
举例说明:
1、地址自动加1模式
发送命令:08 3F 06 5B 4F FF
间隔5ms:delay_ms(5)
发送命令:18 18
0x08:GR1地址
0x3F :GR1数据0
0x06 :GR2数据1
0x5B :GR3数据2
0x4F :GR4数据3
0xFF :GR5数据8.
0x18 :显示控制命令
0x18 :设置占空比为 8/16,设置段驱动电流为 2/8,设置 8 段 5 位输出
TM1652串口调试助手测试
使用串口调试助手就可以测试驱动TM1652。
将USB转TTL的供电连接TM1652的供电(3.3V或5V均可),其次将TXD连接TM1652的SDA引脚。
1、打开串口调试助手 V5.0.2.12 免费版
2、选择串口号,波特率,校验位,数据位。停止位。并打开串口
3、接收及发送设置选择HEX,其他不选。
4、先发送显示帧数据 08 3F 06 5B 4F FF
5、再发送控制帧数据 18 18
6、手输即可,间隔超过3ms即可。显示效果展示:
TM1652样例代码(基于HC32L130)
串口调试助手已经测过串口控制方式,下面代码使用GPIO模拟方式进行控制。使用任意GPIO即可。
tm1652.h文件
#ifndef __TM1652_H__
#define __TM1652_H__
#include "ddl.h"
#include "gpio.h"
//TM1652 GPIO定义
#define TM1652_SDA_PORT GpioPortA
#define TM1652_SDA_PIN GpioPin2
void delay_52us(uint32_t u32Cnt);
void tm1652_init(void);
void tm1652_send(uint8_t data);
uint8_t tm1652_transform(uint8_t showChar) ;
void tm1652_show_updata(uint8_t char1, uint8_t char2, uint8_t char3, uint8_t char4, uint8_t char5);
#endif /* __TM1652_H__ */
tm1652.c文件(52us使用软定时,方便引用,如有精确定时可替换)
#include "tm1652.h"文件
//TM1652显示控制调节命令
//位驱动占空比8/16,段驱动电流2/8,显示模式8段5位输出
uint8_t tm1652ShowMode=0x18;
#define TM1652_SDA_PIN_LOW Gpio_ClrIO(TM1652_SDA_PORT,TM1652_SDA_PIN);
#define TM1652_SDA_PIN_HIGH Gpio_SetIO(TM1652_SDA_PORT,TM1652_SDA_PIN);
//延时取27为4MHz的取值,delay_52us(x)延时时长约52us
//若使用ddl库中的delay1us()函数则不能取到,delay1us(0)的延时时间超过59us
uint32_t x = 27;
//一个while循环大约5个时钟周期,一个时钟周期271ns
//进入退出循环大约8个时钟周期
//加上函数调用大约15个时钟周期
//一个时钟周期271ns
void delay_52us(uint32_t u32Cnt)
{
//while一次循环约1.25us
//一次函数调用约4.2us
while(u32Cnt--);
}
//TM1652GPIO初始化
void tm1652_init(void)
{
stc_gpio_cfg_t GpioInitStruct;
DDL_ZERO_STRUCT(GpioInitStruct);
///<使能GPIO外设时钟门控开关
Sysctrl_SetPeripheralGate(SysctrlPeripheralGpio,TRUE);
///<配置SDA引脚输出模式
GpioInitStruct.enDir = GpioDirOut;
GpioInitStruct.enDrv = GpioDrvL;//低驱动
///<配置SDA引脚上拉
GpioInitStruct.enPu = GpioPuEnable;
GpioInitStruct.enPd = GpioPdDisable;
Gpio_Init(TM1652_SDA_PORT,TM1652_SDA_PIN,&GpioInitStruct);
}
//向TM1652发送1byte数据
void tm1652_send(uint8_t data)
{
uint8_t nBit=0;
uint8_t fParity =0;
TM1652_SDA_PIN_LOW
delay_52us(x);
for(nBit=0; nBit<8; nBit++)
{
if(data&0x01)
{
fParity ++;
TM1652_SDA_PIN_HIGH
}
else
{
TM1652_SDA_PIN_LOW
}
delay_52us(x);
data>>=1;
}
if(fParity%2==0)
{
TM1652_SDA_PIN_HIGH
}
else
{
TM1652_SDA_PIN_LOW
}
delay_52us(x);
TM1652_SDA_PIN_HIGH
delay_52us(x);
delay_52us(x);
}
//数码管显示字符对应显示数据转换
uint8_t tm1652_transform(uint8_t showChar)
{
uint8_t data = 0xff;
switch(showChar)
{
case '0': data = 0x3F; break; // 0
case '1': data = 0x06; break; // 1
case '2': data = 0x5B; break; // 2
case '3': data = 0x4F; break; // 3
case '4': data = 0x66; break; // 4
case '5': data = 0x6D; break; // 5
case '6': data = 0x7D; break; // 6
case '7': data = 0x07; break; // 7
case '8': data = 0x7F; break; // 8
case '9': data = 0x6F; break; // 9
case 'A': data = 0x77; break; // A
case 'B': data = 0x7C; break; // B
case 'C': data = 0x39; break; // C
case 'D': data = 0x5E; break; // D
case 'E': data = 0x79; break; // E
case 'F': data = 0x71; break; // F
}
return data;
};
//TM652 5位数码管显示字符更新函数
void tm1652_show_updata(uint8_t char1, uint8_t char2, uint8_t char3, uint8_t char4, uint8_t char5)
{
//显示帧数据
tm1652_send(0x08);
tm1652_send(tm1652_transform(char1));
tm1652_send(tm1652_transform(char2));
tm1652_send(tm1652_transform(char3));
tm1652_send(tm1652_transform(char4));
tm1652_send(tm1652_transform(char5));
//命令间隔
delay1ms(3);
//控制帧数据
tm1652_send(0x18);
tm1652_send(tm1652ShowMode);
}
main.c文件
#include "gpio.h"
#include "ddl.h"
#include "tm1652.h"
int main(void)
{
tm1652_init();
while(1)
{
tm1652_show_updata('1','2','3','4','5');
delay1ms(1000);
}
}