0x04 使用数码管显示数字(动态)

【目标】

  • 通过动态扫描的方式,驱动多位数码管

【所需素材】

  • 4位7段数码管 x 1
  • 270Ω左右电阻 x 9
  • 6x6x5毫米轻触开关 x 1
4位7段数码管
6x6x5毫米轻触开关

 

【基本原理】

上一篇我们点亮了数码管的一位数字,但是点亮所有4位数码管,并不是9pin x 4 = 36个pin。

我们再看下4位7段数码管的原理图:

4位7段数码管原理图

上图最下面的电路图,发现所有4位数码管的相同段的引脚是并联起来的,

也就是说,我们通过数码管的引脚给A段高电平时,所有4位数字的A段的阳极得到的都是高电平。

而每个数字都有一个独立的共阴极,所以我们需要使用动态扫描的方式来让4位数码管分别显示不同的数字。

所谓动态扫描,并不是让4位数字同时显示不同的数字,而是让程序每次只点亮一位数字,持续一段时间后,再显示下一位数字,

这样循环的显示所有的数字,只要循环的时间足够短,视觉上的效果就是4位数字同时显示的效果。

为了实现分别点亮每位数字的效果,我们的做法是通过控制共阴(阳)极的高低电平,来实现点亮和熄灭的效果。

而且由于二极管是有极性的,所以就算共阴极得到高电平,电流也不会从阴极流向阳极。

【硬件连接】

树莓派数码管备注
211E段,串联270Ω电阻
222D段,串联270Ω电阻
233DP段,串联270Ω电阻
244C段,串联270Ω电阻
255G段,串联270Ω电阻
297B段,串联270Ω电阻
2810F段,串联270Ω电阻
2711A段,串联270Ω电阻
212Dig1,第一位数字共阴极
39Dig2,第二位数字共阴极
48Dig3,第三位数字共阴极
56Dig4,第四位数字共阴极

【程序实现】

#include <wiringPi.h>
#include <stdbool.h>
#include <time.h>

#define SEG_A 27
#define SEG_B 29
#define SEG_C 24
#define SEG_D 22
#define SEG_E 21
#define SEG_F 28
#define SEG_G 25
#define SEG_DP 23

#define DIG1 2
#define DIG2 3
#define DIG3 4
#define DIG4 5

#define BTN 6


int matrix[10] = {
    0b11111100,  // 0
    0b01100000,  // 1
    0b11011010,  // 2
    0b11110010,  // 3
    0b01100110,  // 4
    0b10110110,  // 5
    0b10111110,  // 6
    0b11100100,  // 7
    0b11111110,  // 8
    0b11110110  // 9
};

int seg[8] = {
    SEG_A,
    SEG_B,
    SEG_C,
    SEG_D,
    SEG_E,
    SEG_F,
    SEG_G,
    SEG_DP
};

int dig[4] = {
	DIG1,
	DIG2,
	DIG3,
	DIG4
};

void showDig(short digtoshow, short num, bool showDP)    // 我们修改一下上一篇的这个函数,增加一个指定显示哪位的参数
{
    short i, tmp;
	tmp = matrix[num];
	if(showDP)
	    tmp |= 1;
	for (i=0;i<4;i++)   // 先将所有位的共阴极拉高,关闭显示
	{
		digitalWrite(dig[i],HIGH);
	}
    for (i=0;i<8;i++)  // 给A-G和DP段置状态
    {
        if((tmp&0x80) == 0x80)
        {
            digitalWrite(seg[i],HIGH);
        } else {
            digitalWrite(seg[i],LOW);
        }
		tmp<<=1;
    }
    digitalWrite(dig[digtoshow],LOW);  // 打开指定位数字的显示
}

/*
 * 根据传入参数page,选择显示时间或者日期
 * @param page 需要显示的页码
 * @return void
*/
void showPage(short page)  // 增加一个根据参数决定显示内容的函数
{
    time_t timep;
    struct tm *p;
    time(&timep);
    p = localtime(&timep);

	switch(page) {
		case 1:
			showDig(0,p->tm_hour / 10, FALSE);

			/* 显示2ms
			 * 由于树莓派是多任务系统,所以定时函数并不是很准,
			 * 系统负载越高,这个延时函数越容易乱,
			 */
			delay(2);
			showDig(1,p->tm_hour % 10, ((p->tm_sec % 2) == 0));  // 制作一个小数点闪烁的效果
			delay(2);
			showDig(2,p->tm_min / 10, FALSE);
			delay(2);
			showDig(3,p->tm_min % 10, FALSE);
			delay(2);
			break;
		case 2:
			showDig(0,(p->tm_mon + 1) / 10, FALSE);
			delay(2);
			showDig(1,(p->tm_mon + 1) % 10, TRUE);
			delay(2);
			showDig(2,p->tm_mday / 10, FALSE);
			delay(2);
			showDig(3,p->tm_mday % 10, FALSE);
			delay(2);
			break;
	}
}

int main(void)
{
    short i,page=1;

    if(wiringPiSetup() != 0)
        return 1;

	pinMode(BTN,INPUT);
	pullUpDnControl(BTN, PUD_UP);

    for(i=0;i<8;i++)
    {
        pinMode(seg[i],OUTPUT);
    }

	for(i=0;i<4;i++)
	{
		pinMode(dig[i],OUTPUT);
	}

	while(1)
	{
		if(!digitalRead(BTN))
		{  // 按钮被按下后,循环切换页码
			page++;
			if(page > 2)
			{
				page = 1;
			}
			for (i=0;i<4;i++)
			{
				digitalWrite(dig[i],HIGH);
			}

        /* 按钮按下去之后会有一个极短时间的电平震荡,大概几us,但这个震荡容易导致输入PIN识别到一个脉冲周期,
         * 所以这里设置一个延时,跳过电平不稳定的时间。
         * 二来,这个延时可以实现一个熄灭再点亮的切换显示的效果,
         * 再者,按钮从按下到抬起来的时间约100ms,如果一直按住按钮不放,会一直在这个循环里不停的切换page。
        */
			delay(200);
		} else {
			showPage(page);
		}
	}

    return 0;
}

【实现效果】

发表评论

电子邮件地址不会被公开。 必填项已用*标注