数码管学习

七、数码管学习

7.1 单个数码管

  • 一个数码管由a、b、c、d、e、f、g、dp,八个二极管组成,八个二极管一段组在一起,另外一端接出来。如果二极管阳极接一起就是共阳极,当二极管阴极接一起就是共阴极。
  • 图中为共阴极,如要显示不同的数字,只需要点亮不同的二极管,如要数码管显示6,只需要点亮afedcg,将b和dp关闭即可。

  • 数码管内部图,分为共阴极和共阳极。

7.1.1 多个数码管驱动

  • 在我们驱动时,需要程序去选定去驱动哪些数码管,这就叫做位选,选定数码管后再对数码管进行驱动操作,其操作方式去单个数码管操作方式一样(后面详讲),这就叫做段选。

7.1.2 数码管与芯片连接

  • 为何使用锁存器
  • 5mA的电流,如果数码管直接连接单片机,单片机I/O无法输出这么高的电流,对于共阴极的数码管,可以在阳极直接接上上拉电阻,对于共阳极的数码管,可以在阴极接上下拉电阻,但是位选也要另外处理。
  • LED工作电流的问题,还可以使用锁存器进行位选和段选。
  • 锁存器的电路连接

图中可以看到,连接两块锁存器,一块为位选,一块为段选。上个章节讲了锁存器,这里再次回顾。

 根据OE一直接地,所以锁存器工作状态只有前三种,LE软件置1时,锁存器的输入端D与输出端Q同高电平,同低电平,当LE软件置0时,锁存器输出为Q0。

从电路可以看出:

单片机引脚P00~ P07分别连接到U1和U2的D0 ~D7,简单来说就是U1和U2都与P00 ~P07相连,所以当数码管处于工作状态时,两个锁存器不能同时打开,就是两个锁存器LE脚不能同时处于高电平。锁存器U1的输出接数码管的阳极,锁存器U2的输出接数码管WE,控制数码管选择。

锁存器U2控制位选,U2打开时,U1关闭,此时U2的输入和输出同高低电平。如下图,若使用数码管1,则只需D0置0,其他引脚置1,就是芯片P00输出为0,P01 ~P07输出为1,就是P0寄存器的状态值为0xfe(上面低位,从下往上读)。

 锁存器U1控制段选,如刚刚位选了数码管1,则接下来段选是对数码管1的操作。此时关闭U2,打开U1,就是U2的LE软件置0,U1的LE软件置1,而U2的LE与芯片的P27相连,U1的LE与芯片的P26相连(如下图),所以我们只需要使芯片的P27输出低电平来关闭U2锁存器,P26输出高电平来打开U1锁存器。

 打开U1锁存器后,是数码管显示某个数字,我们在第一节中总结过了,比如显示一个数字6,需要afedcg六个点亮,所以锁存器输出01111101(共阴极数码管,输出1时点亮),就是P0寄存器输出0111101,P0的寄存器的状态值为0x7d。

  显示数字6的代码程序如下:

#include <reg52.h>
sbit dula=P2^6;//定义数码管的引脚
sbit wela=P2^7;
void main()
{
    wela=1; //段选数码管
    P0=0xfe;//显示数字
    wela=0;
 
    dula=1;
    P0=0x7d;
    dula=0;
    weile(1);
}
  • 现在使用自己的开发板,我这里使用共阳极数码管来驱动。

 

 因为是共阳极所以需要与上面讲的反过来设置,打开阴通道。

  • 建立ssd1文件夹,打开四个数码管显示2023。
#include <reg52.h>
unsigned char Display_table[]={
0xc0,0xf9,0xa4,0xb0,0x99,
0x92,0x82,0xf8,0x80,0x90};//这里的数组一定要写完整不然会胡乱显示。

sbit ssd1=P1^0;//定义所有段选引脚
sbit ssd2=P1^1;
sbit ssd3=P1^2;
sbit ssd4=P1^3;

//延时函数
void Delay_ms(unsigned char ms)
{
    unsigned char i,j;
    for(ms;ms>0;ms--)
    {
       i=2;
       j=239;
        do// 循环执行,在条件执行前至少执行一次
        {
            while(--j);
          } while(--i);
    }
}
//主函数
void main()
{
    //主循环  
    while(1)
    {
        ssd1=0;//位选
        P0=Display_table[3];//显示数字信息
        Delay_ms(3);
        ssd1=1;//关闭
          
       ssd2=0;
        P0=Display_table[2];
        Delay_ms(3);
        ssd2=1;
          
       ssd3=0;
        P0=Display_table[0];
        Delay_ms(3);
        ssd3=1;
          
       ssd4=0;
        P0=Display_table[2];
        Delay_ms(3);
        ssd4=1;
    }
}
  • 分析上述代码:
  • U1、U2锁存器LE的芯片引脚P26与P27进行位操作,重新设置名称为dula和wela,表示段选和位选。主函数里,先打开位选,wela=1,选择第一个数码管,则U2锁存器输入和输出都为11111110(从下至上),P0的输出也为11111110,就是0xfe,位选结束后关闭位选:wela=0。
  • dula=1,对第一个数码管操作,显示数字6,U1锁存器输入输出均为01111101,就是P0输出为01111101,就是P0的状态值为0x7d。最后关闭断选。
  • 特别注意:正是因为锁存器U1和U2同时接在芯片的P0引脚上,所以两个锁存器不能同时打开,否则芯片引脚P0输出的状态值会在U1和U2之间同时发生反应,造成紊乱。

7.2 芯片引脚状态值

 以下为共阴数码管值。

  - 显示数字0abcdef亮,状态值00111111——>0x3f
  - 显示数字1bc亮,状态值00000110——>0x06
  - 显示数字2abdeg亮,状态值01011011——>0x5b
  - 显示数字3abcdg亮,状态值01001111——>0x4f
  - 显示数字4bcfg亮,状态值01100110——>0x66
  - 显示数字5acdfg亮,状态值01101101——>0x6d
  - 显示数字6acdefg亮,状态值01111101——>0x7d
  - 显示数字7abc亮,状态值00000111——>0x07
  - 显示数字8abcdefg亮,状态值01111111——>0x7f
  - 显示数字9abcdfg亮,状态值01101111——>0x6f
  - 显示字母“A”abcefg亮,状态值01110111——>0x77
  - 显示字母“B”,cdefg亮,状态值01111100——>0x7c
  - 显示字母“C”adef亮,状态值00111001——>0x39
  - 显示字母“D”bcdeg亮,状态值01011110——>0x5e
  - 显示字母“E”,adefg亮,状态值01111001——>0x79
  - 显示字母“F”,aefg亮,状态值0
  1110001——>0x71

  • 这里顺便给出个人总结的共阳数码管转换值。

 

0:00000011   头尾调换:11000000 转换十六进制:0xc0
1:10011111       11111001              0xf9
2:00100101       10100100              0xa4
3:00001101       10110000              0xb0
4:10011001       10011001              0x99
5:01001001       10010010              0x92
6:01000001       10000010              0x82
7:00011111       11111000              0xf8
8:00000001       10000000              0x80
9:00001001       10010000              0x90
A:10001000,0x88
B:10000011,0x83
C:11000110,0xC6
D:10100001,0xA1
E:10000110,0x86
F:10001110,0x8E
G:11000010,0xC2
H:10001001,0x89
I:11101111,0xEF
J:11110001,0xF1
K:10000101,0x85
L:11000111,0xC7
M:10101010,0xAA
N:10101011,0xAB
O:10100011,0xA3
P:10001100,0x8C
Q:10011000,0x98
R:10101111,0xAF
S:10011011,0x9B
T:10000111,0x87
U:11000001,0xc1
V:10011101,0x9D
W:10010101,0x95
X:11001001,0xC9
Y:10010001,0x91
Z:10110110,0xB6

在编写代码时将上面的状态值放入数组中,通过数组来实现数码管的动态显示。

放置到如下数组中:

#define uchar unsigned char
uchar code table[]={
0x3f,0x06,0x5b,0x4f,
0x66,0x6d,0x7d,0x07,
0x7f,0x6f,0x77,0x7c,
0x39,0x5e,0x79,0x71
}

在table数组名字前加了code,代表编码的意思,单片机程序把不需要更改的东西通过code关键字定义为编码,单片机执行程序时,table只需要占用程序存储空间即可,可以理解为占用flash,而不占用RAM。

7.3 数码管动态显示

7.3.1 一个数码管从0到F动态显示

#include <reg52.h>
#define uint unsigned int
#define uchar unsigned char
uchar code table []={
0x3f,0x06,0x5b,0x4f,
0x66,0x6d,0x7d,0x07,
0x7f,0x6f,0x77,0x7c,
0x39,0x5e,0x79,0x71
} ;
uchar num;
sbit wela=P2^6;
sbit dula=P2^7;
void delay_ms(uint);
void main()
{
    wela=1;
    P0=0xfe;
    wela=0;
    while(1)
    {
        for(num=0;num<16;num++)
        {
            dula=1;
            P0=table[num];
            dula=0;
            delay_ms(500);
        }
    }
}
void delay_ms(uint ms)
{
    uint i,j;
    for(i=ms;i>0;i--)
    for(j=110;j>0;j--);
}
  • 这里使用自己的板子实现显示。
  • 建立文件ssd2。
#include <reg52.h>
#define uint unsigned int
#define uchar unsigned char
uchar code table []={
0xc0,0xf9,0xa4,0xb0,
0x99,0x92,0x82,0xf8,
0x80,0x90,0x88,0x83,//这里是0123456789ABCDEF的显示编码,为什么和上面代码不一样,因为这是共阳极
0xC6,0xA1,0x86,0x8E
};//这里的数组一定要写完整不然会胡乱显示。
uchar num=0; //初始化为0
sbit ssd1=P1^0;
sbit ssd2=P1^1;
sbit ssd3=P1^2;
sbit ssd4=P1^3;
void Delay_ms(uint ms){
    uchar i,j;
    for(ms;ms>0;ms--){
        i=2;
       j=239;
        do{
           while (--j);
        }while(--i);
    }
}
void main(){
    unsigned char i;
    for(i=0;i<16;i++)
    {
           num=i;
           ssd4=0;  
           P0=table[num];
           Delay_ms(500);
           ssd4=1;
    }
}
  • 此时第一个数码管从0变化到F。
  • 若使数码管从0到F反复变化,只需要在weile()语句里添加下面的代码:
if(num==16)
    num=0;
  • 完整程序如下:
#include <reg52.h>
#define uint unsigned int
#define uchar unsigned char
uchar code table []={
0x3f,0x06,0x5b,0x4f,
0x66,0x6d,0x7d,0x07,
0x7f,0x6f,0x77,0x7c,
0x39,0x5e,0x79,0x71
} ;
uchar num;
sbit dula=P2^6;
sbit dula=P2^7;
void delay_ms(uint);
void main()
{
    wela=1;
    P0=0xfe;
    wela=0;
   
    while(1)
    {
        for(num=0;num<16;num++)
        {
            dula=1;
            P0=table[num];
            dula=0;
            delay_ms(500);
        }
        if(num==16)  //新加
       num=0;       //新加
    }
}
void delay_ms(uint ms)
{
    uint i,j;
    for(i=ms;i>0;i--)
    for(j=110;j>0;j--);
}

7.3.2 多个数码管从0到F显示

  • 和之前的数码管比较,多个数码管的显示只需要改变位选时P0的输出,如果让6个数码管同时显示, 就输出11000000,转换为16进制就是0xc0

 位选代码:

wela=1;
P0=0xc0;
wela=0;
  • 完整代码:
#include <reg52.h>
#define uint unsigned int   //#开头都是预处理指令,include也一样
#define uchar unsigned uchar  //define为常量,又称宏定义,功能类似变量但又要区分开,变量表示一个变量,但是宏表示一个常量,可以给变量赋值,但绝不可以给常量赋值,宏表示的常量可以是数字、字符、字符串、表达式。
uchar code table[]={
0x3f,0x06,0x5b,0x4f,
0x66,0x6d,0x7d,0x07,
0x7f,0x6f,0x77,0x7c,
0x39,0x5e,0x79,0x71
};
uchar num;
sbit dula=P2^6;
sbit wela=P2^7;
void delay_ms(uint);
void main()
{
    wela=1;
    P0=0xc0;
    wela=0;
   
    while(1)
    {
        for(num=0;num<16;num++)
        {
            dula=1;
            P0=tabla[num];
            dula=0;
            delay_ms(500);
        }
        if(num==16)
        num=0;
    }
}
void delay_ms(uint ms)
{
    uint i,j;
    for(i=ms;i>0;i--)
    for(j=110;j>0;j--);
}
  • 现在使用自己的开发板实现。
  • 建立文件夹ssd3。
//4个数码管从0到F循环动态显示
#include <reg52.h>
#define uint unsigned int
#define uchar unsigned char
uchar code table[]={
0xc0,0xf9,0xa4,0xb0,
0x99,0x92,0x82,0xf8,
0x80,0x90,0x88,0x83,//这里是0123456789ABCDEF的显示编码,为什么和上面代码不一样,因为这是共阳极
0xC6,0xA1,0x86,0x8E
};
uchar num;

sbit ssd1=P1^0;//定义所有段选引脚
sbit ssd2=P1^1;
sbit ssd3=P1^2;
sbit ssd4=P1^3;

void delay_ms(uint );
void main()
{
    while(1)
    {  
       for(num=0;num<16;num++)
       {
           ssd1=1;
           P0=table[num];
           ssd1=0;
           delay_ms(500);  
          
           ssd2=1;
           P0=table[num];
           ssd2=0;
           delay_ms(500);  
          
           ssd3=1;
           P0=table[num];
           ssd3=0;
           delay_ms(500);
          
           ssd4=1;
           P0=table[num];
           ssd4=0;
           delay_ms(500);
          
       }
       if(num==16)
       num=0;
    }
}
void delay_ms(uint ms)
{
    uint i,j;
    for(i=ms;i>0;i--)
    for(j=110;j>0;j--);
}

7.3.3 举个栗子

  • 现在有6个数码管,第一个数码管显示数字1,间隔一秒后第二个数码管显示2,以此类推,直到显示第六个数码管显示6。
  • 解题:6个数码管需要轮流显示,所以位选的时候需要依次选择数码管1、2、3、4、5、6,每次位选后再段选输出需要显示的数字。
  • 第一个数码管的位选:
wela=1;
P0=0xfe;//选择第一个数码管
wela=0;
  • 开始段选输出数字1:
dula=1;
P0=table[1];
dula=0;
delay_ms(1000);
  • 位选时P0的输出之前已经学过了 ,再次回忆,如下图,从左到右分别为数码管1、2、3、4、5、6,再 从下往上读,得到8位二进制编码,变为16进制即可。

  • 完整程序:
#include <reg52.h>
#define uint unsigned int
#define uchar unsigned uchar
uchar code table[]={
0x3f,0x06,0x5b,0x4f,
0x66,0x6d,0x7d,0x07,
0x7f,0x6f,0x77,0x7c,
0x39,0x5e,0x79,0x71
};
uchar num;
sbit dula=P2^6;
sbit wela=P2^7;
void delay_ms(uint);
void main()
{
    while(1)
    {
        wela=1;
        P0=0xfe;//第一个数码管
        wela=0;
       
        dula=1;
        P0=table[1];
        dula=0;
        delay_ms(1000);
       
        wela=1;
        P0=0xfd;//第二个数码管
        wela=0;
       
        dula=1;
        P0=table[1];
        dula=0;
        delay_ms(1000);
       
        wela=1;
        P0=0xfb;//第三个数码管
        wela=0;
       
        dula=1;
        P0=table[1];
        dula=0;
        delay_ms(1000);
       
        wela=1;
        P0=0xf7;//第四个数码管
        wela=0;
       
        dula=1;
        P0=table[1];
        dula=0;
        delay_ms(1000);
       
        wela=1;
        P0=0xef;//第五个数码管
        wela=0;
       
        dula=1;
        P0=table[1];
        dula=0;
        delay_ms(1000);
       
        wela=1;
        P0=0xdf;//第六个数码管
        wela=0;
       
        dula=1;
        P0=table[1];
        dula=0;
        delay_ms(1000);
    }
}
void delay_ms(uint ms)
{
    uint i,j;
    for(i=ms;i>0;i--)
    for(j=100;j>0;j--;);
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

向明月和赵沟渠

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值