江科大7_2按键控制LED流水灯模式&定时器时钟

目录

一、配置TMOD寄存器工作模式

二、配置TCON控制寄存器

三、配置TH0,TH1

四、测试一下中断:

效果:

注意:

 

五、另一种流水灯的实现(K1可改变流水方向):

代码部分

Key.c

Key.h

main.c

仿真

遇到的问题:

效果:

六、定时器时钟

代码:

效果:

 

一、配置TMOD寄存器工作模式

我们选择16位定时器(0000 0001)

9227d28dcea645c8be03344dad862f6c.png

注:TMOD为不可位寻址,即不能位赋值,不能像P2_1=0;

二、配置TCON控制寄存器

可以位寻址:我们单独赋值

d051c07e879a4ca58159872f44aa3001.png

TF0=0;

三、配置TH0,TH1

配置我们想要定时一毫秒(TH0,TL0高低位赋值)

a6febee1b75f43b7a8c97e34c91e25f8.png

十进制取值:123/100=1   高位         123%100=23 低位

底下的十六进制类似

4801e886d23942bf9750d034acccf120.png

TH0=64535/256;
TH1=64535%256;

配置中断:

739323e5372141bb81c7d22087c8056d.png

ET0=1;
EA=1;
PT0=0;

中断子函数

这是定时器到了要跳转执行的函数(主函数不用调用自动跳转)

参考:

f9cbdf730dda4cddb5f9cd21956d25f6.png

四、测试一下中断:

我让寄存器计数每过2S,P2_1亮灭一次

#include <REGX52.H>

void Timer0_Init()
{
	TMOD=0x01;
	//TCON
	TF0=0; //先清零,防止一开始就产生中断
	TR0=1;
	//TH0,TL0
	TH0=64535/256;
	TL0=64535%256;
	//中断
	ET0=1;
	EA=1;
	PT0=0;
}

void main()
{
	Timer0_Init();
	while(1)
	{
		
	}
}

unsigned int T0Count;
//中断子函数
void Timer0_Routine() interrupt 1
{
	TH0=64535/256;//移到这边防止第二次计数的时候从0开始
	TL0=64535%256;
	T0Count++;
	if(T0Count>=1000)//1000ms
	{
		T0Count=0;
		P2_0=~P2_0;
	}
	
}

效果:

7_2计时器中断测试

 

注意:

其实在TMOD寄存器赋值是有问题的:因为他是不可位寻址的,如果我们的定时器1被赋值后,我们再用

TMOD=0x01;

就把定时器清零了。

82ee33870c924bb699a9617532dc9f07.png

解决:我们用与或赋值法

TMOD=TMOD&0xF0; // 把TMOD的低四位清零,高四位保持不变
TMOD=TMOD|0x01; // 把TMOD的最低位 置1,高四位不变

举例:比如TMOD原为1010 0011

1010 0011 & 1111 0000 ==>1010 0000

1010 0000 | 0000 0001 ==> 1010 0001 

这样就配置定时器0就不会影响到定时器1了

 

然后其实我们在TH0,TF0的配置中会有一微秒的差距(具体解释见UP主视频)

解决:我们用STC-ISP软件生成,但他不能配置中断,我们得在复制来的代码加上中断的配置;

f62a2265499a4671be5f277729015b99.png

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

然后我们就可以将上方(就是定时器0的初始函数)模块化了:

这是定时器一秒的模板:需要可以直接复制修改

//中断子函数
void Timer0_Routine() interrupt 1
{
	static unsigned int T0Count;
	TL0 = 0x18;		//设置定时初始值
	TH0 = 0xFC;		//设置定时初始值
	T0Count++;
	if(T0Count>=1000)//1000ms
	{
		T0Count=0;
		P2_0=~P2_0;
	}
}

 

 

五、另一种流水灯的实现(K1可改变流水方向):

我们需要引入一个软件自带库

#include <INTRINS.H>,他的_crol_和_cror函数可以左移右移,且不会溢出。

代码部分

我们还是采用模块化编程;

c3c7f71d850a49e6ae74ad19ba794939.png

之前封装过的直接复制就不说了

Key.c

#include <REGX52.H>
#include "Delay.h"

/**
  * @brief  获取独立按键键码
  * @param  无
  * @retval  按下按键的键码,范围:0-4;无按键按下返回0
  */
unsigned char Key()
{
	unsigned char KeyNumber=0;
	
	// Delay消抖 
	if(P3_1==0){Delay(20);while(P3_1==0);Delay(20);KeyNumber=1;}
	if(P3_0==0){Delay(20);while(P3_0==0);Delay(20);KeyNumber=2;}
	if(P3_2==0){Delay(20);while(P3_2==0);Delay(20);KeyNumber=3;}
	if(P3_3==0){Delay(20);while(P3_3==0);Delay(20);KeyNumber=4;}
	
	return KeyNumber;
}

Key.h

#ifndef __Key_H__
#define __Key_H__

unsigned char Key();

#endif

main.c

#include <REGX52.H>
#include "Timer0.h"
#include "Key.h"
#include <INTRINS.H>

unsigned char KeyNum,LEDMode;

void main()
{
	P2=0xFE;
	Timer0Init();
	while(1)
	{
		KeyNum=Key();
		if(KeyNum)
		{
			if(KeyNum==1)
			{
				LEDMode++;
				if(LEDMode>=2)LEDMode=0;
			}
		}
	}
}


//中断子函数
void Timer0_Routine() interrupt 1
{
	static unsigned int T0Count;
	TL0 = 0x18;		//设置定时初始值
	TH0 = 0xFC;		//设置定时初始值
	T0Count++;
	if(T0Count>=500)
	{
		T0Count=0;
		if(LEDMode==0)
			P2=_crol_(P2,1);
		if(LEDMode==1)
			P2=_cror_(P2,1);
	}
}

仿真

遇到的问题:

仿真部分我又踩了大坑,无论怎么试就是只有第一个灯(P2_0)亮灭一下。代码检查了N遍都没发现问题。因为上方中断小测试的仿真都是有用的,我一直以为是库函数的问题,百度了一堆也没解决。然后最后终于看到说可能LED灯(二极管)他的电压太大承受不住,我就在P2每个灯加一个100R的电阻,结果真的可以了,简直是浪费了我好多时间。

效果:

一开始P2值为1111 1110 仅最低位(P2_0)亮,移位==>1111 1101,在我的仿真图中就是向下移动。要是我按了K1,P2右移==>1111 1110 在我的仿真图中就是向上移动。再按一下就又向下移动……

7-2流水灯

 

六、定时器时钟

代码:

LCD第一行显示clock,第二行第三个和第六个显示“:”

while循环内不断更新时间;

定时器中每隔一秒(1000ms) Sec+1   

  Sec==>60==> Min+1

  Min==>60==>Hour+1

Hour==>24==>Hour=0

#include <REGX52.H>
#include "LCD1602.h"
#include "Timer0.h"

unsigned char Sec,Min,Hour;

void main()
{
	LCD_Init();
	Timer0Init();
	
	LCD_ShowString(1,1,"clock:");
	LCD_ShowString(2,3,":  :");
	while(1)
	{
		LCD_ShowNum(2,1,Hour,2);
		LCD_ShowNum(2,4,Min,2);
		LCD_ShowNum(2,7,Sec,2);
	}
}

void Timer0_Routine() interrupt 1
{
	static unsigned int T0Count;
	TL0 = 0x18;		//设置定时初始值
	TH0 = 0xFC;		//设置定时初始值
	T0Count++;
	if(T0Count>=1000)//1000ms
	{
		T0Count=0;
		Sec++;
		if(Sec>=60)
		{
			Sec=0;
			Min++;
			if(Min>=60)
			{
				Min=0;
				Hour++;
				if(Hour>=24)
				{
					Hour=0;
				}
			}
		}
	}
}

效果:

为了方便演示我为时分秒赋初始值

Sec=55,Min=59;Hour=23;

7-2定时器时钟

 

 

  • 12
    点赞
  • 19
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值