去年8月一时兴起,从淘宝上买了块由TM1637驱动的四位数据管模块,本着买来驱动着去玩一玩想法,可惜的是到货了之后没有了下文。又是一个8月,偶然看到未拆包装的这个模块,打开它花上半天时间驱动成功,驱动过程中由于使用的是1T的c51单片机,反反复复花了很长时间始终没有点亮,看芯片说明书TM1637的时序时间基本在1us以下,所以延时设定在3us左右,后来估计资料不一定准确把延时设在30us左右成功驱动模块,以下记录C51单片机(STC15W408AS)驱动TM1637四位数码管的过程,模块如下图所示。
一、模块概述:
1、数码管:
采用7段共阳极的数码管,带有时钟点,其中两个实钟点是集成在DIG2显示管上,在淘宝的评论区中看到有买家的评论问为什么不显示小数点,这种数码管不会显示小数点,管型就不支持显示。
2、芯片TM1637:
TM1637是一块带键盘扫描和数码管显示驱动的控制专用芯片。本模块仅使用芯片的显示驱动功能,通信方式采用I2C总线,大大节约单片机的IO端口,还可以通过指令调节数码管的显示亮度。
二、模块与单片机电路连接:
序号 | 单片机 | TM1637模块 |
1 | +5V | +5V |
2 | GND | GND |
3 | P3.5 | DIO |
4 | P3.6 | CLK |
三、模块驱动协议:
TM1637在I2C协议下工作,本文不再讨论I2C的基础协议。单片机向TM1637写数据有两种方式。
第一种是地址自动加1模式,即只需要告诉芯片首个数码管的地址,写完第一个数码管的数据后地址自动加1再,直接给第二个、第三个、第四个数据即可。
第二种是固定地址模式,即必须是一个地址对应一个数据,直至写完。
我们下面以第一种自动加1模式为基础。以下为协议。
1、分析写入过程如下:
Start信号+命令1+ACK信号+Stop信号+ Start信号+首个数码管地址数据+ACK信号+首个数码管显示数据+ ACK信号+第二个数码管显示数据+ ACK信号+第三个数码管显示数据+ ACK信号+第四个数码管显示数据+ ACK信号+ Stop信号+ Start信号+显示控制命令+ ACK信号+ Stop信号
2、命令1内容如下表:
根据上表我们需要写数据到显示寄存器,0100 0000即(0x40)
3、数据管的地址如下表:
根据上表我们需要第一个数码管的地址,1100 0000即(0xC0)
4、显示控制命令:
现在我们需要显示开到高5位10001,再需要最亮显示低3位111,合并后1000 1111即(0x8F)
四、代码部分:
1、I2C.c文件部分:
sbit SDA=P3^5; //DIO端
sbit SCL=P3^6; //CLK端
void Delay20us() //@11.0592MHz
{
unsigned char i;
_nop_();
_nop_();
_nop_();
i = 52;
while (--i);
}
void DelayUs2x(unsigned char x)
{
while(x--)
{
Delay20us();
}
}
void I2C_Init()
{
SDA=1;
SCL=1;
}
//起始信号
void I2C_Start()
{
SDA=1;
SCL=1;
DelayUs2x(2);
SDA=0;
//Delay3us();
}
//结束信号
void I2C_Stop()
{
SCL=0;
DelayUs2x(2);
SDA=0;
DelayUs2x(2);
SCL=1;
DelayUs2x(2);
SDA=1;
}
//发送时接收从机应答信号
void I2C_Wait_Ack()
{
unsigned char i=0;
SCL=0;
SDA=1;
DelayUs2x(2);
while(SDA&&i<10)
{
i++;
DelayUs2x(2);
}
SCL=1;
DelayUs2x(2);
SCL=0;
DelayUs2x(2);
}
//接收时发送至从机应答信号
void I2C_Send_Ack(unsigned char ack)
{
if(ack==1)
SDA=1;
else
SDA=0;
DelayUs2x(3);
SCL=1;
DelayUs2x(3);
DelayUs2x(3);
SCL=0;
SDA=1; //很关键,没有后续不能连续读
DelayUs2x(3);
}
//发送8位字节
void I2C_Write_Byte(unsigned char c)
{
unsigned char i;
SCL=0;
//DelayUs2x(2);
for(i=0;i<8;i++)//必须从低位开始
{
SDA=c&0x01;
c=c>>1;
SCL=1;
DelayUs2x(3);
SCL=0;
DelayUs2x(3);
}
I2C_Wait_Ack();
}
2、main主程序部分:
bit dot1=0;
unsigned char dat[]={
0x3F,/*0*/
0x06,/*1*/
0x5B,/*2*/
0x4F,/*3*/
0x66,/*4*/
0x6D,/*5*/
0x7D,/*6*/
0x07,/*7*/
0x7F,/*8*/
0x6F/*9*/
};
void Delay500ms() //@11.0592MHz
{
unsigned char i, j, k;
_nop_();
_nop_();
i = 22;
j = 3;
k = 227;
do
{
do
{
while (--k);
} while (--j);
} while (--i);
}
//h1小时的十位,h0小时个位,m1分的十位,m0分的个位,dot两点,1表示显示,0表示不显
void display(unsigned char h1,unsigned char h0,unsigned char m1,unsigned char m0,unsigned char dot)
{
unsigned char i;
I2C_Start();
I2C_Write_Byte(0x40);
I2C_Stop();
I2C_Start();
I2C_Write_Byte(0xC0);
I2C_Write_Byte(dat[h1]);
if(dot)
{
I2C_Write_Byte(dat[h0]|0x80);
}
else
{
I2C_Write_Byte(dat[h0]&0x7F);
}
I2C_Write_Byte(dat[m1]);
I2C_Write_Byte(dat[m0]);
I2C_Stop();
I2C_Start();
I2C_Write_Byte(0x8f);
I2C_Stop();
}
void main()
{
//输入程序代码
while(1)
{
display(1,2,3,0,dot1);
Delay500ms();
Delay500ms();
dot1=~dot1;
}
}
五、运行效果: