键盘驱动程序程鼐

合集下载

单片机系统中ps2键盘驱动程序的设计

单片机系统中ps2键盘驱动程序的设计

在单片机系统中,经常使用的键盘都是专用键盘.此类键盘为单独设计制作的,成本高、使用硬件连接线多,且可靠性不高,这一状况在那些要求键盘按键较多的应用系统中更为突出.与此相比,在PC系统中广泛使用PS/2键盘具有价格低、通用可靠,且使用连接线少(仅使用2根信号线)的特点,并可满足多种系统的要求.因此在单片机系统中应用PS/2键盘是一种很好的选择.文中在介绍PS/2协议和PS/2键盘工作原理与特点的基础上,给出了一个在单片机上实现对PS/2键盘支持的硬件连接与驱动程序设计实现.该设计实现了在单片机系统中对PS/2标准104键盘按键输入的支持.使用Keil C51开发的驱动程序接口和库函数可以方便地移植到其他单片机或嵌入式系统中.所有程序在Keil uVision2上编译通过,在单片机AT89C51上测试通过.1 PS/2协议目前,PC机广泛采用的PS/2接口为mini-DIN 6pin的连接器,如图1所示.PS/2设备有主从之分,主设备采用Female插座,从设备采用Male插头.现在广泛使用的PS/2键盘鼠标均在从设备方式下工作.PS/2接口的时钟与数据线都是集电极开路结构,必须外接上拉电阻(一般上拉电阻设置在主设备中).主从设备之间数据通信采用双向同步串行方式传输,时钟信号由从设备产生.1.1 从设备到主设备的通信当从设备向主设备发送数据时,首先检查时钟线,以确认时钟线是否为高电平.如果是高电平,从设备就可以开始传输数据;反之,从设备要等待获得总线的控制权,才能开始传输数据.传输的每一帧由11位组成,发送时序及每一位的含义如图2所示.每一帧数据中开始位总是为0,数据校验采用奇校验方式,停止位始终为1.从设备到主设备通信时,从设备总是在时钟线为高时改变数据线状态,主设备在时钟下降沿读人数据线状态.1.2 主设备到从设备的通信主设备与从设备进行通信时,主设备首先将时钟线和数据线设置为“请求发送”状态,具体方式为:首先下拉时钟线至少100us抑制通信,然后下拉数据线“请求发送”,最后释放时钟线.在此过程中,从设备在不超过10us 的间隔内必须检查这个状态,当设备检测到这个状态时,它将开始产生时钟信号.此时数据传输的每一帧由12位构成,其时序和每一位含义如图3所示.与从设备到主设备通信相比,其每帧数据多了一个ACK位.这是从设备应答接收到字节的应答位,由从设备通过拉低数据线产生,应答位ACK总是为0.主设备到从设备通信过程中,主设备总是在时钟线为低电平时改变数据线的状态,从设备在时钟上升沿读人数据线状态.2 PS/2键盘的编码与命令集2.1 PS/2键盘的编码目前,PC机使用的PS/2键盘都默认采用第2套扫描码集.扫描码有两种不同的类型:“通码(make code)”和“断码(break code)”.当一个键被按下或持续按住时,键盘会将该键的通码发送给主机;而当一个键被释放时,键盘会将该键的断码发送给主机.根据键盘按键扫描码的不同,可将按键分为3类:第1类按键通码为一个字节,断码为0xF0+通码形式.如A键,其通码为0x1C;断码为0xF0 0x1C.第2类按键通码为两字节0xE0+0xXX形式,断码为0xE0+0xF0+0xXX形式.如Right Ctrl键,其通码为0xE0 0x14;断码为0xE0 0xF0 0x14.第3类特殊按键有两个,Print Screen键,其通码为0xE0 0x12 0xE0 0x7C;断码为0xE0 0xF0 0x7C 0xE0 0xF0 0x12.Pause键,其通码为0xE1 0x14 0x77 0xE1 0xF0 0xl4 0xF0 0x77;断码为空.组合按键扫描码的发送是按照按键发生的次序,如按下面顺序按左Shift十A键:①按下左Shift键;②按下A键;③释放A键;④释放左Shift键,那么计算机上接收到的一串数据为0x12 0x1C 0xF0 0x1C 0xF0 0x12.在文中的驱动程序设计中,就是根据按键的分类对其分别进行处理.2.2 PS/2键盘的命令集主机可通过向PS/2键盘发送命令对键盘进行设置或者获得键盘的状态等操作.每发送一个字节,主机都会从键盘获得一个应答0xFA(“重发resend”和“回应echo”命令例外).驱动程序在键盘初始化过程中所用的指令:0xED,主机在该命令后跟随发送一个参数字节,用于指示键盘上Num Lock,Caps Lock,Scroll Lock Led的状态;0xF3,主机在这条命令后跟随发送一个字节参数定义键盘机打的速率和延时;0xF4,用于当主机发送0xF5禁止键盘后,重新使能键盘.3 PS/2键盘与单片机的连接电路PS/2键盘与AT89C51单片机的连接方式如图4所示.P1.0接PS/2数据线;P3.2(INT0)接PS/2时钟线.因为单片机的P1,P3口内部是带上拉电阻的,所以PS/2的时钟线和数据线可以直接与单片机的P1,P3相连接.4 驱动程序设计驱动程序的开发使用Keil C51语言以及KeiluVision2编程环境.PS/2 104键盘驱动程序主要任务是实现单片机与键盘间PS/2通信,同时将接收到的按键扫描码转换为该按键的键值KeyVal,提供给系统上层软件使用.4.1 单片机与键盘间PS/2通信的程序设计在PS/2通信过程中,主设备(文中是单片机)是在时钟信号为低时发送和接收数据信号.因为单片机向键盘发送的是指令,需要键盘回应,所以这部分程序采用查询方式;而单片机接收键盘数据时,数据线上的信号在时钟为低时已经稳定,所以这部分程序采用中断方式,且不需要在程序中加入延时程序.单片机向PS/2键盘发送数据程序代码为:void ps2_sentchar(unsigned char sentchar){//ps2主设备向从设备发送数据unsigned char sentbit_cnt= 0x00;unsigned char sentchar_chk = 0x00;EX0=0; //关外部中断0//发起一个传送,发起始位PS2_SGN_CLOCK = 0; //将时钟线拉低并保持100 usdelay100us();PS2_SGN_DATA= 0; //起始位PS2_SGN_CLOCK = 1;//发送DATA0-7for(sentbit_cnt=0;sentbit_cnt< 8;sentbit_cnt++){while(PS2_SGN_CLOCK) _nop_(); //等待时钟线变为低PS2_SGN_DATA = sentchar& 0x01;//发送数据if(PS2_SGN_DATA) sentchar_chk++; //计算校验while(!PS2_SGN_CL0CK) _nop_(); //等待时钟线变高sentchar>>=1; //待发送数据右移一位}//发送校验位while(PS2_SGN_CLOCK) _nop_(); //等待时钟线变低switch(sentchar_chk){case 0:case 2:case 4:case 6:PS2_SGN_DATA =1;break;//奇校验case 1:case 3:case 5:case 7:PS2_SGN_DATA = 0;break;//奇校验default;break;)while(!PS2_SGN_CLOCK) _nop_(); //等待时钟线变高while(PS2_SGN_CLOCK) _nop_(); //等待时钟线变低PS2_SGN_DATA =1;//发送停止位,停止位总为1while(!PS2_SGN_CLOCK) _nop_(); //等待时钟线变高while(PS2_SGN_CLOCK) _nop_(); //等待时钟线变低//接收ACK//if(PS2_SGN_DATA) error();//ACK信号由键盘发出,总为低电平while(!PS2_SGN_CLOCK) _nop_(); //等待时钟线变高EX0= 1; //开外部中断0}单片机由PS/2键盘接收数据程序:外部中断0设置为下降沿触发void int0() interrupt 0 using 0 {//EX0=0; //关外部中断0switch(ps2_revchar_cnt){case 1:……case 8:mcu_revchar<<=1;if(PS2_SGN_DATA) mcu_revchar |= 0x01;ps2_revchar_cnt++;break;case 0:ps2_revchar_cnt++;break; //开始位,case 9:ps2_revchar_cnt++;break; //校验位,可添加校验程序case 10: _nop_();//停止位ps2_revchar_cnt= 0;revchar_flag=1;//置接收到数据标识位break;default:break;}EX0=1;//开外部中断0}4.2 键盘扫描码转换程序设计由于键盘扫描码无规律可循,因此由键盘扫描码获得相应按键的键值(字符键为其ASCII值,控制键如F1,Ctrl等为自定义值),只能通过查表的方式获得.由于按键的3种类型及部分按键对应着两个键值(如A键的键值根据Caps和Shift键状态有0x41(A)和0x61(a)两种),因此综合考虑查表转换速度和资源消耗,设计中使用4个键盘表:键盘扫描码转换基本集和切换集(kb_plain_map[NR_KEYS]与kb_shift_map[NR_KEYS]);包含E0前缀的键盘扫描码转换基本集和切换集(kbeO_plain_map[NR_KEYS]与kbe0_shiftmap[NR_KEYS]).PS/2 104键盘按键扫描码最大值为0x83,所以设置NR_KEYS为132.所有4个键盘表的定义均为如下形式:KB_MAP[MAKE CODE]=KEYVAL,如果扫描码对应的按键为空(如KB_MAP[0x00]),则定义相应键值为NULL_KEY(0x00).以下是键盘扫描码基本集的部分代码实例:kb_plain_map[NR_K EYS]={……NULL_KEY;0x2C;0x6B;0x69;0x6F;0x30;0x39;NULL_KEY; //扫描码0x40~0x47//对应按键空,逗号,K,I,O,0,9,空//对应键值0x00,',','k','i','o','O','9',0x00…… };如此设计键盘转换表的另一个好处在于,以后如需扩展支持有ACPI、Windows多媒体按键键盘时,只需要将键表中相应处修改即可,如ACPIPower按键通码为0xE0 0x37,修改kbe0_plain_map[0x37]=KB_ACPI_PWR即可.特殊按键Pause使用单独程序处理,如果接收到0xE1就转入这段程序.而Print Screen键则将其看作是两个通码分别为0xE0 0x12和0xE0 0x7C的“虚键”的组合键处理.在驱动程序中设定如下全局变量:led_status记录Scroll Lock Led,Num Lock Led和Caps Lock Led的状态(关为0,开为1);agcs_status记录左右Shift Ctrl Gui Alt状态,相应键按下则对应位为1,释放为0.E0_FLAG接到0xE0置1;E1_FLAG接收到0xE1置1;F0_FLAG接收到0xF0置1.按键键值通过KeyVal提供上层程序使用.PS/2键盘扫描码键值转换程序ps2_codetrans()流程框架如图5所示.第1类按键的扫描码键值转换程序代码。

基于嵌入式linux的串口自定义键盘驱动开发

基于嵌入式linux的串口自定义键盘驱动开发

291基于嵌入式Linux 的串口自定义键盘驱动开发张士林(江苏自动化研究所,江苏连云港222006)摘要:近年,随着科技发展,嵌入式已成为当今时代产业主流。

而嵌入式Linux 的优势使其成为主要的操作系统之一。

本文介绍了Linux 下驱动开发的一般模式,详细分析了基于串口通讯的自定义键盘驱动的开发方法,对嵌入式Linux 驱动开发有一定程度的指导作用。

关键词:嵌入式Linux 系统;串口键盘;驱动开发中图分类号:TP316.2文献标识码:A 文章编号:1673-1131(2019)12-0291-02Abstract:In recent years,with the development of science and technology,embedded technology has become the mainstream of the industry.The advantages of embedded Linux make it one of the main operating systems.This paper introduces the general mode of driver development under Linux,and analyzes in detail the development method of custom keyboard driver based on serial port communication.This paper has certain reference signification for the research and development of embedded system.Key words:embedded Linux system;serial keyboard driver;driver development0引言嵌入式系统(Embedded system ),是一种“完全嵌入受控器件内部,为特定应用而设计的专用计算机系统”。

19264显示驱动程序

19264显示驱动程序

19264控制器KS0108#include <at89x52.h>#include <intrins.h>#include "zimo.h"#define RS P2_6 /*"H" is send or read the data;"L" is the instruction*/ #define RW P3_6#define E P2_5 /*Operation enable*/#define CS1 P2_4#define CS2 P2_3#define CS3 P2_2#define DATA P0#define uchar unsigned char#define uint unsigned int/* -------------------------------------------------Delay some time----------- */void delay10ms(unsigned char x){unsigned char i,j,k;for(i=0;i<x;i++)for(j=0;j<10;j++)for(k=0;k<120;k++);}/* -------------------------------------------------Send the instruction to the First KS0108 window--*/void OutFI(uchar i){unsigned char data_sta;do{E=0;RW=1;RS=0;CS1=0;_nop_();E=1;_nop_();data_sta=DATA;E=0;RW=0;CS1=1;E=1;}while(data_sta&0x80);E=0;RW=0;RS=0;CS1=0;_nop_();E=1;_nop_();DATA=i;_nop_();E=0;RW=1;CS1=1;E=1;}/* ------------------------------------------------- Send the instruction to the Second KS0108 window.--*/void OutSI(uchar i){unsigned char data_sta;do{E=0;RW=1;RS=0;CS2=0;_nop_();E=1;_nop_();data_sta=DATA;E=0;RW=0;CS2=1;E=1;}while(data_sta&0x80);E=0;RW=0;RS=0;CS2=0;_nop_();E=1;_nop_();DATA=i;_nop_();E=0;RW=1;CS2=1;E=1;}/* ------------------------------------------------- Send the instruction to the Third KS0108 window--*/void OutTI(uchar i){unsigned char data_sta;do{E=0;RW=1;RS=0;CS3=0;_nop_();E=1;_nop_();data_sta=DATA;E=0;RW=0;CS3=1;E=1;}while(data_sta&0x80);E=0;RW=0;RS=0;CS3=0;_nop_();E=1;_nop_();DATA=i;_nop_();E=0;RW=1;CS3=1;E=1;}/* -------------------------------------------------Send the data to the First ks0108 Window--*/void OutFD(uchar i){unsigned char data_sta;do{E=0;RW=1;RS=0;CS1=0;_nop_();E=1;_nop_();data_sta=DATA;E=0;RW=0;CS1=1;E=1;}while(data_sta&0x80);E=0;RW=0;RS=1;CS1=0;_nop_();E=1;_nop_();DATA=i;_nop_();E=0;RW=1;CS1=1;E=1;}/* ------------------------------------------------- Send the data to the Second ks0108 Window--*/void OutSD(uchar i){unsigned char data_sta;do{E=0;RW=1;RS=0;CS2=0;_nop_();E=1;_nop_();data_sta=DATA;E=0;RW=0;CS2=1;E=1;}while(data_sta&0x80);E=0;RW=0;RS=1;CS2=0;_nop_();E=1;_nop_();DATA=i;_nop_();E=0;RW=1;CS2=1;E=1;}/* ------------------------------------------------- Send the data to the Third ks0108 Window--*/void OutTD(uchar i){unsigned char data_sta;do{E=0;RW=1;RS=0;CS3=0;_nop_();data_sta=DATA;E=0;RW=0;CS3=1;E=1;}while(data_sta&0x80);E=0;RW=0;RS=1;CS3=0;_nop_();E=1;_nop_();DATA=i;_nop_();E=0;RW=1;CS3=1;E=1;}/* ------------------------------------------------- Read the data to the First ks0108 Window--*//*unsigned char RD_data_F(){unsigned char data_sta;do{E=0;RW=1;RS=0;CS1=0;_nop_();E=1;_nop_();data_sta=DATA;E=0;RW=0;CS1=1;E=1;}while(data_sta&0x80);E=0;RW=1;RS=1;CS1=0;_nop_();E=1;_nop_();_nop_();_nop_();data_sta=DATA;_nop_();E=0;RW=0;CS1=1;E=1;return (data_sta);}/* ------------------------------------------------- Read the data to the Second ks0108 Window--*//*unsigned char RD_data_S(){unsigned char data_sta;do{E=0;RW=1;RS=0;CS2=0;_nop_();E=1;_nop_();_nop_();_nop_();data_sta=DATA;E=0;RW=0;CS2=1;E=1;}while(data_sta&0x80);E=0;RW=1;RS=1;CS2=0;_nop_();data_sta=DATA;_nop_();E=0;CS2=1;E=1;return (data_sta);}/* ------------------------------------------------- Read the data to the Third ks0108 Window--*//*unsigned char RD_data_T(){unsigned char data_sta;do{E=0;RW=1;RS=0;CS3=0;_nop_();E=1;_nop_();_nop_();_nop_();data_sta=DATA;E=0;RW=0;CS3=1;E=1;}while(data_sta&0x80);E=0;RW=1;RS=1;CS3=0;_nop_();E=1;_nop_();data_sta=DATA;_nop_();E=0;CS3=1;E=1;return(data_sta);}/* ------------------------------------------------- Initialize the LCD,The system reset,invoke First time-*/void InitLCD(){OutFI(0x40); /*Set the Y address 0 */OutSI(0x40);OutTI(0x40);OutFI(0xb8); /*Set the Page 0 */OutSI(0xb8);OutTI(0xb8);OutFI(0xc0); /*Set the display start line 0 */OutSI(0xc0);OutTI(0xc0);OutFI(0x3f); /*Display ON */OutSI(0x3f);OutTI(0x3f);}/* -------------------------------------------------Clear the three ks0108's display ram.Clrscr screen-*/void Clrscreen(){unsigned char i,j;for(i=0;i<8;i++){OutFI(0xb8|i);for(j=0;j<64;j++){OutFI(j|0x40);OutFD(0);}}for(i=0;i<8;i++)(OutSI(0xb8|i);for(j=0;j<64;j++)(OutSI(j|0x40);OutSD(0);}}for(i=0;i<8;i++)(OutTI(0xb8|i);for(j=0;j<64;j++)(OutTI(j|0x40);OutTD(0);}}}/* -------------------------------------------------Display Chinese ideograph;x_add is the x address;It has 4 layers,0,1,2,3; Width is the Chinese ideograph width;bmp is the table's name-*/void DrawBmp(uchar x_add,uchar layer,uchar width,uchar *bmp)(unsigned char x;unsigned int i=0;for(x=x_add;x<x_add+width;x++)(if (x>127) /*The Third KS0108*/(OutTI((x-128)|0x40); /*Set the x address*/OutTI(layer|0xb8); /*Set the y address*/OutTD(bmp[i]); /*Send thd data to LCD ram*/OutTI((x-128)|0x40); /*Display the down screen*/ OutTI((layer|0xb8)+1); i++; /*Display zimo table address add 1*/ OutTD(bmp[i]);}else if (x>63) /*The Second ks0108*/{OutSI((x-64)|0x40);OutSI(layer|0xb8);OutSD(bmp[i]);OutSI((x-64)|0x40);OutSI((layer|0xb8)+1);i++;OutSD(bmp[i]);}else /*The First ks0108*/{OutFI(x|0x40);OutFI(layer|0xb8);OutFD(bmp[i]);OutFI(x|0x40);OutFI((layer|0xb8)+1);i++;OutFD(bmp[i]);}i++;}}/* -------------------------------------------------Display Chinese ideograph;x_add is the x address;It has 4 layers,0,1,2,3; Width is the Chinese ideograph width;bmp is the table's name.-*/void DrawBmp_f(uchar x_add,uchar layer,uchar width,uchar *bmp) {unsigned char x;unsigned int i=0;for(x=x_add;x<x_add+width;x++) (if (x>127)(OutTI((x-128)|0x40);OutTI(layer|0xb8);OutTD(~bmp[i]);OutTI((x-128)|0x40);OutTI((layer|0xb8)+1);i++;OutTD(~bmp[i]);}else if (x>63)(OutSI((x-64)|0x40);OutSI(layer|0xb8);OutSD(~bmp[i]);OutSI((x-64)|0x40);OutSI((layer|0xb8)+1);i++;OutSD(~bmp[i]);}else(OutFI(x|0x40);OutFI(layer|0xb8);OutFD(~bmp[i]);OutFI(x|0x40);OutFI((layer|0xb8)+1);i++;OutFD(~bmp[i]);}i++;}}/*Display indention; x_add is the x address;It has 4 layers,0,1,2,3; Width is the Chinese ideograph width-*/void _DrawBmp_(uchar x_add,uchar layer,uchar width){unsigned char x;for(x=x_add;x<x_add+width;x++){if (x>127){OutTI((x-128)|0x40);OutTI(layer|0xb8);OutTD(0);OutTI((x-128)|0x40);OutTI((layer|0xb8)+1);OutTD(0);}else if (x>63){OutSI((x-64)|0x40);OutSI(layer|0xb8);OutSD(0);OutSI((x-64)|0x40);OutSI((layer|0xb8)+1);OutSD(0);}else{OutFI(x|0x40);OutFI(layer|0xb8);OutFD(0);OutFI(x|0x40);OutFI((layer|0xb8)+1);OutFD(0);/* --------------------------------------------------Display indention; x_add is the x address;It has 4 layers,0,1,2,3; Width is the Chinese ideograph width-*/void _DrawBmp_black(uchar x_add,uchar layer,uchar width){unsigned char x;for(x=x_add;x<x_add+width;x++){if (x>127){OutTI((x-128)|0x40);OutTI(layer|0xb8);OutTD(0xff);OutTI((x-128)|0x40);OutTI((layer|0xb8)+1);OutTD(0xff);}else if (x>63){OutSI((x-64)|0x40);OutSI(layer|0xb8);OutSD(0xff);OutSI((x-64)|0x40);OutSI((layer|0xb8)+1);OutSD(0xff);}else{OutFI(x|0x40);OutFI(layer|0xb8);OutFD(0xff);}}OutFI(x|0x40);OutFI((layer|0xb8)+1);OutFD(0xff);}}}/* --------------------------------------------------Display the line display_data_graph is the display graph data-*/void _DrawBmp_line(uchar x_add,uchar layer,uchar width,uchar display_data_graph) {unsigned char x;unsigned int i=0;for(x=x_add;x<x_add+width;x++){if (x>127){OutTI((x-128)|0x40);OutTI(layer|0xb8);OutTD(display_data_graph);}else if (x>63){OutSI((x-64)|0x40);OutSI(layer|0xb8);OutSD(display_data_graph);}else{OutFI(x|0x40);OutFI(layer|0xb8);OutFD(display_data_graph);}i++;/*Display the column display_data_graph is the display graph data-*/void _DrawBmp_column(uchar x,uchar width) {unsigned int i=0;if (x>127){for(i=0;i<width;i++){OutTI((x-128)|0x40);OutTI(i|0xb8);OutTD(0xff);}}else if (x>63){for(i=0;i<width;i++){OutSI((x-64)|0x40);OutSI(i|0xb8);OutSD(0xff);}}else{for(i=0;i<width;i++){OutFI(x|0x40);OutFI(i|0xb8);OutFD(0xff);}}}}}。

C51的4X4键盘程序设计

C51的4X4键盘程序设计

二、中断请求标志
1、TCON的中断标志
IT0(TCON.0),外部中断0触发方式控制位。 当IT0=0时,为电平触发方式。 当IT0=1时,为边沿触发方式(下降沿有效)。 IE0(TCON.1),外部中断0中断请求标志位。 IT1(TCON.2),外部中断1触发方式控制位。 IE1(TCON.3),外部中断1中断请求标志位。 TF0(TCON.5),定时/计数器T0溢出中断请求标志位。 TF1(TCON.7),定时/计数器T1溢出中断请求标志位。
图 3-3-4 利用延时函数消除键盘抖动实现键盘输入电路
二、程序设计
#include<reg51.h> #define uchar unsigned char code uchar seven_seg[10] = {0xc0,0xf9,0xa4,0xb0,0x99,0x92,0x82,0xf8,0x80,0x90}; sbit key1 = P3.0; sbit key2 = P3.1; uchar key1_state,key2_state; //按键按下的状态变量 void delay(uchar i) { while (i) i--; } void key_scan (void) //键盘扫描函数 { if(key1 == 0) //如果按键按下 { delay(200); //延时一段时间,消除键抖 while(key1 == 0) key1_state = 1; //再对按键检测,如果确实按 下,按键状态变量为1 } if(key2 == 0) { delay(200); while(key2 == 0) key2_state = 1; } }
3.3.4 4×4键盘程序设计

4×4键盘16键盘阵列,本案例采用P1口完成, 见图3-3-5所示,把P18条I/O口分成4条列线4条行 线交叉但不接触,16个按键放置交叉位置,在单 片机复杂系统需要较多按键时,这种接法可以节 省单片机的硬件资源。键盘和P1口之间采用总线 连接布局,在电路原理设计过程中,总线只是图 示引脚之间的相连接关系,但不具有电气连接特 性,相连引脚之间需要标注相同的网络标号采用 电气连接特性,如图3-3-5中,单片机的P1.0与键 盘阵列上的P1.0相连。在设计单片机系统或其它 电子系统时,由于器件引脚较多,器件与器件之 间会经常采用总线连接,并且把电路模块化设计。

usb键盘驱动 (2)

usb键盘驱动 (2)

USB键盘驱动简介USB键盘驱动是一种用于连接计算机和USB键盘的软件程序。

它的作用是使计算机能够正确地识别和响应来自USB键盘的输入信号,并将其转化为计算机可以理解的指令。

在计算机发展的早期阶段,键盘通常是通过传统的PS/2接口连接到计算机主机。

但随着USB(Universal Serial Bus,通用串行总线)技术的不断发展,USB键盘开始逐渐取代传统的PS/2键盘。

与PS/2键盘相比,USB键盘具有更高的传输速度、更大的数据带宽和更广泛的兼容性。

为了正常使用USB键盘,用户需要安装正确的USB键盘驱动程序。

本文将介绍USB键盘驱动的工作原理、安装方法和常见问题解决方法。

工作原理USB键盘驱动的工作原理可以简单分为以下几个步骤:1.设备识别:当用户将USB键盘插入计算机时,计算机会自动检测到新的USB设备并尝试识别其类型。

在识别过程中,计算机会自动加载适当的驱动程序。

2.驱动加载:计算机根据USB设备的类型加载相应的驱动程序。

对于USB键盘,计算机会加载USB键盘驱动程序。

驱动程序通常存储在操作系统的驱动库中。

3.功能映射:USB键盘驱动会解析来自键盘的输入信号,并将其转化为计算机可以理解的指令。

这些指令通常与键盘上的特定按键和功能相对应。

4.指令传递:USB键盘驱动将转化后的指令传递给操作系统,操作系统会根据指令执行相应的操作。

例如,当用户按下键盘上的某个按键时,驱动程序会将相应的指令传递给操作系统,并在屏幕上显示相应的字符或执行相应的操作。

安装方法安装USB键盘驱动可以通过以下几种方式实现:1.自动安装:大多数操作系统(如Windows、Mac和Linux)都具有自动安装驱动程序的功能。

当用户将USB键盘插入计算机时,操作系统会自动检测并加载相应的驱动程序。

用户只需要按照系统提示进行操作即可完成安装过程。

2.手动安装:在某些情况下,操作系统可能无法自动安装USB键盘驱动程序。

这时,用户可以尝试手动安装驱动程序。

STM32-矩阵键盘程序4×4课件.doc

STM32-矩阵键盘程序4×4课件.doc

/*--------------------------------------------------------------------------------------* 矩阵键盘驱动* 文件: keyboard.c* 编写人:LiuHui* 描述:扫描4x4 矩阵键盘输入,并返回键值* 适用范围:驱动采用ST3.5 库编写,适用于STM32F10x 系列单片机* 所用引脚:PA0-PA7* 编写时间:2014 年5 月20 日--------------------------------------------------------------------------------------*/#include "stm32f10x.h"#include "keyboard.h"#include "dealy.h"/*-------------------------------- 矩阵键盘初始化----------------------------------------* 功能:初始化stm32 单片机GPIO //PA0-PA7* 参数传递:* 输入:无* 返回值:无--------------------------------------------------------------------------------------*/void KeyBoard_Init(void){GPIO_InitTypeDef GPIO_InitStructure;GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0 | GPIO_Pin_1 | GPIO_Pin_2 | GPIO_Pin_3;GPIO_InitStructure.GPIO_Speed = GPIO_Speed_10MHz;GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;GPIO_Init(GPIOA, &GPIO_InitStructure);GPIO_InitStructure.GPIO_Pin = GPIO_Pin_4 | GPIO_Pin_5 | GPIO_Pin_6 | GPIO_Pin_7;GPIO_InitStructure.GPIO_Speed = GPIO_Speed_10MHz;GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPD;GPIO_Init(GPIOA, &GPIO_InitStructure);GPIO_SetBits(GPIOA, GPIO_Pin_0 | GPIO_Pin_1 | GPIO_Pin_2 | GPIO_Pin_3);GPIO_ResetBits(GPIOA, GPIO_Pin_4 | GPIO_Pin_5 | GPIO_Pin_6 | GPIO_Pin_7);}/*------------------------------ 矩阵键盘扫描--------------------------------------------* 功能:扫描矩阵键盘,并返回键值* 参数:* 输入:无* 返回:有键按下返回该键值* 无键按下时则返回0--------------------------------------------------------------------------------------*/u8 Read_KeyValue(void){u8 KeyValue=0;if((GPIO_ReadInputData(GPIOA)&0xff)!=0x0f){Delay_ms(10);if((GPIO_ReadInputData(GPIOA)&0xff)!=0x0f){GPIO_SetBits(GPIOA, GPIO_Pin_0);GPIO_ResetBits(GPIOA, GPIO_Pin_1 | GPIO_Pin_2 | GPIO_Pin_3);switch(GPIO_ReadInputData(GPIOA)&0xff){case 0x11: KeyValue = 1; break;case 0x21: KeyValue = 5; break;case 0x41: KeyValue = 9; break;case 0x81: KeyValue = 13;break;}GPIO_SetBits(GPIOA, GPIO_Pin_1);GPIO_ResetBits(GPIOA, GPIO_Pin_0 | GPIO_Pin_2 | GPIO_Pin_3);switch(GPIO_ReadInputData(GPIOA)&0xff){case 0x12: KeyValue = 2; break;case 0x22: KeyValue = 6; break;case 0x42: KeyValue = 10;break;case 0x82: KeyValue = 14;break;}GPIO_SetBits(GPIOA, GPIO_Pin_2);GPIO_ResetBits(GPIOA, GPIO_Pin_0 | GPIO_Pin_1 | GPIO_Pin_3);switch(GPIO_ReadInputData(GPIOA)&0xff){case 0x14: KeyValue = 3; break;case 0x24: KeyValue = 7; break;case 0x44: KeyValue = 11;break;case 0x84: KeyValue = 15;break;}GPIO_SetBits(GPIOA, GPIO_Pin_3);GPIO_ResetBits(GPIOA, GPIO_Pin_0 | GPIO_Pin_1 | GPIO_Pin_2);switch(GPIO_ReadInputData(GPIOA)&0xff){case 0x18: KeyValue = 4; break;case 0x28: KeyValue = 8; break;case 0x48: KeyValue = 12;break;case 0x88: KeyValue = 16;break;}GPIO_SetBits(GPIOA, GPIO_Pin_0 | GPIO_Pin_1 | GPIO_Pin_2 | GPIO_Pin_3); GPIO_ResetBits(GPIOA, GPIO_Pin_4 | GPIO_Pin_5 | GPIO_Pin_6 |GPIO_Pin_7);while((GPIO_ReadInputData(GPIOA)&0xff)!=0x0f);return KeyValue;}}return 0;}/*--------------------------------THE END--------------------------------------------*//*--------------------------------------------------------------------------------------* 矩阵键盘驱动* 文件: keyboard.h* 编写人:LiuHui* 描述:扫描4x4 矩阵键盘输入,并返回键值* 适用范围:驱动为ST3.5 库编写,适用于STM32F10x 系列单片机* 所用引脚:PA0-PA7* 编写时间:2013 年11 月22 日* 版本: 1.0--------------------------------------------------------------------------------------*/#ifndef __KEYBOARD_H#define __KEYBOARD_Hvoid KeyBoard_Init(void);u8 Read_KeyValue(void);#endif/*----------------------------------THE END------------------------------------------*#include "stm32f10x.h"void KeyBoard_Init(void){GPIO_InitTypeDef GPIO_InitStructure;GPIO_InitStructure.GPIO_Pin = GPIO_Pin_All;GPIO_InitStructure.GPIO_Speed = GPIO_Speed_2MHz;GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;GPIO_Init(GPIOA, &GPIO_InitStructure);GPIO_InitStructure.GPIO_Pin = GPIO_Pin_All;GPIO_InitStructure.GPIO_Speed = GPIO_Speed_2MHz;GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPD;GPIO_Init(GPIOB, &GPIO_InitStructure);GPIO_SetBits(GPIOB, GPIO_Pin_3 | GPIO_Pin_4 | GPIO_Pin_5 | GPIO_Pin_6);GPIO_ResetBits(GPIOB, GPIO_Pin_7 | GPIO_Pin_8 | GPIO_Pin_9 | GPIO_Pin_10);}//3?ê?? ˉPA,PBvoid Delay_ms(int time){int i=0;while(time--){i=12000;while(i--);}}u8 Read_KeyValue(void){u8 KeyValue=1;if((GPIO_ReadInputData(GPIOB)&0xff)!=0x0f){Delay_ms(10);if((GPIO_ReadInputData(GPIOB)&0xff)!=0x0f){GPIO_SetBits(GPIOB, GPIO_Pin_3);GPIO_ResetBits(GPIOB, GPIO_Pin_4 | GPIO_Pin_5 | GPIO_Pin_6); switch(GPIO_ReadInputData(GPIOB)&0xff){case 0x11: KeyValue = 7; break;case 0x21: KeyValue = 4; break;case 0x41: KeyValue = 1; break;case 0x81: KeyValue = 0; break;}GPIO_SetBits(GPIOB, GPIO_Pin_4);GPIO_ResetBits(GPIOB, GPIO_Pin_3 | GPIO_Pin_5 | GPIO_Pin_6); switch(GPIO_ReadInputData(GPIOB)&0xff){case 0x12: KeyValue = 8; break;case 0x22: KeyValue = 5; break;case 0x42: KeyValue = 2; break;case 0x82: KeyValue = 0; break;}GPIO_SetBits(GPIOB, GPIO_Pin_5);GPIO_ResetBits(GPIOB, GPIO_Pin_3 | GPIO_Pin_4 | GPIO_Pin_6);switch(GPIO_ReadInputData(GPIOB)&0xff){case 0x14: KeyValue = 9; break;case 0x24: KeyValue = 6; break;case 0x44: KeyValue = 3; break;case 0x84: KeyValue = 0; break;}GPIO_SetBits(GPIOB, GPIO_Pin_6);GPIO_ResetBits(GPIOB, GPIO_Pin_3 | GPIO_Pin_4 | GPIO_Pin_5);switch(GPIO_ReadInputData(GPIOB)&0xff){case 0x18: KeyValue = 0; break;case 0x28: KeyValue = 0; break;case 0x48: KeyValue = 0;break;case 0x88: KeyValue = 0;break;}GPIO_SetBits(GPIOB, GPIO_Pin_3 | GPIO_Pin_4 | GPIO_Pin_5 | GPIO_Pin_6); GPIO_ResetBits(GPIOB, GPIO_Pin_7 | GPIO_Pin_8 | GPIO_Pin_9 | GPIO_Pin_10);//while((GPIO_ReadInputData(GPIOB)&0xff)!=0x0f);return KeyValue;}}return 0;}uint16_t table[]={0xEB,0x28,0xB3,0xBA,0x78,0xDA,0xDB,0xA8,0xFB,0xFA};int main(){RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA,ENABLE);RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB,ENABLE);KeyBoard_Init();int keyvalue=Read_KeyValue();GPIO_Write(GPIOA, table[keyvalue]);/*while(1){int i;for(i=0;i<10;i++){GPIO_Write(GPIOA, table[i]);Delay_ms(500);}}*//*u8 keyvalue;for(int i=0;;i++){KeyBoard_Init();keyvalue=Read_KeyValue();GPIO_Write(GPIOA,table[keyvalue]);Delay_ms(500);}*/}#include "stm32f10x.h"void KeyBoard_Init(void){GPIO_InitTypeDef GPIO_InitStructure;GPIO_InitStructure.GPIO_Pin = GPIO_Pin_All;GPIO_InitStructure.GPIO_Speed = GPIO_Speed_2MHz;GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;GPIO_Init(GPIOA, &GPIO_InitStructure);GPIO_InitStructure.GPIO_Pin = GPIO_Pin_3|GPIO_Pin_4|GPIO_Pin_5|GPIO_Pin_6|GPIO_Pin_7|GPIO_Pin_8 | GPIO_Pin_9 | GPIO_Pin_10;GPIO_InitStructure.GPIO_Speed = GPIO_Speed_2MHz;GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPD;GPIO_Init(GPIOB, &GPIO_InitStructure);GPIO_SetBits(GPIOB, GPIO_Pin_3 | GPIO_Pin_4 | GPIO_Pin_5 | GPIO_Pin_6);GPIO_ResetBits(GPIOB, GPIO_Pin_7 | GPIO_Pin_8 | GPIO_Pin_9 | GPIO_Pin_10);}void Delay_ms(int time){int i=0;while(time--){i=12000;while(i--);}}u8 Read_KeyValue(void){if((GPIO_ReadInputData(GPIOB)&0xff)!=0x73)// 在这个程序下为什么无论是GPIO_ReadInputData(GPIOB)&0xff)!=0x73 还是GPIO_ReadInputData(GPIOB)&0xff)==0x73 都能往下运行,而在屏蔽Delay_ms(10) 后则只能运行一种,是因为这个Delay_ms(10) 对if 里的判断有影响吗?{Delay_ms(10);GPIO_Write(GPIOA,0x33);}return 0;}int main(){RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA,ENABLE);RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB,ENABLE);KeyBoard_Init();Read_KeyValue();}。

linux设备驱动之键盘驱动分析 - linux设备模型 - Linux内核学习

linux设备驱动之键盘驱动分析 - linux设备模型 - Linux内核学习

static int atkbd_connect(struct serio *serio, struct serio_driver *drv)
{
struct atkbd *atkbd;
struct input_dev *dev;
int err = -ENOMEM;
atkbd = kzalloc(sizeof(struct atkbd), GFP_KERNEL); dev = input_allocate_device(); if (!atkbd || !dev)
三:键盘驱动入口 在atkbd.c中,module的入口函数为:
static int __init atkbd_init(void)
…/…/showart_1089643.h…
1/6
2011/5/26
linux设备驱动之键盘驱动分析 - linux设…
{
dmi_check_system(atkbd_dmi_quirk_table);
strlcpy(serio->phys, I8042_KBD_PHYS_DESC, sizeof(serio->phys));
port->serio = serio; port->irq = I8042_KBD_IRQ;
return 0; } 初始化了一个serio 结构. 在i8 04 2 _register_po rts()中: static void __devinit i8042_register_ports(void) {
-----------------------------------------本文系本站原创,欢迎转载! 转载请注明出处:/ ------------------------------------------

单片机驱动4X4矩阵式键盘输入程序(1)

单片机驱动4X4矩阵式键盘输入程序(1)

单片机驱动4X4矩阵式键盘输入程序(1)单片机驱动4X4矩阵式键盘输入程序 (1)用AT89S51单片机的并行口P1接4×4矩阵键盘,以P1.0-P1.3作输入线,以P1.4-P1.7作输出线;在数码管上显示每个按键的“0-F”序号。

实现键盘输入的识别。

我将给大家提供c和汇编两个版本的4X4矩阵式键盘输入程序。

如汇编语言源程序:KEYBUF EQU 30HORG 00HSTART: MOV KEYBUF,#2WAIT:MOV P3,#0FFHCLR P3.4MOV A,P3ANL A,#0FHXRL A,#0FHJZ NOKEY1LCALL DELY10MSMOV A,P3ANL A,#0FHXRL A,#0FHJZ NOKEY1MOV A,P3ANL A,#0FHCJNE A,#0EH,NK1MOV KEYBUF,#0LJMP DK1NK1: CJNE A,#0DH,NK2MOV KEYBUF,#1LJMP DK1NK2: CJNE A,#0BH,NK3 MOV KEYBUF,#2LJMP DK1NK3: CJNE A,#07H,NK4 MOV KEYBUF,#3LJMP DK1NK4: NOPDK1:MOV A,KEYBUFMOV DPTR,#TABLE MOVC A,@A+DPTRMOV P0,ADK1A: MOV A,P3ANL A,#0FHXRL A,#0FHJNZ DK1ANOKEY1:MOV P3,#0FFHCLR P3.5MOV A,P3ANL A,#0FHXRL A,#0FHJZ NOKEY2LCALL DELY10MSMOV A,P3ANL A,#0FHXRL A,#0FHJZ NOKEY2MOV A,P3ANL A,#0FHCJNE A,#0EH,NK5MOV KEYBUF,#4LJMP DK2NK5: CJNE A,#0DH,NK6 MOV KEYBUF,#5LJMP DK2NK6: CJNE A,#0BH,NK7 MOV KEYBUF,#6LJMP DK2NK7: CJNE A,#07H,NK8 MOV KEYBUF,#7LJMP DK2NK8: NOPDK2:MOV A,KEYBUFMOV DPTR,#TABLE MOVC A,@A+DPTRMOV P0,ADK2A: MOV A,P3ANL A,#0FHXRL A,#0FHJNZ DK2ANOKEY2:MOV P3,#0FFHCLR P3.6MOV A,P3ANL A,#0FHXRL A,#0FHLCALL DELY10MSMOV A,P3ANL A,#0FHXRL A,#0FHJZ NOKEY3MOV A,P3ANL A,#0FHCJNE A,#0EH,NK9MOV KEYBUF,#8LJMP DK3NK9: CJNE A,#0DH,NK10 MOV KEYBUF,#9LJMP DK3NK10: CJNE A,#0BH,NK11 MOV KEYBUF,#10LJMP DK3NK11: CJNE A,#07H,NK12 MOV KEYBUF,#11LJMP DK3NK12: NOPDK3:MOV A,KEYBUFMOV DPTR,#TABLEMOVC A,@A+DPTRMOV P0,ADK3A: MOV A,P3ANL A,#0FHXRL A,#0FHJNZ DK3AMOV P3,#0FFHCLR P3.7MOV A,P3ANL A,#0FHXRL A,#0FHJZ NOKEY4LCALL DELY10MSMOV A,P3ANL A,#0FHXRL A,#0FHJZ NOKEY4MOV A,P3ANL A,#0FHCJNE A,#0EH,NK13MOV KEYBUF,#12LJMP DK4NK13: CJNE A,#0DH,NK14 MOV KEYBUF,#13LJMP DK4NK14: CJNE A,#0BH,NK15 MOV KEYBUF,#14LJMP DK4NK15: CJNE A,#07H,NK16 MOV KEYBUF,#15LJMP DK4NK16: NOPDK4:MOV A,KEYBUFMOV DPTR,#TABLEMOVC A,@A+DPTRMOV P0,ADK4A: MOV A,P3ANL A,#0FHXRL A,#0FHJNZ DK4ANOKEY4:LJMP WAITDELY10MS:MOV R6,#10D1: MOV R7,#248DJNZ R7,$DJNZ R6,D1RETTABLE: DB 3FH,06H,5BH,4FH,66H,6DH,7DH,07H DB 7FH,6FH,77H,7CH,39H,5EH,79H,71HEND。

  1. 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
  2. 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
  3. 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。

EDA技术课程设计任务书
班级:姓名:程鼐学号:
设计题目:键盘驱动程序
一、设计目的
进一步巩固理论知识,培养所学理论知识在实际中的应用能力;掌握EDA设计的一般方法;熟悉一种EDA软件,掌握一般EDA系统的调试方法;利用EDA软件设计一个电子技术综合问题,培养VHDL编程、书写技术报告的能力。

为以后进行工程实际问题的研究打下设计基础。

二、设计任务
利用外接键盘实现键盘按键的选择,在8位动态七段数码管上实现按键扫描码的显示,在16X16点阵上实现按键字符的显示。

三、设计要求
(1)通过对相应文献的收集、分析以及总结,给出相应课题的背景、意义及现状研究分析。

(2)通过课题设计,掌握计算机组成原理的分析方法和设计方法。

(3)学习按要求编写课程设计报告书,能正确阐述设计和实验结果。

(4)学生应抱着严谨认真的态度积极投入到课程设计过程中,认真查阅相应文献以及实现,给出个人分析、设计以及实现。

四、设计时间安排
查找相关资料(1天)、设计并绘制系统原理图(2天)、编写VHDL程序(2天)、调试(2天)、编写设计报告(2天)和答辩(1天)。

五、主要参考文献
[1] 江国强编著. EDA技术与实用(第三版). 北京:电子工业出版社,2011.
[2] 曹昕燕,周凤臣.EDA技术实验与课程设计.北京:清华大学出版社,2006.5
[3] 阎石主编.数字电子技术基础.北京:高等教育出版社,2003.
[4] Mark Zwolinski. Digital System Design with VHDL.北京:电子工业出版社,2008
[5] Alan B. Marcovitz Introduction to logic Design.北京:电子工业出版社,2003
指导教师签字:年月日。

相关文档
最新文档