第8讲自己动手学习单片机系列-键盘_第1页
第8讲自己动手学习单片机系列-键盘_第2页
第8讲自己动手学习单片机系列-键盘_第3页
第8讲自己动手学习单片机系列-键盘_第4页
第8讲自己动手学习单片机系列-键盘_第5页
已阅读5页,还剩30页未读 继续免费阅读

下载本文档

版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领

文档简介

1、第8讲 输入-键盘主讲:王泽华 电话岛科技大学这一章刚做好,为了做出一个不管单键还是矩阵键盘都能用的状态机消抖,费了点功夫。同时对第6讲的LCD添加了一个显示单字符的函数。 2013.1.31本章重点一般键盘消抖方法状态机的概念键盘状态机键盘矩阵材料清单+5V电源最小系统板液晶显示板小按键17个(用作键盘),万能版1块圆孔插座(2.54)若干,排线若干,焊锡若干,面包板跳线若干。键盘连接电路当按键少,I/O口资源不紧张时,可采用一个按键占用一个I/O口的连接方式。如图,此时只要将该口设为输入,内部上拉电阻使能(DDRXn,PORTXn)=(0,1)即可。一旦按键按下,

2、电平被拉到低电平,按键松开的时候,引脚电平为高。所以只需读寄存器PINXn的电平可判断按键是否按下。扫描端口引脚电平的函数中代码可以这样写:unsigned char key_scan()DDRX &= 0 xFE; /PX0输入PORTX |= 0 x01; /上拉电阻使能if(PINX & 0 x01) /若为真,无键闭合 return(0);else/有键闭合 return(1);当按键多,例如16个按键,此时采用上述连接方式会占用16个I/O口资源。可采用矩阵方式。如图,这样只占用8个I/O口。键盘扫描方法: 和单键扫描一致,有键闭合返回非零;无键闭合返回0。(1)初步确定有无按键:P

3、X0-PX3输入,上拉电阻使能,这样这4个脚是高电平(0 x0F);PX4-PX7输出低电平。读PX0- PX3口引脚电平,一旦有键闭合,引脚电平不再是0 x0F。(2)行扫描法确定哪一个键闭合:扫描第1行:PX7-PX4送出0b1110,拉低第一行电平,其它三行电平为高,读PX3-PX0。若第1行若无键闭合,读出的数据为0b1111。有键闭合,例如第1列闭合,读出的数据为0b1110;同样第2列有键闭合,读出的数据为0b1101;若读出的数据为0b1011;表示第三列有键闭合;0b0111表示第4列有键闭合若要扫描第2行,PX7-PX4送出0b1101,拉低第2行电平;同样,送出0b1011

4、和0b0111可扫描第3行和第4行。(3)value_row高4位存储行扫描码,value_col低4位存储读取码,做运算value_key = (value_row & 0 xF0) + (value_col & 0 x0F);在只有单键闭合的情况下,value_key的取值与键闭合对应如图所示扫描代码可以这样写:unsigned char key_scan()int i;unsigned char value_key, value_row, value_col;value_key = 0 x00;/缺省无键闭合key_DDR = 0 xF0;/高四位输出,低四位输入。key_PORT =

5、0 x0F;/高四位输出低电平,低四位上拉电阻能_NOP();value_col = key_PIN & 0 x0F;/读列if(value_col != 0 x0F)/有按键闭合value_row = 0 xEF;for(i=0;i4;i+)/扫描第i行key_PORT = value_row & 0 xF0;/第i行电平拉低_NOP();value_col = key_PIN & 0 x0F; if(value_col) != 0 x0F)/第一行各列有键按下 switch(value_col)case 0b00001110:/第一列按键case 0b00001101:/第二列按键case

6、 0b00001011:/第三列按键case 0b00000111:/第四列按键 value_key = (value_row & 0 xF0) + value_col); break;default value_key = 0; break; value_row = 1; /移位,扫描其余各行 return(value_key);键盘电路的焊接u本章现在1只独立按键实现所有程序,然后由浅如深的拓展到键盘矩阵。所用到的键盘焊接如图,左面是焊接正面图,右面是焊接反面图。按键消抖为什么要消抖为什么要消抖:通常键盘所用为机械弹性开关,在按下和弹起的瞬间伴随一系列抖动。为确保CPU对一次闭合仅做一次处

7、理,必须对键盘的抖动进行消抖处理。一般来说,前沿和后沿抖动时间大约在5-10ms。一般键盘消抖的思路一般键盘消抖的思路:一旦检测到有键按下时,延时10ms,跳过前沿抖动,再次检测,仍然检测到该键按下,则认为是有效按键;检测到该键释放后,延时10ms,再检测,该键仍在释放状态;则认为完成了一次完整的按键。假定键盘扫描程序为key_scan(),有键按下返回键值;无键按下返回0。定义一个键盘消息结构struct sMsg_Keyint value ;/有键,存储键值int state;/存储当前键状态,按/下为1弹起为0;struct sMsg_Key msg_key;int keyDelay_D

8、ither(const int key_value)/key_value为key_scan() 返回值int tmp;if(key_value)/key_value!=0,有键按下执行以下程序; 前沿消抖_delay_ms(10);/延时10ms去掉抖动前沿if(key_value = key_scan()/若两次按键相等 msg_key.value = key_value;/返回键值msg_key.state = 1;/标记键盘在按下状态return(0);else if(msg_key.state = 1) /键没有释放,检测到释放;后沿消抖_delay_ms(10);/延时10ms去掉抖

9、动后沿tmp = msg_key.value;PA0接一只小按键到地;PB0接LED发光二极管。按下按键松手后LED两0.2s,其它时间熄灭。来检验以上键盘处理程序是否能用。#define F_CPU 8000000UL#include#include/定义键盘使用的端口PA0#define key_DDR DDRA#define key_PORT PORTA#define key_PIN PINA#define _NOP() _asm_ _volatile_(nop:)struct sMsg_Keyint value ;/有键,存储键值int state;/存储当前键状态,按下为1弹起为0;

10、struct sMsg_Key msg_key;int key_scan()key_DDR = 0 x00;key_PORT |= 0 xFF;/ PA0输入内部上拉,PA0脚高电平,一旦按键按下,PA变为低电平_NOP();if(key_PIN & 0 x01) = 0)/有键按下return(1);/返回PA0端口值else /无键按下return(0);msg_key.state = 0;/标记按键释放msg_key.value =0;/按键值清零return(tmp);/返回键值else /一直无键按下msg_key.state = 0;/标记按键释放msg_key.value =0;

11、/按键值清零return(0);/上一页的键盘处理int key_process(int)粘贴到此处int main(void)int key_value, key_release;/led使用PB0,端口输出DDRB |= 0 x01;while(1)key_value = key_scan();/扫描key_release = keyDelay_Dither(key_value);/键盘延时消抖if(key_release)/键释放PORTB |= 0 x01;/点亮LED,200ms_delay_ms(200);else/其它时间,LED熄灭PORTB &= 0 xFE;return(0

12、);状态机(FSM)状态机研究的起因:状态机最早应用于时序逻辑电路的设计中,在时钟信号的控制下接收事件输入,进行状态迁移,并执行相应操作。现在这一思想被借鉴到程序设计中。传统应用程序的控制流程基本是顺序的,遵循事先设定的逻辑,从头到尾地执行。很少有事件能改变标准执行流程。 缺点不足以应对相对复杂的控制;另一类应用程序由外部事件(可能发生也可能不发生)来驱动,事件在应用程序之外生成,无法由应用程序或程序员来控制。具体需要执行的代码取决于接收到的事件,或者它相对于其他事件的抵达时间。所以,控制流程既不能是顺序的,也不能是事先设定好的,因为它要依赖于外部事件。状态机是对具有逻辑顺序和时序规律的事件的

13、一种描述方法。状态机三要素:输入(事件);状态;输出(执行操作)理解状态机举例:状态机分类:按状态个数,有限状态机:状态数有限个无限状态机:状态数无限个。输出是否与输入有关moore状态机:输出仅与当前状态有关,与输入无关melay状态机:输出不仅与当前状态有关,还与输入有关状态机实现按键消抖n主要实现两个功能n按键消抖n键盘释放时返回按键值n按键状态机三要素n输入:通常作为状态机函数的输入参数。此处该输入参数每隔20ms的键盘扫描key_scan()。n状态:无键按下状态;有键按下状态;有效按键状态;键释放状态n输出:通常作为函数的返回值。除键释放状态返回键值外(第二个功能),其它的各个状态

14、返回0。状态图:不考虑长按键状态和连续按键状态#define State_NoKey0/无键按下状态#define State_KeyPress1/有键按下状态#define State_ValidKey2/有效按键状态#define State_KeyRelease3/键盘释放状态int State_Key = State_NoKey;/键状态,初始为无键按下状态 char Fsm_KeyDither(char event_trig) static char f_key_release;static char key_value;switch(State_Key)case State_NoK

15、ey:if(event_trig) /key_scan!=0,转到有键按下状态 State_Key = State_KeyPress;else/key_scan=0,在无键状态下循环 State_Key = State_NoKey;f_key_release = 0;key_value = 0;break;case State_KeyPress:if(event_trig) /key_scan!=0,转到有效按键状态 State_Key = State_ValidKey;else/key_scan=0,无效按键,转无键状态State_Key = State_NoKey;f_key_releas

16、e = 0;key_value = 0;break;case State_ValidKey:if(event_trig) /key_scan!=0,在状态中循环,存储键值 State_Key = State_ValidKey;key_value = event_trig;else/key_scan=0,转键释放状态State_Key = State_KeyRelease;f_key_release = 0;break;case State_KeyRelease:if(event_trig) /key_scan!=0,有新的按键 State_Key = State_KeyPress;else/k

17、ey_scan=0,转无键按下状态State_Key = State_NoKey;f_key_release = 1;/一次按键完成break;default:/其它未考虑的情况。key_value = 0;f_key_release = 0;break;if(f_key_release)/键释放,返回键值 return(key_value);else /否则返回0值 return(0);PA0接一只小按键到地;PB0接LED发光二极管。按下按键后LED点亮,再一次按键LED熄灭;重复按键,重复以上步骤。来检验以上键盘处理程序是否能用。#define F_CPU 8000000UL#inclu

18、de#include#include/定义键盘使用的端口PA0#define key_DDR DDRA#define key_PORT PORTA#define key_PIN PINA#define _NOP() _asm_ _volatile_(nop:)#define State_NoKey0#define State_KeyPress1#define State_ValidKey2#define State_KeyRelease3int State_Key = State_NoKey;/键状态,初始为无键按下状态 volatile int value_keyscan;/扫描到的键值ch

19、ar key_scan()key_DDR &= 0 xfe;key_PORT |= 0 x01;/ PA0输入,内部上拉,这样PA0引脚高电平/按键按下,PA变为低电平_NOP();if(key_PIN & 0 x01)/无键按下返回0return(0);else /有键按下返回1return(1);/前面定义的Fsm_KeyDither键盘状态机处理程序粘贴到此处。ISR(TIMER0_OVF_vect) TCNT0 = 256 - F_CPU* 0.015/1024 ;/重载定时器 value_keyscan = key_scan();/键盘扫描 int main(void)_delay_

20、ms(500);int key_counter = 0;/设定定时器中断DDRB |= 0 x01;/PB0输出,其它位保持原状态TIMSK = 0 x01;/允许TIMER0溢出中断TCNT0 = 256 - F_CPU * 0.015/1024;/设定时间TCCR0 = 0 x05;/设定分频系数,启动定时器sei();/开全局中断while(1)if(Fsm_KeyDither(value_keyscan)key_counter+;if(key_counter % 2)PORTB |= 0 x01;elsePORTB &= 0 xFE;return(0); LCD1602显示矩阵键盘按键

21、LCD1602接口PB0-PB7接DB0-DB7PC0(RS),PC1(RW),PC2(E)键盘接口PA0,PA1,PA2,PA3连接1-4列PA4,PA5,PA6,PA7连接1-4行实现功能:在LCD1602显示所按下的键。Key_scan()函数返回值与键对应关系见图,其中CLR是清屏。分析:键盘显示程序采用液晶部分,接口完全相同,各子程序不需改动;键盘扫描见本章,由于矩阵键盘的返回值和单键盘的返回值意义相同,状态机消抖函数两者通用。代码如下:#define F_CPU 8000000UL#include #include #include #include #include #defin

22、e _NOP() _asm_ _volatile_(nop:)/*/LCD定义/*/ #define clear_scr 0 x01/清屏 #define cursor_return 0 x02/光标回左上角 #define data_cur_right 0 x06/数据写入光标右移,AC+1 #define disp_on 0 x0C/显示开 #define disp_off 0 x08/显示关 #define cursor_right 0 x14/整体显示,光标右移,AC+1 #define disp_line 0 x38/两行显示,5*7点阵/LCD控制端口定义#define LCD_C

23、TRL_PORT PORTC#define LCD_CTRL_DDR DDRC/LCD数据端口定义#define LCD_PORT PORTB#define LCD_PIN PINB #define LCD_DDR DDRB / LCD控制功能定义 #define RS_0() LCD_CTRL_PORT &= 0 xFE#define RS_1() LCD_CTRL_PORT |= 0 x01#define RW_0() LCD_CTRL_PORT &= 0 xFD#define RW_1() LCD_CTRL_PORT |= 0 x02#define EN_0() LCD_CTRL_POR

24、T &= 0 xFB#define EN_1() LCD_CTRL_PORT |= 0 x04/定义键盘口#define key_DDR DDRA#define key_PORT PORTA#define key_PIN PINA/按键四状态#define State_NoKey0#define State_KeyPress1#define State_ValidKey2#define State_KeyRelease3int State_Key = State_NoKey; /键状态,初始为无键按下状态 volatile unsigned char value_keyscan;/扫描到的键值

25、/本章矩阵键盘扫描函数key_scan()放于此处/本章键盘状态机函数放于此处/键盘扫描返回值对应按键函数unsigned char key_process(unsigned char key_value)unsigned char key_x;switch(key_value)case 0 x11:/检测到第1行第1列按键key_x = 0 x43;/C的Ascii码,清屏指令 break;case 0 x12:/检测到第1行第2列按键key_x = 0 x31;/1的Ascii码break;case 0 x14:/检测到第1行第3列按键key_x = 0 x32;/2的Ascii码brea

26、k;case 0 x18:/检测到第1行第4列按键key_x = 0 x2B;/+的Ascii码break;case 0 x21:/检测到第2行第1列按键key_x = 0 x33;/3的Ascii码break;case 0 x22:/检测到第2行第2列按键key_x = 0 x34;/4的Ascii码break;case 0 x24:/检测到第2行第3列按键key_x = 0 x35;/5的Ascii码break;case 0 x28:/检测到第2行第4列按键key_x = 0 x2D;/+的Ascii码break;case 0 x41:/检测到第3行第1列按键key_x = 0 x36;/6的Ascii码break;case 0 x42:/检测到第3行第2列按键key_x = 0 x37;/7的Ascii码break;case 0 x44:/检测到第3行第3列按键key_x = 0 x38;/8的Ascii码break;case 0 x48:/检测到第3行第4列按键key_x = 0 x78;/X的Ascii码break;case 0 x81:/检测到第4行第1列按键key_x = 0 x39;/9的Ascii码break;case 0 x82:/检测到第4行第2列按键key_x

温馨提示

  • 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
  • 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
  • 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
  • 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
  • 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
  • 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
  • 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。

评论

0/150

提交评论