蓝桥杯实验3--数码管(proteus仿真)

例程下载:https://github.com/xiaoengineer/lanqiano

首先得说说什么是数码管

数码管其实就是一堆发光二极管,将这些发光二极管封装在一起,每一个发光二极管做成字符的一个段,就组成了所谓的七段LED字符显示器。根据内部连接的不同,LED显示有共阴和共阳之分。共阴的适用于高电平驱动,共阳的适用于低电平驱动。由于集成电路的高电平输出电流小,而低电平输出电流相对比较大,所以集成电路直接驱动LED时,较多采用低电平的驱动方式。

知道了这些就可以控制数码管了:首先控制位选,指定数字是在哪一位数码管上显示,禁止位选使能,之后是段选,控制数码管显示什么,禁止段选使能。这样就完成任务了。

下面是静态显示,控制一个数字

#include <STC89C5xRC.H>
typedef unsigned int u16;
typedef unsigned char u8;


void close()
{
	P2 = (P2 & 0X1F) | 0XA0;
	P0 = 0XAF;
	P2 = 0x1f; //关闭蜂鸣器,继电器
}

void main()
{
	close();
	P2 = (P2 & 0X1F) | 0XC0; //这个是位选使能,是不是感觉和普通的
							//开发板不一样?那是由于开发板的设计决定的
							//这样做是可以保证我可以修改我想要的位而保证
							//其他位不变
	P0 = 0X01;   //位选,选第一个位
	P2 = P2 & 0X1F; //禁止使能
		
	P2 = (P2 & 0X1F) | 0XE0; //这个是段选,也不太一样,理由同上
	P0 = 0xC0; //段选,显示一个数
	P2 = 0X1F;
	while(1);
}

下面这个是动态显示,何为动态显示?动态显示就是利用人眼的视觉暂留(这个仿真的不太好),闪动地播放数字。

先说一下共阳的段位表(0~F)

0xC0, 0xF9, 0xA4, 0xB0, 0x99, 0x92, 0x82, 0xF8, 0x80, 0x90, 0x88, 0x83, 0xC6, 0xA1, 0x86, 0x8E

我将以两种方式来实现0 ~9999的数字显示(使用定时器)

方式一:

#include <STC89C5xRC.H>
typedef unsigned int u16;
typedef unsigned char u8;

u8 seg_ment[] = {0xC0, 0xF9, 0xA4, 0xB0, 0x99, 0x92, 0x82, 0xF8, 0x80,
					0x90, 0x88, 0x83, 0xC6, 0xA1, 0x86, 0x8E}; //定义段位
u8 seg_bit[] = {0x80, 0x40, 0x20, 0x10}; //定义位选
u16 count, sec_flag;

void close()
{
	P2 = (P2 & 0X1F) | 0XA0;
	P0 = 0XAF;
	P2 = P2 & 0X1F;
}

void delay(u8 ms)
{
	u8 i, j;
	for(i = ms; i > 0; i --)
		for(j = 114; j > 0; j --);
}

void led_show(u16 number)
{
	/*这种处理数字的方法很简单,C语言课上老师应该都讲过*/
	u16 kilobit = number / 1000;
	u16 hundreds_place = number % 1000 / 100;
	u16 decade = number % 1000 % 100 / 10;
	u16 unit = number - (kilobit * 1000 + hundreds_place * 100 + decade * 10);
	
	/*下面是显示函数*/  
	/*显示个位*/
	P2 = (P2 & 0X1F) | 0XC0;
	P0 = seg_bit[0];
	P2 = P2 & 0X1f;
	
	P2 = (P2 & 0X1F) | 0XE0;
	P0 = seg_ment[unit];
	P2 = P2 & 0X1f;
	delay(10);
	
	/*显示十位*/
	P2 = (P2 & 0X1F) | 0XC0;
	P0 = seg_bit[1];
	P2 = P2 & 0X1f;
	
	P2 = (P2 & 0X1f) | 0XE0;
	P0 = seg_ment[decade];
	P2 = P2 & 0X1f;
	delay(10);
	
	/*显示百位*/
	P2 = (P2 & 0X1f) | 0XC0;
	P0 = seg_bit[2];
	P2 = P2 & 0X1f;
	
	P2 = (P2 & 0X1F) | 0XE0;
	P0 = seg_ment[hundreds_place];
	P2 = P2 & 0x1f;
	delay(10);
	
	/*显示千位*/
	P2 = (P2 & 0X1F) | 0XC0;
	P0 = seg_bit[3];
	P2 = P2 & 0X1f;
	
	P2 = (P2 & 0X1F) | 0XE0;
	P0 = seg_ment[kilobit];
	P2 = P2 & 0X1f;
	delay(10);
}

void Timer0Init(void)		//100微秒@12.000MHz
{
	AUXR &= 0x7F;		//定时器时钟12T模式
	TMOD &= 0xF0;		//设置定时器模式
	TMOD |= 0x01;		//设置定时器模式
	TL0 = 0x9C;		//设置定时初值
	TH0 = 0xFF;		//设置定时初值
	TF0 = 0;		//清除TF0标志
	TR0 = 1;		//定时器0开始计时
	EA = 1;
	ET0 =1;
}

void main()
{
	u16 sec;
	close();
	Timer0Init();
	while(1)
	{
		if(sec_flag)
		{
			sec_flag = 0;
			if(sec < 9999)
			{
				sec ++;
				led_show(sec);
			}
			else
				sec = 0;
		}
	}
}

void interruptTimer0() interrupt 1
{
	TL0 = 0x9C;		//设置定时初值
	TH0 = 0xFF;		//设置定时初值
	count ++;
	if(count > 100)
	{
		count = 0;
		sec_flag = 1;
	}
}

方法二:

#include <STC90C5xAD.H>
typedef unsigned int u16;
typedef unsigned char u8;

u8 seg_ment[] = {0xC0, 0xF9, 0xA4, 0xB0, 0x99, 0x92, 0x82, 0xF8, 0x80,
					0x90, 0x88, 0x83, 0xC6, 0xA1, 0x86, 0x8E}; //定义段位
u8 led_buff[] = {0xff, 0xff, 0xff, 0xff};//确保在上电的时候不亮

u16 count, sec_flag;

void close()
{
	P2 = (P2 & 0X1F) | 0XA0;
	P0 = 0XAF;
	P2 = P2 & 0X1F;
}

void delay(u8 ms)
{
	u8 i, j;
	for(i = ms; i > 0; i --)
		for(j = 114; j > 0; j --);
}

void Timer0Init(void)		//100微秒@12.000MHz
{
	AUXR &= 0x7F;		//定时器时钟12T模式
	TMOD &= 0xF0;		//设置定时器模式
	TMOD |= 0x01;		//设置定时器模式
	TL0 = 0x9C;		//设置定时初值
	TH0 = 0xFF;		//设置定时初值
	TF0 = 0;		//清除TF0标志
	TR0 = 1;		//定时器0开始计时
	EA =1;
	ET0 =1;
}

/*这个函数使用来显示的*/
void led_scan()
{
	static u8 index = 0; //这个静态变量使用来自动移位的
	P2 = (P2 & 0x1f) | 0xe0;
	P0 = 0XFF; //这个是消影
	P2 = P2 & 0X1F;
	delay(5);
	
	P2 = (P2 & 0X1F) | 0XC0;
	P0 = 0X80 >> index; //这个就实现了自动移位
	P2 = 0x1f;
	
	P2 = (P2 &0x1f) | 0xe0;
	P0 = led_buff[index];
	P2 = P2 & 0X1F;
	
	if(index < 3)
		index ++;
	else
		index = 0;
}

/*这个函数是用来处理数据的,用了缓存的思想*/
void show_number(u16 dat)
{
	char i;
	u8 buf[4];
	
	for(i = 0; i < 4; i ++)
	{
		buf[i] = dat % 10; 
		dat = dat / 10;  //将数字是各个位分离出来并存入缓存
	}
	for(i = 3; i > 0; i --)
	{
		if(buf[i] == 0) //如果临时缓存区里代表高位的没有数字
			led_buff[i] = 0xff; //那么就为0xff,否则就可以正式填入数据
		else		
			break;
	}
	for(; i >= 0; i --)
	{
		led_buff[i] = seg_ment[buf[i]];
	}
}
void main()
{
	u16 sec;
	close();
	Timer0Init();
	while(1)
	{
		if(sec_flag)
		{
			sec_flag = 0;
			if(sec < 9999)
			{
				sec ++;
				show_number(sec);
				led_scan();
			}
			else
				sec = 0;
		}
	}
}

void T0_interrput() interrupt 1
{
	TL0 = 0x9C;		//设置定时初值
	TH0 = 0xFF; 	//设置定时初值
	count ++;
	if(count > 100)
	{
		count = 0;
		sec_flag = 1;
	}
}

两种方法各有好处,以自己而定。

发布了25 篇原创文章 · 获赞 19 · 访问量 1万+

猜你喜欢

转载自blog.csdn.net/little_engineer/article/details/86559656