STC89C51单片机定时器扫描按键

思路:

问题:机械按键在按下的过程中会出现抖动的现象,导致导致单片机多判或者误判。

解决:方法一 延时 但会大量占用单片机资源。方法二 利用定时器代替延时,每经过一定的时间进入中断函数扫描按键状态减少单片机资源的占用。

静态局部变量使用static修饰符定义,即使在声明时未赋初值,编译器也会把它初始化为0。且静态局部变量存储于进程的全局数据区,即使函数返回,它的值也会保持不变。

按键单击

按键模块

#include <REGX52.H>
sbit k1=P3^1;
sbit k2=P3^0;
sbit k3=P3^2;
sbit k4=P3^3;
unsigned char temp;
unsigned char key()
{
	unsigned char keynum=0;
	if(k1==0) keynum=1;
	if(k2==0) keynum=2;
	if(k3==0) keynum=3;
	if(k4==0) keynum=4;
	return keynum;
}
/****
	*@介绍		用于定时器扫描函数,达到要求置位相应的键码
	*@参数		无
	*@返回值	无
	*/
void  key_loop()
{
	static unsigned char now,last;
	last=now;
	now=key();
	if(last==1&&now==0)
	{
		temp=1;
	}
	if(last==2&&now==0)
	{
		temp=2;
	}
	if(last==3&&now==0)
	{
		temp=3;
	}
	if(last==4&&now==0)
	{
		temp=4;
	}
}
/****
	*@介绍		返回键码,并将键码置零
	*@参数		无
	*@返回值	key_temp
	*/
unsigned char key_return()
{
	static unsigned char key_temp;
	key_temp=temp;
	temp=0;                   //定义一个新变量,使键值置零,不会导致重复操作
	return key_temp;
}

定时器T0模块

#include <REGX52.H>
void Timer0_Init()//定时器T0初始化
{
	TMOD&=0XF0;
	TMOD|=0X01;
	TL0 = (65536-1000)%256;		//设置定时初值   1ms
	TH0 = (65536-1000)/256;		//设置定时初值
	TR0=1;
	TF0=0;
    EA=1;
    ET0=1;
}
/*
void Timer0() interrupt 1
{
	int count;
	TL0 = (65536-1000)%256;		//设置定时初值
	TH0 = (65536-1000)/256;		//设置定时初值
	if(count++>20)//每20ms调用一次
	{
		key_loop();
		count=0;
	}	
}
*/

主程序

unsigned char key_temp=0;
void main()
{
	Timer0_Init();
	while(1)
	{
		key_temp=key_return();
	}
}
void Timer0() interrupt 1
{
	int count;
	TL0 = (65536-1000)%256;		//设置定时初值
	TH0 = (65536-1000)/256;		//设置定时初值
	if(count++>20)//每20ms调用一次
	{
		key_loop();
		count=0;
	}	
}

按键单击和双击

按键模块

#include <REGX52.H>
sbit k1=P3^1;
sbit k2=P3^0;
sbit k3=P3^2;
sbit k4=P3^3;
unsigned char temp,count;
char key_flag;
unsigned char key()
{
	unsigned char keynum=0;
	if(k1==0) keynum=1;
	if(k2==0) keynum=2;
	if(k3==0) keynum=3;
	if(k4==0) keynum=4;
	return keynum;
}
/****
	*@介绍		用于定时器扫描函数,达到要求置位相应的键码
	*@参数		无
	*@返回值	无
	*/
void  key_loop()
{
	static unsigned char now,last;
	last=now;
	now=key();
	if(last==1&&now==0)
	{
		key_flag++;//按键按下,标志位自加
	}
	if(last==2&&now==0)
	{
		temp=2;
	}
	if(last==3&&now==0)
	{
		temp=3;
	}
	if(last==4&&now==0)
	{
		temp=4;
	}
	//
	if(count<=20&&key_flag==2)//当标志位为2且两次按键间隔少于400ms,表示为连击
	{
		count=0;
		temp=10;
		key_flag=0;
	}
	if(count>=20&&key_flag==1)//当标志位为1且两次按键间隔大于400ms,表示为单击
	{
		count=0;
		temp=1;
		key_flag=0;
	}
}
/****
	*@介绍		返回键码,并将键码置零
	*@参数		无
	*@返回值	key_temp
	*/
unsigned char key_return()
{
	static unsigned char key_temp;
	key_temp=temp;
	temp=0;
	return key_temp;
}

主程序

#include <REGX52.H>
#include "NIXIE.H"
#include "key.H"
#include "TIMER0.H"
#include "DELAY.H"
char key_temp;//key_temp用于承接键值
extern unsigned char count;//为全局变量,当key_flag为1时开始计数,用于判断按键是否连击
extern char key_flag;//为全局变量,记录按键按下的次数
void main()
{
	Timer0_Init();
	while(1)
	{
		key_temp=key_return();
	}
}
/****
	*@介绍		定时器1,用于定时器扫描按键和单击双击的计时
	*@参数		
	*@返回值
	*/
void Timer0() interrupt 1
{
	
	TL0 = (65536-20000)%256;		//设置定时初值
	TH0 = (65536-20000)/256;		//设置定时初值
	key_loop();
	if(key_flag==1)
	{
		count++;
	}
	
}

按键的单击和连击

按键模块

#include <REGX52.H>
sbit k1=P3^1;
sbit k2=P3^0;
sbit k3=P3^2;
sbit k4=P3^3;
unsigned char temp,count;
bit key_flag;
unsigned char key()
{
	unsigned char keynum=0;
	if(k1==0) {keynum=1;key_flag=1;}
	if(k2==0) {keynum=2;key_flag=1;}
	if(k3==0) keynum=3;
	if(k4==0) keynum=4;
	return keynum;
}
/****
	*@介绍		用于定时器扫描函数,达到要求置位相应的键码
	*@参数		无
	*@返回值	无
	*/
void  key_loop()
{
	static unsigned char now,last;
	last=now;
	now=key();
	if(count>=50&&last==1)//计时1000ms
	{
		temp=10;
	}
	if(count>=50&&last==2)//计时1000ms
	{
		temp=20;
	}
	if(last==1&&now==0)
	{
		key_flag=0;
		count=0;
		temp=1;
	}
	if(last==2&&now==0)
	{
		key_flag=0;
		count=0;
		temp=2;
	}
	if(last==3&&now==0)
	{
		temp=3;
	}
	if(last==4&&now==0)
	{
		temp=4;
	}
}
/****
	*@介绍		返回键码,并将键码置零
	*@参数		无
	*@返回值	key_temp
	*/
unsigned char key_return()
{
	static unsigned char key_temp;
	key_temp=temp;
	temp=0;
	return key_temp;
}

主程序

#include <REGX52.H>
#include "NIXIE.H"
#include "key.H"
#include "TIMER0.H"
#include "DELAY.H"
unsigned char key_temp,num;//key_temp承接键值
extern bit key_flag;//按键按下后置位为1,定时器开始计时
extern unsigned char count;//用于定时器的计数,当大于一定值时,判定为长按否则为短按
unsigned char count1;//用于定时,长按时使num按一定的时间间隔连续加减
void show()
{
	display(7,num/100);
	display(6,num/10%10);
	display(5,num%10);
}
void main()
{
	Timer0_Init();
	while(1)
	{
		key_temp=key_return();
		if(key_temp==1)
		{
			num++;
		}
		if(key_temp==10&&count1%20==0)
		{
			count1=0;
			num++;
		}
		if(key_temp==2)
		{
			num--;
		}
		if(key_temp==20&&count1%20==0)
		{
			count1=0;
			num--;
		}
		if(key_temp==3)
		{
			num=0;
		}
		show();
	}
}
void Timer0() interrupt 1
{
	TL0 = (65536-20000)%256;		//设置定时初值
	TH0 = (65536-20000)/256;		//设置定时初值
	key_loop();
	if(key_flag==1)
	{
		count++;count1++;
	}
		


}

纯粹学习笔记

  • 1
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
单片机课程设计报告 单 片 机 秒 表 系 统 课 程 设 计 班级: 课程名称: 秒表设计 成员: 实训地点:北校机房 实训时间:6月4日至6月15日 目录 1课程设计的目的和任务 1.1 单片机秒表课程设计的概述 1.2课程设计思路及描述 1.3 课程设计任务和要求 2硬件与软件的设计流程 2.1系统硬件方案设计 2.2所需元器件 3 程序编写流程及课程设计效果 3.1源程序及注释 3.2原理图分析 3.3课程设计效果 4 心得体会 1. 课程设计的目的和任务 1.1单片机秒表课程设计的概述 一、课程设计题目 秒表系统设计——用STC89C51设计一个4位LED数码显示"秒表",显示时间为000.0~9分 59.9秒,每10毫秒自动加一,每1000毫秒自动加一秒。 二、增加功能 增加一个"复位"按键(即清零),一个"暂停"和"开始"按键。 三、课程设计的难点 单片机电子秒表需要解决几个主要问题,一是有关单片机定时器的使用;二是如何实 现LED的动态扫描显示;三是如何对键盘输入进行编程;四是如何进行安装调试。 四、课程设计内容提要 本课程利用单片机定时器/计数器定时和记数的原理,结合集成电路芯片8051、LE D数码管以及课程箱上的按键来设计计时器。将软、硬件有机地结合起来,使得系统能够 正确地进行计时,数码管能够正确地显示时间。其中本课程设计有三个开关按键:其中 key1按键按下去时开始计时,即秒表开始键,key2按键按下去时数码管清零,复位为"0 0.00". key3按键按下去时数码管暂停。 五、课程设计的意义 1) 通过本次课程设计加深对单片机课程的全面认识复习和掌握,对单片机课程的应用进 一步的了解。 2) 掌握定时器、外部中断的设置和编程原理。 3) 通过此次课程设计能够将单片机软硬件结合起来,对程序进行编辑,校验。 4) 该课程通过单片机定时器/计数器定时和计数原理,设计简单的计时器系统,拥有正 确的计时、暂停、清零,并同时可以用数码管显示,在现实生活中应用广泛,具有 现实意义 1.2课程设计思路及描述 该课程设计要求进行计时并在数码管上显示时间,则可利用MCS- 51系列单片机的芯片AT89C51的P3.2,P3.3,RST作为按键的入口;定时器T1作为每0.1秒 加一的定时器。其中"开始"按键当开关由上向下拨时开始计时,此时若再拨"暂停"按键 则数码管暂停;"清零"按键当开关由上向下拨时数码管清零,此时若再拨"开始"按键则 又可重新开始计时。 1.3 课程设计任务和要求 1.3.1 设计指标 。 了解8051芯片的的工作原理和工作方式 ,使用该芯片对LED数码管进行显示控制,实现用单片机的端口控制数码管,显示分、秒 ,并能用按钮实现秒表起动、停止、9分59.9秒、清零等功能,精确到0.1秒。 要求选用定时器的工作方式,画出使用单片机控制LED数码管显示的电路图,并实现 其硬件电路,并编程完成软件部分,最后调试秒表起动、停止、清零等功能。 2.软件与硬件设计 2.1系统硬件方案设计 单片机应用系统由硬件系统和软件系统两部分组成。硬件系统是指单片机以及扩展的 存储器、I\O接口、外围扩展的功能芯片以及接口电路。软件系统包括监控程序和各种应 用程序。 在单片机应用系统中,单片机是整个系统的核心,对整个系统的信息输入、处理、信 息输出进行控制。与单片机配套的有相应的复位电路、时钟电路以及扩展的存储器和I\ O接口,使单片机应用系统能够运行。 在一个单片机应用系统中,往往都会输入信息和显示信息,这就涉及键盘和显示器 。在单片机应用系统中,一般都根据系统的要求配置相应的键盘和显示器。配置键盘和 显示器一般都没有统一的规定,有的系统功能复杂,需输入的信息和显示的信息量大, 配置的键盘和显示器功能相对强大,而有些系统输入/输出的信息少,这时可能用几个按 键和几个LED指示灯就可以进行处理了。在单片机应用系统在中配置的键盘可以是独立键 盘,也可能是矩阵键盘。 2.2 所需原器件 "名称 "数量 " "四位数码管 "1个 " "200欧电阻 "13个 " "1千欧电阻 "4个 " "开关 "3个 " "电容 "3个 " "晶振 "1个 " "三极管 "4个 " "AT89C51 "1个 " "导线 "若干 " AT89C51的接口连接示意图 四位数码管的接口连接示意图 共阴级数码管编码 主程序流程图: 子程序流程图 3.程序编写的流程及课程设计效果 3.1 源程序及注释 ORG 0000H AJMP TOU ORG 000BH 外部中断0入口地址 LJMP MIAO ORG 0003H 外部中断0入口地址 LJMP KG ORG 0030H 定时器中0断入口地址 TOU:MOV b,#02H MOV r3,#00H MOV
以下是一个使用C语言编写的九齐单片机矩阵键盘扫描程序示例: ```c #include <reg52.h> // 定义矩阵键盘行和列的引脚 sbit ROW1 = P1^0; sbit ROW2 = P1^1; sbit ROW3 = P1^2; sbit ROW4 = P1^3; sbit COL1 = P1^4; sbit COL2 = P1^5; sbit COL3 = P1^6; sbit COL4 = P1^7; // 定义键盘按键的状态 #define KEY_PRESSED 0 // 矩阵键盘按键值 unsigned char keyMap[4][4] = { {'1', '2', '3', 'A'}, {'4', '5', '6', 'B'}, {'7', '8', '9', 'C'}, {'*', '0', '#', 'D'} }; // 延时函数 void delay(unsigned int ms) { unsigned int i, j; for(i = 0; i < ms; i++) { for(j = 0; j < 120; j++) { } } } // 获取按键值 unsigned char getKeyValue() { unsigned char row, col; // 设置列引脚为高电平 COL1 = 1; COL2 = 1; COL3 = 1; COL4 = 1; // 检测行引脚的状态 row = (ROW1 << 0) | (ROW2 << 1) | (ROW3 << 2) | (ROW4 << 3); // 判断按下的是哪一列按键 if(row != 0x0F) { delay(10); // 延时消抖 if(row != 0x0F) { // 检测列引脚的状态 COL1 = 0; COL2 = 1; COL3 = 1; COL4 = 1; if(row == 0x07) col = 0; if(row == 0x0B) col = 1; if(row == 0x0D) col = 2; if(row == 0x0E) col = 3; // 返回按键值 return keyMap[row][col]; } } return 0; // 没有按键按下 } // 主函数 void main() { unsigned char key; while(1) { key = getKeyValue(); // 判断是否有按键按下 if(key != 0) { // 执行相应的操作,例如输出按键值到LCD屏幕或者进行其他处理 // 这里只简单地输出按键值到串口 SBUF = key; while(!TI); // 等待发送完成 TI = 0; // 清除发送中断标志位 } } } ``` 这个程序通过扫描九齐单片机矩阵键盘的行和列,从而获取按键值。你可以根据自己的需要修改程序中的部分代码,例如按键值的处理方式和输出方式。注意,程序中的延时函数只是简单的延时,你可能需要根据具体情况进行调整。同时,为了使程序能够正确运行,你需要根据实际硬件连接情况修改引脚定义。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值