51单片机矩阵键盘输入的值保存到一个数组了里并显示出来最后再控制LED灯闪烁对应数值的次数

51单片机矩阵键盘输入的值保存到一个数组了里并显示出来最后再控制LED灯闪烁对应数值的次数,第1张

例如按下1、2、3,我可以令result=num[0]100+num[1]10+num[2],得到123。--每次怎么可能按下 1、2、3 ?每次,只能按下一个。你把值保存到数组num[i]的一个元素中,再 i++。 i == 3,可令result=num[0]100+num[1]10+num[2],得到123。然后可以读这些数进行计算。


//
unsigned char keymap[] = {1;
控制打开或者关闭键盘中断
SW= 0;关闭端口中断
else
KEY_IE =0xf0;/7 接上拉电阻
/控制键盘开关/消除抖动
Check_Key():
[p13]→ 1 2 3 4
[p12]→ 5 6 7 8
[p11]→ 9 10 11 12
[p10]→ 13 14 15 16
/
void Key_Event(void)
{
unsigned char tmp;/
void delay(void)
{
unsigned int tmp;/如果有键按下
{
delay();/ //是否P1IN的P1;/ 列检测
{
if((KEY_IN tmp2) == 0x00) / 获取键值
return; 设置P1OUT全为0,P1h>/ /p14\///
KEY_IES =0xf0; / /设置键盘逻辑键值
与程序计算键值的映射
tmp1 = 0x08/
void Check_Key(void)
{
unsigned char row ;P1;6\= 1;/
函数名称; tmp2用于检测出哪一位为0
for(col = 0,15;/ 获取 p1IN
if((tmp 0xf0) < /gt4~P1,7,完成消抖功能
参 数;
if(Key_Val; /
/msp430x14x;/ //
函数名称!=0)
{
Key_Event();/
KEY_OUT =0,并获取键值
参 数;打开端口中断
}
//
void Init_Keypad(void)
{
KEY_DIR = 0x0f;P10~P14~p1;P1; 0;
key_Val 对应键值
列;row++) /5\ / /col lt; ELSE;
for(tmp = 12000;
for(row = 0,4:t= tmp5clk 根据使用时钟调整tmp值
/ tmp2右移1位
}
}
}
}
/键值,9:delay
功 能:扫描键盘的IO端口:无
返回值 ,12; /关键盘中断
}
}
KEY_IFG=0;KEY_OUT=0;col++) / 4;/ 0xf0) /row lt,14;=1;端口1按键中断/ / /行扫描
{
KEY_OUT = 0x0f; / 4;0xf0) / /////tmp >
#pragma vector=PORT1_VECTOR
__interrupt void Port(void)
{
if((KEY_IFG0xf0):无
返回值 ;存放键值
void CtrlKey(unsigned char sw)4~P1;< // 调用check_Key()!=0) /P17输出四位中有一个为0
tmp1 gt!=0有键按下
{
CtrlKey(0),等待按键输入
tmp = KEY_IN; /全局变量/sw=0关 sw=1开
/// //
if((KEY_IN 0xf0)< 退出循环
}
tmp2 < / / 是否是该列;
#define KEY_DIR P1DIR
#define KEY_OUT P1OUT
#define KEY_IN P1IN
#define KEY_IE P1IE
#define KEY_IES P1IES
#define KEY_IFG P1IFG
//
}
//
void CtrlKey(unsigned char sw)
{
if(sw==0)
KEY_IE =0;/中断标志清0
Key_Val = 0;
函数名称;
}
// /P1;msp430F149 44矩阵键盘P1口中断扫描
#includelt,8;47

独立式按键:直接由I / O线组成的单个按钮电路,其特征在于每个按钮分别占用一条I / O线,适用于八个按键。

矩阵式键盘:它由行和列线组成,按钮位于行和列线的交点处。当按钮数量很大时,矩阵式键盘较之独立式按键键盘要节省很多I/O口,适合于八个键以上使用。

扩展资料:

矩阵式键盘的按键识别方法:线扫描

线扫描方法,也称为渐进式(或列)扫描查询方法,是最常用的键识别方法之一。流程如下:

1、确定键盘上是否有按键:将所有线设置为低电平,然后检查列线的状态。只要一列的电平为低,就表示键盘上有按下的键,并且闭合键在与低电平线和四行线交叉的四个键之中。如果所有列线都高,则键盘上没有按键。

2、确定关闭按钮的位置:确认按下按钮后,可以进入确定特定关闭按钮的过程。该方法是:依次将行线设置为低电平,即当某行线为低电平时,其他线为高电平。在确定某个行线位置低之后,逐行检测每个列线的电平状态。如果列为低,则列线和行线的交点处设置为低的按钮为关闭按钮。

参考资料来源:百度百科-矩阵键盘

参考资料来源:百度百科-QWERTY独立键盘

4条线作为输出,4条线作为输入,1根输出线先输出低电平,它上面接有4个按键,如果有按键按下,这个低电平就会(通过按键)传到相应的输入端口,根据哪根线是低电平就 知道哪 个键按下了,4根线轮流输出低电平,就 可以检测16个按键,由于轮流扫描速度很快,所以任何时候按任意键都 可以被检测到

在学习之前一直对驱动开发非常的陌生,感觉有点神秘。不知道驱动开发和普通的程序开发究竟有什么不同;它的基本框架又是什么样的;他的开发环境有什么特殊的地方;以及怎么写编写一个简单的字符设备驱动前编译加载,下面我就对这些问题一个一个的介绍。

一、驱动的基本框架

1.  那么究竟什么是驱动程序,它有什么用呢:

l     驱动是硬件设备与应用程序之间的一个中间软件层

l 它使得某个特定硬件能够响应一个定义良好的内部编程接口,同时完全隐蔽了设备的工作细节

l     用户通过一组与具体设备无关的标准化的调用来完成相应的 *** 作

l 驱动程序的任务就是把这些标准化的系统调用映射到具体设备对于实际硬件的特定 *** 作上

l     驱动程序是内核的一部分,可以使用中断、DMA等 *** 作

l     驱动程序在用户态和内核态之间传递数据

2.  Linux驱动的基本框架

3.  Linux下设备驱动程序的一般可以分为以下三类

1)        字符设备

a)         所有能够象字节流一样访问的设备都通过字符设备来实现

b)        它们被映射为文件系统中的节点,通常在/dev/目录下面

c)        一般要包含open read write close等系统调用的实现

2)        块设备

d)        通常是指诸如磁盘、内存、Flash等可以容纳文件系统的存储设备。

e)         块设备也是通过文件系统来访问,与字符设备的区别是:内核管理数据的方式不同

f)         它允许象字符设备一样以字节流的方式来访问,也可一次传递任意多的字节。

3)        网络接口设备

g)        通常它指的是硬件设备,但有时也可能是一个软件设备(如回环接口loopback),它们由内核中网络子系统驱动,负责发送和接收数据包。

h)        它们的数据传送往往不是面向流的,因此很难将它们映射到一个文件系统的节点上。

二、怎么搭建一个驱动的开发环境

因为驱动是要编译进内核,在启动内核时就会驱动此硬件设备;或者编译生成一个o文件, 当应用程序需要时再动态加载进内核空间运行。因此编译任何一个驱动程序都要链接到内核的源码树。所以搭建环境的第一步当然是建内核源码树

1       怎么建内核源码树

a) 首先看你的系统有没有源码树,在你的/lib/ modules目录下会有内核信息,比如我当前的系统里有两个版本:

#ls /lib/ modules

2615-rc7  2621-13194fc7

查看其源码位置:

## ll /lib/modules/2615-rc7/build

lrwxrwxrwx 1 root root 27 2008-04-28 19:19 /lib/modules/2615-rc7/build -> /root/xkli/linux-2615-rc7

发现build是一个链接文件,其所对应的目录就是源码树的目录。但现在这里目标目录已经是无效的了。所以得自己重新下载

b)下载并编译源码树

有很多网站上可以下载,但官方网址是:

>

下载完后当然就是解压编译了

# tar –xzvf linux-261654targz

#cd linux-261654

## make menuconfig (配置内核各选项,如果没有配置就无法下一步编译,这里可以不要改任何东西)

#make

如果编译没有出错。那么恭喜你。你的开发环境已经搭建好了

三、了解驱动的基本知识

1         设备号

1)        什么是设备号呢?我们进系统根据现有的设备来讲解就清楚了:

#ls -l /dev/

crwxrwxrwx 1 root root     1,   3 2009-05-11 16:36 null

crw------- 1 root root     4,   0 2009-05-11 16:35 systty

crw-rw-rw- 1 root tty      5,   0 2009-05-11 16:36 tty

crw-rw---- 1 root tty      4,   0 2009-05-11 16:35 tty0

在日期前面的两个数(如第一列就是1,3)就是表示的设备号,第一个是主设备号,第二个是从设备号

2)        设备号有什么用呢?

l 传统上, 主编号标识设备相连的驱动 例如, /dev/null 和 /dev/zero 都由驱动 1 来管理, 而虚拟控制台和串口终端都由驱动 4 管理

l 次编号被内核用来决定引用哪个设备 依据你的驱动是如何编写的自己区别

3)        设备号结构类型以及申请方式

l   在内核中, dev_t 类型(在 中定义)用来持有设备编号, 对于 260 内核, dev_t 是 32 位的量, 12 位用作主编号, 20 位用作次编号

l   能获得一个 dev_t 的主或者次编号方式:

MAJOR(dev_t dev); //主要

MINOR(dev_t dev);//次要

l   但是如果你有主次编号, 需要将其转换为一个 dev_t, 使用: MKDEV(int major, int minor);

4)        怎么在程序中分配和释放设备号

在建立一个字符驱动时需要做的第一件事是获取一个或多个设备编号来使用 可以达到此功能的函数有两个:

l       一个是你自己事先知道设备号的

register_chrdev_region, 在 中声明:

int register_chrdev_region(dev_t first, unsigned int count, char name);

first 是你要分配的起始设备编号 first 的次编号部分常常是 0,count 是你请求的连续设备编号的总数 name 是应当连接到这个编号范围的设备的名子; 它会出现在 /proc/devices 和 sysfs 中

l       第二个是动态动态分配设备编号

int alloc_chrdev_region(dev_t dev, unsigned int firstminor, unsigned int count, char name);

使用这个函数, dev 是一个只输出的参数, 它在函数成功完成时持有你的分配范围的第一个数 fisetminor 应当是请求的第一个要用的次编号; 它常常是 0 count 和 name 参数如同给 request_chrdev_region 的一样

5)        设备编号的释放使用

不管你是采用哪些方式分配的设备号。使用之后肯定是要释放的,其方式如下:

void unregister_chrdev_region(dev_t first, unsigned int count);

6)

2         驱动程序的二个最重要数据结构

1)         file_operation

倒如字符设备scull的一般定义如下:
struct file_operations scull_fops = {
owner =  THIS_MODULE, 
 llseek =  scull_llseek, 
 read =  scull_read, 
 write =  scull_write, 
 ioctl =  scull_ioctl, 
 open =  scull_open, 
 release =  scull_release,  
};

file_operation也称为设备驱动程序接口

定义在 , 是一个函数指针的集合 每个打开文件(内部用一个 file 结构来代表)与它自身的函数集合相关连( 通过包含一个称为 f_op 的成员, 它指向一个 file_operations 结构) 这些 *** 作大部分负责实现系统调用, 因此, 命名为 open, read, 等等

2)         File

定义位于include/fsh

struct file结构与驱动相关的成员

l         mode_t f_mode      标识文件的读写权限

l         loff_t f_pos           当前读写位置

l         unsigned int_f_flag 文件标志,主要进行阻塞/非阻塞型 *** 作时检查

l         struct file_operation f_op  文件 *** 作的结构指针

l         void private_data 驱动程序一般将它指向已经分配的数据

l         struct dentry f_dentry  文件对应的目录项结构

3         字符设备注册

1)        内核在内部使用类型 struct cdev 的结构来代表字符设备 在内核调用你的设备 *** 作前, 必须编写分配并注册一个或几个这些结构 有 2 种方法来分配和初始化一个这些结构

l             如果你想在运行时获得一个独立的 cdev 结构,可以这样使用:

struct cdev my_cdev = cdev_alloc();

my_cdev->ops = &my_fops;

l             如果想将 cdev 结构嵌入一个你自己的设备特定的结构; 你应当初始化你已经分配的结构, 使用:

void cdev_init(struct cdev cdev, struct file_operations fops);

2)        一旦 cdev 结构建立, 最后的步骤是把它告诉内核, 调用:

int cdev_add(struct cdev dev, dev_t num, unsigned int count);

说明:dev 是 cdev 结构, num 是这个设备响应的第一个设备号, count 是应当关联到设备的设备号的数目 常常 count 是 1, 但是有多个设备号对应于一个特定的设备的情形

3)        为从系统去除一个字符设备, 调用:

void cdev_del(struct cdev dev);

4         open 和 release

//msp430F149
44矩阵键盘P1口中断扫描
#include<msp430x14xh>
#define
KEY_DIR
P1DIR
#define
KEY_OUT
P1OUT
#define
KEY_IN
P1IN
#define
KEY_IE
P1IE
#define
KEY_IES
P1IES
#define
KEY_IFG
P1IFG
/全局变量/
unsigned
char
Key_Val;
//存放键值
void
CtrlKey(unsigned
char
sw);
//控制键盘开关//sw=0关
sw=1开
/
函数名称:Init_Keypad

能:初始化扫描键盘的IO端口

数:无
返回值
:无
/
void
Init_Keypad(void)
{
KEY_DIR
=
0x0f;
//P10~P13设置为输出状态,P14~P17输入
状态(上拉H)
KEY_OUT=0;
KEY_IES
=0xf0;
//P14~P17允许中断
KEY_IE
=0xf0;
//P14~P17下降沿触发中断
KEY_IFG=0;
//中断标志清0
Key_Val
=
0;
}
/
函数名称:Check_Key

能:扫描键盘的IO端口,获得键值

数:无
返回值
:无
/
//p14\5\6\7
接上拉电阻
/
key_Val
对应键值
列:[p14]
[p15]
[p16]
[p17]




行:
[p13]→
1
2
3
4
[p12]→
5
6
7
8
[p11]→
9
10
11
12
[p10]→
13
14
15
16
/
void
Check_Key(void)
{
unsigned
char
row
,col,tmp1,tmp2;
unsigned
char
keymap[]
=
{1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16};//设置键盘逻辑键值
与程序计算键值的映射
tmp1
=
0x08;
for(row
=
0;row
<
4;row++)
//行扫描
{
KEY_OUT
=
0x0f;
//P14~P17输出全1
KEY_OUT
-=
tmp1;
//P14~p17输出四位中有一个为0
tmp1
>>=1;
if((KEY_IN
&
0xf0)<0xf0)
//是否P1IN的P10~P13中有一位为0
{
tmp2
=
0x10;
//
tmp2用于检测出哪一位为0
for(col
=
0;col
<
4;col++)
//
列检测
{
if((KEY_IN
&
tmp2)
==
0x00)
//
是否是该列,等于0为是
{
Key_Val
=
keymap[row4
+
col];
//
获取键值
return;
//
退出循环
}
tmp2
<<=
1;
//
tmp2右移1位
}
}
}
}
/
函数名称:delay

能:延时约15ms,完成消抖功能

数:无
返回值
:t=
tmp5clk
根据使用时钟调整tmp值
/
void
delay(void)
{
unsigned
int
tmp;
for(tmp
=
12000;tmp
>
0;tmp--);
}
/
函数名称:Key_Event

能:检测按键,并获取键值

数:无
返回值
:无
/
void
Key_Event(void)
{
unsigned
char
tmp;
KEY_OUT
=0;
//
设置P1OUT全为0,等待按键输入
tmp
=
KEY_IN;
//
获取
p1IN
if((tmp
&
0xf0)
<
0xf0)
//如果有键按下
{
delay();
//消除抖动
Check_Key();
//
调用check_Key(),获取键值
}
}
/
控制打开或者关闭键盘中断
SW=
0:关闭;
ELSE:打开
/
void
CtrlKey(unsigned
char
sw)
{
if(sw==0)
KEY_IE
=0;
//关闭端口中断
else
KEY_IE
=0xf0;
//打开端口中断
}
/端口1按键中断/
#pragma
vector=PORT1_VECTOR
__interrupt
void
Port(void)
{
if((KEY_IFG&0xf0)!=0)
{
Key_Event();
if(Key_Val!=0)
//键值!=0有键按下
{
CtrlKey(0);
//关键盘中断
}
}
KEY_IFG=0;KEY_OUT=0;
//清中断标志
}

#include <reg52h>
#include <intrinsh>
#define uchar unsigned char
#define uint unsigned int
uchar code DSY_CODE[]=
{
0xc0,0xf9,0xa4,0xb0,0x99,0x92,0x82,0xf8,0x80,0x90,0x88,0x83,0xc6,0xa1,0x86,0x8e,0x00
};
uchar code KeyCodeTable[]=
{
0x11,0x12,0x14,0x18,0x21,0x22,0x24,0x28,0x41,0x42,0x44,0x48,0x81,0x82,0x84,0x88
};
void Delay() //延时,不用多说,延时时间600us左右
{
uchar i;
for(i=0;i<200;i++);
}
uchar Keys_Scan() //键盘扫描程序
{
uchar sCode,kCode,i,k;
P1 = 0xf0; //P1低四位置零
if((P1&0xf0)!=0xf0) //读高四位数据,根据高四位是否有零判断是否有键按下
{
Delay(); //若有键按下,延时,去抖动
if((P1&0xf0)!=0xf0) //再次判断是否有键按下,防止上一步是误判断
{
sCode = 0xfe; //确实有键按下,准备读键值
for(k=0;k<4;k++) //44矩阵键盘,需要扫描四次
{
P1 = sCode; //行线最低位置零
if((P1&0xf0)!=0xf0) //判断第一行是否有键按下
{
kCode = ~P1; //若有键按下,读键值
for(i=0;i<16;i++) //键值总共会有16种可能情况
{
if(kCode == KeyCodeTable[i]) //读键值表,判断是几号键按下
return i; //返回按键编号
}
}
else
sCode = _crol_(sCode,1); //若第一行没有键按下,循环左移一位,扫描第二行
}
}
}
return -1; //若没有键按下,返回错误值
}
void main()
{
uchar KeyNO = -1;
uchar i,P2_LED,P3_LED;
while(1)
{
KeyNO = Keys_Scan(); //扫描键盘
if(KeyNO != -1) //有键按下
{
P2_LED = 0xff; //显示清零
P3_LED = 0xff;
for(i=0;i<=KeyNO;i++) //显示程序,16个LED对应16个按键,一一对应,根据按键编号显示对应LED
{
if(i<8)
P3_LED>>=1;
else
P2_LED>>=1;
}
P3 = P3_LED;
P2 = P2_LED;
}
}
}
这是程序是一个按键扫描程序,P1口接44矩阵键盘,P2,P3分别接8个LED,灌电流点亮,每个按键对应一个LED,每按下一个键,相应的LED便被点亮
DSY_CODE 这个数组是4位8段数码管的码表,码表上看是共阳数码管,对应数码管显示1-f,最后一个是全亮;
KeyCodeTable 是44矩阵键盘的键值,44矩阵键盘每按下一个键,有两位被拉低,取反就是有两位置高,这两位一位位于低四位,一位位于高四位,所有总共有16种情况
建议你看一看51单片机的书,里面矩阵键盘跟数码管讲得很清楚


欢迎分享,转载请注明来源:内存溢出

原文地址: http://outofmemory.cn/yw/13387978.html

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
上一篇 2023-07-26
下一篇 2023-07-26

发表评论

登录后才能评论

评论列表(0条)

保存