单片机第一季:零基础6——按键

这篇具有很好参考价值的文章主要介绍了单片机第一季:零基础6——按键。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

目录

1,独立按键

2,矩阵按键


(注意:文章中的代码仅供参考学习,实际使用时要根据需要修改)

1,独立按键

按键管脚两端距离长的表示默认是导通状态,距离短的默认是断开状态, 如果按键按下,初始导通状态变为断开,初始断开状态变为导通。

由于机械点的弹性作用,按键开关在闭合时不会马上稳定的接通,在断开时也不会一下子断开,因而在闭合和断开的瞬间均伴随着一连串的抖动。抖动时间的长短由按键的机械特性决定的,一般为5ms 到10ms。按键稳定闭合时间的长短则由操作人员的按键动作决定的,一般为零点几秒至数秒。按键抖动会引起按键被误读多次。为了确保CPU 对按键的一次闭合仅作一次处理,必须进行消抖。

按键消抖有两种方式,一种是硬件消抖,另一种是软件消抖。为了使电路更加简单,通常采用软件消抖。我们开发板也是采用软件消抖,一般来说一个简单的按键消抖就是先读取按键的状态,如果得到按键按下之后,延时10ms,再次读取按键的状态,如果按键还是按下状态,那么说明按键已经按下。

单片机常用的软件去抖动方法:

1,先设置IO 口为高电平(由于开发板IO 都有上拉电阻,所以默认IO 为高电平)。

2,读取IO 口电平确认是否有按键按下。

3,如有IO 电平为低电平后,延时几个毫秒。

4,再读取该IO 电平,如果仍然为低电平,说明按键按下。

5,执行按键控制程序。

单片机第一季:零基础6——按键,单片机,嵌入式硬件

独立按键电路构成是由各个按键的一个管脚连接在一起接地,按键其他引脚分别接到单片机IO 口。

我们知道单片机的IO 口既可作为输出也可作为输入使用,当检测按键时用的是它的输入功能,独立按键的一端接地, 另一端与单片机的I/O 口相连,开始时先给该IO 口赋一高电平,然后让单片机不断地检测该I/O 口是否变为低电平,当按键闭合时,即相当于该I/O 口通过按键与地相连,变成低电平,程序一旦检测到I/O 口变为低电平则说明按键被按下,然后执行相应的指令。

 CPU如何处理按键
(1)轮询式。所谓轮询式就是CPU不断的隔很小时间去查看有没有按键被按下,如果按下就处理按键,如果没按下就过一会再来查看。(按键什么时候被按下CPU是无法预知的)
(2)中断式

轮询式处理按键代码:

#include <reg51.h>

// 当前要处理的是K1,对应P1.0IO口,操控的LED是LED1,对应P0.0

/*********************变量定义************************************/
sbit key1 = P1^0;
sbit key2 = P1^1;
sbit key8 = P1^7;



// 独立数码管的段码表
unsigned char val[16] = {0xc0, 0xf9, 0xa4, 0xb0, 0x99, 0x92, 0x82, 0xf8, 0x80, 0x90, 0x88, 0x83, 0xc6, 0xa1, 0x86, 0x8e};



/*********************************** 函数声明 ***********************/
void AddDisplay(void);
void delay(void);
void delay10ms(void);

/******************************全局变量定义*************************/
unsigned char dnum = 0;

void main(void)
{
	unsigned char flag = 0;		// 默认状态等于0

	while (1)
	{
		if (key1 == 0)
		{
			// 发现1次低电平,有可能是按键按下,也有可能是抖动,软件消抖
			delay10ms();
			if (key1 == 0)
			{
				 // 10ms后还是低电平,说明真的是按键按下了,不是抖动
				 // 这里说明发现了一个按下事件
				//flag = 1;
				if (flag == 0)
				{
					AddDisplay();
					flag = 1;
				}
			}
		}
		else
		{
			// 电平 == 1
			delay10ms();
			if (key1 == 1)
			{
				// 说明弹起了
				if (flag == 1)
				{
					//AddDisplay();
					flag = 0;
				}
			}
		}

		delay(); 
	}
}


// 该函数将num数字送到独立数码管去显示
void AddDisplay(void)
{

	dnum = dnum + 1;
	if (dnum > 15)
	{
		dnum = 0;
	}

	P0 = val[dnum];
}

// 延时函数
void delay(void)
{
	unsigned char i, j;

	for (i=0; i<100; i++)
		for (j=0; j<200; j++);
}

void delay10ms(void)   //误差 0us
{
    unsigned char a,b,c;
    for(c=5;c>0;c--)
        for(b=4;b>0;b--)
            for(a=248;a>0;a--);
}

中断式处理按键源代码:

#include <reg51.h>

// 当前要处理的是K1,对应P1.0IO口,操控的LED是LED1,对应P0.0

/*********************变量定义************************************/
sbit key1 = P1^0;
sbit key2 = P1^1;

sbit key4 = P3^4;

sbit led1 = P2^7;
sbit led2 = P2^6;


// 独立数码管的段码表
unsigned char val[16] = {0xc0, 0xf9, 0xa4, 0xb0, 0x99, 0x92, 0x82, 0xf8, 0x80, 0x90, 0x88, 0x83, 0xc6, 0xa1, 0x86, 0x8e};



/*********************************** 函数声明 ***********************/
void delay10ms(void);

/*************中断处理程序*************/

void Eint0Isr() interrupt 0
{
    // 任务2:按键监测及led控制
	// 进入中断后LED状态转换。原来亮则灭,原来灭就亮
	if (led1 == 1)
		led1 = 0;
	else
		led1 = 1;
}


void main(void)
{
	unsigned char i = 0;

	// 中断初始化
	IT0 = 1;
	EX0 = 1;
	EA = 1;

	// 主线任务
	while (1)
	{
		// 任务1:数码管显示
		for (i=0; i<16; i++)
		{
			P0 = val[i];
			delay10ms();
		}
	}
}



// 延时函数
void delay10ms(void)   //误差 0us
{
    unsigned char a,b,c;
    for(c=5;c>0;c--)
        for(b=4;b>0;b--)
            for(a=248;a>0;a--);
}

上述代码中主线任务是使用数码显示0-F,利用中断功能去检测按键是否按下,当检测到按键按下时中断主线任务去执行中断程序点亮或熄灭LED灯。

中断的思路:
(1)“主线任务”为常规任务,默认运行;
(2)中断发生后CPU暂停主线任务转去处理中断任务,完成后再回来接着执行主线任务;

中断的意义:
(1)中断处理能力让CPU可以全力处理主线任务而不用担心会错过中断任务(举例:看电影和收快递);
(2)中断式比轮询式更适合处理异步事件,效率更高;
(3)中断中处理的事件的特点是:无法预料、处理时间短、响应要求急。

中断任务的处理时间要远远小于主线程序的处理时间才能通过中断来处理。

IT0:这一位用来设置中断的触发模式:下降沿触发(Falling)或者低电平触发(low level);
EX0:这一位是INT0的开关。如果EX0等于0则外部中断在单片机内部被关闭,此时CPU无法收到INT0的中断信息所以不会处理INT0,如果需要使用INT0就一定要设置为1。
EA:是全局的中断开关。EA如果关掉则整个CPU不能响应中断,所有中断都被关了。光EA打开也不一定能响应中断,还得具体的中断开关打开才行。

总结:
(1)中断能力是CPU本身设计时支持的,并不是编程制造出来的;
(2)程序员只要负责2件事即可:主程序中初始化中断、定义中断处理程序;
(3)当中断条件发生时,硬件会自动检测到并且通知CPU,CPU会自动去执行中断处理程序,这一切都是CPU设计时定下的,不需要编程干预。

2,矩阵按键

单片机第一季:零基础6——按键,单片机,嵌入式硬件

电路中的ARRAY_H1表示矩阵键盘第1 行,ARRAY_L1 表示矩阵键盘第1 列。

需要注意的是,按键两端如果分别接单片机的两个端口,一个端口置高电平,一个端口置低电平,按下按键时会把高电平的端口拉低,端口置低可以认为是在单片机内部将这个端口接地。

矩阵按键实验程序,按下矩阵按键显示对应的0-F:

第一种方法:

/********************************************************************
******************
实验名称:矩阵按键实验
接线说明:
实验现象:下载程序后,按下“矩阵按键”模块中S1-S16 键,对应静态数码管显示0-F
注意事项:
*********************************************************************
******************/
#include "reg52.h"
typedef unsigned int u16; //对系统默认数据类型进行重定义
typedef unsigned char u8;
#define KEY_MATRIX_PORT P1 //使用宏定义矩阵按键控制口
#define SMG_A_DP_PORT P0 //使用宏定义数码管段码口
//共阴极数码管显示0~F 的段码数据
u8 gsmg_code[17]={0x3f,0x06,0x5b,0x4f,0x66,0x6d,0x7d,0x07,0x7f,0x6f,0x77,0x7c,0x39,0x5e,0x79,0x71};
/********************************************************************
***********
* 函数名: delay_10us
* 函数功能: 延时函数,ten_us=1 时,大约延时10us
* 输入: ten_us
* 输出: 无
*********************************************************************
**********/
void delay_10us(u16 ten_us)
{
	while(ten_us--);
}
/********************************************************************
***********
* 函数名: key_matrix_ranks_scan
* 函数功能: 使用行列式扫描方法,检测矩阵按键是否按下,按下则返回对应键值
* 输入: 无
* 输出: key_value:1-16,对应S1-S16 键,0:按键未按下
*********************************************************************
**********/
u8 key_matrix_ranks_scan(void)
{
	u8 key_value=0;
	KEY_MATRIX_PORT=0xf7;//给第一列赋值0,其余全为1
	if(KEY_MATRIX_PORT!=0xf7)//判断第一列按键是否按下
	{
		delay_10us(1000);//消抖
		switch(KEY_MATRIX_PORT)//保存第一列按键按下后的键值
		{
			case 0x77: key_value=1;break;
			case 0xb7: key_value=5;break;
			case 0xd7: key_value=9;break;
			case 0xe7: key_value=13;break;
		}
	}
	while(KEY_MATRIX_PORT!=0xf7);//等待按键松开

	KEY_MATRIX_PORT=0xfb;//给第二列赋值0,其余全为1
	if(KEY_MATRIX_PORT!=0xfb)//判断第二列按键是否按下
	{
		delay_10us(1000);//消抖
		switch(KEY_MATRIX_PORT)//保存第二列按键按下后的键值
		{
			case 0x7b: key_value=2;break;
			case 0xbb: key_value=6;break;
			case 0xdb: key_value=10;break;
			case 0xeb: key_value=14;break;
		}
	}
	while(KEY_MATRIX_PORT!=0xfb);//等待按键松开

	KEY_MATRIX_PORT=0xfd;//给第三列赋值0,其余全为1
	if(KEY_MATRIX_PORT!=0xfd)//判断第三列按键是否按下
	{
		delay_10us(1000);//消抖
		switch(KEY_MATRIX_PORT)//保存第三列按键按下后的键值
	{
		case 0x7d: key_value=3;break;
		case 0xbd: key_value=7;break;
		case 0xdd: key_value=11;break;
		case 0xed: key_value=15;break;
	}
	}
	while(KEY_MATRIX_PORT!=0xfd);//等待按键松开

	KEY_MATRIX_PORT=0xfe;//给第四列赋值0,其余全为1
	if(KEY_MATRIX_PORT!=0xfe)//判断第四列按键是否按下
	{
		delay_10us(1000);//消抖
		switch(KEY_MATRIX_PORT)//保存第四列按键按下后的键值
		{
			case 0x7e: key_value=4;break;
			case 0xbe: key_value=8;break;
			case 0xde: key_value=12;break;
			case 0xee: key_value=16;break;
		}
	}
	while(KEY_MATRIX_PORT!=0xfe);//等待按键松开
	return key_value;
}


void main()
{
	u8 key=0;
	while(1)
	{
		key=key_matrix_ranks_scan();
		if(key!=0)
		SMG_A_DP_PORT=~gsmg_code[key-1];//得到的按键值减1 换算成数组下标对应0-F 段码
	}
}

第二种方法:文章来源地址https://www.toymoban.com/news/detail-563312.html

#include <reg51.h>

typedef unsigned int u16; //对系统默认数据类型进行重定义
typedef unsigned char u8;

#define KEY_MATRIX_PORT P1 //使用宏定义矩阵按键控制口

#define SMG_A_DP_PORT P0 //使用宏定义数码管段码口

//共阳极数码管显示0~F 的段码数据
u8 gsmg_code[16]={0xc0,0xf9,0xa4,0xb0,0x99,0x92,0x82,0xf8,0x80,0x90,0x88,0x83,0xc6,0xa1,0x86,0x8e};
void delay_10us(u16 ten_us)
{
	while(ten_us--);
}

u8 key_matrix_flip_scan(void)
{
   	static u8 key_value=0;

   	KEY_MATRIX_PORT=0xf0;//给所有行赋值0,列全为1
	if(KEY_MATRIX_PORT != 0xf0)
	{
	   delay_10us(1000);
	   if(KEY_MATRIX_PORT != 0xf0)
	   {
	   	   switch(KEY_MATRIX_PORT)
		   {
			   case 0xe0: key_value = 1;break;
			   case 0xd0: key_value = 2;break;
			   case 0xb0: key_value = 3;break;
			   case 0x70: key_value = 4;break;
		   }
	   }

	
		KEY_MATRIX_PORT=0x0f;//给所有行赋值1,列全为0
		if(KEY_MATRIX_PORT != 0x0f)
		{
		   delay_10us(1000);
		   if(KEY_MATRIX_PORT != 0x0f)
		   {
		   	  switch(KEY_MATRIX_PORT)
			 {
				  case 0x0e: key_value = key_value;break;	 //代表第一行的按键
				  case 0x0d: key_value = key_value+4;break;  //代表第二行的按键
				  case 0x0b: key_value = key_value+8;break;	 //代表第三行的按键
				  case 0x07: key_value = key_value+12;break; //代表第四行的按键 
			 }
		   }
		   while(KEY_MATRIX_PORT!=0x0f);//等待按键松开

	
	}

	   else
	   {
	   		key_value = 0;	
	   }

	}

	return 	key_value;

}

void main()
{
	u8 key = 0;

   while(1)
   {
   		key = key_matrix_flip_scan();

		if (key != 0)
		{
			SMG_A_DP_PORT =  gsmg_code[key-1];
		}
   }

}

到了这里,关于单片机第一季:零基础6——按键的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • 单片机第一季:零基础13——AD和DA转换

    51 单片机系统内部运算时用的全部是数字量,即0 和1,因此对单片机系统而言,无法直接操作模拟量,必须将模拟量转换成数字量。所谓数字量,就是用一系列0 和1 组成的二进制代码表示某个信号大小的量。用数字量表示同一个模拟量时,数字位数可以多也可以少,位数越多

    2024年02月13日
    浏览(44)
  • 单片机第一季:零基础6——定时器和计时器

    目录 1,单片机定时器原理 2,51单片机定时器/计数器结构 3,定时器配置  4,示例代码-通过定时器控制LED灯间隔1s闪烁  51 单片机有两组定时器/计数器,因为既可以定时,又可以计数,故称之为定时器/计数器。 定时器/计数器和单片机的CPU 是相互独立的。定时器/计数器工作

    2024年02月15日
    浏览(53)
  • 单片机第一季:零基础9——直流电机和步进电机

    目录 1,直流电机 2,步进电机  直流电机是指能将直流电能转换成机械能(直流电动机)或将机械能转换成直流电能(直流发电机)的旋转电机。它是能实现直流电能和机械能互相转换的电机。当它作电动机运行时是直流电动机,将电能转换为机械能;作发电机运行时是直流

    2024年02月16日
    浏览(39)
  • 单片机第一季:零基础12——I2C和EEPROM

    目录 1,EEPROM 2,I2C  2.1,I2C物理层  2.2,I2C协议层  3,AT24C02介绍  4,代码  为什么需要EEPROM? 单片机内部的ROM只能在程序下载时进行擦除和改写,但是程序运行本身是不能改写的。单片机内部的RAM中的数据程序运行时可以改,但是掉电就丢失了。有时候我们有一些数据要

    2024年02月14日
    浏览(43)
  • 嵌入式51单片机04-矩阵按键系列

    一、矩阵按键基础知识 矩阵按键工作原理 : 逐行扫描 :通过高四位轮流输出低电平来对矩阵键盘进行扫描,当低四位接收到的数据不全为1的时候,说明有按键按下,然后通过判断低四位数据中哪一位为零来判断哪一个按键被按下。 逐列扫描 :通过低四位轮流输出低电平来

    2024年02月07日
    浏览(61)
  • 嵌入式(二)单片机基础 | 单片机特点 内部结构 最小系统 电源 晶振 复位

    上一篇文章我们介绍了嵌入式系统 嵌入式系统(Embedded System)是一种特定用途的计算机系统,它通常嵌入在更大的产品或系统中,用于控制、监测或执行特定的任务。这些系统通常由硬件和软件组成,旨在满足特定的需求,如嵌入在家电、汽车、医疗设备、工业自动化、消费

    2024年02月02日
    浏览(104)
  • 嵌入式系统基础 单片机MCU 树莓派 飞控 cpu

    一些有趣的软硬件设计 嵌入式与linux shell 单片机 电机控制 基于树莓派和Arduino制作的多种移动机器人 Altium Designer 导出pcb制作文件 cpu 浮点峰值 先来谈一下ARM的发展史:1978年12月5日,物理学家赫尔曼·豪泽(Hermann Hauser)和工程师Chris Curry,在英国剑桥创办了CPU公司(Cambridg

    2024年02月11日
    浏览(59)
  • 【STM32】基础知识 第一课 单片机简介

    单片机 (Single-Chip Microcomputer) 单品微型计算机, 是一种集成电路芯片. 电脑 vs 单片机: 电脑 单片机 CPU CPU 内存 SRAM 硬盘 Flash 主板 外设 SRAM 静态随机读取器 (Static Random-Access Memory): SRAM 是随机存储器的一种, 属于静态数据, 这类存储器要是维持电源, 里面存储的信息就可以恒常维持

    2024年02月11日
    浏览(93)
  • 单片机第三季-第一课:STM32基础

    STM32系列分类: 型号命名原则: STM32F103系列: 涉及到的几个概念: DMA:Direct Memory Access,直接存储器访问。DMA传输将数据从一个地址空间复制到另一个地址空间,提供外设和存储器或存储器和存储器之间的高速数据传输; 2.0到3.6V供电,IO口可以兼容5V电压; 与51单片机不同

    2024年02月09日
    浏览(41)
  • 单片机之独立按键(多种按键代码编写)

    单片机之独立按键原理:按键右端接GND,左边接到单片机的IO口,同时接了一个上拉电阻,当按键未按下时,P2.0为高电平(学过模电的人都应该知道为什么吧)当按键按下时,相当于P2.0口与GND相连为 低电平。

    2024年02月03日
    浏览(58)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包