当前位置:   article > 正文

定时器扫描8位数码管(含滚动显示)_数码管滚动显示

数码管滚动显示


前言

  本次编程实验以IAP15F2K61S2为单片机主控芯片,其编程使用与STC15F2K60S2完全相同,头文件为STC15F2K60S2.H。若用于51系列单片机,以reg52.h为头文件,则需将后文中timer0.c中void Timer0_Init(void)函数中的AUXR &= 0x7F;一行删除(后文有提示)。程序中涉及的定时器初始化程序和LED亮灭程序和数码管显示程序,读者可根据自身所用单片机原理图和手册自行修改。


一、为什么使用定时器扫描数码管?

  在对主程序执行效率要求低、项目工程复杂度低的情况下,通常我们对数码管位选、段选后用delay延时函数进行延时,利用人眼视觉暂留效应实现8位数码管的静态、动态显示。但数码管延时时间,以2ms为例,相比机器周期微秒级别还是太长。为了提高主程序执行效率,故使用定时器扫描数码管的方式。

二、定时器扫描数码管的原理及代码

  定时器定时1ms,每隔2ms刷新1位数码管的显示,从而代替了delay延时函数。

#include <STC15F2K60S2.H>

typedef unsigned char u8;
#define outputp0(y,x)  P0=x,P2&=0x1f,P2|=y,P2&=0x1f; //P2高三位用于74HC138译码器选择锁存器,P0由于发送数据

int shownum=123;   //数码管显示数值
unsigned char Seg_sy[]={10,10,10,10,10,10,10,10};  //数码管段选索引数组,上电默认数码管全灭
unsigned char code Seg_Table[]={
0xc0,    //共阳数码管
0xf9,
0xa4,
0xb0,
0x99,
0x92,
0x82,
0xf8,
0x80,
0x90,
0xff   //8段全灭
};

void Timer0_Init(void)		//1毫秒@11.0592MHz
{
	AUXR &= 0x7F;			//定时器时钟12T模式,若以reg52.h为头文件时删除这行代码
	TMOD &= 0xF0;			//设置定时器模式
	TMOD |= 0x01;			//设置定时器模式
	TL0 = 0x66;				//设置定时初始值
	TH0 = 0xFC;				//设置定时初始值
	TF0 = 0;				//清除TF0标志
	TR0 = 1;				//定时器0开始计时
	
	ET0 = 1;				//使能定时器0中断
	EA=1;                   //使能总中断
}
/*
  *  @brief     数码管显示函数
  *  @param     pos:位选;dat:显示数字;dot:小数点选择位,1有0无
  *  @reval      
  *  @note:    
*/
void showbit(unsigned char pos,dat,dot) //数码管显示函数
{
	outputp0(0xc0,0x01<<pos);       //位选
	outputp0(0xe0,Seg_Table[10]);    //段选,这两行用于消影
	
	outputp0(0xc0,0x01<<pos);      //位选
	outputp0(0xe0,Seg_Table[dat]+0x80*dot);	   //段选
}
/*
  *  @brief     8位数码管显示函数
  *  @param     
  *  @reval      
  *  @note:    
*/
void showloop()
{
	static unsigned char sy=0;  //sy用于选择位选和位选对应的段选索引
	showbit(sy,Seg_sy[sy],0); //刷新1位数码管
    sy++;   //每执行一次,sy加一,从而下次执行时刷新下一位数码管
	sy%=8;  //8位数码管,因此sy不超过8
}

void main()
{
	Timer0_Init();	
	Seg_sy[0]=shownum/100;    //赋初值
	Seg_sy[1]=shownum/10%10;
	Seg_sy[2]=shownum%10;	
	while(1)
	{

	}
}

void Timer0_Isr(void) interrupt 1
{
	static u8 tsmg=0;  //用于数码管扫描时间计数
	TL0 = 0x66;				//设置定时初始值
	TH0 = 0xFC;				//设置定时初始值
	tsmg++;
	if(tsmg>=2)    //每2ms扫描一次数码管
	{
		tsmg=0;   //清零
		showloop();   //刷新数码管
	}
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72
  • 73
  • 74
  • 75
  • 76
  • 77
  • 78
  • 79
  • 80
  • 81
  • 82
  • 83
  • 84
  • 85
  • 86

  编译下载程序后,数码管正常显示123。

三、滚动显示

  有时候我们希望数码管显示像滚动屏一样,数据能够从左向右或从右向左进入然后从另一端消失。以显示"HELLO",从右向左,每1s滚动一次为例,首先写出对应的段码表,将上文代码中的unsigned char code Seg_Table[]修改为如下值:

unsigned char code Seg_Table[]={     //数码管段选数组
0x89,   //H
0x86,   //E
0xc7,   //L
0xc7,   //L
0xc0,   //O
0xff   //0xff,用于熄灭1位数码管
};
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8

  为了实现滚动显示,数码管段选索引数组应该每1秒向左移动一次。当”HELLO“全部移出数码管后,此时数码管应该全灭,下一秒再将”H“移入数码管,从而在数码管段选数组中需要8个连续0xff用于全灭8位数码管,即在数码管段选索引数组中有8个连续5。将上文代码中的unsigned char Seg_sy[]修改为如下值:

unsigned char Seg_sy[]={5,5,5,5,5,5,5,5,0,1,2,3,4};
  • 1

  完整代码如下:

#include <STC15F2K60S2.H>

typedef unsigned char u8;
#define outputp0(y,x)  P0=x,P2&=0x1f,P2|=y,P2&=0x1f; //P2高三位用于74HC138译码器选择锁存器,P0由于发送数据
unsigned char Seg_sy[]={5,5,5,5,5,5,5,5,0,1,2,3,4};  //数码管段选索引数组
unsigned char code Seg_Table[]={     //数码管段选数组
0x89,   //H
0x86,   //E
0xc7,   //L
0xc7,   //L
0xc0,   //O
0xff   //0xff,用于熄灭1位数码管
};

void Timer0_Init(void)		//1毫秒@11.0592MHz
{
	AUXR &= 0x7F;			//定时器时钟12T模式,若以reg52.h为头文件时删除这行代码
	TMOD &= 0xF0;			//设置定时器模式
	TMOD |= 0x01;			//设置定时器模式
	TL0 = 0x66;				//设置定时初始值
	TH0 = 0xFC;				//设置定时初始值
	TF0 = 0;				//清除TF0标志
	TR0 = 1;				//定时器0开始计时
	
	ET0 = 1;				//使能定时器0中断
	EA=1;                   //使能总中断
}
/*
  *  @brief     数码管显示函数
  *  @param     pos:位选;dat:显示数字;dot:小数点选择位,1有0无
  *  @reval      
  *  @note:    
*/
void showbit(unsigned char pos,dat,dot) //数码管显示函数
{
	outputp0(0xc0,0x01<<pos);       //位选
	outputp0(0xe0,Seg_Table[10]);    //段选,这两行用于消影
	
	outputp0(0xc0,0x01<<pos);      //位选
	outputp0(0xe0,Seg_Table[dat]+0x80*dot);	   //段选
}
/*
  *  @brief     8位数码管显示函数
  *  @param     
  *  @reval      
  *  @note:    
*/
void showloop()
{
	static unsigned char sy=0;  //sy用于选择位选和位选对应的段选索引
	showbit(sy,Seg_sy[sy],0); //刷新1位数码管
    sy++;   //每执行一次,sy加一,从而下次执行时刷新下一位数码管
	sy%=8;  //8位数码管,因此sy不超过8
}
void dongtaishaomiao()
{
	u8 i=0,temp=0;
	temp=Seg_sy[0];   //temp用于保存数码管段选索引数组第0位
	for(i=0;i<sizeof(Seg_sy)-1;i++)
		Seg_sy[i]=Seg_sy[i+1]; //数码管段选索引数组循环向左移动,每次移动一位
	Seg_sy[sizeof(Seg_sy)-1]=temp;   //数码管段选索引数组第0位向左移动一位后变成第12位
}
void main()
{
	outputp0(0x80,0xff);
	outputp0(0xa0,0x00);
	Timer0_Init();	
	while(1)
	{

	}
}

void Timer0_Isr(void) interrupt 1
{
	static u8 tsmg=0;  //用于数码管扫描时间计数
static int dtaismg=0;
	TL0 = 0x66;				//设置定时初始值
	TH0 = 0xFC;				//设置定时初始值
	tsmg++;
	if(tsmg>=2)    //每2ms扫描一次数码管
	{
		tsmg=0;   //清零
		showloop();   //刷新数码管
	}
	
	dtaismg++;
	if(dtaismg>=1000)  //每1秒
	{
		dtaismg=0;
		dongtaishaomiao();  //将数码管段选索引数组循环向左移动,每次移动一位
	}
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72
  • 73
  • 74
  • 75
  • 76
  • 77
  • 78
  • 79
  • 80
  • 81
  • 82
  • 83
  • 84
  • 85
  • 86
  • 87
  • 88
  • 89
  • 90
  • 91
  • 92
  • 93

  编译下载程序,数码管滚动显示"HELLO"。


总结

  通过上述程序,可以实现定时器扫描数码管(含滚动显示)以提高主程序执行效率。通过类比,也可以实现定时器扫描独立按键和矩阵按键,详情见定时器扫描按键(短按/长按)定时器扫描矩阵键盘简易代码(短按/长按)
  此外,由于定时器每1ms进入一次中断,对于具有IIC和One-Wire通信等具有严格时序要求的项目来说,容易使通信被干扰,因此不建议使用定时器扫描的方式。当然,通过一些方法也可以实现二者兼容并存,在DS1302可调时钟(按键短按/长按)中提供了其中一种方法。

  有任何问题和补充,欢迎评论区交流。

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/不正经/article/detail/709382
推荐阅读
相关标签
  

闽ICP备14008679号