独闷闷网

 找回密码
 立即注册
搜索
查看: 4616|回复: 3
收起左侧

[原创] 数码管芯片TM1639的C程序

[复制链接]
发表于 2014-1-29 13:56:52 | 显示全部楼层 |阅读模式

马上注册,结交更多好友,享用更多功能,让你轻松玩转社区。

您需要 登录 才可以下载或查看,没有帐号?立即注册

x
第二十五节:专用集成芯片TM1639驱动8位数码管

(1)开场白:
     在那么多种数码管的驱动方案中,我最喜欢使用专用集成芯片TM1639来驱动数码管。我认为这种方案是性价比最高的。既然是专用的集成芯片,那么我们可以把TM1639看成是一个独立的单片机,这个单片机也是利用动态扫描数码管的办法,只是厂家出厂时就已经把扫描驱动数码管的程序都写好了,并且烧录进了TM1639,他们预留3根IO口出来让外部的单片机跟TM1639通讯,我们编写程序时,只要按照厂家提供的通讯协议,往里面写入对应的指令和数据就可以间接静态驱动数码管。注意,我这里提到了“动态驱动”和“静态驱动”的概念,TM1639直接驱动数码管是属于动态的,但是我们编写程序跟TM1639通讯,这种间接驱动数码管是属于静态驱动的,因为我们的单片机不用定时扫描数码管。总之,我认为TM1639有4个好处:
(a)节省单片机IO口,3根IO口就可以控制8位数码管.
(b)CPU开销小。对于单片机来说,是属于静态驱动控制。
(c)外围电路简单,连串接的限流电阻和三极管也不用了,因为此芯片内部集成了8级灰度调节电路,我们  只要发送相应的指令,就可以调节数码管的亮度。
(d)这个芯片本身价格不算高。

(2)功能需求:     
在8个数码管中,从左到右,依次显示“12345678”。

(3)硬件原理:  
用单片机的3根IO口跟TM1639通讯。TM1639跟数码管的电路特别简单,不用串电阻,也不用加三极管,具体的电路与通讯协议请读者自己在网上下载,资料很容易获得,而且还是中文的。本程序是驱动8位的共阴数码管。

(4)源码适合的单片机: PIC18f4520,晶振为11.0592MHz。

(5)源代码讲解如下:
#include<pic18.h>         //包含芯片相关头文件


//tm1639的IO宏定义
#define  tm1639_stb_dr     LATA3
#define  tm1639_clk_dr     LATA4
#define  tm1639_dio_dr     LATA5


//位地址,共8位地址,每位地址里面的1个字节的数据代表8个LED灯的亮或灭
#define const_dig_addr0 0xc0
#define const_dig_addr1 0xc2
#define const_dig_addr2 0xc4
#define const_dig_addr3 0xc6
#define const_dig_addr4 0xc8
#define const_dig_addr5 0xca
#define const_dig_addr6 0xcc
#define const_dig_addr7 0xce


//数码管或者LED灯的显示亮度级别
#define const_level_off   0x80     //级别最低,最暗
#define const_level_1     0x88
#define const_level_2     0x89
#define const_level_4     0x8a     //本程序采取这个级别的亮度
#define const_level_10    0x8b
#define const_level_11    0x8c
#define const_level_12    0x8d
#define const_level_13    0x8e
#define const_level_14    0x8f    //级别最高,最亮

      
#define const_auto_add_addr     0x40  //采用地址自动加一方式写显存


void write_byte_tm1639(unsigned char tm1639_byte);  //写入一个字节数据进tm1639   
                     
void display_tm1639(unsigned char dig_addr,unsigned char dig_data,unsigned char dig_level); //一次显示8个LED灯或者一位数码管
//其中dig_addr是地址,dig_data是地址的数据,dig_level是亮度

void display_drive(); //数码管驱动程序,放在main函数的while(1)循环里

unsigned char number_left1=0;   //左边第1位数码管显示的内容
unsigned char number_left2=0;   //左边第2位数码管显示的内容
unsigned char number_left3=0;   //左边第3位数码管显示的内容
unsigned char number_left4=0;   //左边第4位数码管显示的内容
unsigned char number_left5=0;   //左边第5位数码管显示的内容
unsigned char number_left6=0;   //左边第6位数码管显示的内容
unsigned char number_left7=0;   //左边第7位数码管显示的内容
unsigned char number_left8=0;   //左边第8位数码管显示的内容


unsigned char led_update=0;     //更新显示变量,等于1时将执行一次更新显示数码管的程序

unsigned char number_temp[8];   //即将更新显示内容的中间变量

const unsigned char number_table[]=  //数码管的字模转换表
{
0x3F,    //0
0x06,    //1
0x5B,    //2
0x4F,    //3
0x66,    //4
0x6D,    //5
0x7D,    //6
0x07,    //7
0x7F,    //8
0x6F,    //9
};


//主程序
main()
{
    ADCON0=0x00;  
    ADCON1=0x0f;                               //全部为数字信号
    ADCON2=0xa1;                               //右对齐
    RBPU=0;                                      //上拉电阻
    SSPEN=0;                                 



    TRISA3=0;    //TM1639的3根驱动IO之一
    TRISA4=0;    //TM1639的3根驱动IO之一
    TRISA5=0;    //TM1639的3根驱动IO之一


    number_left1=1;   //左边第1位数码管显示"1"
    number_left2=2;   //左边第2位数码管显示"2"
    number_left3=3;   //左边第3位数码管显示"3"
    number_left4=4;   //左边第4位数码管显示"4"
    number_left5=5;   //左边第5位数码管显示"5"
    number_left6=6;   //左边第6位数码管显示"6"
    number_left7=7;   //左边第7位数码管显示"7"
    number_left8=8;   //左边第8位数码管显示"8"

   
    led_update=1;  //更新显示



   while(1)   
   {
       CLRWDT(); //喂看门狗,大家不用过度关注此行
       display_drive(); //数码管驱动程序,放在main函数的while(1)循环里

   }

}


void display_drive()    //数码管驱动程序,放在main函数的while(1)循环里
{
    if(led_update==1)  //有数据更新
    {
        led_update=0; //标志及时清零,避免一直扫描

        number_temp[0]=number_table[number_left1];  //载入即将显示的内容
        number_temp[1]=number_table[number_left2];  //载入即将显示的内容
        number_temp[2]=number_table[number_left3];  //载入即将显示的内容
        number_temp[3]=number_table[number_left4];  //载入即将显示的内容
        number_temp[4]=number_table[number_left5];  //载入即将显示的内容
        number_temp[5]=number_table[number_left6];  //载入即将显示的内容
        number_temp[6]=number_table[number_left7];  //载入即将显示的内容
        number_temp[7]=number_table[number_left8];  //载入即将显示的内容

        display_tm1639(const_dig_addr0,number_temp[0],const_level_4); //显示左边第1位
        display_tm1639(const_dig_addr1,number_temp[1],const_level_4); //显示左边第2位
        display_tm1639(const_dig_addr2,number_temp[2],const_level_4); //显示左边第3位
        display_tm1639(const_dig_addr3,number_temp[3],const_level_4); //显示左边第4位
        display_tm1639(const_dig_addr4,number_temp[4],const_level_4); //显示左边第5位
        display_tm1639(const_dig_addr5,number_temp[5],const_level_4); //显示左边第6位
        display_tm1639(const_dig_addr6,number_temp[6],const_level_4); //显示左边第7位
        display_tm1639(const_dig_addr7,number_temp[7],const_level_4); //显示左边第8位
    }
}



//写入一个字节数据进tm1639
void write_byte_tm1639(unsigned char tm1639_byte)                           
{
    unsigned char tm1639_i;

    tm1639_stb_dr=0;                    //stb为低电平,程序不依赖于之前端口的状态,避免出现“端口迷失”
    for(tm1639_i=0;tm1639_i<8;tm1639_i++)
    {
        tm1639_clk_dr=0;            
        if((tm1639_byte & 0x01)!=0)
           tm1639_dio_dr=1;           
        else
           tm1639_dio_dr=0;            
        tm1639_clk_dr=1;              
        tm1639_byte=tm1639_byte>>1;     
    }                                 
}



//一次显示8个LED灯或者一位数码管
void display_tm1639(unsigned char dig_addr,unsigned char dig_data,unsigned char dig_level)
{
    tm1639_dio_dr=1;
    tm1639_clk_dr=1;
    tm1639_stb_dr=1;      
            

    write_byte_tm1639(const_auto_add_addr);       //设置成自动加一方式   
    tm1639_stb_dr=1;                              
    write_byte_tm1639(dig_addr);        //设置显示的位地址      


    write_byte_tm1639(dig_data & 0x0f);         //显示的低4位数据,共代表4个led灯
    write_byte_tm1639(dig_data >> 4 & 0x0f);     //显示的高4位数据,共代表4个led灯

    tm1639_stb_dr=1;            
    write_byte_tm1639(dig_level);     //设置显示的亮度
    tm1639_stb_dr=1;                 
}


(6)小结:   
前面花了几个章节来讲常用的数码管驱动方式,下一节将要讲一下操作数码管显示的基本程序框架。

(7)下集预告:   
按键操作数码管菜单的基本程序框架。

(未完待续,下节更精彩,不要走开哦)
乐于分享,勇于质疑!
发表于 2014-8-15 13:23:07 | 显示全部楼层
我们点数码管用LM1628多
乐于分享,勇于质疑!
发表于 2014-8-15 15:17:59 | 显示全部楼层
yao1318 发表于 2014-8-15 13:23
我们点数码管用LM1628多

涨知识了。下次用到数码管的,我也关注一下这款芯片LM1628
乐于分享,勇于质疑!
发表于 2014-8-15 21:47:23 | 显示全部楼层
就不知哪 个便宜,我们全是用1628的,1639不怎见。
乐于分享,勇于质疑!
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

QQ|Archiver|手机版|独闷闷网 ( 粤ICP备12007667号-2 )

GMT+8, 2021-5-15 07:44 , Processed in 0.145395 second(s), 18 queries .

快速回复 返回顶部 返回列表