晓飛飛 发表于 2024-4-2 15:05:35

简简单单点个6条腿的8段LED数码管

开发板上常见的7段数码管都是共阴或者共阳结构的,
分为SEG和COM段,驱动代码也比较好写,行列刷新嘛,
但是很多廉价的电子产品比如充电宝、电池仓上面用的,
数码管就比较简单了,只有很少的引脚,
看灯珠的结构也是比较无序的,相对来说比较难搞,
由于项目需要嘛,不得不搞一下,于是某宝买了几个样品,
试着驱动一下。

数码管的灯珠结构如下,看起来比较乱,实际上也是真的乱。
试了一下点亮所有段码,亮度还行,可以进行下一步驱动了。
PS:点亮所有段码的方式很简单,
每次使1个引脚拉低,其余拉高即可,然后循环扫描。






晓飛飛 发表于 2024-4-2 15:06:19

驱动好的效果如下,貌似还不错115

晓飛飛 发表于 2024-4-2 15:19:02

下面介绍一下实现方法,
单片机为STC8G1K17,其它STC单片机也一样用的
定义管脚
sbit PIN1 = P3^0;      //数码管
sbit PIN2 = P3^1;      //数码管
sbit PIN3 = P3^2;      //数码管
sbit PIN4 = P3^3;      //数码管
sbit PIN5 = P5^5;      //数码管
sbit PIN6 = P5^4;      //数码管
3个7段数码管,2个小数点,2个温度符号,一共是25个段,定义32位段位码,每个段占一位
//各个LED灯珠代表的位
#define A1 0x00000001
#define B1 0x00000002
#define C1 0x00000004
#define D1 0x00000008
#define E1 0x00000010
#define F1 0x00000020
#define G1 0x00000040

#define A2 0x00000080
#define B2 0x00000100
#define C2 0x00000200
#define D2 0x00000400
#define E2 0x00000800
#define F2 0x00001000
#define G2 0x00002000

#define A3 0x00004000
#define B3 0x00008000
#define C3 0x00010000
#define D3 0x00020000
#define E3 0x00040000
#define F3 0x00080000
#define G3 0x00100000

#define DP1 0x00200000
#define DP2 0x00400000
#define K1 0x00800000
#define K2 0x01000000定义三位数码管的显示表 其实就是显示字符需要点对应段位码,比如显示1,就点亮B1 C1,一行一个状态。
//第一个7段码从0~9对应的编码
code u32 digit1 =
{
      A1|B1|C1|D1|E1|F1,         //0
      B1|C1,                              //1
      A1|B1|D1|E1|G1,                //2
      A1|B1|C1|D1|G1,                //3
      B1|C1|F1|G1,                //4
      A1|C1|D1|F1|G1,                //5
      A1|C1|D1|E1|F1|G1,      //6
      A1|B1|C1,                        //7
      A1|B1|C1|D1|E1|F1|G1,//8
      A1|B1|C1|D1|F1|G1,      //9
      0,                        //黑 消隐
};

//第二个7段码从0~9对应的编码
code u32 digit2 =
{
      A2|B2|C2|D2|E2|F2,         //0
      B2|C2,                              //1
      A2|B2|D2|E2|G2,                //2
      A2|B2|C2|D2|G2,                //3
      B2|C2|F2|G2,                //4
      A2|C2|D2|F2|G2,                //5
      A2|C2|D2|E2|F2|G2,      //6
      A2|B2|C2,                        //7
      A2|B2|C2|D2|E2|F2|G2,//8
      A2|B2|C2|D2|F2|G2,      //9
      0,                  //黑 消隐
};

//第三个7段码从0~9对应的编码
code u32 digit3 =
{
      A3|B3|C3|D3|E3|F3,         //0
      B3|C3,                              //1
      A3|B3|D3|E3|G3,                //2
      A3|B3|C3|D3|G3,                //3
      B3|C3|F3|G3,                //4
      A3|C3|D3|F3|G3,                //5
      A3|C3|D3|E3|F3|G3,      //6
      A3|B3|C3,                        //7
      A3|B3|C3|D3|E3|F3|G3, //8
      A3|B3|C3|D3|F3|G3,      //9
      0,                  //黑 消隐
};
点灯IO控制代码,所有IO全部设置为开漏输出,利用使能内部4K上拉输出高电平,关闭上拉为高阻,输出0为低电平,三种IO状态
//6个IO全部设为输入,关闭上拉
void ALL_IN (void)
{      
    P3M0 = 0x00; P3M1 = 0x0f; P3PU = 0x00;
    P5M0 = 0x00; P5M1 = 0x30; P5PU = 0x00;
}

void PIN1_OUT_L(void)
{
    P3M0 |= 0x01;
      P3M1 &= ~0x01;
      PIN1 = 0;
}

void PIN2_OUT_L(void)
{
    P3M0 |= 0x02;
      P3M1 &= ~0x02;
      PIN2 = 0;
}

void PIN3_OUT_L(void)
{
    P3M0 |= 0x04;
      P3M1 &= ~0x04;
      PIN3 = 0;
}

void PIN4_OUT_L(void)
{
    P3M0 |= 0x08;
      P3M1 &= ~0x08;
      PIN4 = 0;
}

void PIN5_OUT_L(void)
{
    P5M0 |= 0x20;
      P5M1 &= ~0x20;
      PIN5 = 0;
}

void PIN6_OUT_L(void)
{
    P5M0 |= 0x10;
      P5M1 &= ~0x10;
      PIN6 = 0;
}


void PIN1_OUT_H(void)
{
    P3PU |= 0x01;
}

void PIN2_OUT_H(void)
{
    P3PU |= 0x02;
}

void PIN3_OUT_H(void)
{
    P3PU |= 0x04;
}

void PIN4_OUT_H(void)
{
    P3PU |= 0x08;
}

void PIN5_OUT_H(void)
{
    P5PU |= 0x20;
}

void PIN6_OUT_H(void)
{
    P5PU |= 0x10;
}显示函数,参数num为3为10进制整型,比如赋值123,就显示123,dp1,dp2,k1,k2是两位小数点和两个温度符号
void display(u16 num,bit dp_1,bit dp_2,bit KK1,bit KK2)
{
      u8 num1,num2,num3;
      num1 = num / 100;               //拆分出百位
      num2 = (num % 100) / 10;          //拆分出十位
      num3 = num % 10;                //拆分出个位               
      display_num = digit1 | digit2 | digit3;   
      if(dp_1)display_num |= DP1;   //暂未写消隐功能可根据小数点位置和小数点前数字为零处理消隐
      if(dp_2)display_num |= DP1;
      if(KK1)display_num |= K1;
      if(KK2)display_num |= K2;
}下面是刷数码管的过程,使用定时器0的 1ms中断自动刷屏,不设置任何等待过程,对单片机的指令开销占用极小,而且刷屏流畅不闪烁。
//刷数码管定时器 1000Hz三个数码管平均333Hz
void Timer0_Isr(void) interrupt 1
{
      static u8 sta;
      ALL_IN();   //关闭数码管      
      switch (sta)
      {
                case 1:
                        PIN1_OUT_L();
                        if(display_num & A3) PIN6_OUT_H();   //1                A3      G3      K1      K2
                        if(display_num & G3) PIN5_OUT_H();
                        if(display_num & K1) PIN4_OUT_H();
                        if(display_num & K2) PIN3_OUT_H();               
                        sta++;
                        break;
                case 2:
                        PIN2_OUT_L();
                        if(display_num & A1) PIN3_OUT_H();   //2                A1      B1      D1      E1      DP1
                        if(display_num & B1) PIN4_OUT_H();
                        if(display_num & D1) PIN6_OUT_H();
                        if(display_num & E1) PIN5_OUT_H();
                        if(display_num & DP1) PIN1_OUT_H();               
                        sta++;
                        break;
                case 3:               
                        PIN3_OUT_L();
                        if(display_num & B2) PIN5_OUT_H();   //3                B2      D2      B3      F1      DP2
                        if(display_num & D2) PIN4_OUT_H();
                        if(display_num & B3) PIN6_OUT_H();
                        if(display_num & F1) PIN2_OUT_H();
                        if(display_num & DP2) PIN1_OUT_H();                        
                        sta++;
                        break;
                case 4:      
                        PIN4_OUT_L();
                        if(display_num & C2) PIN5_OUT_H();   //4                C2      E3      G1      F2
                        if(display_num & E3) PIN6_OUT_H();
                        if(display_num & G1) PIN2_OUT_H();
                        if(display_num & F2) PIN3_OUT_H();               
                        sta++;
                        break;
                case 5:
                        PIN5_OUT_L();
                        if(display_num & C1) PIN2_OUT_H();   //5                C1      A2      C3      G2
                        if(display_num & A2) PIN4_OUT_H();
                        if(display_num & C3) PIN6_OUT_H();
                        if(display_num & G2) PIN3_OUT_H();
                        sta++;
                        break;
                case 6:               
                        PIN6_OUT_L();
                        if(display_num & E2) PIN3_OUT_H();   //6                E2      D3      F3
                        if(display_num & D3) PIN4_OUT_H();
                        if(display_num & F3) PIN5_OUT_H();               
                        sta = 1;
                        break;
                default:
                        sta = 1;
                        break;
      }
}

yjawei 发表于 2024-4-2 21:58:03

这种数码管复用的方式和传统的共阳、共阳不一样,代码扫描的时候复杂很多,但万变不离其宗。

晓飛飛 发表于 2024-4-2 22:52:38

yjawei 发表于 2024-4-2 21:58
这种数码管复用的方式和传统的共阳、共阳不一样,代码扫描的时候复杂很多,但万变不离其宗。 ...

有多少个引脚,就相当于多少个COM,而且是共阴共阳混合复用的,驱动机理的确很简单,但是要组织成好用的接口还是需要很多繁冗的工作。看上面的代码就很多行,普通数码管的话,要简单的多。

21cnsound 发表于 2024-4-2 23:32:07

通过代码节省了硬件{:4_174:}

小飞侠 发表于 2024-4-3 07:45:45

这种方式比较节省IO口,但是代码量就稍微大一点了

晓飛飛 发表于 2024-4-3 10:08:15

小飞侠 发表于 2024-4-3 07:45
这种方式比较节省IO口,但是代码量就稍微大一点了

普通3位的数码管刷三次,这种需要刷6次,总刷新率不变的情况下,刷新中断频率需要翻倍。

小涵子爸爸 发表于 2024-4-3 15:29:14

学习

angmall 发表于 2024-4-3 15:37:49

查理复用(Charlieplex)是一种在驱动大量LED时有效地节约IO口的方法,理论上可点亮 脚数*(脚数-1)个LED
驱动这种数码管的技术称作查理复用技术(Charlieplexing)
charlieplexing利用单片机端口的三态。
一般规则是,只有两个端口可以同时输出,而其他所有端口都可以通过将它们定义为输入来处于高阻抗状态。

就是用这个查理复用技术(Charlieplexing)。

5个IO口最多可以控制20个LED
6个IO口最多可以控制30个LED
页: [1] 2 3
查看完整版本: 简简单单点个6条腿的8段LED数码管