世界网站排名查询,局网站建设制度,佳城建站 网站,网站建设费用申报文章目录 1.矩阵按键是什么2.矩阵按键的控制原理3.矩阵按键程序的编写将数值转化为键码完整代码#xff1a;demo.c#xff1a;key.c:key.h: 密码锁#xff08;简易版#xff09;需求分析#xff1a; 总结课后练习#xff1a; 1.矩阵按键是什么
这个矩阵按键也是我们这个… 文章目录 1.矩阵按键是什么2.矩阵按键的控制原理3.矩阵按键程序的编写将数值转化为键码完整代码demo.ckey.c:key.h: 密码锁简易版需求分析 总结课后练习 1.矩阵按键是什么
这个矩阵按键也是我们这个开发版上最后一个GPIO的一个应用如果对IO回的输入跟输出还有什么问题的话一定要回过头去看一下我们之前的程序理清楚思路。 之前的按键电路图 1个按键占用一个IO口的。 在按键数量较多时为了减少I/O口的占用将按键排列成矩阵排列的形式的按键阵列我们称位矩阵按键。
2.矩阵按键的控制原理
电路图
按键识别原理端口默认为高电平实时读取到引脚为低电平是表示按下。再次读取到高电平表示松开。
第一步现将P0.0-P0.3输出低电平P0.6-P0.7输出高电平如果有按键按下按下的那一列的IO就会变成低电平就可以判断出哪一列按下了。
第二步现将P0.0-P0.3输出高电平P0.6-P0.7输出低电平如果有按键按下按下的那一行的IO就会变成低电平就可以判断出哪一行按下了。
第三步行列组合一下就可以判断出是哪个按键按下了。
按键按下后导线导通哪条线上有高电平就会被拉低为低电平从而检测出是哪条线路二次检查交叉节点就是有按键按下的按键位置。
3.矩阵按键程序的编写
先完成矩阵按键的功能编写。 复制9.TIM多任务为10.矩阵按键用到P0端口还是在之前的KEY模块基础上进行修改 在key.h中定义#define MateixKEY P0 //矩阵按键的引脚 定义函数MateixKEY_Read u8 MateixKEY_Read(void); //矩阵按键读取当前是哪一个按钮按下返回值是按键序号 在key.c中实现函数MateixKEY_Read 先增加函数头并把实现思路复制过来作为编写依据围绕这三步编写矩阵按键的读取程序 MateixKEY 0XC0; //1100 0000 P0.6-P0.7输出高电平,
增加延时函数MateixKEY_delay留反应时间 MateixKEY_delay(); //留反应时间 MateixKEY_delay的实现并添加函数头
void MateixKEY_delay(void)
{u8 i;i 60; //根据之前的毫秒延时函数可以算出此处延时的时间while(--i);
}第一步假设P0.7按下 则为0100 0000如果想实现哪路按下哪位变成1可以采用异或运算。 即0100 0000 ^1100 0000 1000 0000 则有keystate MateixKEY^0XC0;
第二步第二次扫描高位输出低电平,低位输出高电平MateixKEY 0X0f; //0000 1111 保存按键状态假设P0.0按下 则为0000 1110^0000 1111 0000 0001,这里要采用|0000 0001 | 1000 0000 1000 0001 0x81 keystate | (MateixKEY^0X0f);是为了避免把之前的数值覆盖。 第三步keystate中已经保存了行、列的状态行列组合一下就可以判断出是哪个按键按下了。 printf(“%02x\r\n”,keystate); //强制变为2位以16进制显示。 return keystate; 在demo.c中调用 将10ms扫描按键的代码部分注释掉只检测MateixKEY_Read加入该函数编译运行。按动按键串口打印对应的16进制数值。
将数值转化为键码
u8 key_val 0; //表示按键的键码 这里采用switch关键词直接有模板插入编写switch函数 switch (keystate) //单选开关函数{case 0x41: key_val 1;break;case 0x42: key_val 2;break;case 0x44: key_val 3;break;case 0x48: key_val 4;break;case 0x81: key_val 5;break;case 0x82: key_val 6;break;case 0x84: key_val 7;break;case 0x88: key_val 8;break;default: key_val 0;break;}关闭数码管初始化显示main函数中新建变量u8 KEY_NUM 0; //保存矩阵按键的键码 读取矩阵按键的键码保存在KEY_NUM中并在数码管最后1位显示 KEY_NUM MateixKEY_Read();SEG7 KEY_NUM; //在数码管最后一位显示编译下载按动按键就可以判断是哪个按键按下了。
完整代码
demo.c
#include COMM/stc.h //调用头文件
#include COMM/usb.h
#include seg_led.h
#include key.h //调用头文件
#include beep.h
#include tim0.h#define MAIN_Fosc 24000000UL //定义主时钟char *USER_DEVICEDESC NULL;
char *USER_PRODUCTDESC NULL;
char *USER_STCISPCMD STCISP#;bit TIM_10MS_Flag; //10ms标志位void sys_init(); //函数声明
void delay_ms(u16 ms);void Timer0_Isr(void);void main() //程序开始运行的入口
{u8 KEY_NUM 0; //保存矩阵按键的键码sys_init(); //USB功能IO口初始化usb_init(); //usb库初始化Timer0_Init();EA 1; //CPU开放中断打开总中断。//数码管初始化显示0-7
// SEG0 0;
// SEG1 1;
// SEG2 2;
// SEG3 3;
// SEG4 4;
// SEG5 5;
// SEG6 6;
// SEG7 7;LED 0x0f; //赋初值亮一半灭一半,可以写8位的变量.从7开始数到0while(1) //死循环{
// if( DeviceState ! DEVSTATE_CONFIGURED ) //
// continue;if( bUsbOutReady ){usb_OUT_done();}if(TIM_10MS_Flag 1) //将需要延时的代码部分放入{TIM_10MS_Flag 0; //TIM_10MS_Flag 变量清空置位
// KEY_Deal(); //P3上所有端口都需要执行一遍BEEP_RUN(); //蜂鸣运行// if(KEY_ReadState(KEY1) KEY_RESS) //判断KEY1按钮是否为单击
// {
// BEEP_ON(2); //蜂鸣20ms
// LED0 0;
// }
// else if(KEY_ReadState(KEY1) KEY_LONGPRESS) //判断KEY1按钮是否为长按
// {
// BEEP_ON(2); //蜂鸣20ms
// LED1 0;
// }
// else if(KEY_ReadState(KEY1) KEY_RELAX) //判断KEY1按钮是否为松开
// {
// LED 0XFF;
// }KEY_NUM MateixKEY_Read();SEG7 KEY_NUM; //在数码管最后一位显示}}
}void sys_init() //函数定义
{WTST 0; //设置程序指令延时参数赋值为0可将CPU执行指令的速度设置为最快EAXFR 1; //扩展寄存器(XFR)访问使能CKCON 0; //提高访问XRAM速度P0M1 0x00; P0M0 0x00; //设置为准双向口P1M1 0x00; P1M0 0x00; //设置为准双向口P2M1 0x00; P2M0 0x00; //设置为准双向口P3M1 0x00; P3M0 0x00; //设置为准双向口P4M1 0x00; P4M0 0x00; //设置为准双向口P5M1 0x00; P5M0 0x00; //设置为准双向口P6M1 0x00; P6M0 0x00; //设置为准双向口P7M1 0x00; P7M0 0x00; //设置为准双向口P3M0 0x00;P3M1 0x00;P3M0 ~0x03;P3M1 | 0x03;//设置USB使用的时钟源IRC48MCR 0x80; //使能内部48M高速IRCwhile (!(IRC48MCR 0x01)); //等待时钟稳定USBCLK 0x00; //使用CDC功能需要使用这两行HID功能禁用这两行。USBCON 0x90;
}void delay_ms(u16 ms) //unsigned int
{u16 i;do{i MAIN_Fosc/6000;while(--i);}while(--ms);
}void Timer0_Isr(void) interrupt 1 //1ms进来执行一次无需其他延时重复赋值
{static timecount 0;SEG_LED_Show(); //数码管刷新timecount; //1ms1if(timecount10) //如果这个变量大于等于10说明10ms到达{timecount 0;TIM_10MS_Flag 1; //10ms到了}
}key.c:
#include key.h //调用头文件
u16 Count[8] {0,0,0,0,0,0,0,0}; //按键的时间状态变量初始化8位
u8 LastState 0; //8位变量b01 则表示key0上一次按下过//
// 函数名称:KEY_Deal
// 函数功能:按键状态的获取
// 入口参数:无
// 函数返回:无
// 当前版本: VER1.0
// 修改日期: 2023-1-1
// 当前作者:
// 其他备注:循环读取8个端口的状态并将按下的时间赋值给Count数组然后按下的状态赋值给变量LastState
//
void KEY_Deal(void) //检查所有的按键状态10ms执行一次
{u8 i 0;for(i0;i8;i) //for循环变量 循环8次i取值为0-7代表P30-P37的状态查询{if(~KEY (1i) ) //如果持续按下变量加1{if(Count[i] 60000) // Count是u16类型最大值小于65535故增加限定条件。Count[i] ; //如果持续按下这个变量加1}else //如果按键松开变量清0{if(Count[i] 0 ) //如果这个按键是按下过的{LastState | (1i); //这个变量相应的标志位置1单独写对应位}else{LastState ~(1i); //仅操作这个变量相应的标志位清0}Count[i] 0; //如果松开计数变量清0}}}
//
// 函数名称:KEY_ReadState
// 函数功能:读取指定的按钮的状态
// 入口参数: keynum; 按钮的端口号例如P32的端口号是2
// 函数返回:见KEY的返回值的各种状态看其他备注
// 当前版本: VER1.0
// 修改日期: 2023-1-1
// 当前作者:
// 其他备注: 函数返回值如下
状态 功能
//#define KEY_NOPRESS 0 //按键未按下 0
//#define KEY_FLCKER 1 //消抖 1
//#define KEY_RESS 2 //单击 2
//#define KEY_PRESSOVER 3 //单击结束 3
//#define KEY_LONGPRESS 4 //长按3s 4
//#define KEY_LONGOVER 5 //长按结束 5
//#define KEY_RELAX 6 //按键松开 6
//u8 KEY_ReadState(u8 keynum) //读取指定按键的状态,10ms执行1次
{if(Count[keynum] 0) //判断按键是按下的{if(Count[keynum] 3) //按下小于30ms返回消抖状态{return KEY_FLCKER;}else if(Count[keynum] 3) //按正好等于30ms返回单击状态{return KEY_RESS;}else if(Count[keynum] 300 ) //按下小于3000ms返回单击结束{return KEY_PRESSOVER;}else if(Count[keynum] 300 ) //按下正好等于3000ms返回长按{return KEY_LONGPRESS;}else //长按结束{return KEY_LONGOVER;}}else //按键已经松开了,返回KEY_RELAX状态{if(LastState (1keynum)) //按键之前按下过要判断上1s是不是高电平如果上1s是低电平说明是按键按下//例如要判断P32,P30,31,32,左移2位//按键已经松开了{return KEY_RELAX;}else //按键之前没有按下过返回未按下{return KEY_NOPRESS;}}
}
//
// 函数名称:MateixKEY_delay
// 函数功能:矩阵按键读取专用延时函数
// 入口参数:无
// 函数返回:无
// 当前版本: VER1.0
// 修改日期: 2023
// 当前作者:
// 其他备注:
//
void MateixKEY_delay(void)
{u8 i;i 60; //根据之前的ms延时的函数可以算出此处延时的时间while(--i);
}
//
// 函数名称:MateixKEY_Read
// 函数功能:矩阵按键读取当前是哪一个按钮按下
// 入口参数:无
// 函数返回:0表示没有按键按下1-8表示当前是第几个按键按下
// 当前版本: VER1.0
// 修改日期: 2023-1-1
// 当前作者:
// 其他备注:
//
u8 MateixKEY_Read(void) //矩阵按键读取当前是哪一个按钮按下返回值是按键序号
{u8 keystate; //表示当前的按钮状态值u8 key_val 0; //表示按键的键码
// 第一步现将P0.0-P0.3输出低电平P0.6-P0.7输出高电平如果有按键按下按下的那一列的IO就会变成低电平就可以判断出哪一列按下了。MateixKEY 0XC0; //1100 0000 P0.6-P0.7输出高电平,MateixKEY_delay(); //留反应时间keystate (MateixKEY^0XC0); //保存按键状态假设P0.7按下 则为0100 0000如果想实现变成哪路按下变成1用异或// 第二步现将P0.0-P0.3输出高电平P0.6-P0.7输出低电平如果有按键按下按下的那一行的IO就会变成低电平就可以判断出哪一行按下了。MateixKEY 0X0f; //0000 1111 高位输出低电平,低位输出高电平MateixKEY_delay(); //留反应时间keystate | (MateixKEY^0X0f); //保存按键状态假设P0.0按下 则为0000 1110^0000 1111 0000 0001,这里要采用|为了避免把之前的数值覆盖。// 第三步行列组合一下就可以判断出是哪个按键按下了。
// printf(%02x\r\n,keystate); //强制变为2位以16进制显示。switch (keystate) //单选开关函数{case 0x41: key_val 1;break;case 0x42: key_val 2;break;case 0x44: key_val 3;break;case 0x48: key_val 4;break;case 0x81: key_val 5;break;case 0x82: key_val 6;break;case 0x84: key_val 7;break;case 0x88: key_val 8;break;default: key_val 0;break;}return key_val;}key.h:
#ifndef __KEY_H
#define __KEY_H#include COMM/stc.h //调用头文件
#include COMM/usb.h//------------------------引脚定义------------------------//
#define KEY P3 //定义一个按键 引脚选择P32-P36#define KEY1 2 //按键1
#define KEY2 3 //按键2
#define KEY3 4 //按键3
#define KEY4 5 //按键4#define MateixKEY P0 //矩阵按键的引脚//------------------------变量声明------------------------//
//状态 功能
#define KEY_NOPRESS 0 //按键未按下 0
#define KEY_FLCKER 1 //消抖 1
#define KEY_RESS 2 //单击 2
#define KEY_PRESSOVER 3 //单击结束 3
#define KEY_LONGPRESS 4 //长按3s 4
#define KEY_LONGOVER 5 //长按结束 5
#define KEY_RELAX 6 //按键松开 6//------------------------函数声明-----------------------//
void KEY_Deal(void); //检查所有的按键状态
u8 KEY_ReadState(u8 keynum); //读取指定按键的状态u8 MateixKEY_Read(void); //矩阵按键读取当前是哪一个按钮按下返回值是按键序号#endif密码锁简易版 由于KEY_NUM MateixKEY_Read();执行后会持续输出1需要修改3s内只输出1次即可让它符合今天的主题。 先定义一个静态变量这是一个很常见的用法static u8 keystate_Last; //表示当前的按钮上一次的状态值 增加判断条件 if(keystate_Last ! keystate) //如果本次获取到的按键状态值和之前的不一样{keystate_Last keystate; //把本次的按键状态值写入进去switch (keystate) //单选开关函数{case 0x41: key_val 1;break;case 0x42: key_val 2;break;case 0x44: key_val 3;break;case 0x48: key_val 4;break;case 0x81: key_val 5;break;case 0x82: key_val 6;break;case 0x84: key_val 7;break;case 0x88: key_val 8;break;default: key_val 0;break;}printf(%d\r\n,(int)key_val); //强制转化为整形变量}需求分析
1.通过LED0模拟门锁状态LED点亮表示门锁打开熄灭表示门锁锁上 增加横线显示值SEG_Tab[22] 默认显示横线u8 Show_Tab[8] {21,21,21,21,21,21,21,21}; 新增变量u8 KEY_Str 0; //表示当前输入了几个密码 2.增加8位数码管可以动态显示8位的密码无密码时显示 “- - - - - - - -” 3.通过矩阵按键可以输入1-8的数字表示密码并依次显示在数码管上 4.每输入一个数字蜂鸣器响20ms表示有数字按下 5.密码正确打开LED0密码错误蜂鸣响2秒 根据条件修改demo.c中的main函数代码如下
void main() //程序开始运行的入口
{u8 KEY_NUM 0; //保存矩阵按键的键码u8 KEY_Str 0; //表示当前输入了几个密码位sys_init(); //USB功能IO口初始化usb_init(); //usb库初始化Timer0_Init();EA 1; //CPU开放中断打开总中断。//数码管初始化显示0-7
// SEG0 0;
// SEG1 1;
// SEG2 2;
// SEG3 3;
// SEG4 4;
// SEG5 5;
// SEG6 6;
// SEG7 7;//LED 0x0f; //赋初值亮一半灭一半,可以写8位的变量.从7开始数到0LED 0xff; //赋初值密码锁应用初始状态熄灭所有LEDwhile(1) //死循环{
// if( DeviceState ! DEVSTATE_CONFIGURED ) //
// continue;if( bUsbOutReady ){usb_OUT_done();}if(TIM_10MS_Flag 1) //将需要延时的代码部分放入{TIM_10MS_Flag 0; //TIM_10MS_Flag 变量清空置位
// KEY_Deal(); //P3上所有端口都需要执行一遍BEEP_RUN(); //蜂鸣运行// if(KEY_ReadState(KEY1) KEY_RESS) //判断KEY1按钮是否为单击
// {
// BEEP_ON(2); //蜂鸣20ms
// LED0 0;
// }
// else if(KEY_ReadState(KEY1) KEY_LONGPRESS) //判断KEY1按钮是否为长按
// {
// BEEP_ON(2); //蜂鸣20ms
// LED1 0;
// }
// else if(KEY_ReadState(KEY1) KEY_RELAX) //判断KEY1按钮是否为松开
// {
// LED 0XFF;
// }KEY_NUM MateixKEY_Read(); //当前矩阵按键的键值//SEG7 KEY_NUM; //在数码管最后一位显示if( KEY_NUM 0) //如果有按键按下{KEY_NUM 0; //键值先清空清空按键BEEP_ON(2); //蜂鸣20msShow_Tab[KEY_Str] KEY_NUM; //表示当前输入了几个密码 KEY_NUM; //将当前的按键状态保存到数组KEY_Str; //输入的密码位数1if(KEY_Str 8) //如果密码已经等于8位{if((Show_Tab[0]1)(Show_Tab[1]1)(Show_Tab[2]1)(Show_Tab[3]1)(Show_Tab[4]1)(Show_Tab[5]1)(Show_Tab[6]1)(Show_Tab[7]1)){LED0 0; //如果密码正确LED0点亮}else{BEEP_ON(200); //密码错误蜂鸣2s。单位是10ms2000ms2s}}}}}
}编译下载发现按键后均显示0KEY_NUM 0;位置有误应该放在调用以后再置0. 重新测试8位输入后不能自动清空应该添加代码到达长度后回到初始值显示横杠SEG0 SEG1 SEG2 SEG3 SEG4 SEG5 SEG6 SEG7 21; 重新测试输入错误后复位再按键输入显示有问题KEY_Str 8后忘记归0了。 经过修改功能已正常实现。 完整代码请参考《STC单片机原理-教学视频配套附件-20230731.zip
总结
1.了解矩阵按键的工作原理和代码编写的过程
课后练习
给今天的门锁增加如下功能 1.LED0门锁打开后5秒后自动关闭 2.增加门内的手动开门按钮按下按钮门锁打开 3.10秒内没有输入密码自动数码管熄灭省电有按键按下时再显示。 4.用for去改写一下密码判断的地方。