12.矩阵键盘,定时器,外部中断课后练习

1.系统上电后数码管显示0,按下S4用定时器以间隔500ms在数码管上依次显示0-F,重复,按下S5用定时器以间隔1s显示0-F,按下S6用定时器以间隔2S显示0-F

#include<STC15F2K60S2.H>
unsigned int tt=0;
unsigned char tab[]={0XC0,0XF9,0XA4,0XB0,0X99,0X92,0X82,0XF8,0X80,0X90,0X88,0X83,0XC6,0XA1,0X86,0X8E};
unsigned char num=0;
unsigned char key;

void Delayms(int ms);
void Timer0Init(void);
void KEY_Scan(void);

void main(void)
{
	P2=0XA0;P0=0X00;P2=0X80;P0=0XFF;   //初始化程序
	P2=0XC0;P0=0X01;P2=0XFF;P0=0XFF;   //数码管初始化程序,打开第一个数码管
	//配置定时器0
	Timer0Init();
	ET0=1;
	EA=1;
	
	P0=0XC0;				//上电后显示0
	
	while(1)
	{
		KEY_Scan();
		P0=tab[num];
	}
}

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

void KEY_Scan(void)
{
	if(P33==0)			//S4
	{
		Delayms(5);
		if(P33==0)
		{
			key=4;
		}
		while(!P33);
	}
	else if(P32==0)			//S5
	{
		Delayms(5);
		if(P32==0)
		{
			key=5;
		}
		while(!P32);
	}
	else if(P31==0)			//S6
	{
		Delayms(5);
		if(P31==0)
		{
			key=6;
		}
		while(!P31);
	}
}

void Delayms(int ms)
{
	int i,j;
	for(i=0;i<ms;i++)
		for(j=845;j>0;j--);
}

void Timer0(void) interrupt 1
{
	if(key==4)						//S4按下时间隔500ms显示
	{
		if(tt>100)tt=0;			//避免超出范围
		tt++;
		if(tt==100)
		{
			tt=0;
			num++;
			if(num==16)num=0;
		}
	}
	else if(key==5)				//S5按下时间隔1s显示
	{
		if(tt>200)tt=0;			//避免超出范围
		tt++;
		if(tt==200)
		{
			tt=0;
			num++;
			if(num==16)num=0;
		}
	}
	else if(key==6)				//S6按下时间隔2s显示
	{
		if(tt>400)tt=0;			//避免超出范围
		tt++;
		if(tt==400)
		{
			tt=0;
			num++;
			if(num==16)num=0;
		}
	}
}

程序的大致思路是:初始化数码管打开第一个数码管后,由于我们要用到定时器0,故我们要初始化配置定时器0(利用下载器进行配置),然后由于用到了三个独立按键,我们编写判断是哪一个按键的函数,用key来区分按下不同按键所导致的结果,传递到定时器0中断函数中设置key不同情况的对应结果。
注:
1.tt变量需要用int型,因为char型的范围是0~255,400>255超出了范围程序会卡死。
2.由上面的定时器0中断函数可以看到,有三个地方设置了超出范围即归0,一开始尝试的时候没有判断是否超出范围,导致按完S6后,再按S4、S5时以及按完S5再按S4时因为超出范围程序可能会出现卡死。
3.选择按键方式的跳线帽跳在右边两针。

2.独立按键S4,S5使用外部中断分别控制数码管显示0-9正计时和倒计时

#include<STC15F2K60S2.H>
unsigned char tab[]={0XC0,0XF9,0XA4,0XB0,0X99,0X92,0X82,0XF8,0X80,0X90};
unsigned char seg;
char num=0;

void Delayms(int ms);
void main(void)
{
	P2=0XA0;P0=0X00;P2=0X80;P0=0XFF;   //初始化程序
	P2=0XC0;P0=0X01;P2=0XFF;P0=0XFF;   //数码管初始化程序,打开第一个数码管
	
	EX0=1;		//打开中断0
	EX1=1;		//打开中断1
	IT0=0;		//上升沿下降沿均可触发
	IT1=0;		//上升沿下降沿均可触发
	EA=1;			//打开总中断
	
	while(1)
	{
		if(seg==0)
		{
			P0=tab[num];
			num--;
			if(num==-1)num=9;
			Delayms(1000);
		}
		else if(seg==1)
		{
			P0=tab[num];
			num++;
			if(num==10)num=0;
			Delayms(1000);
		}
	}
}

void Delayms(int ms)
{
	int i,j;
	for(i=0;i<ms;i++)
		for(j=845;j>0;j--);
}

void exint0(void) interrupt 0
{
	if(P32==1)				//松开S4触发外部中断0
	{
		seg=0;
	}
}

void exint1(void) interrupt 2
{
	if(P33==1)				//松开S5触发外部中断1
	{
		seg=1;
	}
}

大致思路:初始化数码管,初始化配置外部中断0和外部中断1,按键S4,S5分别用外部中断1,0控制,按下和松开都会触发中断,但是我们只想要松开时候触发,因此使用了if函数,只有松开时才会赋值seg,根据触发中断引起的seg值分别指向数码管的正计时和倒计时。
注:
1.num值用于表示数组中的第几个数据,由于自减过程会出现负值,故此时不能再定义其为无符号型。
2.曾经尝试使用了for循环用于数码管倒计时正计时,但是此时会出现的情况是每次重新触发后,数码管需要继续走完此次计时才可以响应之后的计时,而选用if函数的话,数码管变化一次数值则判断一次,能够立即从所在位置开始正计时或者倒计时,响应更加及时。

3.再次尝试编写:数码管9秒倒计时,计时完成L1灯点亮

#include<STC15F2K60S2.H>
unsigned char tab[]={0X90,0X80,0XF8,0X82,0X92,0X99,0XB0,0XA4,0XF9,0XC0};
unsigned char num=0;
unsigned char tt=0;
unsigned char t=0;

void Timer0Init(void);

void main(void)
{
	//定时器0初始化配置
	Timer0Init();
	ET0=1;
	EA=1;
	
	P2=0XA0;P0=0X00;P2=0X80;P0=0XFF;   //初始化程序
	while(1)
	{
	}
}

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

void Timer0(void) interrupt 1
{
		tt++;
		if(tt==200)
		{
			tt=0;
			t++;
			P2=0XC0;P0=0X01;P2=0XE0;
			P0=tab[num];
			num++;
			if(num==10)num=0;
		}
		if(t==10)
		{
			P2=0X80;P0=0XFF;
			P00=0;
		}
		if(t==11)
		{
			t=t-10;
			P2=0X80;P0=0XFF;
			P00=1;
		}
}

大致思路:此程序在上次课后练习尝试编写程序的基础上,使用了定时器来控制间隔为1s。定时器程序每次5ms,那么200次就是1s,我们只需要让每200次,数码管变化一次,用t记录变化次数,变化10次也即倒计时结束时L1点亮,变化11次时也即重新开始倒计时时L1熄灭且t变量归1。关于数码管和LED的初始化程序,可以参考后来一篇有关初始化程序的博客。
4.再次尝试编写:数码管99秒倒计时程序,用定时器延迟。

#include<STC15F2K60S2.H>
unsigned char tab[]={0XC0,0XF9,0XA4,0XB0,0X99,0X92,0X82,0XF8,0X80,0X90};
unsigned char num=99;
unsigned char tt=0;

void Delayms(int ms);
void Timer0Init(void);

void main(void)
{
	P2=0XA0;P0=0X00;P2=0X80;P0=0XFF;			//关闭蜂鸣器继电器LED
	//初始化配置定时器0
	Timer0Init();
	ET0=1;
	EA=1;
	
	while(1)
	{
		P2=0XC0;				//打开数码管位选537锁存器
		P0=0X01;				//选中第一个数码管
		P2=0XE0;				//打开数码管段选537锁存器
		P0=tab[num/10];	//数码管显示十位的数字
		Delayms(1);
		
		P2=0XC0;				//打开数码管位选537锁存器
		P0=0X02;				//选中第二个数码管
		P2=0XE0;				//打开数码管段选537锁存器
		P0=tab[num%10];	//数码管显示个位的数字
		Delayms(1);
	}
}

void Delayms(int ms)
{
	int i,j;
	for(i=0;i<ms;i++)
		for(j=845;j>0;j--);
}

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

void Timer0(void) interrupt 1
{
	tt++;
	if(tt==200)
	{
		tt=0;
		if(num==0)num=100;
		num--;
	}
}

此程序实现了用定时器0来进行数码管计时间隔1s的延时,而扫描的1ms仍使用了软件延时。
大致思路:我们可以看到原来的程序是在主函数中,计数循环次数,循环500次即1s,操作使num自减,而此程序是在定时器中定时1s,定时到了num自减。其核心思想都是使num每1s自减1。

  • 10
    点赞
  • 22
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值