51单片机使用TM1638驱动的数码管键盘模块

这篇具有很好参考价值的文章主要介绍了51单片机使用TM1638驱动的数码管键盘模块。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

前几天差不多把清翔的视频教程写完了,然后玩了两天,这次准备把以前买的TM1638芯片驱动的数码管按键模块用在51单片机上。

这个模块我在pdd上买的,用了2块的优惠券后付款7元包邮,价格还行吧,对比了下这个价格几乎就是最低价了。TM1638芯片都要1块多,再加上PCB,焊接,LED,电阻,数码管,还有运费,已经比较划算了。tm1638驱动数码管程序,清翔51学习笔记,51单片机,计算机外设,嵌入式硬件

 买模块店家有送显示程序,但是我还是想自己看一下数据手册,趁热打铁,记录下学习过程

一、模块图片

上面的LED全亮是我刚才写的测试程序

tm1638驱动数码管程序,清翔51学习笔记,51单片机,计算机外设,嵌入式硬件

最上面是8个LED,下方是8个8段数码管 ,再下方是芯片,芯片右侧是二极管(非发光的普通二极管),左侧是VCC,GND以及3条数据线总共5条线。最下方是8个按键

我的这个模块数码管是共阴极的接法,其实这个芯片可以接共阴极也可以接共阳极数码管,不过我感觉共阳极的接法用起来比较麻烦。 

 二、TM1638

2.1 管脚定义

tm1638驱动数码管程序,清翔51学习笔记,51单片机,计算机外设,嵌入式硬件

 带k的都是可以按键扫描的,SEG和GR是数码管段和位,STB,CLK,DIO是与数据相关的引脚 

 数据手册有说,不管芯片连接的是共阳极数码管还是共阴极数码管,SEG都必须接阳极,GR接阴极,不能反过来,这也是跟他们是P管开漏输出和N管开漏输出有关。tm1638驱动数码管程序,清翔51学习笔记,51单片机,计算机外设,嵌入式硬件

 P管开漏输出和N管开漏输出有什么区别,我们不需要关心,这是电路设计才需要考虑的

tm1638驱动数码管程序,清翔51学习笔记,51单片机,计算机外设,嵌入式硬件

 这一段告诉我们如果要读取数值,需要在上升沿读才稳定。

2.2 按键扫描

一般按键扫描是最多接3*8=24个按键,可能店家为了节省成本,我这里只接了1*8=8个按键。

数据手册推荐按键接法

tm1638驱动数码管程序,清翔51学习笔记,51单片机,计算机外设,嵌入式硬件

 K1接8个,K2接8个,K3接8个按键。

实际我的模块上只用了K3的8个按键

tm1638驱动数码管程序,清翔51学习笔记,51单片机,计算机外设,嵌入式硬件

 虽然只接了K3,但是芯片还是考虑全部,所以读取的时候会发送4个字节。

读取方式:先发送读取按键命令,DIO就会按顺序输出4个字节,数据输出也是从低位到高位

输出数据结构tm1638驱动数码管程序,清翔51学习笔记,51单片机,计算机外设,嵌入式硬件

每个字节都是KS(偶)K1 K2 K3 KS(偶-1)K1 K2 K3 的结构,如果按下对应的按键,那么对应的位置就是1.比如我按下了K3和KS4的按键,那么在读取的第2个字节就是1001 0001,在程序里面就可以根据读到的数值判断出按下了哪个键,然后去处理什么事情。

2.3 命令

在管脚定义图里面说了,在STB为低的第一个字节视为命令

 2.3.1 显示控制命令

 tm1638驱动数码管程序,清翔51学习笔记,51单片机,计算机外设,嵌入式硬件

 显示控制命令的高4位固定是8,BIT3控制是否打开显示,剩下的控制亮度。这个芯片总共有8档亮度可调.比如我想打开显示,亮度1/16,那么就可以发送0x88(1000 1000)

2.3.2 数据命令

tm1638驱动数码管程序,清翔51学习笔记,51单片机,计算机外设,嵌入式硬件

 高四位固定是4,低四位设置具体功能。比如我想设置普通模式,自动增加地址,写数据到显示寄存器,就可以发送0x40(0100 0000),如果我想读取按键数据,就可以发送0x42(0100 0010)

2.3.3 显示地址设置

tm1638驱动数码管程序,清翔51学习笔记,51单片机,计算机外设,嵌入式硬件 这个命令的高四位固定是C,低四位设置具体数值,来设置16个显示寄存器地址。其实这个命令的低四位就是对应地址的低四位。上电默认地址是00H。

 显示寄存器地址

tm1638驱动数码管程序,清翔51学习笔记,51单片机,计算机外设,嵌入式硬件

 他这个表官方的就是没有对齐,有点难受。写数据的时候,在某个地址先发送低位再发送高位数据。SEG10后面的X直接写0就行。

根据我的原理图,tm1638驱动数码管程序,清翔51学习笔记,51单片机,计算机外设,嵌入式硬件

SEG1到8控制段选,GR控制位置。 

tm1638驱动数码管程序,清翔51学习笔记,51单片机,计算机外设,嵌入式硬件 板载的8个红色LED接在SEG9上,所以要想亮就需要把SEG9拉高

2.4 时序图

tm1638驱动数码管程序,清翔51学习笔记,51单片机,计算机外设,嵌入式硬件

 Twait要求大于1us,但是51单片机1个机器周期1.085us大于1us,所以在51单片机里面可以不考虑这个延时。

tm1638驱动数码管程序,清翔51学习笔记,51单片机,计算机外设,嵌入式硬件

 tm1638驱动数码管程序,清翔51学习笔记,51单片机,计算机外设,嵌入式硬件

tm1638驱动数码管程序,清翔51学习笔记,51单片机,计算机外设,嵌入式硬件 驱动共阳极数码管就是没有驱动共阴极方便。

2.5 地址增加模式数据流程

tm1638驱动数码管程序,清翔51学习笔记,51单片机,计算机外设,嵌入式硬件

 2.6 地址固定模式数据流程

tm1638驱动数码管程序,清翔51学习笔记,51单片机,计算机外设,嵌入式硬件

 2.7 读按键数据流程

 Command1就是发送读按键命令,这个命令由2.3.2 数据命令里面的一个位控制

 三、编程

知道理论之后,就可以开启编程了。

3.1 地址自动增加模式

#include <reg52.h>

typedef unsigned char uchar;
typedef unsigned char ucahr;
typedef unsigned int uint;

sbit TM1638STB = P1^0;
sbit TM1638CLK = P1^1;
sbit TM1638DIO = P1^2;

void TM1638_WByte(ucahr cmd);

void main()
{
    TM1638STB = 0;
    TM1638_WByte(0x88);//1000 1000显示开,脉冲宽度为1/16
    TM1638STB = 1;
    
    TM1638STB = 0;
    TM1638_WByte(0x40);//普通模式,地址自动增加,写显示数据
    TM1638_WByte(0x3f);//数字0------------------------此时地址为0x00
    TM1638_WByte(0x00);//让SEG9为0,这样上方LED就不会亮
    TM1638_WByte(0x06);//数字1------------------------此时地址为0x01
    TM1638_WByte(0x00);//让SEG9为0,这样上方LED就不会亮
    TM1638_WByte(0x5b);//数字2------------------------此时地址为0x02
    TM1638STB = 1;
    
    while(1);
}

    //TM1638写一个字节(只负责送数据到线上)
void TM1638_WByte(ucahr cmd)
{
    uchar i;
    for (i = 0; i < 8; i++)
    {
        TM1638CLK = 0;
        TM1638DIO = cmd & 0x01;
        cmd >>= 1;
        TM1638CLK = 1;
    }
}



先写一个简单的程序测试一下。数码管前3个显示123,上方8个LED全不亮。在这里我没有设置显示地址,是因为默认地址就是0x00,也就是第一个数码管,当写入一个命令,后面跟一个显示数据后,地址会自动增加1个(0x01),但是这个时候地址就增加到了SEG9和SEG10这一块了,其中SEG9是控制LED的,其余没用全为0就行了,如果再继续写入一个数据,才会到0x02,这个是和第二个数码管显示内容相关的数据,以此类推。

如果使用的是固定地址模式,那么每次每次发送显示数据前都要指明显示地址。

如果想让数码管模块在单片机按下复位键还能正常显示,那么就需要一个初始化函数,也就是清屏函数,如下:

void TM1638_clear()
{
    uchar i;
    TM1638STB = 1;
    TM1638STB = 0;
    TM1638_WByte(0x40);
    for (i = 0; i < 16; i ++)
        TM1638_WByte(0x00);//在所有16个地址中写入0x00
    TM1638STB = 1;
    TM1638STB = 0;
    TM1638_WByte(0xc0);//设置显示地址为0x00
    TM1638STB = 1;
}

void main()
{
    TM1638_clear();
    TM1638STB = 0;
    TM1638_WByte(0x88);//1000 1000显示开,脉冲宽度为1/16
    TM1638STB = 1;
    
    TM1638STB = 0;
    TM1638_WByte(0x40);//普通模式,地址自动增加,写显示数据
    TM1638_WByte(0x3f);//数字0------------------------此时地址为0x00
    TM1638_WByte(0x00);//让SEG9为0,这样上方LED就不会亮
    TM1638_WByte(0x06);//数字1------------------------此时地址为0x01
    TM1638_WByte(0x00);//让SEG9为0,这样上方LED就不会亮
    TM1638_WByte(0x5b);//数字2------------------------此时地址为0x02
    TM1638STB = 1;
    
    while(1);
}

写一个清屏函数,在主函数调用一下就可以了 

写一个命令还需要自己先把STB拉低,写完再拉高,比较麻烦,封装一下

void TM1638_Wcmd(ucahr cmd)
{
    TM1638STB = 0;
    TM1638_WByte(cmd);
    TM1638STB = 1;
}

 

3.2 现象

tm1638驱动数码管程序,清翔51学习笔记,51单片机,计算机外设,嵌入式硬件

显示出了123,但是我没有设置地址,这就是地址增加模式。肉眼看到的是和LED一样的红色,但是拍出来颜色编程黄白色了。

 3.3 固定地址模式

void main()
{
    TM1638_clear();
    TM1638STB = 0;
    TM1638_WByte(0x88);//1000 1000显示开,脉冲宽度为1/16
    TM1638STB = 1;
    
    TM1638STB = 0;
    TM1638_WByte(0x44);//普通模式,地址固定,写显示数据
    TM1638STB = 1;
    
    TM1638STB = 0;
    TM1638_WByte(0xc0);//设置显示地址为0x00
    TM1638_WByte(0x3f);//数字0------------------------此时地址为0x00
    TM1638STB = 1;
    
    TM1638STB = 0;
    TM1638_WByte(0xc2);//设置显示地址为0x02
    TM1638_WByte(0x06);//数字1------------------------此时地址为0x02
    TM1638STB = 1;
    
    TM1638STB = 0;
    TM1638_WByte(0xc4);//设置显示地址为0x04
    TM1638_WByte(0x5b);//数字2------------------------此时地址为0x04
    TM1638STB = 1;
    
    TM1638STB = 0;
    TM1638_WByte(0xc8);//设置显示地址为0x08
    TM1638_WByte(0x4f);//数字3------------------------此时地址为0x08
    TM1638STB = 1;
    
    while(1);
}

固定地址模式,就是在每次发送显示数据之前都要发送显示位置地址

3.4 现象

tm1638驱动数码管程序,清翔51学习笔记,51单片机,计算机外设,嵌入式硬件

我在代码里面跳过了第4个数码管的显示地址,所以第四个数码管没有显示。

经过对比发现,如果用地址自动增加模式,我也可以实现发一次地址写一个数据,相当于拥有固定地址模式可以实现的功能,也可以指定一个起始地址然后连续发送数据,可见地址自动增加模式似乎更有优势。

3.5 按键扫描

我这个按键扫描读取到的数值和数据手册不一样,不知道为什么,我实际读取到的值与对应按键关系如下表

按键 \数据 byte1 byte2 byte3 byte4
S1 01 00 00 00
S2 00 01 00 00
S3 00 00 01 00
S4 00 00 00 01
S5 10 00 00 00
S6 00 10 00 00
S7 00 00 10 00
S8 00 00 00 10

我就按我的情况来编程了。我判断键值的想法是先把读取到的4个字节数据存放在一个数组里面,然后判断数组里面的数是否有0x01或者0x10,如果有这两个任何一个,说明有按键被按下了,再看如果有的是0x01,那么说明前4个按键里面的某个按键被按下了,直接跳出数组循环,当前循环次数就是按键序号。如果检测到0x10,说明后4个按键被按下,当前循环次数+4就是对应的按键序号。

读取数据并判断键值的函数

uchar TM1638_RByte()
{
    uchar temp,i;
    temp = 0;
    TM1638DIO = 1;//释放数据线
    for (i = 0; i < 8; i++)
    {
        temp >>= 1;
        TM1638CLK = 0;
        TM1638CLK = 1;
        if (TM1638DIO) temp |= 0x80;
        
    }
    return temp;
}

uchar TM1638_keyscan()
{
    uchar i,temp[4];
    TM1638STB = 0;
    TM1638_WByte(0x42);
    for (i = 0; i < 4; i++)
        temp[i] = TM1638_RByte();
    TM1638STB = 1;
    
    for (i = 0; i < 4; i++)
    {
        if (temp[i] == 0x01 || temp[i] == 0x10)
            return ((temp[i] == 0x01) ? i:(4+i));
    }
    return 8;
}

如果有按键被按下,返回值哪里用了三元运算符。

完整代码如下。我的程序写的是按下S1让LED8翻转,按下S2让蜂鸣器翻转。

在main函数里面我对按键进行了消抖

#include <reg52.h>

typedef unsigned char uchar;
typedef unsigned char ucahr;
typedef unsigned int uint;

sbit TM1638STB = P1^0;
sbit TM1638CLK = P1^1;
sbit TM1638DIO = P1^2;
sbit LED8 = P1^7;
sbit beep = P2^3;

uchar code du[23];

void TM1638_clear();
void TM1638_WByte(ucahr cmd);
void TM1638_Wcmd(ucahr cmd);
uchar TM1638_RByte();
uchar TM1638_keyscan();
void delay(unsigned int i);

void main()
{
    uchar key_val;
    TM1638_clear();
    TM1638_Wcmd(0x8A);//亮度4/16
    TM1638STB = 0;
    TM1638_WByte(0X40);//普通模式,地址自动增加,写显示数据
    TM1638_WByte(du[0]);//在默认的0x00地址写数字0
    TM1638STB = 1;
    
    while(1)
    {
        key_val = TM1638_keyscan();
        delay(20);
        if (TM1638_keyscan() != key_val)
            key_val = 8;
        
        if (key_val != 8)
        {
            switch (key_val)
            {
                case 0: LED8 = !LED8; key_val = 8;break;
                case 1: beep = !beep; key_val = 8;break;
            }
        }
        delay(50);
    }
}


    //TM1638写一个字节(只负责送数据到线上)
void TM1638_WByte(ucahr cmd)
{
    uchar i;
    for (i = 0; i < 8; i++)
    {
        TM1638CLK = 0;
        TM1638DIO = cmd & 0x01;
        cmd >>= 1;
        TM1638CLK = 1;
    }
}

void TM1638_Wcmd(ucahr cmd)
{
    TM1638STB = 0;
    TM1638_WByte(cmd);
    TM1638STB = 1;
}

uchar TM1638_RByte()
{
    uchar temp,i;
    temp = 0;
    TM1638DIO = 1;//释放数据线
    for (i = 0; i < 8; i++)
    {
        temp >>= 1;
        TM1638CLK = 0;
        TM1638CLK = 1;
        if (TM1638DIO) temp |= 0x80;
        
    }
    return temp;
}

uchar TM1638_keyscan()
{
    uchar i,temp[4];
    TM1638STB = 0;
    TM1638_WByte(0x42);
    for (i = 0; i < 4; i++)
        temp[i] = TM1638_RByte();
    TM1638STB = 1;
    
    for (i = 0; i < 4; i++)
    {
        if (temp[i] == 0x01 || temp[i] == 0x10)
            return ((temp[i] == 0x01) ? i:(4+i));
    }
    return 8;
}


void TM1638_clear()
{
    uchar i;
    TM1638STB = 1;
    TM1638STB = 0;
    TM1638_WByte(0x40);
    for (i = 0; i < 16; i ++)
        TM1638_WByte(0x00);//在所有16个地址中写入0x00
    TM1638STB = 1;
    TM1638STB = 0;
    TM1638_WByte(0xc0);//设置显示地址为0x00
    TM1638STB = 1;
}

void delay(unsigned int i)
{
    unsigned int j;
    for (; i > 0; i--)
        for (j = 114; j > 0; j--);
}

uchar code du[]={ 
                //0    1     2     3     4     5     6     7     8
                0x3F, 0x06, 0x5B, 0x4F, 0x66, 0x6D, 0x7D, 0x07, 0x7F,
                //9   A(10) B(11)  C(12) D(13) E(14) F(15) H(16) L(17)     
                0x6F, 0x77, 0x7C, 0x39, 0x5E, 0x79, 0x71, 0x76, 0x38,
                //n(18) u(19) -(20) 熄灭(21)  .(22)
                0x37, 0x3E, 0x40, 0x00,        0x80};

3.6 LED控制

控制LED,只需要 在对应地址让SEG9=0,比如我想让第2个LED亮,那么我就先把地址设置为0x03,然后发送数据0x01,这样就可以了。

TM1638模块差不多都说完了,我没有逻辑分析仪,示波器之类的工具,在分析获取到的数据的时候费点时间,我是把接收到的4个字节数据放在数组里面,然后把数组4个字节通过串口发送到电脑来看我到底接受到了什么信息,然后根据键值的特点来写的程序,我还不清楚为什么我收到的数据跟手册里写的不一样,不过还是用起来了。

|

在自己使用时,还可以把显示函数封装起来,以及LED控制封装,用起来更方便。文章来源地址https://www.toymoban.com/news/detail-776679.html

到了这里,关于51单片机使用TM1638驱动的数码管键盘模块的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • 51单片机数码管

    51单片机的数码管是一种常用的数字显示设备,用于在嵌入式系统中显示数字和一些特定的符号。数码管通常由七段LED组成,每个LED段可以显示数字0到9以及一些字母和符号。通过控制每个LED段的亮灭,可以显示不同的数字和字符。 在51单片机中,数码管通常连接到GPIO(通用

    2024年01月21日
    浏览(49)
  • 【51单片机】动态数码管

    0、前言 参考: 普中51单片机开发攻略–A2.pdf 上一章我们主要是介绍一位数码管的内部结构及控制原理。下面我们再来介 绍下多位数码管及动态显示原理的相关知识。 本章所要实现的功能是:控制动态数码管从左至右显示数字 0-7。 为了正规点,工程弄个正规文件夹: http

    2024年01月21日
    浏览(70)
  • 二、51单片机控制数码管

    (1)数码管的外观: 数码管可分为单个的,联排的(2位、4位、8位) (2)数码管的作用: 数码管是显示器件,是用来显示数字的。 (1)数码管的亮灭是由内部的照明LED的亮灭实现的。 (2)一位数码管内部有八颗LED灯,利用内部的LED灯的亮和灭让数码管显示不同的数字。 (1)驱动方法的

    2023年04月09日
    浏览(52)
  • 51单片机(数码管可调时钟)

    1.数码管(共阴极)如何显示数字:位选+段选(单个) 位选:138译码器通过P22、P23、P24三个端口输入二进制数(011、000等)来选择连同译码器右边的哪一条线,而这些线又分别连着数码管的LED12345678、决定选择哪一个来显示数字 段选:决定输出什么数字,数码管下方又连着一

    2024年02月05日
    浏览(50)
  • 51单片机入门————数码管显示

    我们在马路上看到的红绿灯,就是由数码管来实现的,就是其中可能加入了一些延时和转换 数码管是通过控制138译码器与74HC245来控制数码管的亮灭与数字的显示 我们先讨论一个数码管 数码管有共阳极和共阴极,我们现在使用的STC89C52是共阴极的,说明数码管共用阴极 上面是

    2024年02月13日
    浏览(45)
  • 51单片机静态数码管显示

    51单片机静态数码管显示 数码管是一种简单、廉价的显示器,是由多个发光二极管封装在一起组成“8”字型的器件。   数码管从上右下左中有ABCDEFGDP,共10个引脚,其中3、8号引脚是连接到所有二极管的阴极,A二级管对应7号和38号引脚,B二极管对应6号和38号引脚。所有阴极

    2024年02月08日
    浏览(71)
  • 51单片机数码管显示(三)

    目录 一、静态数码管显示 1、一位数码管 (1)LED数码管各段名称 (2)数码管引脚定义 (3) 共阴极(89C52RC单片机LED数码管采用共阴极方式) (4)共阳极 2、四位一体数码管 (1)四位一体数码管引脚定义 (2)上面共阴极和下面共阳极  3、数码管模块原理图详解 4、编写

    2024年02月08日
    浏览(44)
  • 51单片机矩阵键盘——数码管显示

    当我们熟悉了数码管的位选与段选,并了解的矩阵键盘的扫描之后就可以编写程序了。 按下矩阵键盘S1并松开,数码管第一位(LED8)显示0;按下矩阵键盘S2并松开,数码管第一位显示1;...按下矩阵键盘S16并松开,数码管第一位显示F; 矩阵键盘扫描(输入扫描)     原理:

    2024年02月11日
    浏览(55)
  • 51单片机控制数码管动态显示

    首先打开proteus,导入8位数码管和89c51。 然后如图连线,分清断码和位码, 断码就是一个数码管的7个LED灯。 位码:就是第几位显示,由于是共阴极,所以哪位接地就显示哪位。 下面通过改变位码的接线就可以看出不同的效果 下面就编写程序,从第1位到第8位显示从0到7的八

    2023年04月21日
    浏览(46)
  • 51单片机数码管显示0-9

    初级代码:使用延时函数,延时; 进阶代码:使用定时器,延时:51单片机定时器控制数码管显示_学习笔记吧的博客-CSDN博客 初级代码: 电路接线图:  

    2024年02月12日
    浏览(40)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包