【单片机学习笔记】(三)———数码管和定时器中断

一、原理图

 

二、数码管电路

控制数码管其实与控制LED的原理相似,数码管的一位可以看作八段LED组成。因此控制数码管,则可以从控制段选和控制位选两方面入手。Y6C控制段选,Y7C控制位选。

我的板子上面所配备的数码管是共阳数码管

数码管静态显示:

数码管的静态显示是指段选是一致的,位选可以独立控制,通过位选来控制哪几个数码管亮,显示的数字始终是一样的。

例如我要让数码管的第一位显示数字2且没有小数点,步骤如下:

位选:应该使com1为高电平1,其他为0,P0二进制代码为0000 0001,写成十六进制即为0x01

段选:abdeg为低电平0,其他为高电平1。P0二进制代码为1010 0100,写成十六进制即为0xa4

数码管动态显示:

数码管的动态显示是指一位一位的操作操作每个数码管,多个数码管交替显示,数码管的动态显示是利用人眼的视觉暂留效果,使人看到多个数码管同时显示的效果。

数码管消隐/数码管鬼影:

使用数码管的时候遇到这样的问题:不应该亮的的位隐约有数据,不该亮的段隐约有亮光等情况,

  • 延时
  • 关闭所有段选(0xff),改变好位选后,再打开段即可
  • 关闭所有位选(0x00),赋值过程都做好后,再重新打开即可

 

编码原理

code unsigned char T_DU[10]={0xc0,0xf9,0xa4,0xb0,0x99,0x92,0x82,0xf8,0x80,0x90};// 段码
code unsigned char T_WE[]={0x01,0x02,0x04,0x08,0x10,0x20,0x40,0x80};//位码

编码定义方法与C语言中数组定义方法类似,不同的是多加了code关键字。code即编码的意思,需要注意的是,单片机C语言中定义数组时是占用内存空间的,而定义编码时是直接分配到程序空间中,编译后,编码占用的是程序存储空间,而非内存空间。在调用数组时,T_DU后的[]中数字从0开始,对应后面{}中的第一个元素。

 

三、定时器中断(初步学习)

1.中断源

52单片机共有6个中断源

中断源默认中断级别序号(C语言)入口地址(汇编语言)
INT0,外部中断0最高00003H
T0,定时器/计数器0中断第二1000BH
INT1,外部中断1

第三

20013H
T1,定时器/计数器1中断第四3001BH
TI/RI,串行口中断第五40023H
T2,定时器/计数器2中断最低5002BH

2.单片机的定时器系统

51单片机内部有2个16位可编程的定时器/计数器,即定时器T0和定时器T1,52单片机内部多一个T2定时器/计数器,它们既有定时功能也有计数功能,通过设置与它们相关的特殊功能寄存器,可以选择启用定时功能或计数功能。

3.定时器中断函数部分

stc-isp→定时器计算器→选择定时长度、正确的频率、定时器、模式、时钟等

//定时器
void Timer0Init(void)		//1毫秒@11.0592MHz
{
	AUXR |= 0x80;		//定时器时钟1T模式
	TMOD &= 0xF0;		//设置定时器模式
	TL0 = 0xCD;		//设置定时初值
	TH0 = 0xD4;		//设置定时初值
	TF0 = 0;		//清除TF0标志
	TR0 = 1;		//定时器0开始计时
}

//定时器中断服务函数
void isr_timer_0() interrupt 1 using 工作组
{
	//……
}

//主函数
void main()
{
	Timer0Init();
	EA=1;打开总中断
	ET0=1;打开定时器0中断
	
	while (1)
        {
            //……
        }
}

“using工作组”是指这个中断服务函数使用单片机内存中4组工作寄存器中的哪一组,C51编译器在编译程序时会自动分配工作组,因此最后一句话通常省略,但以后遇到这样的代码要知道是什么意思。

在中断服务函数程序中一般不要写过多的函数处理语句,如果语句过多,中断服务函数代码还未执行完毕,而下一次中断又来临,这样我们会丢失这次中断。一般我们遵循的原则是:能在主程序中完成的功能就不在中断函数中写,若非要在中断函数中完成,那么一定要高效、简洁。

 

四、关于变量需不需要赋初值

unsigned char i;

如果是全局变量,i的值为0

如果是在函数内部定义的局部变量,i的值就是随机的。

局部变量的内存是从栈里分配的,系统会从栈里找到一个int那么大的内存分配给i。 因为这个栈里的东西没有清零,所以这段内存里的内容什么不知道是什么情况。 所以,局部变量使用前必须初始化。

在 C 语言中,static 关键字不仅可以用来修饰变量,还可以用来修饰函数。

在使用 static 关键字修饰变量时,我们称此变量为静态变量

静态变量的存储方式与全局变量一样,都是静态存储方式。但这里需要特别说明的是,静态变量属于静态存储方式,属于静态存储方式的变量却不一定就是静态变量。例如,全局变量虽然属于静态存储方式,但并不是静态变量,它必须由 static 加以定义后才能成为静态全局变量。

有时候,我们希望函数中局部变量的值在函数调用结束之后不会消失,而仍然保留其原值。即它所占用的存储单元不释放,在下一次调用该函数时,其局部变量的值仍然存在,也就是上一次函数调用结束时的值。

这时候,我们就应该将该局部变量用关键字 static 声明为“静态局部变量”。

静态局部变量一般的使用场景,如下所示:

  • 需要保留函数上一次调用结束时的值。
  • 如果初始化后,变量只会被引用而不会改变其值,则这时用静态局部变量比较方便,以免每次调用时重新赋值。
  • 在静态数据区,内存中所有的字节默认值都是 0x00。静态变量与全局变量也一样,它们都存储在静态数据区中,因此其变量的值默认也为 0。

 

五、代码实现

数码管八位都显示0

#include <STC15F2K60S2.h>

//主函数
void main()
{
    //消隐
    P2=((P2&0x1f)|0xe0);
    P0=0xff;
    P2&=0x1f;
	
    //位选
    P2=((P2&0x1f)|0xc0);
    P0=0xff;
    P2&=0x1f;
	
    //段选
    P2=((P2&0x1f)|0xe0);
    P0=0xc0;
    P2&=0x1f;
}

数码管动态扫描

软件延时实现

#include <intrins.h>
#include <STC15F2K60S2.h>
void Delay2ms();//软件延时函数

code unsigned char T_DU[10]={0xc0,0xf9,0xa4,0xb0,0x99,0x92,0x82,0xf8,0x80,0x90};// 段码
code unsigned char T_WE[]={0x01,0x02,0x04,0x08,0x10,0x20,0x40,0x80};//位码

//主函数
void main()
{
	unsigned char i;
	while (1)
	{
		//消隐
		P2=((P2&0x1f)|0xe0);
		P0=0xff;
		P2&=0x1f;
		
		//位选
		P2=((P2&0x1f)|0xc0);
		P0=T_WE[i];
		P2&=0x1f;
		
		//段选
		P2=((P2&0x1f)|0xe0);
		P0=T_DU[i];
		P2&=0x1f;
		
		i++;
		if (i==8)
			i=0;
		
		Delay2ms();
	}
}

//软件延时函数
void Delay2ms()		//@11.0592MHz
{
	unsigned char i, j;

	_nop_();
	_nop_();
	i = 22;
	j = 128;
	do
	{
		while (--j);
	} while (--i);
}

定时器中断实现

#include <STC15F2K60S2.h>
void Timer0Init(void);

code unsigned char T_DU[10]={0xc0,0xf9,0xa4,0xb0,0x99,0x92,0x82,0xf8,0x80,0x90};// 段码
code unsigned char T_WE[]={0x01,0x02,0x04,0x08,0x10,0x20,0x40,0x80};//位码

//主函数
void main()
{
	Timer0Init();
	EA=1;//打开总中断
	ET0=1;//打开定时器0中断
	while(1);
}

//定时器
void Timer0Init(void)		//2毫秒@11.0592MHz
{
	AUXR |= 0x80;		//定时器时钟1T模式
	TMOD &= 0xF0;		//设置定时器模式
	TL0 = 0x9A;		//设置定时初值
	TH0 = 0xA9;		//设置定时初值
	TF0 = 0;		//清除TF0标志
	TR0 = 1;		//定时器0开始计时
}

//定时器中断服务函数
void isr_timer_0() interrupt 1
{
	static unsigned char i;
	
	//消隐
	P2=((P2&0x1f)|0xe0);
	P0=0xff;
	P2&=0x1f;
		
	//位选
	P2=((P2&0x1f)|0xc0);
	P0=T_WE[i];
	P2&=0x1f;
		
	//段选
	P2=((P2&0x1f)|0xe0);
	P0=T_DU[i];
	P2&=0x1f;
		
	i++;
	if (i==8)
		i=0;
}

多位数码显示 软件延时实现

/*
数码管显示 ---- -123
unsigned char定义的不能大于255
例如如果要显示999 那就用int
小数点0xbf
*/
#include <intrins.h>
#include <STC15F2K60S2.h>
void Delay2ms();//软件延时函数
void display();//显示函数
	
code unsigned char tab[]={0xc0,0xf9,0xa4,0xb0,0x99,0x92,0x82,0xf8,0x80,0x90,0xbf};
unsigned char dspbuf[8]={10,10,10,10,10,0,0,0};//显示缓冲区
unsigned char dspcom=0;
unsigned char x=123;

//主函数
void main()
{
    while (1)
    {
        //刷新显示缓冲区
        dspbuf[5]=x/100;
        dspbuf[6]=x%100/10;
        dspbuf[7]=x%10;
        
        display();
        Delay2ms();
    }
}

//软件延时函数
void Delay2ms()		//@11.0592MHz
{
	unsigned char i, j;

	_nop_();
	_nop_();
	i = 22;
	j = 128;
	do
	{
		while (--j);
	} while (--i);
}

//显示函数
void display()
{
		//消隐
    P2=((P2&0x1f)|0xe0);
    P0=0xff;
    P2&=0x1f;
	
		//位选
    P2=((P2&0x1f)|0xc0);
    P0=(1<<dspcom);
    P2&=0x1f;
	
		//段选
    P2=((P2&0x1f)|0xe0);
    P0=tab[dspbuf[dspcom]];
    P2&=0x1f;
	
    if(++dspcom==8)
    {
        dspcom=0;
    }
}

关于小数点的实现

图1:这种情况与显示数字原理一致,只需在tab[]数组里添加显示小数点的元素码。再对刷新显示缓冲区部分代码进行改变即可。

图2:这种情况由于小数点和数字在同一位显示,并且要求数字改变时小数点不能动,所以不能在数组里对段码进行修改。通过以下代码可以实现。思想是知道小数点的位置,通过if判断,此位小数点常亮。

#include <intrins.h>
#include <STC15F2K60S2.h>
void Delay1ms();//软件延时函数
void display();//显示函数

code unsigned char tab[]={0xc0,0xf9,0xa4,0xb0,0x99,0x92,0x82,0xf8,0x80,0x90,0xbf};
unsigned char dspbuf[8]={10,10,10,10,10,0,0,0};//显示缓冲区
unsigned char dspcom=0;
unsigned char x=123;

//主函数
void main()
{
	P2=0xA0;P06=0;P2=0x00;
	P2=0x80;P0=0xff;P2=0x00;
        while (1)
        {
	    //刷新显示缓冲区
            dspbuf[5]=x/100;
            dspbuf[6]=x%100/10;
            dspbuf[7]=x%10;
        
            display();
            Delay1ms();
        }
}

//软件延时函数
void Delay1ms()		//@11.0592MHz
{
	unsigned char i, j;

	_nop_();
	_nop_();
	_nop_();
	i = 11;
	j = 190;
	do
	{
		while (--j);
	} while (--i);
}

//显示函数
void display()
{
    P2=((P2&0x1f)|0xe0);
    P0=0xff;
    P2&=0x1f;
	
    P2=((P2&0x1f)|0xe0);
    if (dspcom==6)
    {
	P0=((tab[dspbuf[dspcom]])&0x7f);//该位小数点常亮
    }
    else
    {
        P0=tab[dspbuf[dspcom]];
    }
    P2&=0x1f;
	
    P2=((P2&0x1f)|0xc0);
    P0=(1<<dspcom);
    P2&=0x1f;
	
    if(++dspcom==8)
    {
        dspcom=0;
    }
}

数码管显示计时 含小数点 每500ms增加0.1

#include <intrins.h>
#include <STC15F2K60S2.h>

void Timer0Init(void);//定时器
void Delay500ms();//软件延时函数
void display();//显示函数

code unsigned char tab[]={0xc0,0xf9,0xa4,0xb0,0x99,0x92,0x82,0xf8,0x80,0x90,0xbf};
unsigned char dspbuf[8]={0,0,0,0,0,0,0,0};//显示缓冲区
unsigned char dspcom=0;
unsigned char x=0;

//主函数
void main()
{
	P2=0xA0;P06=0;P2=0x00;
	P2=0x80;P0=0xff;P2=0x00;
	Timer0Init();
	EA=1;//打开总中断
	ET0=1;//打开定时器0中断
	
        while (1)
        {
	    //刷新显示缓冲区
            dspbuf[5]=x/100;
            dspbuf[6]=x%100/10;
            dspbuf[7]=x%10;
				
	    x+=1;
	    Delay500ms();
        }
}

//定时器
void Timer0Init(void)		//1毫秒@11.0592MHz
{
	AUXR |= 0x80;		//定时器时钟1T模式
	TMOD &= 0xF0;		//设置定时器模式
	TL0 = 0xCD;		//设置定时初值
	TH0 = 0xD4;		//设置定时初值
	TF0 = 0;		//清除TF0标志
	TR0 = 1;		//定时器0开始计时
}

//软件延时函数
void Delay500ms()		//@11.0592MHz
{
	unsigned char i, j, k;

	_nop_();
	_nop_();
	i = 22;
	j = 3;
	k = 227;
	do
	{
		do
		{
			while (--k);
		} while (--j);
	} while (--i);
}

//显示函数
void display()
{
	P2=((P2&0x1f)|0xe0);
	P0=0xff;
	P2&=0x1f;

	P2=((P2&0x1f)|0xe0);
	if (dspcom==6)
	{
		P0=((tab[dspbuf[dspcom]])&0x7f);//该位小数点常亮
	}
	else
	{
		P0=tab[dspbuf[dspcom]];
	}
	P2&=0x1f;

	P2=((P2&0x1f)|0xc0);
	P0=(1<<dspcom);
	P2&=0x1f;

	if(++dspcom==8)
	{
			dspcom=0;
	}
}

//中断服务函数
void isr_timer_0() interrupt 1
{
	display();
}

 

  • 7
    点赞
  • 32
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 3
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

EstherYoo

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值