找回密码
 立即注册

QQ登录

只需一步,快速开始

搜索
查看: 390|回复: 12
打印 上一主题 下一主题
收起左侧

求三位6脚数码管程序

  [复制链接]
跳转到指定楼层
楼主
拆了个数码管,发现是3位的6脚,怎么样用单片机显示数字,玩过的朋友指导一下,谢谢!
分享到:  QQ好友和群QQ好友和群 QQ空间QQ空间 腾讯微博腾讯微博 腾讯朋友腾讯朋友
收藏收藏1 分享淘帖 顶 踩
回复

使用道具 举报

沙发
ID:604515 发表于 2026-3-11 17:16 | 只看该作者
底层逻辑就是查理复用。
回复

使用道具 举报

板凳
ID:1064915 发表于 2026-3-11 17:48 | 只看该作者
正反推驱动LED,更专业的说法是查理复用算法。
回复

使用道具 举报

地板
ID:69038 发表于 2026-3-12 10:39 | 只看该作者
查理复用其实很简单,唯一的要求就是IO能3态就行。
回复

使用道具 举报

5#
ID:56665 发表于 2026-3-12 11:17 | 只看该作者
3位的6脚数码管驱动程序
回复

使用道具 举报

6#
ID:1121801 发表于 2026-3-12 14:12 | 只看该作者
查理利用,理论6脚能点亮30段笔段
回复

使用道具 举报

7#
ID:584814 发表于 2026-3-12 15:15 | 只看该作者
回复

使用道具 举报

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

数码管的灯珠结构如下,看起来比较乱,实际上也是真的乱。
试了一下点亮所有段码,亮度还行,可以进行下一步驱动了。
PS:点亮所有段码的方式很简单,
每次使1个引脚拉低,其余拉高即可,然后循环扫描。
普通3位的数码管刷三次,这种需要刷6次,总刷新率不变的情况下,刷新中断频率需要翻倍。



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

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

5个IO口最多可以控制20个LED
6个IO口最多可以控制30个LED


下面介绍一下实现方法,
单片机为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[11] =
{
        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[11] =
{
        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[11] =
{
        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[num1] | digit2[num2] | digit3[num3];   
        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;
        }
}



回复

使用道具 举报

9#
ID:624769 发表于 2026-3-13 22:29 | 只看该作者
angmall 发表于 2026-3-12 15:43
简简单单点个6条腿的8段LED数码管
开发板上常见的7段数码管都是共阴或者共阳结构的,
分为SEG和COM段,驱 ...

下面是刷数码管的过程,使用定时器0的 1ms中断自动刷屏,不设置任何等待过程,对单片机的指令开销占用极小,而且刷屏流畅不闪烁。
//刷数码管定时器 1000Hz  三个数码管平均333Hz

应该是 167Hz,另外,5ms中断一次,33Hz 亮度会高一些。
回复

使用道具 举报

10#
ID:491577 发表于 2026-3-13 23:23 | 只看该作者
这种方式是能说勉强能用,亮度极低,亮度极不平衡。原因:4K电阻太大,LED电压有1.8v,总电流不到1mA,一次点亮几个LED是不确定的,如果只亮1个LED电流最大,最多可能亮5个LED,电流只有五分之一,明显变暗。认真看就会发现有些灯亮有些灯暗。白天几乎看不清。比较好的方法是:每个IO口串一个电阻51~100Ω,每次只点亮一个LED,3位数码管一共24个LED,0.8ms中断一次,刷完3位数码管总时间=0.8*24=19.2ms,每个LED电流均衡,大概10~20mA。比4K上拉电阻亮10~20倍。
回复

使用道具 举报

11#
ID:624769 发表于 2026-3-14 22:48 | 只看该作者
hhh402 发表于 2026-3-13 23:23
这种方式是能说勉强能用,亮度极低,亮度极不平衡。原因:4K电阻太大,LED电压有1.8v,总电流不到1mA,一次 ...

下拉的那个引脚因为都能承受20mA的灌电流,所以,不管每次点亮几个LED,每个LED经过的电流都是一样的,亮度应该也都是一样的,不会出现你说的亮度不均,但是,由于每个LED的特性可能不一致,造成从给电到LED点亮这个时间可能并不一致,所以如果中断周期过短(比如:500us),确实会因可能造成亮度不一致。但是只要达到2ms以上的中断周期,就不会出现你说的情况,所以,我通常是用5ms。当然,诚如你所说,4.7K的内置上拉的确有点大,如果,追求高亮度的话,应该不串任何电阻,强推挽,用500us周期,逐个点亮,不会烧LED,能达到最高亮度。
回复

使用道具 举报

12#
ID:59341 发表于 2026-3-16 08:14 | 只看该作者
angmall 发表于 2026-3-12 15:43
简简单单点个6条腿的8段LED数码管
开发板上常见的7段数码管都是共阴或者共阳结构的,
分为SEG和COM段,驱 ...

学习了,谢谢指导!
回复

使用道具 举报

13#
ID:491577 发表于 2026-3-16 10:54 | 只看该作者
不串电阻正常情况下是可以的,STC8系列单片机5v,两个IO推挽驱动红色LED电流大约55ma,短时间是没有问题的。有没有可能出现单片机死机造成io口一直输出而烧坏,不知这种可能性有多大?
回复

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

小黑屋|51黑电子论坛 |51黑电子论坛6群 QQ 管理员QQ:125739409;技术交流QQ群281945664

Powered by 单片机教程网

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