【蓝桥杯-单片机】基础模块:数码管

文章目录

【蓝桥杯-单片机】基础模块:数码管

01 数码管原理图


从图2可知,位选和段选最终都接到了D0.7口;从图1可知,对应D0.7的是P0口。因此P0口是数据口,数据应该往P0口写。

但是位选和段选都是写入P0口。P0=0xA4,如何设置为段选?利用锁存器实现。

令P2.6=1,写入段选数据;令P2.6=0,关闭,数据存进去了。

令P2.7=1,写入位选数据;令P2.7=0,关闭,数据存进去了。

c 复制代码
//数码管显示函数
void Seg_Disp(unsigned char wela,dula)
{
	P0 = 0x00; //消影
	P2_6 = 1;
	P2_6 = 0;	
	
	P0 = Seg_Wela[wela];
	P2_7 = 1;
	P2_7 = 0;		
	
	P0 = Seg_Dula[dula];
	P2_6 = 1;
	P2_6 = 0;	
}

什么是位选和段选

  • 位选(Digit Select):

    位选是指在多位数码管中选择哪一位进行显示。例如,4位数码管就有4个位选引脚,通过控制这些引脚的电平状态,可以选择显示哪一位的数字。位选的常见方式是通过一个计时器或者控制芯片,轮流地激活每一位,以达到依次显示多个数字的效果。

    位选引脚一般用W0、W1、W2等表示,其中W0对应最低位,W1对应次低位,以此类推。

  • 段选(Segment Select):

    段选是指选择数码管的哪一段(LED)亮起来,以显示对应数字的哪一部分。例如,7段数码管的每一段可以表示数字0-9中的一部分。段选通常使用BCD码(二进制编码十进制)或其他编码方式,将要显示的数字转化为对应的段选信号。

    段选引脚一般用a、b、c、d、e、f、g等表示,对应数码管的7个LED段。

  • DP是数码管中的一种特殊段,它代表小数点(Decimal Point)。在一些数码管中,除了表示数字0到9的七个段(a到g),还包括一个用于显示小数点的额外段,即DP段。

这里的h即DP。

共阳极数码管和共阴极数码管的区分

共阳极数码管和共阴极数码管是两种常见的数码管类型,它们在工作原理和控制方式上有一些区别:

(1)共阳极数码管(Common Anode):

共阳极数码管 中,所有的LED段的阳极(正极)都是连接在一起 的,而每个LED段的阴极(负极)则分别连接到不同的引脚。

控制时,通过给某一段的阴极引脚接通电流,同时将共阳极引脚设置为高电平,该段就会被激活,显示相应的数字或字符。

(2)共阴极数码管(Common Cathode):

共阴极数码管 中,所有的LED段的阴极(负极)都是连接在一起 的,而每个LED段的阳极(正极)则分别连接到不同的引脚。

控制时,通过给某一段的阳极引脚接通电流,同时将共阴极引脚设置为低电平,该段就会被激活,显示相应的数字或字符。

主要区别在于共阳极数码管是通过通电阴极(负极)来激活LED段,而共阴极数码管是通过通电阳极(正极)来激活LED段。

例如:假设以下是一个共阴极数码管 (共阴极引脚设置为低电平激活),如果我要显示数字2,对8个段选线的电平设置(从h->a)为10100100,转换为16进制为0xA4。即设置段选为0xA4就可以让数码管显示数字2

02 代码

(1)数码管静态显示

普通代码(直接在while循环里写)

c 复制代码
		P0 = 0x00; //消影
	    P2_6 = 1;
		P2_6 = 0;	
		
		P0 = 0xfe;//访客(数据)来了
		P2_7 = 1;//位码门打开
		P2_7 = 0;//位码门关闭,防止别人进来
		
		P0 = 0x5b;//访客(数据)来了
		P2_6 = 1;//段码门打开
		P2_6 = 0;//段码门关闭,防止别人进来(这是用锁存器实现的)

模块化编程:

c 复制代码
/* 变量声明区 */
unsigned char Seg_Wela[6] = {0xfe,0xfd,0xfb,0xf7,0xef,0xdf};
unsigned char Seg_Dula[11] = {0x3f,0x06,0x5b,0x4f,0x66,0x6d,0x7d,0x07,0x7f,0x6f,0x00};
//数码管显示函数
void Seg_Disp(unsigned char wela,dula)
{
	P0 = 0x00; //消影
	P2_6 = 1;
	P2_6 = 0;	
	
	P0 = Seg_Wela[wela];
	P2_7 = 1;
	P2_7 = 0;		
	
	P0 = Seg_Dula[dula];
	P2_6 = 1;
	P2_6 = 0;	
}

这边的代码和蓝桥杯的底层代码是有一点不一样的,但是思路都是一样的,要先学会简单的。

这些代码再蓝桥杯比赛的时候需要凭借肌肉记忆敲出来,不能现场推,会来不及。

(2)数码管动态显示

动态数码管:每位数码管显示不同的数字,若直接重复调用一个数码管显示的函数,会因为程序执行逻辑是由上至下依次执行,会造成后面的数据影响前面的显示效果

  • 一种解决方案,显示后面直接delay。这种做法不建议,程序写多了会卡。
  • 用定时器
特性 定时器(Timer) 延时函数(Delay)
作用 用于计算程序执行时间、生成精确的时间延迟、定时触发事件等。 用于在程序中创建一段固定的时间延迟
工作原理 以某个频率递增或递减的计数器 通过在程序中插入循环,等待一段时间
使用方法 配置计数方向、预分频器、计数模式等参数 确定循环次数,基于系统时钟频率和所需延时时间
应用 生成精确的时间间隔、PWM控制、周期性任务调度等 简单的等待、初始化延时等

总结:定时器提供了更为精确的时间控制,适用于需要准确时间测量和控制的场景。延时函数是一种简单的时间控制方法,适用于一些简单的等待或初始化场景,但在需要高精度时间控制的情况下不够准确。

①定时器生成步骤
  • 打开STC-ISP烧录软件,找到定时器计算器
  • 系统频率12MHz定时长度1毫秒定时器模式十六位定时器时钟127T
  • 复制C代码到工程中
  • 删除AUXR &=Ox7F;
c 复制代码
//定时器初始化函数
void Timer0Init(void)		//1毫秒@12.000MHz
{
	//AUXR &= 0x7F;		//定时器时钟12T模式,没有这个定义,删掉
	TMOD &= 0xF0;		//设置定时器模式
	TL0 = 0x18;		//设置定时初值
	TH0 = 0xFC;		//设置定时初值
	TF0 = 0;		//清除TF0标志
	TR0 = 1;		//定时器0开始计时
	ET0 = 1;//加上
	EA = 1;//加上
}

在嵌入式系统和单片机编程中,ET0 和 EA 是与定时器/计数器相关的控制寄存器。

  • ET0(Timer 0 溢出中断允许位):
    ET0 位是 8051 单片机中的特殊功能寄存器(SFR),用于控制定时器/计数器 0 的溢出中断是否允许。
    当 ET0 位被设置为 1 时,允许定时器/计数器 0 溢出时触发中断。溢出中断是在定时器/计数器达到最大计数值后溢出到 0 时触发的。
  • EA(全局中断允许位):
    EA 位同样是 8051 单片机中的特殊功能寄存器,用于控制全局中断是否允许。
    当 EA 位被设置为 1 时,允许所有中断(包括外部中断、定时器中断等)生效。如果 EA 位被清零,则禁止所有中断,即使各个中断的特定中断允许位(如 ET0)被设置为 1,相应中断也不会触发。

这两个寄存器通常与定时器/计数器模块一起使用,以实现在定时器计数达到某个值时触发中断的功能。在使用定时器中断时,通常需要设置 ET0 位来启用定时器溢出中断,并设置 EA 位来启用全局中断。

②中断配置方法
  • 在生成的定时器初始化函数内增加中断打开命令ET0=1、EA=1
  • 书写中断服务函数(Timer0Server)
  • 在服务函数内初始化计数值
  • 在主程序内添加定时器0初始化函数
c 复制代码
//中断服务函数
void Timer0Server() interrupt 1
{
	TL0 = 0x18;		//设置定时初始值
	TH0 = 0xFC;		//设置定时初始值
	
	Seg_Pos++;
	if(Seg_Pos == 6) Seg_Pos = 0;
	
	Seg_Disp(Seg_Pos,Seg_Buf[Seg_Pos]);
	
}

完整代码

c 复制代码
/* 头文件声明区 */
#include <REGX52.H>
#include <intrins.h>

/* 变量声明区 */
unsigned char Led_Data = 0xFE;//用于循环位移的LED变量 初始值为LED1亮
unsigned char Seg_Wela[6] = {0xfe,0xfd,0xfb,0xf7,0xef,0xdf};
unsigned char Seg_Dula[11] = {0x3f,0x06,0x5b,0x4f,0x66,0x6d,0x7d,0x07,0x7f,0x6f,0x00};
unsigned char Seg_Pos;
unsigned char Seg_Buf[6] = {5,2,1,10,10,10};

/* 五百毫秒延时函数 */
void Delay500ms()		//@12.000MHz
{
	unsigned char i, j, k;
	
	i = 4;
	j = 205;
	k = 187;
	do
	{
		do
		{
			while (--k);
		} while (--j);
	} while (--i);
}

/** 
* @函数名 自定义延时函数
* @函数功能 延时任意毫秒
* @入口参数 延时时间
* @返回值 无
*/
void Delay(unsigned int xms)		//@12.000MHz
{
	unsigned char i, j;
	while(xms--)
	{
		i = 2;
		j = 239;
		do
		{
			while (--j);
		} while (--i);
	}
}

//数码管显示函数
void Seg_Disp(unsigned char wela,dula)
{
	P0 = 0x00; //消影
	P2_6 = 1;
	P2_6 = 0;	
	
	P0 = Seg_Wela[wela];
	P2_7 = 1;
	P2_7 = 0;		
	
	P0 = Seg_Dula[dula];
	P2_6 = 1;
	P2_6 = 0;	
}

//定时器初始化函数
void Timer0Init(void)		//1毫秒@12.000MHz
{
	TMOD &= 0xF0;		//设置定时器模式
	TMOD |= 0x01;		//设置定时器模式
	TL0 = 0x18;		//设置定时初始值
	TH0 = 0xFC;		//设置定时初始值
	TF0 = 0;		//清除TF0标志
	TR0 = 1;		//定时器0开始计时
	ET0 = 1;
	EA = 1;
}

//中断服务函数
void Timer0Server() interrupt 1
{
	TL0 = 0x18;		//设置定时初始值
	TH0 = 0xFC;		//设置定时初始值
	
	Seg_Pos++;
	if(Seg_Pos == 6) Seg_Pos = 0;
	
	Seg_Disp(Seg_Pos,Seg_Buf[Seg_Pos]);
	
}


/* Main */
void main()
{
	Timer0Init();
	while(1)
	{
		
	}
}
  • 头文件和变量声明
    #include <REGX52.H> 和 #include <intrins.h> 分别包含 8051 单片机的头文件和一些内联汇编函数的头文件。
    Led_Data 是用于循环位移的 LED 变量。
    Seg_Wela 和 Seg_Dula 是用于控制共阴数码管的位选和段选的数组。
    Seg_Pos 用于表示当前数码管显示的位置。
    Seg_Buf 是用于存储数码管显示的数字。
  • 延时函数:
    Delay500ms() 实现了一个 500 毫秒的延时函数,通过嵌套循环实现延时。
    Delay(unsigned int xms) 是一个自定义延时函数,根据传入的毫秒数进行延时。
  • 数码管显示函数:
    Seg_Disp(unsigned char wela, dula) 用于控制数码管的显示。通过设置 P0 端口和 P2.6、P2.7 引脚的状态来控制位选和段选。
  • 定时器初始化函数和中断服务函数:
    Timer0Init() 初始化定时器0,配置为工作在方式1,用于产生1毫秒的定时中断。
    Timer0Server() 是定时器0的中断服务函数,通过定时中断实现LED循环位移和数码管显示的刷新。
  • Main 函数:
    main() 函数中初始化了定时器,并进入一个无限循环,程序主要通过定时器中断服务函数进行 LED 和数码管的显示控制。
补充知识:8051的中断源

以下内容搬运自博客:http://blog.chinaunix.net/uid-20629402-id-1608165.html

(1)8051的5个中断源
(2)中断函数写法
c 复制代码
返回值 函数名 interrupt n { ...... }

n对应中断源编号。

例如:

c 复制代码
//中断服务函数
void Timer0Server() interrupt 1
{
	TL0 = 0x18;		//设置定时初始值
	TH0 = 0xFC;		//设置定时初始值
	
	Seg_Pos++;
	if(Seg_Pos == 6) Seg_Pos = 0;
	
	Seg_Disp(Seg_Pos,Seg_Buf[Seg_Pos]);
	
}

interrupt 1表示这个是5个中断源中Timer0的中断服务函数!

(3)中断触发控制寄存器IE (左边是高位)
  • EX0:响应外部/INT0的中断
  • ET0:响应TIMER0的中断
  • EX1、ET1:对应/INT1与TIMER1
  • ES:对应UART
  • ET2:响应TIMER2溢出或捕捉的中断(仅对8052)
  • EA:中断使能。EA=1时才允许中断。
(4)中断优先级控制寄存器IP

分别对应各中断的优先级。仅分0(低)、1(高)两级,同级的中断还是看中断源编号进行优先级排序。

(5)TIMER控制寄存器TCON
  • TF1与TF0分别是硬件去置位的,当Timer1/Counter1溢出时,TF1会被置为1,而当处理器去执行中断服务时,它又被硬件置0。(当然TF0管的就是Timer0/Counter0了)
  • TR1与TR0由软件置位,管的是Timer/Counter的激活。(如在程序里写TR0=1,就是说Counter0开始计数,当然如果这个Timer/Counter被设置为Counter的工作方式的话)
  • IE1与IE0由硬件置位,与TF1、TF0等同,只是IE1与IE0管的是外部中断。
  • IT1与IT0由软件置位,设为1时,对应的外部中断为负缘触发,设0时为低准位触发。
相关推荐
hazy1k33 分钟前
51单片机基础-动态数码管显示
stm32·单片机·嵌入式硬件·51单片机
Heavy sea1 小时前
STM32 DMA直接存储器访问(寄存器与HAL库实现)
stm32·单片机
漫夜8551 小时前
MCU和GPIO (1)
单片机·嵌入式硬件
点灯小铭1 小时前
基于单片机的智能洗碗机设计
单片机·嵌入式硬件·mongodb·毕业设计·课程设计
小莞尔9 小时前
【51单片机】【protues仿真】基于51单片机四层电梯系统
单片机·嵌入式硬件
CFZPL9 小时前
使用江科大串口发送函数发送freertos的vTaskList出现跑飞
单片机
F1331689295710 小时前
WD5030A,24V降5V,15A 大电流,应用于手机、平板、笔记本充电器
stm32·单片机·嵌入式硬件·51单片机·硬件工程·pcb工艺
易享电子11 小时前
基于单片机电器断路器保护器系统Proteus仿真(含全部资料)
单片机·嵌入式硬件·fpga开发·51单片机·proteus
爱倒腾的老唐14 小时前
01、如何学习单片机
单片机·嵌入式硬件·学习
点灯小铭14 小时前
基于单片机的夹具压力控制系统设计
单片机·嵌入式硬件·mongodb·毕业设计·课程设计