51单片机独立按键控制流水灯方向及状态(利用中断)

前言

在此篇文章中,默认读者已经掌握 51单片机定时器中断初始化以及使用 独立按键的读取等的基本使用方法,以下内容仅为对此的应用,若还未掌握,则可以在学习过后(可以参考B站江协视频)再来学习本篇文章。
文末附有主函数源码以及讲解

先展示结果

51单片机独立按键控制流水灯方向及状态(利用中断)

对现象进行简单说明

再次使用上篇文章内容说明现象,四个独立按键从左至右依次为S1,S2,S3,S4
在简单的流水灯基础上,S1使流水灯向左,S2使流水灯向右,S3使流水灯停止,S4使流水灯继续暂停前方向

观前提示

在芯片中,所有的逻辑判断与赋值包括之后使用的goto语句跳转运行时间都是极快的,若你在阅读内容的过程中出现疑惑,可以好好的想想这句话,或许能帮到你

利用中断

首先,流水灯肯定需要某种时间间隔来实现,以目前的知识,仅有Delay()函数和定时器中断。 而本次打算使用按键来改变流水灯的方向及状态,可在使用Delay()函数时,芯片会被占用,无法及时响应对按键的读取和处理(当按下并松开按键完成一次点击时,若函数在Delay函数中延时则会使程序忽略此次输入)。 而使用中断则可以在主函数的循环中不断读取按键状态,转而在中断函数中实现流水灯,以及判断按键来实现目的结果。

goto函数

程序中使用的goto函数可能某些读者并不常用,故在此做简单补充,若已掌握可跳过此部分。

goto label;       label: xxx;

…   ​​​​​​​           或     …

label: xxx;         goto label;

其中label只是一个标记,其可以是任意一个有效的标识符,当程序执行到goto语句时,它会立即跳转到label所指定的位置,并从该位置开始执行代码。

以下为main函数部分

#include <REGX52.H>
#include <INTRINS.H>
#include "Timer0.h"
#include "Key.h"
unsigned char KeyNum,LEDMode=1;
void main()
{
	Timer0_Init();
	P2=0XFE;
	while(1)
	{
		KeyNum=Key();
		switch(KeyNum)
		{
			case 1:
				LEDMode=0;break;
			case 2:
				LEDMode=1;break;
			case 3:
				LEDMode=2;break;
			case 4:
				LEDMode=3;break;
			default:
				break;
		}
	}
}

void T0Routine() interrupt 1
{
	static unsigned char Pre,T0Count=0;
	T0Count++;
	TL0 = 0x00;				//设置定时初始值
	TH0 = 0x4C;				//设置定时初始值
	if(T0Count>=10)
	{
		T0Count=0;
		a:switch(LEDMode)
		{
			case 0:
				P2=_cror_(P2,1);Pre=LEDMode;break;
			case 1:
				P2=_crol_(P2,1);Pre=LEDMode;break;
			case 2:
				break;
			case 3:
				LEDMode=Pre;goto a;
		}
	
	}


}

内容讲解

经过初始化和点亮第一颗LED灯,就进入了主函数(声明的全局变量会在之后讲解)

main函数
1:首先读取独立按键,相对应将KeyNum附为1、2、3、4,若没有按按键,Key()函数的返回值为零
2:之后进入switch语句,KeyNum相对应给LEDMode四种情况。若未按按键,则KeyNum为0,故退出switch语句又重新进入while(1)的循环

中断函数
正式介绍前需先讲解一下_crol_和_cror_函数(l和r为left和right)。 它们都需要两个参数,第一个为被操作对象,第二个为位移动的位数。 在本文中分别为 P2 和 1 ,即将P2向左(右)位移一位。 其与<<和>>的区别我将用一个例子解释。 当P2=1000 0000时, 若使用_crol_(向左)时,其值会变为0000 0001,而若使用<<时,其值会变为0000 0000。更详细的讲解读者可自行学习,本文不过多解释

本人的51单片机频率为11.0952,则给定时器赋赋值,以及if(T0Count>=10)结果为每500ms进入一次中断。   进入中断后判断LEDMode的值
按S1时 LEDMode为0,对应结果则P2右移,即向0(亮灯位)向低位移动,在本人的板子上表现为左移(若您的板子与我相反可以自行做简单调整)。
按S2时 与上同理,故略过。
按S3时 LEDMode为2,即执行空语句,即P2不进行位移,在单片机上表示为停止
按S4时 LEDMode为3,将Pre的值(即暂停前的LEDMode)赋给LEDMode,并通过goto语句再次回到switch()语句前(使用goto语句而不是退出等待下一次中断,可使当流水灯运行时按下S4并不改变流水灯的原有频率)

后记

以上即为所有讲解,因作者水平有限和时间原因,有些部分可能讲解的并不清晰,若有疑问可私信问我,若需要源码,也可将全部源码发送。

51单片机中,通过独立按键控制流水灯通常涉及到以下几个步骤: 1. **硬件连接**: - 将按键接到单片机的输入端口,如P0、P1等,作为输入中断源。 - 使用8个LED或数码管连接到单片机的输出端口,形成流水灯效果。 2. **初始化**: - 初始化输入端口为查询模式,以便检测按键状态变化。 - 对输出端口设置初始状态,如将所有LED关掉。 3. **主循环**: - 循环读取按键的状态,如果按键按下,则改变输出端口的一个LED状态(比如顺时针移动一位),然后释放按键。 - 如果按键松开并且上一次按键操作已经完成(例如,等待一定延时),则恢复流水灯状态(顺向或逆向移动)。 4. **中断处理**: - 当按键被按下时,会触发中断,此时进入中断服务程序(ISR)。检查按键状态,记录按下位置并退出中断。 5. **中间返回代码示例**: ```c #include <reg52.h> //假设是AT89S51系列 // 定义按键和LED的端口地址 sbit keyA = P2^0; // 按键A sbit led1 = P1^0; // LED1 sbit led2 = P1^1; // LED2 ... 等待8个LED void delay(unsigned int time) { // 添加适当延迟函数 } void interrupt() __attribute__((interrupt("KEYB"))) { if (keyA == 1) { // 检测按键A是否按下 led1 = !led1; // 切换LED1状态 // 更新其他LED状态... keyA = 0; // 记录按键已按,退出中断 } } void main() { TRIS_P1 = 0xFF; // 输出模式,所有LED都是输出 TRIS_P2 = 0x00; // 输入模式,按键A是输入 while(1) { if(keyA == 0) { // 非常简单地判断按键是否松开 for(int i=0; i<8; i++) { // 逐位切换流水灯 led1 = led2; led2 = led3; // 更改下一个LED // ... led7 = led1; // 回到第一个LED delay(100); // 延迟一段时间再继续 } } } }
评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值