按键扫描程序(4)
stm32键盘扫描电路原理
stm32键盘扫描电路原理
STM32键盘扫描电路原理是通过使用STM32微控制器的GPIO(通用输入/输出)功能和外部硬件电路,实现对键盘的扫描和检测。
1. 首先需要将键盘的按键连接到STM32微控制器的GPIO引脚上。
可以使用矩阵排列的方式来连接多个按键。
2. 然后将STM32微控制器的GPIO设置为输入模式,需要扫描的按键对应的GPIO引脚设置为输入。
3. 在代码中,设置一个循环,依次对每一个按键进行扫描。
可以使用GPIO外部中断来触发按键的扫描。
4. 在每次扫描过程中,将某一个按键对应的GPIO引脚设置为高电平,并读取引脚的状态。
5. 如果读取到的引脚状态为高电平,则表示该按键被按下。
6. 根据读取到的按键状态,可以执行相应的操作。
需要注意的是,如果使用矩阵排列的方式连接多个按键,还需要使用GPIO引脚的输出模式来控制矩阵的行和列。
总之,STM32键盘扫描电路原理是通过STM32微控制器的GPIO和外部硬件电路,实现对键盘的扫描和检测。
极其简单好用的按键扫描程序(C语言)
不过我在网上游逛了很久,也看过不少源程序了,没有发现这种按键处理办法的踪迹,所以,我将他共享出来,和广大同僚们共勉。我非常坚信这种按键处理办法的便捷和高效,你可以移植到任何一种嵌入式处理器上面,因为C语言强大的可移植性。
同时,这里面用到了一些分层的思想,在单片机当中也是相当有用的,也是本文的另外一个重点。
原理么?可能你也会想到,对于点触开关,按照上面的办法处理一次按下和长按,对于开关型,我们只需要处理Cont就OK了,为什么?很简单嘛,把它当成是一个长按键,这样就找到了共同点,屏蔽了所有的细节。程序就不给了,完全就是应用2的内容,在这里提为了就是说明原理~~
好了,这个好用的按键处理算是说完了。可能会有朋友会问,为什么不说延时消抖问题?哈哈,被看穿了。果然不能偷懒。下面谈谈这个问题,顺便也就非常简单的谈谈我自己用时间片轮办法,以及是如何消抖的。
}
完了。有没有一种不可思议的感觉?当然,没有想懂之前会那样,想懂之后就会惊叹于这算法的精妙!!
下面是程序解释:
Trg(triger) 代表的是触发,Cont(continue)代表的是连续按下。
1:读PORTB的端口数据,取反,然后送到ReadData 临时变量里面保存起来。
2:算法1,用来计算触发变量的。一个位与操作,一个异或操作,我想学过C语言都应该懂吧?Trg为全局变量,其它程序可以直接引用。
{
SysInit();
while(1) // 每20ms 执行一次大循环
{
KeyRead(); // 将每个子程序都扫描一遍
KeyProc();
Func1();
(1) 没有按键的时候
端口为0xff,ReadData读端口并且取反,很显然,就是 0x00 了。
《单片机系统设计技术》实验指导
《单片机系统设计技术》实验指导书适用专业: 电气、自动化、信息等编写单位: 电气信息学院编写人: 曹 林审核人:审批人:批准时间:年月日目 录实验1 IO控制LED流水灯实验 (3)实验2 IO控制数码管动态扫描实验 (5)实验3 外部中断实验 (8)实验4 定时器应用控制实验 (10)实验5 UART实验 (12)实验6 键盘扫描输入编程 (14)实验7 UART与PC对话实验 (17)实验8 ADC数据采集实验 (19)实验1 IO控制LED流水灯实验1.实验目的1)、熟悉KEIL编程环境和调试环境。
2)、掌握单片机汇编语言和指令的用法。
3)、理解简单的IO控制程序,延迟子程序,并对其修改,使其功能改变。
2.实验设备硬件: PC 机,单片机教学实验开发平台;软件: KEIL集成开发环境、STC ISP程序下载软件。
3.实验内容使用P0口控制8个LED 进行流水灯显示。
4.实验预习要求和实验准备要求预习教科书关于单片机硬件架构内容、IO口的内容,特殊寄存器内容。
预习汇编程序编写、MCS-51指令表。
带上教科书、U盘、具备二进制和十六进制转换的科学计算器。
5.实验原理和步骤1)实验原理(1)实验原理图图1 P0口连接的8盏LED灯从图1中可以看出:如果需要把LED点亮有两个条件,其一是需要用短接帽把J1的2脚和3脚短接,在PCB上就是将电路板左上角LED和VCC短接起来;其二是P0.X口给出低电平,让电流从VCC开始流经限流电阻、LED后进入单片机的P0.X口,最后到单片机内部的地线上。
因此,简单地说就是在短接帽接好的前提下,向P0.X口写0则LED将点亮,写1则LED将熄灭。
图中网络标识PORT0_0、PORT0_1……PORT0_7和单片机P0.0、P0.1……P0.7连接,可观察原理图上单片机P0口的网络标识也是PORT0_0、PORT0_1……PORT0_7。
2)实验步骤(1)启动KEIL集成开发环境,按照《KEIL使用方法》中描述步骤进行工程建立、汇编源程序文件添加。
经典的矩阵键盘扫描程序
经典的矩阵键盘扫描程序查找哪个按键被按下的方法为:一个一个地查找。
先第一行输出0,检查列线是否非全高;否则第二行输出0,检查列线是否非全高;否则第三行输出0,检查列线是否非全高;如果某行输出0时,查到列线非全高,则该行有按键按下;根据第几行线输出0与第几列线读入为0,即可判断在具体什么位置的按键按下。
下面是具体程序:void Check_Key(void){unsigned char row,col,tmp1,tmp2;tmp1 = 0x10; //tmp1用来设置P1口的输出,取反后使P1.4~P1.7中有一个为0for(row=0;row<4;row++) // 行检测{P1 = 0x0f; // 先将p1.4~P1.7置高P1 =~tmp1; // 使P1.4~p1.7中有一个为0tmp1*=2; // tmp1左移一位if ((P1 & 0x0f) < 0x0f) // 检测P1.0~P1.3中是否有一位为0,只要有,则说明此行有键按下,进入列检测{tmp2 = 0x01; // tmp2用于检测出哪一列为0for(col =0;col<4;col++) // 列检测{if((P1 & tmp2)==0x00) // 该列如果为低电平则可以判定为该列{key_val =key_Map[ row*4 +col ]; // 获取键值,识别按键;key_Map为按键的定义表return; // 退出循环}tmp2*=2; // tmp2左移一位}}}} //结束这是一种比较经典的矩阵键盘识别方法,实现起来较为简单,程序短小精炼。
4*4矩阵键盘扫描程序/*设置行线为输入线,列线为输出线*/uchar KeyScan(); //按键扫描子程序void delay10ms(); //延时程序uchar key_free(); //等待按键释放程序void key_deal(); //键处理程序//主程序void main(){while(1){KeyScan();key_free();key_deal();}}//按键扫描子程序uchar KyeScan(){unsigned char key,temp;P1=0xF0;if(P1&0xF0!=0xF0){delay10ms(); //延时去抖动if(P1&0xF0!=0xF0){P1=0xFE; //扫描第一列temp=P1;temp=temp&0xF0;if(temp!=0xF0) //如果本列有键按下{switch(temp){case 0xE0: //第一行有键按下key=1;break;case 0xD0: //第二行有键按下key=4;break;case 0xB0: //第三行有键按下key=8;break;case 0x70: //第四行有键按下key=12;break;}}P1=0xFD; //扫描第二列temp=P1;temp&=0xF0;if(temp!=0xF0){switch(temp){case 0xE0: //第一行有键按下key=1;break;case 0xD0: //第二行有键按下key=5;break;case 0xB0: //第三行有键按下key=9;break;case 0x70: //第四行有键按下key=13;break;}}P1=0xFb; //扫描第三列temp=P1;temp&=0xF0;if(temp!=0xF0){switch(temp){case 0xE0: //第一行有键按下key=2;break;case 0xD0: //第二行有键按下key=6;break;case 0xB0: //第三行有键按下key=10;break;case 0x70: //第四行有键按下key=14;break;}}P1=0xF7; //扫描第四列temp=P1;temp&=0xF0;if(temp!=0xF0){switch(temp){case 0xE0: //第一行有键按下key=3;break;case 0xD0: //第二行有键按下key=7;break;case 0xB0: //第三行有键按下key=11;break;case 0x70: //第四行有键按下key=15;break;}}}return(key);}}//延时程序void delay10ms(){unsigned char i,j;for(i=0;i<10;b++)for(j=0;j<120;j++)//延时1ms{}}//等待按键释放程序uchar key_free(){key=key_scan(); //取扫描到的键值P1=0xF0;//置行线全为高电平,列线全为低电平wheile(P1&0xF0!=0xF0) //如果仍有键按下{}return(key);//返回键值}51单片机矩阵键盘扫描、数码管显示键值实验/***********************************************程序名称:矩阵键盘扫描显示键值简要说明:P1口接矩阵键盘:低四位列,高四位行使用共阳型数码管:P0口输出数码管段码,P2口输出数码管位码编写:***********************************************/#include <AT89x52.h>#define uchar unsigned char;uchar key_val=0; //定义键值,初始默认为0uchar code TAB[16]={0xc0,0xf9,0xa4,0xb0,0x99,0x92,0x82,0xf8,0x80,0x90,0x88,0x83,0xC6,0xa1,0x86,0x8e}; //0~F 共阳数码管显示段码/*****按键扫描*****/void Check_Key(void){unsigned char row,col,tmp1,tmp2;tmp1 = 0x10; //tmp1用来设置P1口的输出,取反后使P1.4~P1.7中有一个为0for(row=0;row<4;row++) // 行检测{P1 = 0x0f; // 先将p1.4~P1.7置高P1 =~tmp1; // 使P1.4~p1.7中有一个为0tmp1*=2; // tmp1左移一位if ((P1 & 0x0f) < 0x0f) // 检测P1.0~P1.3中是否有一位为0,只要有,则说明此行有键按下,进入列检测{tmp2 = 0x01; // tmp2用于检测出哪一列为0for(col =0;col<4;col++) // 列检测{if((P1 & tmp2)==0x00) // 该列如果为低电平则可以判定为该列{key_val = row*4 +col; // 获取键值,识别按键return; // 退出循环}tmp2*=2; // tmp2左移一位}}}}/*****主函数,显示键值*****/void main(){P2=0x00; //位码,这里全部置低,点亮8位数码管(见视频效果)while(1){Check_Key();P0=TAB[key_val]; //显示}}实验7 矩阵按键识别技术矩阵按键部分由16个轻触按键按照4行4列排列,连接到JP50端口。
按键控制流水灯系统
按键控制流水灯系统设计摘要本设计旨在于通过所学知识,设计一个简单的按键控制流水灯系统,满足一些基本控制功能。
本设计选用80C51芯片作为核心硬件,组合74LS138译码芯片,4×4键盘,74LS273锁存芯片以及其他必要元器件实现对8个发光二极管和2个数码管显示屏的功能控制。
控制过程中用到了51单片机的定时/计数器和中断技术。
本次设计旨在于在理论学习单片机的基础上,通过实际系统的搭建,提高对所学知识的实际应用能力。
设计中,我们主要做了方案设计,电路搭建,程序编写,控制仿真,报告撰写等一系列工作。
方案设计说明设计要求:(1)利用按键控制流水灯的显示。
(2)利用3×3或者4×4键盘,控制数码管的显示。
(3)利用到定时/计数器。
(4)利用到中断技术。
设计功能:(1)按键0—7键为普通亮灭控制键,对应8个发光二极管,每个按键按一下,对应的灯亮,再按一次,对应的灯熄灭。
(2)按键8,12,13,14号键为功能控制键。
1)8键:按一下,8个灯逐个点亮,熄灭,循环左移三次。
2)12键:按一下,灯全部点亮,闪烁20次,返回原来状态。
3)13键:按一下,从左至右,每次点亮一个灯并保持,至灯全部点亮,再逐个熄灭。
4)14键:左右两侧灯逐对向中间点亮,熄灭,当灯对相遇后,向相反方向进行,循环两次返回。
(3)数码管显示为两位,一号为按键显示(显示被按下的键号),二号为功能号显示(显示执行的功能,从0—4分别对应1—7号键,8号键,12号键,13号键,14号键的功能)功能实现方案:51单片机的P0口(P0.0—P0.7)为低位地址总线,兼做数据总线,连接74LS273锁存器,输出的数据通过其锁存。
单片机P1口(P1.0—P1.7)用作通用I/O口,与键盘连接,其中,高四位(P1.4—P1.7)接为列控制线,低四位(P1.0—P1.3)接行控制线。
单片机P2口(P2.0—P2.5)为高位地址线,接外部74LS138译码芯片。
嵌入式设计实验报告
一、实验目的1. 熟悉嵌入式系统开发的基本流程和常用工具;2. 掌握嵌入式系统硬件资源的使用方法;3. 熟悉嵌入式系统软件开发的基本方法;4. 提高嵌入式系统设计能力。
二、实验内容1. 硬件平台:基于STM32F103系列单片机的开发板;2. 软件平台:Keil uVision5集成开发环境;3. 实验任务:设计一个简单的嵌入式系统,实现按键输入和LED灯控制功能。
三、实验原理1. 硬件原理:STM32F103系列单片机是一款高性能、低功耗的ARM Cortex-M3内核微控制器,具有丰富的片上外设资源,如GPIO、定时器、ADC等。
在本实验中,主要使用GPIO进行按键输入和LED灯控制。
2. 软件原理:嵌入式系统软件开发主要包括底层驱动程序、中间件和应用层。
底层驱动程序负责硬件资源的管理和配置;中间件提供系统服务,如通信、定时器等;应用层实现用户功能。
在本实验中,主要使用C语言编写程序,实现按键输入和LED灯控制功能。
四、实验步骤1. 硬件连接:将开发板上的按键和LED灯分别连接到单片机的GPIO端口;2. 软件编写:(1)创建项目:在Keil uVision5中创建一个新的项目,选择STM32F103系列单片机作为目标设备;(2)添加源文件:添加一个C语言源文件,用于编写主程序;(3)配置GPIO:在源文件中编写GPIO初始化代码,配置按键和LED灯的GPIO端口为输入和输出模式;(4)编写按键输入程序:编写按键扫描函数,用于检测按键状态,并根据按键状态控制LED灯;(5)编译程序:编译项目,生成目标文件;(6)下载程序:将编译好的程序下载到开发板;3. 实验验证:在开发板上运行程序,观察按键输入和LED灯控制功能是否正常。
五、实验结果与分析1. 实验结果:按键按下时,LED灯点亮;按键松开时,LED灯熄灭;2. 实验分析:通过编写程序,实现了按键输入和LED灯控制功能,验证了嵌入式系统开发的基本流程和常用工具。
第4节:“鸿哥三宝”之74HC165(按键扫描篇)
}
else if(key_lock4==0)
{
++ delay_cnt4;
if(delay_cnt4> cnt_delay_cnt1) //延时计数去抖动
hc165_pl_dr=0;
asm("nop");
asm("nop");
hc165_pl_dr=1;
asm("nop");
asm("nop");
for(j=0;j<16;j++)
{
hc165_cp_dr=0;
beep_dr=0; //关蜂鸣器,上电初始化IO
while(1) { Nhomakorabea CLRWDT(); //喂看门狗,大家不用过度关注此行
key_service(); //按键服务
asm("nop");
asm("nop");
} //以上一小段代码是通过驱动2个74HC165来获取16个按键的电平状态
//key_status
//以下代码通过解析每一位电平状态来确定哪个按键被触发
if((key_status &0x0001)==0x0001)
(4)源码适合的单片机:PIC18f4520,晶振为22.1184MHz
(5)源代码讲解如下:
#include<pic18.h> //包含芯片相关头文件
//补充说明:吴坚鸿程序风格是这样的,凡是输出IO后缀都是_dr,凡是输入的//IO后缀都//是_sr
极其简单好用的按键扫描程序C语言
极其简单好用的按键扫描程序(C语言)不过我在网上游逛了很久,也看过不少源程序了,没有发现这种按键处理办法的踪迹,所以,我将他共享出来,和广大同僚们共勉。
我非常坚信这种按键处理办法的便捷和高效,你可以移植到任何一种嵌入式处理器上面,因为C语言强大的可移植性。
同时,这里面用到了一些分层的思想,在单片机当中也是相当有用的,也是本文的另外一个重点。
对于老鸟,我建议直接看那两个表达式,然后自己想想就会懂的了,也不需要听我后面的自吹自擂了,我可没有班门弄斧的意思,hoho~~但是对于新手,我建议将全文看完。
因为这是实际项目中总结出来的经验,学校里面学不到的东西。
以下假设你懂C语言,因为纯粹的C语言描述,所以和处理器平台无关,你可以在MCS-51,AVR,PIC,甚至是ARM平台上面测试这个程序性能。
当然,我自己也是在多个项目用过,效果非常好的。
好了,工程人员的习惯,废话就应该少说,开始吧。
以下我以AVR的MEGA8作为平台讲解,没有其它原因,因为我手头上只有AVR的板子而已没有51的。
用51也可以,只是芯片初始化部分不同,还有寄存器名字不同而已。
核心算法:unsigned char Trg;unsigned char Cont;void KeyRead( void ){unsigned char ReadData = PINB^0xff; // 1Trg = ReadData & (ReadData ^ Cont); // 2Cont = ReadData; // 3}完了。
有没有一种不可思议的感觉?当然,没有想懂之前会那样,想懂之后就会惊叹于这算法的精妙!!下面是程序解释:Trg(triger)代表的是触发,Cont(continue)代表的是连续按下。
1:读PORTB的端口数据,取反,然后送到ReadData 临时变量里面保存起来。
2:算法1,用来计算触发变量的。
一个位与操作,一个异或操作,我想学过C语言都应该懂吧?Trg为全局变量,其它程序可以直接引用。
4×4键盘扫描程序
键盘程序假设P2.0-P2.3为H0-H3,P2.4-P2.7为L0-L3 (列) L0 L1 L2 L3(行) H0 0 1 2 3H1 4 5 6 7H2 8 9 A BH3 C D E F首先,行为P2口的低四位,而列为高四位。
P0口为数码管输出口。
第一种思路就是逐行逐列判断法。
#include<reg51.h>#include<intrins.h>#define uint unsigned int#define uchar unsigned charuchar code table[17] = {0xc0,0xf9,0xa4,0xb0,0x99,0x92,0x82,0xf8,0x80,0x90,0x88,0x83,0xc6,0xa1,0x86,0x8e,0xbf};//八段数码管对应0-F值. uchar temp;void Delay_1ms(uint i)//1ms延时{uint x, j;for(j=0;j<i;j++)for(x=0;x<=148;x++);}void delay()//消除按键抖动延时{int i,j;for(i=0; i<=10; i++)for(j=0; j<=2; j++);}uchar Keyscan(void){uchar i,j,row,col;temp=P2&0xf0;for(i=0; i<4; i++){if(!(temp&(0x10<<i)))row=i;}P2=0x0f;temp=P2&0x0f;for(j=0; j<4; j++){if(!(temp&(0x01<<j)))col=j;}return (row+col*4);}void Main(void){uchar Key_Value=16; //读出的键值uchar i=0;while(1){P2 = 0xf0;temp=P2;if(temp != 0xf0){Delay_1ms(80); //按键消抖if(temp != 0xf0){Key_Value = Keyscan();}Delay_1ms(350); //按键消抖}P0 = table[Key_Value];//P0口输出数据到数码管}次读取结果组合起来就可以得到当前按键的特征编码。
矩阵键盘扫描的C语言实例
矩阵键盘扫描的C语言实例1、按键扫描(线反转)//-------------------------------- ------------------------------------------------------------------// 函数名称:program_SCANkey// 函数功能:程序扫描键盘,// 有键按下完成按键处理,无键按下直接返回//--------------------------------------------------------------------------------------------------void program_SCANkey(){unsigned char key_code;if(judge_hitkey()) //判断是否有键按下{delay(1000); //延时20ms左右,消除抖动干扰if(judge_hitkey()) //判断是否有效按键{key_code=scan_key();//获取键值while(judge_hitkey()); //等待按键释放{}key_manage(key_code); //键盘扫描、键盘散转、按键处理}}}//--------------------------------------------------------------------------------------------------// 函数名称:judge_hitkey// 函数功能://判断是否有键按下,有返回1,没有返回0// 列判断,还可以用行判断。
//--------------------------------------------------------------------------------------------------bit judge_hitkey() //判断是否有键按下,有返回1,没有返回0{unsigned char scancode,keycode;scancode=0x0F; //开始设定P1.0~P1.3输出全1(初值)即表明无键闭合KEY=scancode;keycode=KEY; //读取P1.0~P1.3的真实状态,从而确定有没有键被按下if(keycode==0x0F)return(0); //全1则无键闭合elsereturn(1); //否则有键闭合}//--------------------------------------------------------------------------------------------------// 函数名称:scan_key// 函数功能://扫描键盘,返回键值(高四位代表行,低四位代表列)// 说明:scancode 扫描码,keycode 键值,keycode_line 行,keycode_row 列// 过程:先扫描行,确定那行的按键被按下。
经典的矩阵键盘扫描程序
经典的矩阵键盘扫描程序查找哪个按键被按下的方法为:一个一个地查找。
先第一行输出0,检查列线是否非全高;否则第二行输出0,检查列线是否非全高;否则第三行输出0,检查列线是否非全高;如果某行输出0时,查到列线非全高,则该行有按键按下;根据第几行线输出0与第几列线读入为0,即可判断在具体什么位置的按键按下。
下面是具体程序:void Check_Key(void){unsigned char row,col,tmp1,tmp2;tmp1 = 0x10; //tmp1用来设置P1口的输出,取反后使P1.4~P1.7中有一个为0for(row=0;row<4;row++) // 行检测{P1 = 0x0f; // 先将p1.4~P1.7置高P1 =~tmp1; // 使P1.4~p1.7中有一个为0tmp1*=2; // tmp1左移一位if ((P1 & 0x0f) < 0x0f) // 检测P1.0~P1.3中是否有一位为0,只要有,则说明此行有键按下,进入列检测{tmp2 = 0x01; // tmp2用于检测出哪一列为0for(col =0;col<4;col++) // 列检测{if((P1 & tmp2)==0x00) // 该列如果为低电平则可以判定为该列{key_val =key_Map[ row*4 +col ]; // 获取键值,识别按键;key_Map为按键的定义表return; // 退出循环}tmp2*=2; // tmp2左移一位}}}} //结束这是一种比较经典的矩阵键盘识别方法,实现起来较为简单,程序短小精炼。
4*4矩阵键盘扫描程序/*设置行线为输入线,列线为输出线*/uchar KeyScan(); //按键扫描子程序void delay10ms(); //延时程序uchar key_free(); //等待按键释放程序void key_deal(); //键处理程序//主程序void main(){while(1){KeyScan();key_free();key_deal();}}//按键扫描子程序uchar KyeScan(){unsigned char key,temp;P1=0xF0;if(P1&0xF0!=0xF0){delay10ms(); //延时去抖动if(P1&0xF0!=0xF0){P1=0xFE; //扫描第一列temp=P1;temp=temp&0xF0;if(temp!=0xF0) //如果本列有键按下{switch(temp){case 0xE0: //第一行有键按下key=1;break;case 0xD0: //第二行有键按下key=4;break;case 0xB0: //第三行有键按下key=8;break;case 0x70: //第四行有键按下key=12;break;}}P1=0xFD; //扫描第二列temp=P1;temp&=0xF0;if(temp!=0xF0){switch(temp){case 0xE0: //第一行有键按下key=1;break;case 0xD0: //第二行有键按下key=5;break;case 0xB0: //第三行有键按下key=9;break;case 0x70: //第四行有键按下key=13;break;}}P1=0xFb; //扫描第三列temp=P1;temp&=0xF0;if(temp!=0xF0){switch(temp){case 0xE0: //第一行有键按下key=2;break;case 0xD0: //第二行有键按下key=6;break;case 0xB0: //第三行有键按下key=10;break;case 0x70: //第四行有键按下key=14;break;}}P1=0xF7; //扫描第四列temp=P1;temp&=0xF0;if(temp!=0xF0){switch(temp){case 0xE0: //第一行有键按下key=3;break;case 0xD0: //第二行有键按下key=7;break;case 0xB0: //第三行有键按下key=11;break;case 0x70: //第四行有键按下key=15;break;}}}return(key);}}//延时程序void delay10ms(){unsigned char i,j;for(i=0;i<10;b++)for(j=0;j<120;j++)//延时1ms{}}//等待按键释放程序uchar key_free(){key=key_scan(); //取扫描到的键值P1=0xF0;//置行线全为高电平,列线全为低电平wheile(P1&0xF0!=0xF0) //如果仍有键按下{}return(key);//返回键值}51单片机矩阵键盘扫描、数码管显示键值实验/***********************************************程序名称:矩阵键盘扫描显示键值简要说明:P1口接矩阵键盘:低四位列,高四位行使用共阳型数码管:P0口输出数码管段码,P2口输出数码管位码编写:***********************************************/#include <AT89x52.h>#define uchar unsigned char;uchar key_val=0; //定义键值,初始默认为0uchar code TAB[16]={0xc0,0xf9,0xa4,0xb0,0x99,0x92,0x82,0xf8,0x80,0x90,0x88,0x83,0xC6,0xa1,0x86,0x8 e}; //0~F共阳数码管显示段码/*****按键扫描*****/void Check_Key(void){unsigned char row,col,tmp1,tmp2;tmp1 = 0x10; //tmp1用来设置P1口的输出,取反后使P1.4~P1.7中有一个为0for(row=0;row<4;row++) // 行检测{P1 = 0x0f; // 先将p1.4~P1.7置高P1 =~tmp1; // 使P1.4~p1.7中有一个为0tmp1*=2; // tmp1左移一位if ((P1 & 0x0f) < 0x0f) // 检测P1.0~P1.3中是否有一位为0,只要有,则说明此行有键按下,进入列检测{tmp2 = 0x01; // tmp2用于检测出哪一列为0for(col =0;col<4;col++) // 列检测{if((P1 & tmp2)==0x00) // 该列如果为低电平则可以判定为该列{key_val = row*4 +col; // 获取键值,识别按键return; // 退出循环}tmp2*=2; // tmp2左移一位}}}}/*****主函数,显示键值*****/void main(){P2=0x00; //位码,这里全部置低,点亮8位数码管(见视频效果)while(1){Check_Key();P0=TAB[key_val]; //显示}}实验7 矩阵按键识别技术矩阵按键部分由16个轻触按键按照4行4列排列,连接到JP50端口。
51单片机设计电子锁密码锁含代码
电子锁设计报告一,实验目的1. 学习8051定时器时间计时处理,键盘扫描及LED数码管显示的设计方法。
2. 设计任务及要求利用实验平台上8个LED数码管,设计带有报警功能的可掉电保存的电子密码锁。
3.通过本次实验,加强对所学知识的理解,增强编程能力及实践能力。
二,实验要求A.基本要求:1:用4×4矩阵键盘组成0-9数字键及确认键和删除键。
2:可以自行设定或删除8位密码,能够掉电保存。
3:用5位数码管组成显示电路提示信息,当输入密码时,只显示“8.”,当密码位数输入完毕按下确认键时,对输入的密码与设定的密码进行比较,若密码正确,则门开,此处用绿色led发光二极管亮一秒钟做为提示,若密码不正确,禁止按键输入3秒,同时用红色led发光二极管亮三秒钟做为提示;若在3秒之内仍有按键按下,则禁止按键输入3秒被重新禁止。
4:自由发挥其他功能.5:要求有单片机硬件系统框图,电路原理图,软件流程图B.拓展部分:无三,实验基本原理单片机密码锁是集计算机技术、电子技术、数字密码技术为一体的机电一体化高科技产品,具有安全性高,使用方便等优点。
本系统考虑到单片机密码锁成本及体积因素,在设计单片机密码锁部分时,以AT89S52单片机为核心,24C04、LED等构成外围电路。
本系统单片机密码锁硬件部分结构简单、成本低,软件部分使用电子加密提高锁的安全性,具有比较好的市场前景。
同时,由于本电子密码锁可以实现掉电保存,而且可以自行设计或者删除8位密码,所以具有较高的实用价值。
本密码锁采用5位数码管组成显示电路提示信息,当输入密码时,只显示“8.”,当密码位数输入完毕按下确认键时,对输入的密码与设定的密码进行比较,若密码正确,则门开,此处用绿色led 发光二极管亮一秒钟做为提示,若密码不正确,禁止按键输入3秒,同时用红色led 发光二极管亮三秒钟做为提示;若在3秒之内仍有按键按下,则禁止按键输入3秒被重新禁止。
此项功能方便用户使用。
单片机经典长短按程序
新型的按键扫描程序不过我在网上游逛了很久,也看过不少源程序了,没有发现这种按键处理办法的踪迹,所以,我将他共享出来,和广大同僚们共勉。
我非常坚信这种按键处理办法的便捷和高效,你可以移植到任何一种嵌入式处理器上面,因为C语言强大的可移植性。
同时,这里面用到了一些分层的思想,在单片机当中也是相当有用的,也是本文的另外一个重点。
对于老鸟,我建议直接看那两个表达式,然后自己想想就会懂的了,也不需要听我后面的自吹自擂了,我可没有班门弄斧的意思,hoho~~但是对于新手,我建议将全文看完。
因为这是实际项目中总结出来的经验,学校里面学不到的东西。
以下假设你懂C语言,因为纯粹的C语言描述,所以和处理器平台无关,你可以在MCS-51,AVR,PIC,甚至是ARM平台上面测试这个程序性能。
当然,我自己也是在多个项目用过,效果非常好的。
好了,工程人员的习惯,废话就应该少说,开始吧。
以下我以AVR的MEGA8作为平台讲解,没有其它原因,因为我手头上只有AVR的板子而已没有51的。
用51也可以,只是芯片初始化部分不同,还有寄存器名字不同而已。
核心算法:unsigned char Trg;unsigned char Cont;void KeyRead( void ){unsigned char ReadData = PINB^0xff; // 1Trg = ReadData & (ReadData ^ Cont); // 2Cont = ReadData; // 3}完了。
有没有一种不可思议的感觉?当然,没有想懂之前会那样,想懂之后就会惊叹于这算法的精妙!!下面是程序解释:Trg(triger)代表的是触发,Cont(continue)代表的是连续按下。
1:读PORTB的端口数据,取反,然后送到ReadData 临时变量里面保存起来。
2:算法1,用来计算触发变量的。
一个位与操作,一个异或操作,我想学过C 语言都应该懂吧?Trg为全局变量,其它程序可以直接引用。
单片机按键扫描程序
case 3:y=14;break;
case 4:y=4; break;
case 5:y=5; break;
case 6:y=6; break;
case 7:y=13;break;
case 8:y=1; break;
case 9:y=2; break;
for(j=0; j<4; j++)
{
if(!(P3 & temp))//判断P1口高4位某一行为低电平
x=i+j*4;//使用中间变量X
temp <<= 1;
}
}
}
}
if(P3!=0xf0) goto dingwei;//判断是否松开按键,防止重复赋值
switch(x)
{
case 0:y=7; break;
int aa[]={0xf7,0xfb,0xfd,0xfe,};
dingwei:
P3=0xf0;
if(P3!=0xf0)//判断是否有输入
{
delay(5);//防抖(延时10ms)
if(P3!=0xf0)//再判断是否有输入
{
for(i=0; i<4; i++)
{
P3 = aa[i];
temp=0x10;
}//符号点+-*/=分别为10,11,12,13,14,15。
case 10:y=3;break;
case 11:y=12;break;
case 12:y=10;break;
case 13:y=0; break;
case 14:y=15;break;
case 15:y=11;break;
4x4键盘的程序有扫描法与线反法
4x4键盘的程序有扫描法与线反法,但我个人认为用线反法较好,用扫描法得依次扫描所有行或列,如果用线反法就简单多了。
先使键盘的行置为低、列置为高(或列置为高、行置为低),接着读回端口的值。
比如:如果使用P0为键盘接口就先使低四位为低、高四位为高即P0=0xf0然后就读回P0口的值赋给一个变量,a=P0;紧接就给行列赋相反的值行置为高、列置为低(或列置为低、行置为高)即P0=0x0f然后就读回再与a运算就能得到唯一的识别码下面的程序就是用线反写一个4x4键盘识别程序:#include<AT89X52.H>#include<delay.h>#define KEY_SCAN P1#define uchar unsigned char//char num;/********************************//*函数名称:KEY_DOWN() *//*函数功能:延时子函数 *//*参数:无 *//*返回:返回1或0 *//*备注:1表示有键按下,0则无*//********************************/bit KEY_DOWN(){KEY_SCAN=0x0f; //先给键盘口赋个初值if(KEY_SCAN!=0x0f) //判断是有按键按下,即KEY_SCAN不等于初值时有键按下{delayms(10); //消抖if(KEY_SCAN!=0x0f) //再次判断是否真有键按下return 1; //真有就返回1没有返回零elsereturn 0;}elsereturn 0;}/********************************//*函数名称:SCAN_GET() *//*函数功能:键盘值函数 *//*参数:无 *//*返回:返回1或0 *//*备注:无 *//********************************/uchar SCAN_GET(){char button;uchar key_code;button=KEY_SCAN;KEY_SCAN=0xf0;button=(button|KEY_SCAN);while(KEY_SCAN!=0xf0);delayms(10);switch(button){case 0xd7: key_code='1';break;case 0xdb: key_code='2';break;case 0xdd: key_code='3';break;case 0xb7: key_code='4';break;case 0xbb: key_code='5';break;case 0xbd: key_code='6';break;case 0x77: key_code='7';break;case 0x7b: key_code='8';break;case 0x7d: key_code='9';break;case 0xeb: key_code='0';break;case 0xee: key_code=0xee;break;default : break;}return key_code;}////////////////////////////////////////////////////////////// //此程序是上两个程序结合的/********************************//*函数名称:Key_Get() *//*函数功能:键盘扫描函数 *//*参数:无 *//*返回:无 *//*备注:无 *//********************************/void Key_Get(){char button;KEY_SCAN=0x0f;if(KEY_SCAN!=0x0f){delayms(5);if(KEY_SCAN!=0x0f)button=KEY_SCAN;KEY_SCAN=0xf0;button=(button|KEY_SCAN);while(KEY_SCAN!=0xf0);switch(button){case 0xd7: num='1';P0=0x00;break; case 0xdb: num='2';P0=0x0f;break; case 0xdd: num='3';break;case 0xb7: num='4';break;case 0xbb: num='5';break;case 0xbd: num='6';break;case 0x77: num='7';break;case 0x7b: num='8';break;case 0x7d: num='9';break;case 0xeb: num='0';break;case 0xe7: num='a';break;case 0xed: num='b';break;case 0xee: num='c';break;case 0xde: num='d';break;case 0xbe: num='e';break;case 0x7e: num='f';break;default : break;}}}}qinglei120713的分享分享矩阵键盘C51程序(4*4)(来自互联网) 1111111111111111111111111111111111111111111111 11111111111111111111111111111111111111#include <reg51.h>#include <intrins.h>#define key_port P0 //键盘接口定义sbit key_port_0=key_port^0;sbit key_port_1=key_port^1;sbit key_port_2=key_port^2;sbit key_port_3=key_port^3;/*******************************STC89C59 单片机一毫秒延时函数*******************************/void delay_ms(unsigned int ms){unsigned int i,j;for( i=0;i<ms;i++)for(j=0;j<332;j++); //1947是STC89C58在22.1184MHz晶振下,通过软件仿真反复实验得到的数值}/**************************串口发送一个字符**************************/void com_send_dat( unsigned char dat){SBUF=dat;while (TI== 0);TI= 0 ;}/**************************串口初始化**************************/void init_com( void ){SCON=0x50 ; //SCON: serail mode 1, 8-bit UART, enable ucvr //UART为模式1,8位数据,允许接收TMOD|=0x20 ; //TMOD: timer 1, mode 2, 8-bit reload //定时器1为模式2,8位自动重装TH1=0xfa ; //Baud:19200 fosc="22.1184MHzTL1=0xfa;PCON|=0x80; //SMOD=1;波特率加倍;ES=1; //Enable Serial InterruptTR1 = 1 ; // timer 1 run}/**************************键盘扫描函数**************************/unsigned char keyscan(void){unsigned char key,i;unsigned char co de key_table[16]={0xee,0xed,0xeb,0xe7,0xde,0xdd,0xdb,0xd7,0xbe,0xbd,0x bb,0xb7,0x7e,0x7d,0x7b,0x77};key_port=0x0f; //确定行列位置if(key_port==0x0f)return(0);//无键按下返回0delay_ms(10); //调用延时函数,目的是去前沿键抖。
单片机按键实验报告
单片机按键实验报告篇一:单片机按键扫描实验报告键盘扫描一.实验目的(1)掌握矩阵键盘接口电路和键盘扫描编程方法。
(2)掌握按键值处理与显示电路设计。
二.实验任务(1)设计4*4键盘,编写各个键的特征码和对应的键值(0~F);(2)编程扫描按键,将按键对应的数字值使用数码管显示出来。
三.实验电路及连线方法1.采用动态显示连线方法:电路由2 片74LS573,1 个六字一体的共阴数码管组成。
由U15 输出段选码,U16 做位选码,与单片机的采用I/O 口连接方式,短路片J22 连接P2.0,J23 连接P2.3,做输出信号锁存。
(实际电路连接是d7-d6-d5-d4-d3-d2-d1-d0?h-c-d-e-g-b-a-f)。
PW12 是电源端。
2.键盘电路连线方法:电路由16 个按键组成,用P1 口扩展4×4 行列式键盘。
J20 是键盘连接端,连接到P1 口。
J21 是行列键盘、独立键盘选择端,当J21 的短路片连接2-3脚时,构成4×4 行列式键盘;当J21 的短路片连接2-1 脚时,可形成3×4 行列式键盘,4 个独立式按键S4、S8、S12、S16,这4 个独立按键分别连接P1.4~P1.7;其他12 个键3×4 行列式键盘。
PW15 是电源端。
四.编程思路1.采用反转法识别按键的闭合。
2.采用动态显示将键值显示出来。
五.算法流程图六.资源分配1.用P1口进行查找按键2.用R3做键值指针3.用R1做动态显示为选码指针。
4.R5为延时指针。
七.程序设计KPIN:ORG MOV MOV ANL MOV 0000H P1,#0F0H A,P1 A,#0F0H B,AMOVP1,#0FHMOVA,P1ANLA,#0FHORLA,BCJNE A,#0FFH,KPIN1AJMP EXITKPIN1: MOVB,AMOVDPTR,#TABKPMOVR3,#0KPIN2: MOVA,R3MOVC A,@A+DPTRCJNE A,B,KPIN3MOVA,R3LOOP: MOVR1,#0FEH;键盘动态显示 LOOP1: MOVA,R3ANLA,#0FHMOV DPTR,#TABMOVC A,@A+DPTRCLRP2.0CLRP2.1MOVP0,ASETB P2.0NOPCLRP2.0LOOP2: MOVA,R1;位选码MOVP0,ASETB P2.1MOVR5,#250LOOP3: DJNZ R5,LOOP3CLRP2.1SJMP LOOPKPIN3: INCR3CJNE A,#0FFH,KPIN2EXIT: RETTABKP: DB0EEH,0DEH,0BEH,7EH,0EDH,0DDH,0BDH,7DH,0EBHDB 0DBH,0BBH,7BH,0E7H,0D7H,0B7H,77H,67H,0FFHTAB: DB77H,44H,3EH,6EH,4DH,6BH,7BH,46H,7FH,6FH,5FHDB 79H,33H,7CH,3BH,1BHEND八.调试出现的问题及解决问题1:程序正常运行,但按键显示出现乱码解决:动态显示笔形码错误,并改正。
键盘扫描原理
笔记本键盘的总类:美式、英式、日本各个键盘的区别:键盘的扫描方式:逐行扫描法与线反转法现在的笔记本键盘一般都是16+8的方式,即16个pin输出,对应列;8个输入pin脚,对应行。
键盘输入与输出的结构如下:在Idel状态下,EC把16条输出线全部拉低,使能键盘扫描中断,这样当任意一个按键按下时,就会触发中断(ICU的INT11h),然后EC就开始逐列扫面,比如OUT(0,1,……,15)输出(1,1,……,1,0),(1,1,……,0,1)……(0,1,……,1,1),当数一个列扫描码,得到的行如输入信号为有一个为0的时候,这是得到的列扫描码与行扫描码就是这个键的扫面码。
比如上图按下S6的时候,列与行扫描码就分别为1101,1011。
然后通过扫描码在Scan table里面找对应的键码,传给OS,确定是哪个键。
在上面的图中,我们看到,在输入信号每个上面都有上拉电阻,这个电阻必须有除非EC的输入pin脚上面的有足够的上拉能力,否则扫描就会出现错误。
下图中,是一个正常的键盘矩阵图。
键盘上面的数字就与下面矩阵里面相同的数字对应。
普通键盘结构及工作原理键盘一般有独立式和行列式(矩阵式)两种。
当然还有其它的结构,比如交互式结构等等,不过其它的结构比较少用,在这里就不介绍了。
在中颖的单片机中,有些单片机的LCD 驱动引脚的SEGMENT 口可以共享按键扫描口,当选择为按键扫描口时,可以使用这些口来扫描按键,所以在外部电路可以连接LCD 和按键矩阵,采用分时扫描进行处理,下面也将介绍这个特殊应用的方法和注意的地方。
1、独立式键盘结构独立式键盘是指各个按键相互独立地连接到各自的单片机的I/O 口,I/O口只需要做输入口就能读到所有的按键。
独立式键盘可以使用上拉电阻也可以使用下拉电阻,基本原理是一样的。
使用上拉电阻的独立式键盘结构如图1-3 所示。
(上面这个图是有问题的,应该是行列式的键盘)图1-3 所示的是利用PB 口和PC 口共8 个I/O 口独自连接8 个按键,使用外部上拉电阻构成的独立式键盘。
Microtek 扫描仪用户使用手册
序言版 权©2015,上海中晶科技有限公司版权所有。
未经本公司书面许可,任何组织或个人不得以任何形式,如电子、机械、电磁、光学、化学、人为或其他类似方法,将本手册的任何部份复制、传送、转载、保存于检索系统,或翻译成其他语言。
商 标Microtek,ScanMaker,ArtixScan, ScanWizard及ColoRescue是上海中晶科技有限公司或其关联公司的注册商标,其他商标或注册商标皆属原登记公司所有。
规格、软件、硬件等如有更新将不另行通知。
声 明上海中晶科技有限公司保留变更软件功能、操作方式等权利,如有更新将不另行通知。
本手册的图片及操作说明仅供参考,实际以您所使用的软件版本为准。
I49-005088 ASeptember 2015上海中晶科技有限公司上海市桂平路680号35号楼电话:************传真:************安全警告请仔细阅读以下说明,并妥善保管本手册以便日后参考。
电源和电源线·扫描仪使用的电源,务必与产品标签上标明的电源类型相同。
·将电源插头完全插入到电源插座内,电源插座松动可以引起火花导致火灾。
·请勿在电源线上放置任何物品。
扫描仪的放置位置,应远离人员走动频繁之处,以免人员踩到电源线。
·如果长期不使用扫描仪,请拔下电源插座。
运输和存放扫描仪·请勿将扫描仪置于不稳定的推车、工作台或桌面上,否则可能导致扫描仪跌落和损坏。
·请勿在水边或靠水的地方操作扫描仪,不要将液体洒在扫描仪上,可能会导致短路。
·请将扫描仪置于远离散热器和暖气通风装置的地方。
维修·如果需要维修,请拔掉电源线,并请专业的维修技术人员进行维修。
·如果需要更换部件,请使用生产厂家的原配件。
目 录序言 (2)安全警告 (3)了解您的扫描仪 (6)扫描仪的特点 (6)系统要求 (8)各部件名称 (9)前/顶视图 (9)打开视图 (10)后视图 (11)初始设置 (12)步骤1:打开包装 (12)步骤2:安装软件 (13)步骤3:打开扫描仪镜头锁 (13)搬运前请先锁定扫描仪 (14)步骤4:安装进纸托盘 (15)关闭进纸托盘 (16)步骤5:连接扫描仪 (17)连接到电源适配器 (17)连接到高速USB接口 (17)放置稿件 (19)在ADF上放置稿件 (19)怎样使用挡纸板 (21)稿件放置注意事项 (22)在平板上放置稿件 (23)扫描稿件 (24)使用ScanWizard DI (24)扫描稿件 (24)扫描带有条形码的文件 (28)书本扫描 (30)从应用程序扫描稿件 (32)使用扫描稿件 (33)扫描后进行OCR识别 (33)扫描后用于E-mail (35)扫描后打印 (36)扫描仪按钮 (37)启动按键扫描设置界面 (38)功能按键设置 (39)如何使用按键扫描 (40)保养和清洁 (41)清洁扫描仪的玻璃面板 (41)清洁滚轮 (43)清洁感应器 (44)维护 (45)更换分纸滚轮 (45)更换进纸滚轮组 (47)附录 (50)怎样解决卡纸问题 (50)故障解决 (51)产品规格 (53)了解您的扫描仪您所购买的扫描仪是一台彩色文档扫描仪,配备有高容量的自动进纸器,可以进行多页纸张的连续扫描,最多一次可以扫描75页(18.6 lb文件纸)。
经典按键扫描程序
经典按键扫描程序核心算法:unsigned char Trg;unsigned char Cont;void KeyRead( void ){unsigned char ReadData = PINB^0xff; // 1Trg = ReadData & (ReadData ^ Cont); // 2Cont = ReadData; // 3}完了。
有没有一种不可思议的感觉?当然,没有想懂之前会那样,想懂之后就会惊叹于这算法的精妙!!下面是程序解释:Trg(triger)代表的是触发,Cont(continue)代表的是连续按下。
1:读PORTB的端口数据,取反,然后送到ReadData临时变量里面保存起来。
2:算法1,用来计算触发变量的。
一个位与操作,一个异或操作,我想学过C语言都应该懂吧?Trg为全局变量,其它程序可以直接引用。
3:算法2,用来计算连续变量。
看到这里,有种“知其然,不知其所以然”的感觉吧?代码很简单,但是它到底是怎么样实现我们的目的的呢?好,下面就让我们绕开云雾看青天吧。
我们最常用的按键接法如下:AVR是有内部上拉功能的,但是为了说明问题,我是特意用外部上拉电阻。
那么,按键没有按下的时候,读端口数据为1,如果按键按下,那么端口读到0。
下面就看看具体几种情况之下,这算法是怎么一回事。
(1)没有按键的时候端口为0xff,ReadData读端口并且取反,很显然,就是0x00了。
Trg = ReadData & (ReadData ^ Cont); (初始状态下,Cont也是为0的)很简单的数学计算,因为ReadData为0,则它和任何数“相与”,结果也是为0的。
Cont = ReadData;保存Cont其实就是等于ReadData,为0;结果就是:ReadData=0;Trg=0;Cont=0;(2)第一次PB0按下的情况端口数据为0xfe,ReadData读端口并且取反,很显然,就是0x01了。
- 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
- 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
- 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。
else if(key == D_key)
........//点亮B_LED,关闭A_LED和C_LED
else if(key == S_key)
key_time_1 = 0; // 第1次单击,不返回,到下个状态判断后面是否出现双击
key_m = key_state_1;
}
else
特别操作情况定义:
1。短按操作和长按操作间隔<0.5s,以及,长按操作和短按操作间隔<0.5s,均不产生双击事件
2。连续n次(n为奇数)短按操作,且间隔均<0.5s,产生(n-1)/2次双击事件+1次单击事件
3。连续n次(n为偶数)短按操作,且间隔均<0.5s,产生n/2次双击事件
题目:多功能按键设计。利用一个I/O口,接一个按键,实现3功能操作:单击 + 双击 + 长按。
============================================================================
用户基本操作定义:
1。短按操作:按键按下,按下时间<1s,属于一次短按操作
if (!key_press)
{
key_time = 0; //
key_state = key_state_2; // 按键仍然处于按下,消抖完成,状态转换到按下键时间的计时状态,但返回的还是无键事件
}
else
key_state = key_state_0; // 按键已抬起,转换到按键初始态。此处完成和实现软件消抖,其实按键的按下和释放都在此消抖的。
break;
case key_state_2:
{
time_10ms_ok = 1;
}
main(viod)
{
.........
while
{
if (time_10ms_ok) //每10ms执行一次,
{
{ // 这里500ms内肯定读到的都是无键事件,因为长键>1000ms,在1s前低层返回的都是无键
if(++key_time_1 >= 50)
{
........//点亮C_LED,关闭A_LED和B_LED
}
}
}
=================================================
if(key_press)
{
key_return = S_key; // 此时按键释放,说明是产生一次短操作,回送S_key
key_state = key_state_0; // 转换到按键初始态
2。在1的基础上,编写出符合要求的程序,并进行全面测试。
/*=============
低层按键(I/0)扫描函数,即低层按键设备驱动,只返回无键、短按和长按。具体双击不在此处判断。参考本人教材的例9-1,稍微有变化。教材中为连_发。
===============*/
}
break;
}
return key_reFra bibliotekurn; }
下面,根据程序分析按键事件的反映时间:
1。对于长键,按下超过1s马上响应,反映最快
2。对于双键,第2次按键释放后马上得到反映。
#define L_key 3 //长键
#define key_state_0 0
#define key_state_1 1
#define key_state_2 2
unsigned char key_driver(void)
{
static unsigned char key_state = key_state_0, key_time = 0;
{
key_return = D_key; // 返回双击键事件,回初始状态
key_m = key_state_0;
}
else
#define key_input PIND.7 // 按键输入口
#define N_key 0 //无键
#define S_key 1 //单键
#define D_key 2 //双键
key_return = S_key; // 500ms内没有再次出现单键事件,返回上一次的单键事件
key_m = key_state_0; // 返回初始状态
}
time_10ms_ok =0;
key = key_read(); //《====== 10ms一次调用按键中间层函数,根据返回键值,点亮不同的LED灯,全面测试按键操作是否正常
if (key == L_key)
key_state = key_state_3; // 转换到等待按键释放状态
}
break;
case key_state_3: // 等待按键释放状态,此状态只返回无按键事件
3。对于单键,释放后延时拖后500ms才能响应,反映最慢。这个与需要判断后面是否有双击操作有关,只能这样。实际应用中,可以调整两次单击间隔时间定义,比如为300ms,这样单击的响应回快一点,单按键操作人员需要加快按键的操作过程。如果产品是针对老年人的,这个时间不易太短,因为年纪大的人,反映和动作都比较慢。
key_return = key_temp; // 对于无键、长键,返回原事件
break;
case key_state_1:
if (key_temp == S_key) // 又一次单击(间隔肯定<500ms)
key_temp = key_driver();
switch(key_m)
{
case key_state_0:
if (key_temp == S_key )
{
if (!key_press) key_state = key_state_1; // 键被按下,状态转换到按键消抖和确认状态
break;
case key_state_1: // 按键消抖与确认态
if (key_press) key_state = key_state_0; //按键已释放,转换到按键初始态
break;
}
return key_return;
}
/*=============
中间层按键处理函数,调用低层函数一次,处理双击事件的判断,返回上层正确的无键、单键、双键、长键4个按键事件。
当然,上面两段可以合在一起。我这样做的目的,是为了可以方便的扩展为N击(当然,需要做修改)。可是最底层的就是最基本的操作处理短按和长按,不用改动的。至于双击,还是N击,在中间层处理。这就是程序设计中分层结构的优点。
测试代码环境如下:
interrupt [TIM0_COMP] void timer0_comp_isr(void) // 定时器10ms中断服务
本函数由上层循环调用,间隔10ms
===============*/
unsigned char key_read(void)
{
static unsigned char key_m = key_state_0, key_time_1 = 0;
unsigned char key_return = N_key,key_temp;
unsigned char key_press, key_return = N_key;
key_press = key_input; // 读按键I/O电平
switch (key_state)
{
case key_state_0: // 按键初始态
对按键操作者的建议:
由于按键的多功能性质,建议操作者每次在单击/长按/双击按键事件发生后,隔0.5s后再进行下一次的按键操作。因为在特别操作情况下,程序是保证按定义进行判断和处理的,主要是怕操作者自己记不清楚导致操作失误。
对软件设计者的要求:
1。应该全面进行分析,给出严格定义和判断条件,如上所示。如果自己都不清楚,你的设计出的系统就不稳定,不可靠。
}
else if (++key_time >= 100) // 继续按下,计时加10ms(10ms为本函数循环执行间隔)
{
key_return = L_key; // 按下时间>1000ms,此按键为长按操作,返回长键事件
2。长按操作:按键按下,按下时间>1s,属于一次长按操作
在正常0.5s内无按键操作为启始按键扫描条件下,扫描按键将产生以下3种按键事件:
1。长按事件:任何1次出现的长按操作都属于长按事件
2。单击事件:1次短按操作后,间隔0.5内没有短按操作
3。双击事件:2次短按操作间隔时间<0.5s,则2次短按操作为1次双击事件,且2次短按都取消