矩阵键盘扫描函数
- 格式:pdf
- 大小:177.91 KB
- 文档页数:5
//4*4矩阵式键盘扫描程序module keyscan(row, col, clk, key_buf);input [3:0] col; //列线定义input clk; //150MHZoutput [3:0] row; //行线定义output [7:0] key_buf; //键值输出口reg [3:0] row;reg [7:0] key_buf; //键值输出缓冲寄存器reg [7:0] key_buf1; //键值暂存器reg [3:0] count1;reg [14:0] count2;reg [3:0] state;reg [3:0] state_temp;reg sec, en;/*********************产生5MHZ方波****************/ always@(posedge clk )beginif(count1 == 4'd15)beginsec <= ~sec;count1 <= 4'd0;endelsecount1 <= count1+1'b1;endalways@(negedge sec)beginif(en)begincase(state)/******************** 准备进入行扫描状态*************/4'd0://KEY //开始扫描beginrow[3:0] <= 4'b0000; //行线全部置零state_temp = 4'd1;state = 4'd9; //5ms消抖end/*********************扫描第一行**********************/4'd1://KEYTEMPbeginif(col[3:0] == 4'b1111) //判断是否有键按下?state = 4'd0; //没有就重新扫描elsebeginrow[3:0] <= 4'b1110;state_temp = 4'd2;state = 4'd9; //如果有就延时去抖endend/********************检测第一行键值*******************/4'd2://ROW1begincase({row[3:0],col[3:0]}) //第一行判断8'b1110_1111: //无键按下beginkey_buf1 <= 8'b1111_1111;state = 4'd3; //进入第二行扫描end8'b1110_1110: //键值1beginkey_buf1 <= 8'b1111_1110; //键值放入key_buf1state = 4'd10; //等待弹起end8'b1110_1101: //键值2beginkey_buf1 <= 8'b1111_1101;state = 4'd10;end8'b1110_1011: //键值3beginkey_buf1 <= 8'b1111_1011;state = 4'd10;end8'b1110_0111: //键值4beginkey_buf1 <= 8'b1111_0111;state = 4'd10;enddefault:beginkey_buf1 <= 8'b1111_1111;state = 4'd3; //进入第二行扫描endendcaseend/*********************第二行扫描*********************/4'd3://ROW2TEMPbeginrow[3:0] <= 4'b1101;state_temp = 4'd4;state = 4'd9;end/***********************检测第二行键值***************/4'd4://ROW2begincase({row[3:0], col[3:0]})8'b1101_1111: //若无键按下beginkey_buf1 <= 8'b1111_1111;state = 4'd5; //进入第三行扫描end8'b1101_1110: //键值5beginkey_buf1 <= 8'b1110_1111;state = 4'd10; //等待弹起end8'b1101_1101: //键值6beginkey_buf1 <= 8'b1101_1111;state = 4'd10;end8'b1101_1011: //键值7beginkey_buf1 <= 8'b1011_1111;state = 4'd10;end8'b1101_0111: //键值8beginkey_buf1 <= 8'b0111_1111;state = 4'd10;enddefault:beginkey_buf1 <= 8'b1111_1111;state = 4'd5; //进入第三行扫描endendcaseend/**********************第三行扫描********************/4'd5://ROW3TEMPbeginrow[3:0] <= 4'b1011;state_temp = 4'd6;state = 4'd9;end/*********************检测第三行键值*****************/4'd6://ROW3begincase({row[3:0], col[3:0]})8'b1011_1111: //若无键按下beginkey_buf1 <= 8'b1111_1111;state = 4'd7; //进入第四行扫描end8'b1011_1110: //键值9beginkey_buf1 <= 8'b1111_1110;state = 4'd10; //等待弹起end8'b1011_1101: //键值10beginkey_buf1 <= 8'b1111_1100;state = 4'd10;end8'b1011_1011: //键值11beginkey_buf1 <= 8'b1111_1000;state = 4'd10;end8'b1011_0111: //键值12beginkey_buf1 <= 8'b1111_0000;state = 4'd10;enddefault:beginkey_buf1 <= 8'b1111_1111;state = 4'd7; //进入第四行扫描endendcaseend/********************第四行扫描**********************/4'd7://ROW4TEMPbeginrow[3:0] <= 4'b0111;state_temp = 4'd8;state = 4'd9;end/*********************检测第四行键值******************/ 4'd8://ROW4begincase({row[3:0], col[3:0]})8'b0111_1111: //若无键按下beginkey_buf1 <= 8'b1111_1111;state = 4'd0; //重新进入扫描end8'b0111_1110: //键值13beginkey_buf1 <= 8'b1110_0000;state = 4'd10; //等待弹起end8'b0111_1101: //键值14beginkey_buf1 <= 8'b1100_0000;state = 4'd10;end8'b0111_1011: //键值15beginkey_buf1 <= 8'b1000_0000;state = 4'd10;end8'b0111_0111: //键值16beginkey_buf1 <= 8'b0000_0000;state = 4'd10;enddefault:beginkey_buf1 <= 8'b1111_1111;state = 4'd0; //重新进入扫描endendcaseend/***********************去抖延时********************/ 4'd9://DELAYbeginif(count2 ==15'd25000)beginstate = state_temp;count2 <= 0;endelsecount2 <= count2+1'b1;end/************************等待弹起******************/ 4'd10://WAITbeginif(col[3:0] == 4'b1111)beginkey_buf <= key_buf1;state <= 4'd0;endelsestate = 4'd10;endendcaseend/*******************否则,变量初始化****************/ elsebeginstate = 4'd0;count2 <= 0;key_buf <= 8'b0000_0000;row[3:0] <= 4'b0000;en <= 1;endendendmodule附:程序配套的4*4矩阵键盘电路图其中:P2.3 ~P2.0对应row[3:0];P3.7 ~P3.4对应line[3:0]。
#include<reg52.h>//STC89C52RC 头文件#include<intrins.h>//_crol_函数的头文件#define uint unsigned int//宏定义#define uchar unsigned char//宏定义uchar num;//定义全局变量uchar codetable[]={0x3f,0x06,0x5b,0x4f,0x66,0x6d,0x7d,0x07,0x7f,0x6f,0x77,0x7c,0x39,0x5e, 0x79,0x71};//共阳极数码管字符表void delay(uint xms) //延时函数{uint i,j;for(i=0;i<xms;i++)for(j=0;j<110;j++);}void display(num) //显示函数{uchar numwe,xwei;xwei=6;//用几位数码管显示?numwe=0xfe;//初始化数码管位选控制for(;xwei!=0;xwei--){dula=1; //开段选锁存器P0=table[num];//送显示数dula=0; //关段选锁存器P0=0xff;//消影wela=1; //开位选锁存器P0=numwe;//送数码管位选控制wela=0; //关位选锁存器numwe=_crol_(numwe,1); //对数码管位选控制左移位delay(1);//调用延时函数}}void keyscan()//矩阵键盘扫描函数开始{uchar x,y,key,temp;//定义:行坐标x、列坐标y、按键keytemp=0x0f;// 0000 1111P3=temp;//P3口:4列送0000、4行送1111;if (P3!=temp)//1判断是否有按键按下;{delay(10);//延时10毫秒消抖动;P3=temp;//P3口:列送0000、行送1111;if (P3!=temp)//2次判断是否有按键按下;{x=P3&temp;//取按下矩阵键盘的行坐标temp=~temp;//按位取反,线反转使用;P3=temp;//线反转P3口:4列送高电平、4行送低电平; y=P3&temp;//取按下矩阵键盘的列坐标key=x|y;//行坐标x、列坐标y 进行或运算组合在一起。
单片机矩阵键盘扫描的两种方式单片机矩阵键盘扫描的两种方式矩阵键盘扫描方式:第一种:逐行扫描法,就是一行一行的扫描。
实现代码如下(键盘连接P2口):#define NO_KEY 0XFF#define KEY_LO() P2 &= 0XF0#define KEY_HI() P2 |= 0X0F#define KEY_L(i) P2 &= ~(1<<i)#define KEY_RD() ((P2>>4) & 0x0f)UINT8 OnceKey(void){UINT8 line = 0;UINT8 key = NO_KEY;//key valueKEY_LO();if (KEY_RD() == 0X0F){KEY_HI();return NO_KEY;}for (line=0; line<4; line ++){KEY_HI();KEY_L(line);key = KEY_RD();switch (key){case ROW_FIRST:key = 4*line + 0;break;case ROW_SECOND:key = 4*line + 1;break;case ROW_THIRD:key = 4*line + 2;break;case ROW_FOURTH:key = 4*line +3;break;default :key = 0x0f;break;}if (key < 0x10){return key;}}return NO_KEY;}第二种,线性反转法。
就是行和列分别读出。
实现代码如下:#define CVT(i) ((i)==(~1)&0x0f)? 0: ((i)==(~2)&0x0f)? 1: ((i)==(~4)&0x0f)? 2: ((i)==(~8)&0x0f)? 3: 4;#define KEY0_3HI() P2 |= 0X0F#define KEY0_3LO() P2 &= 0XF0#define KEY4_7HI() P2 |= 0XF0#define KEY4_7LO() P2 &= 0X0F#define KEY0_3RD() (P2 & 0X0F)#define KEY4_7RF() ((P2>>4) & 0X0F)UINT8 OnceKey(void){UINT8 line = NO_KEY;UINT8 row = NO_KEY;UINT8 key;KEY0_3HI();KEY4_7LO();line = KEY0_3RD();//读入行的值if (0x0f == line){key = NO_KEY;}else{KEY0_3LO();KEY4_7HI();row = KEY4_7RD();//读入列的值if (0x0f == row){key = NO_KEY;}else{key = CVT(line)*4 + CVT(row);}}KEY0_3HI();KEY4_7HI();return key; }。
3x4矩阵键盘的扫描程序(C语言)#includeunsigned char code table[]={0xC0,0xF9,0xA4,0xB0,0x99, //0~4 0x92,0x82,0xF8,0x80,0x90, //5~90x88,0x83,0xA7,0xA1,0x86,0x8E}; //A~Fvoid KeyScan();void delay10ms(unsigned char time);void Dispaly(unsigned char k);unsigned char key,temp;void main() //主程序{while(1){KeyScan();}}void KeyScan() //按键扫描子程序{P1=0xFF;P1_3=0;temp=P1;temp&=0xF0;if(temp !=0xF0){delay10ms(1);temp=P1;temp&=0xF0;if(temp !=0xF0){temp=P1;temp&=0xF0;switch(temp){case 0x70:key=1;break;case 0xB0:key=2;break;case 0xD0:key=3;break;}}}P1=0xFF;P1_2=0;temp=P1;temp&=0xF0;if(temp !=0xF0) {delay10ms(1); temp=P1; temp&=0xF0; if(temp !=0xF0) {temp=P1; temp&=0xF0;switch(temp) {case 0x70:key=4;break; case 0xB0:key=5;break; case 0xD0:key=6;break; }Dispaly(key); }}P1=0xFF;P1_1=0;temp=P1;temp&=0xF0;if(temp !=0xF0) {delay10ms(1); temp=P1; temp&=0xF0; if(temp !=0xF0) {temp=P1; temp&=0xF0;switch(temp) {case 0x70:case 0xB0:key=8;break;case 0xD0:key=9;break;}Dispaly(key);}}P1=0xFF;P1_0=0;temp=P1;temp&=0xF0;if(temp !=0xF0){delay10ms(1);temp=P1;temp&=0xF0;if(temp !=0xF0){temp=P1;temp&=0xF0;switch(temp){case 0x70:key=14;break;case 0xB0:key=0;break;case 0xD0:key=15;break;}Dispaly(key);}}}//延时程序void delay10ms(unsigned char time) {unsigned char a,b,c;for(a=0;a for(b=0;b<10;b++)for(c=0;c<120;c++);}void Dispaly(unsigned char k) //显示程序{P0=table[k];P2_1=0;}流水广告灯设计程序利用取表的方法,使端口P1做单一灯的变化:左移2次,右移2次,闪烁2次(延时的时间0.2秒)。
矩阵键盘(Verilog)module matrixKeyboard_drive(input i_clk,input i_rst_n,input [3:0] row, // 矩阵键盘行output reg [3:0] col, // 矩阵键盘列output reg [3:0] keyboard_val // 键盘值);//++++++++++++++++++++++++++++++++++++++// 分频部分开始//++++++++++++++++++++++++++++++++++++++reg [19:0] cnt; // 计数子always @ (posedge i_clk, negedge i_rst_n)if (!i_rst_n)cnt <= 0;elsecnt <= cnt + 1'b1;wire key_clk = cnt[19]; // (2^20/50M = 21)ms //--------------------------------------// 分频部分结束//--------------------------------------//++++++++++++++++++++++++++++++++++++++// 状态机部分开始//++++++++++++++++++++++++++++++++++++++// 状态数较少,独热码编码parameter NO_KEY_PRESSED = 6'b000_001; // 没有按键按下parameter SCAN_COL0 = 6'b000_010; // 扫描第0列parameter SCAN_COL1 = 6'b000_100; // 扫描第1列parameter SCAN_COL2 = 6'b001_000; // 扫描第2列parameter SCAN_COL3 = 6'b010_000; // 扫描第3列parameter KEY_PRESSED = 6'b100_000; // 有按键按下reg [5:0] current_state, next_state; // 现态、次态always @ (posedge key_clk, negedge i_rst_n)if (!i_rst_n)current_state <= NO_KEY_PRESSED;elsecurrent_state <= next_state;// 根据条件转移状态always @ *case (current_state)NO_KEY_PRESSED : // 没有按键按下if (row != 4'hF)next_state = SCAN_COL0;elsenext_state = NO_KEY_PRESSED;SCAN_COL0 : // 扫描第0列if (row != 4'hF)next_state = KEY_PRESSED;elsenext_state = SCAN_COL1;SCAN_COL1 : // 扫描第1列if (row != 4'hF)next_state = KEY_PRESSED;elsenext_state = SCAN_COL2;SCAN_COL2 : // 扫描第2列if (row != 4'hF)next_state = KEY_PRESSED;elsenext_state = SCAN_COL3;SCAN_COL3 : // 扫描第3列if (row != 4'hF)next_state = KEY_PRESSED;elsenext_state = NO_KEY_PRESSED;KEY_PRESSED : // 有按键按下if (row != 4'hF)next_state = KEY_PRESSED;elsenext_state = NO_KEY_PRESSED;endcasereg key_pressed_flag; // 键盘按下标志reg [3:0] col_val, row_val; // 列值、行值// 根据次态,给相应寄存器赋值always @ (posedge key_clk, negedge i_rst_n)if (!i_rst_n)begincol <= 4'h0;key_pressed_flag <= 0;endelsecase (next_state)NO_KEY_PRESSED : // 没有按键按下begincol <= 4'h0;key_pressed_flag <= 0; // 清键盘按下标志endSCAN_COL0 : // 扫描第0列col <= 4'b1110;SCAN_COL1 : // 扫描第1列col <= 4'b1101;SCAN_COL2 : // 扫描第2列col <= 4'b1011;SCAN_COL3 : // 扫描第3列col <= 4'b0111;KEY_PRESSED : // 有按键按下begincol_val <= col; // 锁存列值row_val <= row; // 锁存行值 key_pressed_flag <= 1; // 置键盘按下标志endendcase//--------------------------------------// 状态机部分结束//--------------------------------------//++++++++++++++++++++++++++++++++++++++// 扫描行列值部分开始//++++++++++++++++++++++++++++++++++++++always @ (posedge key_clk, negedge i_rst_n)if (!i_rst_n)keyboard_val <= 4'h0;elseif (key_pressed_flag)case ({col_val, row_val})8'b1110_1110 : keyboard_val <= 4'h0;8'b1110_1101 : keyboard_val <= 4'h4;8'b1110_1011 : keyboard_val <= 4'h8;8'b1110_0111 : keyboard_val <= 4'hC;8'b1101_1110 : keyboard_val <= 4'h1;8'b1101_1101 : keyboard_val <= 4'h5;8'b1101_1011 : keyboard_val <= 4'h9;8'b1101_0111 : keyboard_val <= 4'hD;8'b1011_1110 : keyboard_val <= 4'h2;8'b1011_1101 : keyboard_val <= 4'h6;8'b1011_1011 : keyboard_val <= 4'hA;8'b1011_0111 : keyboard_val <= 4'hE;8'b0111_1110 : keyboard_val <= 4'h3;8'b0111_1101 : keyboard_val <= 4'h7;8'b0111_1011 : keyboard_val <= 4'hB;8'b0111_0111 : keyboard_val <= 4'hF;endcase//--------------------------------------// 扫描行列值部分结束//--------------------------------------endmodule。
矩阵键盘扫描的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端口。