TM1638是一个让人又爱又恨的芯片。说它让人爱,是因为它功能强大,一个芯片即可驱动十位的数码管,可以是共阴极,也可以是共阳极数码管。又能检测最多24个按键。而常用电路里连接数码管所需的限流电阻,或者常用按键电路里所需的上拉电阻全都不需要,芯片内部已经处理好了。
说它让人恨,是因为它的数据手册写的太烂了。细节写的不详细就算了,表格还经常对不齐。如果不是拉低自己的智商,你很可能看不懂。
所以这里,我只说这个芯片如何使用。如果你真的对数据手册感兴趣,可以找时间慢慢研究。
程序执行流程图,手册里提供了两种,这里以第二种为例,进行演示。如下:
看着挺复杂,简单来说,就是4个步骤:
1、初始化
2、依次设置几位数码管要显示的值
3、读取按键状态,并处理相应的按键事件
4、回到步骤2,以此循环。
有人会担心,是不是要不停的设置数码管的值,一旦停了,数码管就不显示了?
不是的!数码管的值只要写一次,就能一直显示。
所以如果你只是要显示数码管,不检测按键。那么上面的步骤,执行到第二步就行了。如果要修改数码管的值,重复第二步即可。
还有人会想,我数码管的值不怎么改,按键要经常检测,从第四步跳回第三步,不跳回第二步了,还能节约时间。可不可以?
不行!芯片会工作异常!
时序部分比较简单,就是常见的三条线:时钟、数据、片选。用过DS1302的都懂,类似,不解释。
电路部分也不难,数据手册里提供了相应的原理图,共阴极如下:
共阳极数码管接法如下:
看不清的,可以去手册看。应用电路这部分,手册画的还是很清晰,没有问题。
最关键的地方在于驱动共阳极与共阴极数码管时,你向芯片内存地址写入的数据,两者方法是完全不一样的。共阴极数码管驱动方法是比较简单的,显示什么数字送入相应的编码即可。
共阳极数码管的驱动方法堪称噩梦,我看了一天也没看懂,只能知道它大概的意思。不仅如此,网上大部分资料都是关于共阴极数码管的。而不幸的是,我当时设计电路使用的是共阳极数码管。幸好后来在网上搜到了一份资料,不然真的要跪了!
我们看下主要部分的代码:
首先是上电初始化:
void Display_Init(void)
{
Send_Command(0x44); //显示模式-固定地址
Send_Command(0x40); //写数据到显示寄存器
//数码管和LED默认都熄灭
LedDisplay1(0x0a,0x0a,0x0a,0x0a,0x0a,0x0a,0,0);
Send_Command(0x8f); //显示控制-显示开
}
共阳极数码管的显示代码:
void LedDisplay1(unsigned char data0,unsigned char data1,unsigned char data2,unsigned char data3,unsigned char data4,unsigned char data5,unsigned char data6,unsigned char data7)
{ //操作TM1638前八个数码管(共阳极-SEG1~SEG8)
unsigned char writedata0,writedata1,writedata2,writedata3,writedata4,writedata5,writedata6,writedata7;
MX_DIO_OUT_Init();
//一次将SEG数值写完(SEG1|SEG2...SEG8)
writedata0=(DispHexToSegTbl[data0]&0x01)+((DispHexToSegTbl[data1]&0x01)<<1)+((DispHexToSegTbl[data2]&0x01)<<2)+((DispHexToSegTbl[data3]&0x01)<<3)+((DispHexToSegTbl[data4]&0x01)<<4)
+((DispHexToSegTbl[data5]&0x01)<<5)+((data6&0x01)<<6)+((data7&0x01)<<7);
writedata1=((DispHexToSegTbl[data0]&0x02)>>1)+((DispHexToSegTbl[data1]&0x02))+((DispHexToSegTbl[data2]&0x02)<<1)+((DispHexToSegTbl[data3]&0x02)<<2)+((DispHexToSegTbl[data4]&0x02)<<3)
+((DispHexToSegTbl[data5]&0x02)<<4)+((data6&0x02)<<5)+((data7&0x02)<<6);
writedata2=((DispHexToSegTbl[data0]&0x04)>>2)+((DispHexToSegTbl[data1]&0x04)>>1)+((DispHexToSegTbl[data2]&0x04))+((DispHexToSegTbl[data3]&0x04)<<1)+((DispHexToSegTbl[data4]&0x04)<<2)
+((DispHexToSegTbl[data5]&0x04)<<3)+((data6&0x04)<<4)+((data7&0x04)<<5);
writedata3=((DispHexToSegTbl[data0]&0x08)>>3)+((DispHexToSegTbl[data1]&0x08)>>2)+((DispHexToSegTbl[data2]&0x08)>>1)+((DispHexToSegTbl[data3]&0x08))+((DispHexToSegTbl[data4]&0x08)<<1)
+((DispHexToSegTbl[data5]&0x08)<<2)+((data6&0x08)<<3)+((data7&0x08)<<4);
writedata4=((DispHexToSegTbl[data0]&0x10)>>4)+((DispHexToSegTbl[data1]&0x10)>>3)+((DispHexToSegTbl[data2]&0x10)>>2)+((DispHexToSegTbl[data3]&0x10)>>1)+((DispHexToSegTbl[data4]&0x10))
+((DispHexToSegTbl[data5]&0x10)<<1)+((data6&0x10)<<2)+((data7&0x10)<<3);
writedata5=((DispHexToSegTbl[data0]&0x20)>>5)+((DispHexToSegTbl[data1]&0x20)>>4)+((DispHexToSegTbl[data2]&0x20)>>3)+((DispHexToSegTbl[data3]&0x20)>>2)+((DispHexToSegTbl[data4]&0x20)>>1)
+((DispHexToSegTbl[data5]&0x20))+((data6&0x20)<<1)+((data7&0x20)<<2);
writedata6=((DispHexToSegTbl[data0]&0x40)>>6)+((DispHexToSegTbl[data1]&0x40)>>5)+((DispHexToSegTbl[data2]&0x40)>>4)+((DispHexToSegTbl[data3]&0x40)>>3)+((DispHexToSegTbl[data4]&0x40)>>2)
+((DispHexToSegTbl[data5]&0x40)>>1)+((data6&0x40))+((data7&0x40)<<1);
writedata7=((DispHexToSegTbl[data0]&0x80)>>7)+((DispHexToSegTbl[data1]&0x80)>>6)+((DispHexToSegTbl[data2]&0x80)>>5)+((DispHexToSegTbl[data3]&0x80)>>4)+((DispHexToSegTbl[data4]&0x80)>>3)
+((DispHexToSegTbl[data5]&0x80)>>2)+((data6&0x80)>>1)+((data7&0x80));
TM1638_WriteAddressData(0XC0,writedata0);//操作 C0地址
TM1638_WriteAddressData(0XC2,writedata1);//操作 C2地址
TM1638_WriteAddressData(0XC4,writedata2);//操作 C4地址
TM1638_WriteAddressData(0XC6,writedata3);//操作 C6地址
TM1638_WriteAddressData(0XC8,writedata4);//操作 C8地址
TM1638_WriteAddressData(0XCa,writedata5);//操作 Ca地址
TM1638_WriteAddressData(0XCc,writedata6);//操作 Cc地址
TM1638_WriteAddressData(0Xce,writedata7);//操作 Ce地址
}
读按键值:
unsigned char Read_key(void)
{
unsigned char c[4],i,key_value=0;
Reset(STB);
delay_us(5);
Send_Command(0x42); //读键扫数据 -命令
for(i=0;i<4;i++)
c[i]=TM1638_Read();
Set(STB);
for(i=0;i<4;i++)
key_value|=c[i]<<i;
for(i=0;i<8;i++)
if((0x01<<i)==key_value)
break;
return i;
}
我这里只接了三个按键,如图:
如果是共阴极数码管,写入数码管数据部分的代码如下:
void Write_DATA(unsigned char add,unsigned char DATA)
{
//指定地址写入数据
Write_COM(0x44);
STB=0;
TM1638_Write(0xc0|add);
TM1638_Write(DATA);
STB=1;
}
看到了吧,共阴极与共阳极的写入数据部分的代码,复杂程度完全不一样。除了这里,按键扫描部分是完全一样的。
我分别把这两类详细代码传到了百度网盘,想要的童鞋关注公众号:单片机爱好者,回复关键词:TM1638,即可获取下载链接。
TM1638
不是这里~~~
TM1638
兄弟,不是这里
老师好 我用STC15W4K48S4 芯片驱动TM1638 不显示,同样的代码 下载到STC12C5612AD芯片就可以显示了。15W的芯片端口配置了,初始化了。15W芯片速度更快,是否时序有问题
只能说是有可能,各方面原因都要排查
测试过几次这种LED驱动,没有限流电阻所以噪声还是比较大的,最好不要跟MCU公用电源,否则ADC就遭罪了。
很宝贵的经验啊!
您好!请问我能看一下你的关于这部分的所有程序吗?我大致看了一下程序都是分块的,有完整的显示程序吗?比如控制某一个数码管显示出数值,我最近再用GN1629C控制共阳的显示屏,但是小白一个,很头大。
完整的代码公众号后台有提供,看不懂的话估计还是基础不扎实。
加油
多谢!