当前位置: 首页 > news >正文

第八章 矩阵按键实验

目录

1. 矩阵按键介绍

2. 矩阵按键检测方式

3. 实验硬件设计

3.1 LCD1602

3.1.1 硬件图

3.1.2 相关控制API

3.2 矩阵按键

3.2.1 硬件图

4. 实验软件设计

4.1 项目结构图

4.1.1 main.c

4.1.2 Delay.c

4.1.3 Delay.h

4.1.4 LCD1602.c

4.1.5 LCD1602.h

4.1.6 MartixKey.c

4.1.7 MartixKey.h

5. 小结


1. 矩阵按键介绍

独立按键在于单片机连接的时候,每一个按键都需要单片机的一个I/O口,若某单片机系统需较多按键, 如果用独立按键便会占用过多的 I/O 口资源。 单片机系统中 I/O 口资源往往比较宝贵, 当用到多个按键时为了减少 I/O 口引脚, 引入了矩阵按键。

本章以 4*4 矩阵键盘为例讲解其工作原理和检测方法。开发板上将 16 个按键排成 4 行 4 列, 第一行将每个按键的一端连接在一起构成行线, 第一列将每个按键的另一端连接在一起构成列线, 这样便一共有 4 行 4 列共 8 根线, 我们将这 8 根线连接到单片机的 8 个 I/O 口上, 通过程序扫描键盘就可检测 16 个键。

无论是对立按键还是矩阵键盘,检测是否按下都是一样的(检测该端口是否为低电平)

独立键盘有一端固定为低电平, 此种方式编程比较简单。 而矩阵键盘两端都与单片机 I/O 口相连, 因此在检测时需编程通过单片机 I/O 口送出低电平。 检测方法有多种, 最常用的是行列扫描线翻转法

2. 矩阵按键检测方式

行列扫描法:先给一列为低电平,其余列为高电平,然后立即检测一次各行是否为低电平,若检测到某一行为低电平,   则我们便可确认当前被按下的键是哪一行哪一列的。

线翻转法:使所有的行线为低电平,检测所有列线是否有低电平,如果有, 就记录列线值; 然后再翻转, 使所有列线都为低电平, 检测所有行线的值,由于有按键按下, 行线的值也会有变化, 记录行线的值。 从而就可以检测到全部按键。

普中A7的参考资料就是线翻转法,按键检测逻辑代码如下:

/*******************************************************************************
* 函 数 名       : key_matrix_flip_scan
* 函数功能		 : 使用线翻转扫描方法,检测矩阵按键是否按下,按下则返回对应键值
* 输    入       : 无
* 输    出    	 : key_value:1-16,对应S1-S16键,0:按键未按下
//*******************************************************************************/
u8 key_matrix_flip_scan(void)
{static u8 key_value=0;KEY_MATRIX_PORT=0x0f;//给所有行赋值0,列全为1if(KEY_MATRIX_PORT!=0x0f)//判断按键是否按下{delay_10us(1000);//消抖if(KEY_MATRIX_PORT!=0x0f){//测试列KEY_MATRIX_PORT=0x0f;switch(KEY_MATRIX_PORT)//保存行为0,按键按下后的列值	{case 0x07: key_value=1;break;case 0x0b: key_value=2;break;case 0x0d: key_value=3;break;case 0x0e: key_value=4;break;}//测试行KEY_MATRIX_PORT=0xf0;switch(KEY_MATRIX_PORT)//保存列为0,按键按下后的键值	{case 0x70: key_value=key_value;break;case 0xb0: key_value=key_value+4;break;case 0xd0: key_value=key_value+8;break;case 0xe0: key_value=key_value+12;break;}while(KEY_MATRIX_PORT!=0xf0);//等待按键松开	}}elsekey_value=0;		return key_value;		
}

我主要用的行列扫描法,但是和江协科技代码稍有区别,其实大差不差,甚至我觉得上面普中案例给的代码执行效率更高。

3. 实验硬件设计

本实验使用到硬件资源如下:

  • LCD1602

  • 矩阵按键

3.1 LCD1602

LCD1602 还没讲呢,就是先给出了一些实用的API,先提供调用,后面详细学习的时候再看。

3.1.1 硬件图

3.1.2 相关控制API

LCD1602.H

#ifndef __LCD1602_H__
#define __LCD1602_H__//用户调用函数:
void LCD_Init();
void LCD_ShowChar(unsigned char Line,unsigned char Column,char Char);
void LCD_ShowString(unsigned char Line,unsigned char Column,char *String);
void LCD_ShowNum(unsigned char Line,unsigned char Column,unsigned int Number,unsigned char Length);
void LCD_ShowSignedNum(unsigned char Line,unsigned char Column,int Number,unsigned char Length);
void LCD_ShowHexNum(unsigned char Line,unsigned char Column,unsigned int Number,unsigned char Length);
void LCD_ShowBinNum(unsigned char Line,unsigned char Column,unsigned int Number,unsigned char Length);#endif

LCD1602.C

// #include <REGX52.H>
#include <STC89C5xRC.H>//引脚配置:
sbit LCD_RS=P2^6;
sbit LCD_RW=P2^5;
sbit LCD_EN=P2^7;
#define LCD_DataPort P0//函数定义:
/*** @brief  LCD1602延时函数,12MHz调用可延时1ms* @param  无* @retval 无*/
void LCD_Delay()
{unsigned char i, j;i = 2;j = 239;do{while (--j);} while (--i);
}/*** @brief  LCD1602写命令* @param  Command 要写入的命令* @retval 无*/
void LCD_WriteCommand(unsigned char Command)
{LCD_RS=0;LCD_RW=0;LCD_DataPort=Command;LCD_EN=1;LCD_Delay();LCD_EN=0;LCD_Delay();
}/*** @brief  LCD1602写数据* @param  Data 要写入的数据* @retval 无*/
void LCD_WriteData(unsigned char Data)
{LCD_RS=1;LCD_RW=0;LCD_DataPort=Data;LCD_EN=1;LCD_Delay();LCD_EN=0;LCD_Delay();
}/*** @brief  LCD1602设置光标位置* @param  Line 行位置,范围:1~2* @param  Column 列位置,范围:1~16* @retval 无*/
void LCD_SetCursor(unsigned char Line,unsigned char Column)
{if(Line==1){LCD_WriteCommand(0x80|(Column-1));}else if(Line==2){LCD_WriteCommand(0x80|(Column-1+0x40));}
}/*** @brief  LCD1602初始化函数* @param  无* @retval 无*/
void LCD_Init()
{LCD_WriteCommand(0x38);//八位数据接口,两行显示,5*7点阵LCD_WriteCommand(0x0c);//显示开,光标关,闪烁关LCD_WriteCommand(0x06);//数据读写操作后,光标自动加一,画面不动LCD_WriteCommand(0x01);//光标复位,清屏
}/*** @brief  在LCD1602指定位置上显示一个字符* @param  Line 行位置,范围:1~2* @param  Column 列位置,范围:1~16* @param  Char 要显示的字符* @retval 无*/
void LCD_ShowChar(unsigned char Line,unsigned char Column,char Char)
{LCD_SetCursor(Line,Column);LCD_WriteData(Char);
}/*** @brief  在LCD1602指定位置开始显示所给字符串* @param  Line 起始行位置,范围:1~2* @param  Column 起始列位置,范围:1~16* @param  String 要显示的字符串* @retval 无*/
void LCD_ShowString(unsigned char Line,unsigned char Column,char *String)
{unsigned char i;LCD_SetCursor(Line,Column);for(i=0;String[i]!='\0';i++){LCD_WriteData(String[i]);}
}/*** @brief  返回值=X的Y次方*/
int LCD_Pow(int X,int Y)
{unsigned char i;int Result=1;for(i=0;i<Y;i++){Result*=X;}return Result;
}/*** @brief  在LCD1602指定位置开始显示所给数字* @param  Line 起始行位置,范围:1~2* @param  Column 起始列位置,范围:1~16* @param  Number 要显示的数字,范围:0~65535* @param  Length 要显示数字的长度,范围:1~5* @retval 无*/
void LCD_ShowNum(unsigned char Line,unsigned char Column,unsigned int Number,unsigned char Length)
{unsigned char i;LCD_SetCursor(Line,Column);for(i=Length;i>0;i--){LCD_WriteData(Number/LCD_Pow(10,i-1)%10+'0');}
}/*** @brief  在LCD1602指定位置开始以有符号十进制显示所给数字* @param  Line 起始行位置,范围:1~2* @param  Column 起始列位置,范围:1~16* @param  Number 要显示的数字,范围:-32768~32767* @param  Length 要显示数字的长度,范围:1~5* @retval 无*/
void LCD_ShowSignedNum(unsigned char Line,unsigned char Column,int Number,unsigned char Length)
{unsigned char i;unsigned int Number1;LCD_SetCursor(Line,Column);if(Number>=0){LCD_WriteData('+');Number1=Number;}else{LCD_WriteData('-');Number1=-Number;}for(i=Length;i>0;i--){LCD_WriteData(Number1/LCD_Pow(10,i-1)%10+'0');}
}/*** @brief  在LCD1602指定位置开始以十六进制显示所给数字* @param  Line 起始行位置,范围:1~2* @param  Column 起始列位置,范围:1~16* @param  Number 要显示的数字,范围:0~0xFFFF* @param  Length 要显示数字的长度,范围:1~4* @retval 无*/
void LCD_ShowHexNum(unsigned char Line,unsigned char Column,unsigned int Number,unsigned char Length)
{unsigned char i,SingleNumber;LCD_SetCursor(Line,Column);for(i=Length;i>0;i--){SingleNumber=Number/LCD_Pow(16,i-1)%16;if(SingleNumber<10){LCD_WriteData(SingleNumber+'0');}else{LCD_WriteData(SingleNumber-10+'A');}}
}/*** @brief  在LCD1602指定位置开始以二进制显示所给数字* @param  Line 起始行位置,范围:1~2* @param  Column 起始列位置,范围:1~16* @param  Number 要显示的数字,范围:0~1111 1111 1111 1111* @param  Length 要显示数字的长度,范围:1~16* @retval 无*/
void LCD_ShowBinNum(unsigned char Line,unsigned char Column,unsigned int Number,unsigned char Length)
{unsigned char i;LCD_SetCursor(Line,Column);for(i=Length;i>0;i--){LCD_WriteData(Number/LCD_Pow(2,i-1)%2+'0');}
}

3.2 矩阵按键

3.2.1 硬件图

我们可以看到该模块独立,4*4 矩阵按键引出的 8 根控制管脚并未直接连接到 51 单片机的 IO 上, 而是连接到 JP3 端子上。Hx(1-4)代表的是行,Lx(1-4)代表的是列。(4行4列)

我的接线方式是 P10-P17 分别接矩阵键盘的 1-8 管脚(P10-P13是行,P14-P17是列)

4. 实验软件设计

要实现的功能是:通过矩阵按键S1~S16按下后,LCD1602显示数字1-16

4.1 项目结构图

4.1.1 main.c
#include <STC89C5xRC.H>#include "Delay.h"
#include "LCD1602.h"
#include "MatrixKey.h"unsigned char KeyNumber;/******************************************************
*	功能:按动矩阵键盘 1-16 按键,显示相应编号在 LCD1602 上
*******************************************************/
void main(){LCD_Init();LCD_ShowString(1,1,"MatrixKey");while(1){KeyNumber =  MatrixKey();// 0 不参与显示if(KeyNumber){LCD_ShowNum(2,1,KeyNumber,2);}}
}
4.1.2 Delay.c
// 可调毫秒延时函数(12MHz晶振)
void delay_ms(unsigned int ms) {unsigned int i, j;for(i = ms; i > 0; i--)for(j = 110; j > 0; j--);
}
4.1.3 Delay.h
#ifndef __DELAY__H__
#define __DELAY__H__void delay_ms(unsigned int ms);#endif
4.1.4 LCD1602.c
// #include <REGX52.H>
#include <STC89C5xRC.H>//引脚配置:
sbit LCD_RS=P2^6;
sbit LCD_RW=P2^5;
sbit LCD_EN=P2^7;
#define LCD_DataPort P0//函数定义:
/*** @brief  LCD1602延时函数,12MHz调用可延时1ms* @param  无* @retval 无*/
void LCD_Delay()
{unsigned char i, j;i = 2;j = 239;do{while (--j);} while (--i);
}/*** @brief  LCD1602写命令* @param  Command 要写入的命令* @retval 无*/
void LCD_WriteCommand(unsigned char Command)
{LCD_RS=0;LCD_RW=0;LCD_DataPort=Command;LCD_EN=1;LCD_Delay();LCD_EN=0;LCD_Delay();
}/*** @brief  LCD1602写数据* @param  Data 要写入的数据* @retval 无*/
void LCD_WriteData(unsigned char Data)
{LCD_RS=1;LCD_RW=0;LCD_DataPort=Data;LCD_EN=1;LCD_Delay();LCD_EN=0;LCD_Delay();
}/*** @brief  LCD1602设置光标位置* @param  Line 行位置,范围:1~2* @param  Column 列位置,范围:1~16* @retval 无*/
void LCD_SetCursor(unsigned char Line,unsigned char Column)
{if(Line==1){LCD_WriteCommand(0x80|(Column-1));}else if(Line==2){LCD_WriteCommand(0x80|(Column-1+0x40));}
}/*** @brief  LCD1602初始化函数* @param  无* @retval 无*/
void LCD_Init()
{LCD_WriteCommand(0x38);//八位数据接口,两行显示,5*7点阵LCD_WriteCommand(0x0c);//显示开,光标关,闪烁关LCD_WriteCommand(0x06);//数据读写操作后,光标自动加一,画面不动LCD_WriteCommand(0x01);//光标复位,清屏
}/*** @brief  在LCD1602指定位置上显示一个字符* @param  Line 行位置,范围:1~2* @param  Column 列位置,范围:1~16* @param  Char 要显示的字符* @retval 无*/
void LCD_ShowChar(unsigned char Line,unsigned char Column,char Char)
{LCD_SetCursor(Line,Column);LCD_WriteData(Char);
}/*** @brief  在LCD1602指定位置开始显示所给字符串* @param  Line 起始行位置,范围:1~2* @param  Column 起始列位置,范围:1~16* @param  String 要显示的字符串* @retval 无*/
void LCD_ShowString(unsigned char Line,unsigned char Column,char *String)
{unsigned char i;LCD_SetCursor(Line,Column);for(i=0;String[i]!='\0';i++){LCD_WriteData(String[i]);}
}/*** @brief  返回值=X的Y次方*/
int LCD_Pow(int X,int Y)
{unsigned char i;int Result=1;for(i=0;i<Y;i++){Result*=X;}return Result;
}/*** @brief  在LCD1602指定位置开始显示所给数字* @param  Line 起始行位置,范围:1~2* @param  Column 起始列位置,范围:1~16* @param  Number 要显示的数字,范围:0~65535* @param  Length 要显示数字的长度,范围:1~5* @retval 无*/
void LCD_ShowNum(unsigned char Line,unsigned char Column,unsigned int Number,unsigned char Length)
{unsigned char i;LCD_SetCursor(Line,Column);for(i=Length;i>0;i--){LCD_WriteData(Number/LCD_Pow(10,i-1)%10+'0');}
}/*** @brief  在LCD1602指定位置开始以有符号十进制显示所给数字* @param  Line 起始行位置,范围:1~2* @param  Column 起始列位置,范围:1~16* @param  Number 要显示的数字,范围:-32768~32767* @param  Length 要显示数字的长度,范围:1~5* @retval 无*/
void LCD_ShowSignedNum(unsigned char Line,unsigned char Column,int Number,unsigned char Length)
{unsigned char i;unsigned int Number1;LCD_SetCursor(Line,Column);if(Number>=0){LCD_WriteData('+');Number1=Number;}else{LCD_WriteData('-');Number1=-Number;}for(i=Length;i>0;i--){LCD_WriteData(Number1/LCD_Pow(10,i-1)%10+'0');}
}/*** @brief  在LCD1602指定位置开始以十六进制显示所给数字* @param  Line 起始行位置,范围:1~2* @param  Column 起始列位置,范围:1~16* @param  Number 要显示的数字,范围:0~0xFFFF* @param  Length 要显示数字的长度,范围:1~4* @retval 无*/
void LCD_ShowHexNum(unsigned char Line,unsigned char Column,unsigned int Number,unsigned char Length)
{unsigned char i,SingleNumber;LCD_SetCursor(Line,Column);for(i=Length;i>0;i--){SingleNumber=Number/LCD_Pow(16,i-1)%16;if(SingleNumber<10){LCD_WriteData(SingleNumber+'0');}else{LCD_WriteData(SingleNumber-10+'A');}}
}/*** @brief  在LCD1602指定位置开始以二进制显示所给数字* @param  Line 起始行位置,范围:1~2* @param  Column 起始列位置,范围:1~16* @param  Number 要显示的数字,范围:0~1111 1111 1111 1111* @param  Length 要显示数字的长度,范围:1~16* @retval 无*/
void LCD_ShowBinNum(unsigned char Line,unsigned char Column,unsigned int Number,unsigned char Length)
{unsigned char i;LCD_SetCursor(Line,Column);for(i=Length;i>0;i--){LCD_WriteData(Number/LCD_Pow(2,i-1)%2+'0');}
}
4.1.5 LCD1602.h
#ifndef __LCD1602_H__
#define __LCD1602_H__//用户调用函数:
void LCD_Init();
void LCD_ShowChar(unsigned char Line,unsigned char Column,char Char);
void LCD_ShowString(unsigned char Line,unsigned char Column,char *String);
void LCD_ShowNum(unsigned char Line,unsigned char Column,unsigned int Number,unsigned char Length);
void LCD_ShowSignedNum(unsigned char Line,unsigned char Column,int Number,unsigned char Length);
void LCD_ShowHexNum(unsigned char Line,unsigned char Column,unsigned int Number,unsigned char Length);
void LCD_ShowBinNum(unsigned char Line,unsigned char Column,unsigned int Number,unsigned char Length);#endif
4.1.6 MartixKey.c
#include <STC89C5xRC.H>
#include "Delay.h"/***************************
*	函数名		:	MatrixKey
*	函数功能	:	返回按键值
*	输入		:	无
* 输出		:	按键编号
***************************/
unsigned char MatrixKey() {unsigned char KeyNumber = 0;unsigned char i, j;// 扫描4行for(i = 0; i < 4; i++) {// 设置当前行为低电平P1 = ~(0x01 << i); // 检查4列for(j = 0; j < 4; j++) {if(!(P1 & (0x10 << j))) { // 检查对应列是否为低电平delay_ms(20); // 消抖while(!(P1 & (0x10 << j))); // 等待按键释放delay_ms(20); // 再次消抖// 计算按键编号: 行号*4 + 列号 + 1KeyNumber = i * 4 + j + 1;return KeyNumber; // 直接返回,提高效率}}}return 0; // 没有按键按下
}// 江协科技代码
//unsigned char MatrixKey(){//	// 想直接引用就要设置初始值
//	unsigned char KeyNumber=0;
//	
//	// 初始化P1
//	P1 = 0xFF;
//	
//	// 逐行-逐列扫描,P10是第一行
//	P10 = 0;
//	// 如果说P10代表第一行,那么 P14 是第一列,
//	// 如果P14等于0,说明P10和P14是联通的,说明第一行第一列按钮被按下
//	if(P14 == 0){delay_ms(20);while(P14 == 0);delay_ms(20);KeyNumber=1;}
//	if(P15 == 0){delay_ms(20);while(P15 == 0);delay_ms(20);KeyNumber=2;}
//	if(P16 == 0){delay_ms(20);while(P16 == 0);delay_ms(20);KeyNumber=3;}
//	if(P17 == 0){delay_ms(20);while(P17 == 0);delay_ms(20);KeyNumber=4;}
//	
//	P11 = 0;
//	if(P14 == 0){delay_ms(20);while(P14 == 0);delay_ms(20);KeyNumber=5;}
//	if(P15 == 0){delay_ms(20);while(P15 == 0);delay_ms(20);KeyNumber=6;}
//	if(P16 == 0){delay_ms(20);while(P16 == 0);delay_ms(20);KeyNumber=7;}
//	if(P17 == 0){delay_ms(20);while(P17 == 0);delay_ms(20);KeyNumber=8;}
//	
//	P12 = 0;
//	if(P14 == 0){delay_ms(20);while(P14 == 0);delay_ms(20);KeyNumber=9;}
//	if(P15 == 0){delay_ms(20);while(P15 == 0);delay_ms(20);KeyNumber=10;}
//	if(P16 == 0){delay_ms(20);while(P16 == 0);delay_ms(20);KeyNumber=11;}
//	if(P17 == 0){delay_ms(20);while(P17 == 0);delay_ms(20);KeyNumber=12;}
//	
//	P13 = 0;
//	if(P14 == 0){delay_ms(20);while(P14 == 0);delay_ms(20);KeyNumber=13;}
//	if(P15 == 0){delay_ms(20);while(P15 == 0);delay_ms(20);KeyNumber=14;}
//	if(P16 == 0){delay_ms(20);while(P16 == 0);delay_ms(20);KeyNumber=15;}
//	if(P17 == 0){delay_ms(20);while(P17 == 0);delay_ms(20);KeyNumber=16;}
//	
//	return KeyNumber;
//	
//}// 普中例程代码
/*******************************************************************************
* 函 数 名       : key_matrix_flip_scan
* 函数功能		 : 使用线翻转扫描方法,检测矩阵按键是否按下,按下则返回对应键值
* 输    入       : 无
* 输    出    	 : key_value:1-16,对应S1-S16键,0:按键未按下
//*******************************************************************************/
//u8 key_matrix_flip_scan(void)
//{
//	static u8 key_value=0;
//	KEY_MATRIX_PORT=0x0f;//给所有行赋值0,列全为1
//	if(KEY_MATRIX_PORT!=0x0f)//判断按键是否按下
//	{
//		delay_10us(1000);//消抖
//		if(KEY_MATRIX_PORT!=0x0f)
//		{
//			//测试列
//			KEY_MATRIX_PORT=0x0f;
//			switch(KEY_MATRIX_PORT)//保存行为0,按键按下后的列值	
//			{
//				case 0x07: key_value=1;break;
//				case 0x0b: key_value=2;break;
//				case 0x0d: key_value=3;break;
//				case 0x0e: key_value=4;break;
//			}
//			//测试行
//			KEY_MATRIX_PORT=0xf0;
//			switch(KEY_MATRIX_PORT)//保存列为0,按键按下后的键值	
//			{
//				case 0x70: key_value=key_value;break;
//				case 0xb0: key_value=key_value+4;break;
//				case 0xd0: key_value=key_value+8;break;
//				case 0xe0: key_value=key_value+12;break;
//			}
//			while(KEY_MATRIX_PORT!=0xf0);//等待按键松开	
//		}
//	}
//	else
//		key_value=0;		
//	
//	return key_value;		
//}
4.1.7 MartixKey.h
#ifndef __MATRIXKEY_H__
#define __MATRIXKEY_H__/***************************
*	函数名		:	MatrixKey
*	函数功能	:	返回按键值
*	输入		:	无
* 输出		:	按键编号
***************************/
unsigned char MatrixKey();#endif

5. 小结

因为其他的比较简单并且有简单注释,这里只解释 MartixKey.c 核心逻辑代码

/***************************
*	函数名		:	MatrixKey
*	函数功能	:	返回按键值
*	输入		:	无
* 输出		:	按键编号
***************************/
unsigned char MatrixKey() {// 声明一个变量KeyNumber并初始化为0,用于存储检测到的按键编号。unsigned char KeyNumber = 0;// 声明两个循环变量i和j,用于控制行和列的循环。unsigned char i, j;// 开始一个for循环,循环4次,对应4行。i的值从0到3。for(i = 0; i < 4; i++) {// 将P1口设置为当前行为低电平,其他行为高电平。0x01 << i将1左移i位,然后取反,使得第i位// 为0(低电平),其他位为1(高电平)。例如,当i=0时,0x01<<0为0x01,取反后为0xFE(二进// 制11111110),即P1.0为低电平,其他为高电平。P1 = ~(0x01 << i); // 内层for循环,循环4次,对应4列。j的值从0到3。for(j = 0; j < 4; j++) {// 检查P1口的第(4+j)位(即列线)是否为低电平。0x10 << j表示将0x10(即二进制00010000)左移j位,例如j=0时,为0x10(即P1.4),j=1时为0x20(P1.5)等等。然后与P1进行按位与操作,如果该列线为低电平,则表达式结果为0,取非后为真,进入if语句。if(!(P1 & (0x10 << j))) {delay_ms(20); // 消抖while(!(P1 & (0x10 << j))); // 等待按键释放delay_ms(20); // 再次消抖// 计算按键编号。按键编号的计算公式为:行号i乘以4(因为每行有4个按键)加上列号j,然后加1(因为编号从1开始)。例如,第0行第0列对应按键1,第0行第1列对应按键2,以此类推。KeyNumber = i * 4 + j + 1;return KeyNumber; // 直接返回,提高效率}}}return 0; // 没有按键按下
}


文章转载自:

http://ZbXYu0zb.fdmtr.cn
http://BVwy6m37.fdmtr.cn
http://sd3GSctf.fdmtr.cn
http://g9D8f1Ix.fdmtr.cn
http://PcOWRrCi.fdmtr.cn
http://eadpMan0.fdmtr.cn
http://gc63INWz.fdmtr.cn
http://xMKVUG1z.fdmtr.cn
http://ikHnurRQ.fdmtr.cn
http://YsFn4W2a.fdmtr.cn
http://v0qdWDGG.fdmtr.cn
http://lJwZEFmL.fdmtr.cn
http://765NtSeU.fdmtr.cn
http://WpICZQrq.fdmtr.cn
http://zbrZOiqS.fdmtr.cn
http://nnP7YBbr.fdmtr.cn
http://fUKneoLy.fdmtr.cn
http://YQCXOg9y.fdmtr.cn
http://GpkCbdA9.fdmtr.cn
http://4W0Pw738.fdmtr.cn
http://Dh1xBRL4.fdmtr.cn
http://xhENlgEJ.fdmtr.cn
http://MafGlamn.fdmtr.cn
http://KHq6HB6h.fdmtr.cn
http://iqjI5F5X.fdmtr.cn
http://Lw4s0jHL.fdmtr.cn
http://0QJVhR9F.fdmtr.cn
http://lXNwLW38.fdmtr.cn
http://X7zQMwH3.fdmtr.cn
http://6fRA9Q3d.fdmtr.cn
http://www.dtcms.com/a/375551.html

相关文章:

  • 【CSS 3D 实战】从零实现旋转立方体:理解 3D 空间的核心原理
  • C++互斥锁使用详解与案例分析
  • Python+DRVT 从外部调用 Revit:批量创建柱
  • Matlab机器人工具箱6.2 导入stl模型——用urdf文件描述
  • 网页设计模板 HTML源码网站模板下载
  • 南京大学计算机学院 智能软件工程导论 + Luciano Baresi 教授讲座
  • Rust/C/C++ 混合构建 - Buck2构建工具一探究竟
  • Drawnix:开源一体化白板工具,让你的创意无限流动!
  • stm32 链接脚本没有 .gcc_except_table 段也能支持 C++ 异常
  • K8S集群管理(4)
  • flutter TabBar 设置isScrollable 第一个有间距
  • 学习 Android (二十一) 学习 OpenCV (六)
  • Maven项目中修改公共依赖项目并发布到nexus供三方引用全流程示例
  • GD32VW553-IOT开发板移植适配openharmony
  • nuxt3在使用vue-echarts报错 document is not defined
  • 嵌入式第四十九天(ARM汇编指令)
  • RS485通信 , 和modus RTU
  • 7. LangChain4j + 记忆缓存详细说明
  • 【超简单】Anaconda 安装教程(Windows 图文版)
  • Docker 搭建 Harbor 镜像仓库
  • 数据采集平台的起源与演进:从ETL到数据复制
  • Blender 制作中世纪风格的水磨坊(2):场景元素、纹理与渲染后期
  • 【Python】pytorch安装(使用conda)
  • 阿里云centos7-mysql的使用
  • Android实战进阶 - 启动页
  • 【从零开始编写数据库系统】基于Python语言实现存储引擎
  • 【Pywinauto库】8.3 pywinauto.findwindows 模块
  • 351章:Python Web爬虫入门:使用Requests和BeautifulSoup
  • 禅道,用域名访问之后不能登录的问题
  • Lodash-es 完整开发指南:ES模块化JavaScript工具库实战教程