打印
[AVR单片机]

(转载)双龙教主在AVR中的n个io实现的n×n个键盘的方案

[复制链接]
2053|4
手机看帖
扫描二维码
随时随地手机跟帖
跳转到指定楼层
楼主
hotpower|  楼主 | 2010-8-8 23:58 | 只看该作者 回帖奖励 |倒序浏览 |阅读模式
本帖最后由 hotpower 于 2010-8-9 00:05 编辑

时间关系,没有做过试验。恳请大家指正。
电路如图,下面的例子用4个io实现16个按键的方案。

原理:
AVR单片机内部的IO上拉电阻大约在36K欧姆,初始化设置4列IO为输入,并启动内部上拉电阻。

当没有任何按键按下时,任何一个IO的输入电压为:
Vin =(1000K+2K)/(1000 K+2K+36K)×Vcc= 0.965×Vcc。
这个电压对于单片机来说算是高电平。

当其中一个按键按下后,该列的输出电压变成:
Vin =2K /(2K+36K)×Vcc= 0.052×Vcc。
这个电压对于单片机来说算是低电平。

单片机可以启动按键电平改变中断,或者扫描检测IO。当该IO由高变成低后,则说明该列有一个按键按下,单片机记录PC口的PIN值。
然后单片机取消内部的上拉电阻,并将变低的列输出高电平,输出管脚高电平为Vcc,其负载电阻为2K,与该2K电阻连接的1M电阻将另外一路输入变成高电平,其余为低电平。再次读取PC口的PIN值。根据2次读取得值来判断按键.

下面举一个具体的例子,说明一个按键的读取。
1、    初始化,4个IO设置成为输入,带内部上拉电阻。
2、    如按键9被按下,则PC1管脚变成低电平,单片机读取PC口,键值为1101。
3、    单片机取消内部上拉,并将PC1设置成为输出高电平,如果按键9仍然按下,则与按键9相连的2K电阻R3输出为高电平,与2K连接的1M电阻R7输出也为高,其他口由于1M和2K电阻的下拉则输出为低,单片机读取PC口,键值为0110。
4、    将键值1左移4位和键值2相加:键值为11010110,等于0xd6。
5、    根据键值表查到按键的相应键值。

键值表如下:

按键名称    键值        按键名称    键值   
1    01111001    0x79    7    01111100    0x7c
2    10110101    0xb5    8    10110100    0xb4
3    11010011    0xd3    9    11010110    0xd6
a    11100001    0xe1    c    11100101    0xe5
4    01111010    0x7a    *    01111000    0x78
5    10110110    0xb6    0    10111100    0xbc
6    11010010    0xd2    #    11011010    0xda
b    11100011    0xe3    d    11101001    0xe9
没有按键    11110000    0xf0            

程序:



程序如下:
zsmbj 发表于 2006-11-12 20:28 AVR 单片机 ←返回版面 举报该贴

//winavr20060421
//last edit 2006/11/12
//copyright by zsmbj

#define    KeyDir        DDRC
#define    KeyPort        PORTC
#define    KeyVal        PINC
#define    NoKey        0xff

unsigned char    PROGMEM    KEYTAB2[17][2]={
            {0xf0,0xff},
            {0x79,'1'},{0xb5,'2'},{0xd3,'3'},{0xe1,'a'},
            {0x7a,'4'},{0xb6,'5'},{0xd2,'6'},{0xe3,'b'},
            {0x7c,'7'},{0xb4,'8'},{0xd6,'9'},{0xe5,'c'},
            {0x78,'*'},{0xbc,'0'},{0xda,'#'},{0xe9,'d'}
            };  
unsigned char GetPortkey2(void)
{
    unsigned char        i,getkey;
    unsigned char        temp_getkey = NoKey        ;


    KeyPort |= 0x0f;                //key input with pullup
    KeyDir &= 0xf0;                //PC low 4 bit input
    asm("nop");
    asm("nop");
    getkey  = KeyVal & 0x0f;        //get 4 bit

    KeyPort &= 0xf0;                //key input without pullup
    KeyDir |= ~getkey;                //
    asm("nop");
    asm("nop");
    getkey <<= 4;                    //
    getkey += KeyVal & 0x0f;        //get 4 bit

    KeyPort |= 0x0f;                 //key input with pullup
    KeyDir &= 0xf0;                //PC low 4 bit input
   
    for(i=0;i<17;i++)                //scan key value
    {
        if( getkey == pgm_read_byte(KEYTAB2[0]) )
        {
            temp_getkey= pgm_read_byte(KEYTAB2[1]);    //get key value
            break;
        }
    }
    return temp_getkey;
}

可以成立,但去抖有问题。
农民讲习所 发表于 2006-11-12 21:53 AVR 单片机 ←返回版面 举报该贴

S4、S7、S8、S13是从其它3个输入不为1推导出来的,所以没法进行去抖判断。

所以这个图可以将上述4个按键去掉,组成4个IO构成3*4阵列好象不错。

哈哈~~~对角键消抖用3次扫描即可搞定~~~
hotpower 发表于 2006-11-14 22:54 AVR 单片机 ←返回版面 举报该贴

农忙没看见这个非典帖真是不幸~~~

对角键S4,S7,S10,S13不同与其他键可以"反馈",这"自留地"的事估计种田人比较在行~~~

这个设计确实很奇妙~~~

首先它是在"静止"时,利用AVR的输入方式下的内部上拉来读取无键状态'1'.
因为此时为内部上拉和外部高阻的分压,肯定为高电平.
当有键压下时,利用短路1M来打破原来的分压比,换来电平的翻转,从而得到列键值.
由于此时只能证明某1列有键压下但不能确定,故需要二次扫描.

由于送低电平肯定无用,故教主的高电平很非典~~~谁让AVR有能量呢~~~

但是这只能真正地扫描非对角键盘,但对角键S4,S7,S10,S13在其他3列的值并未变.
实际上对角键值就是第1步的列值!!!
所以在第2步后认为是对角键后就应该再回到第1步来消抖(此时应该属于第3次扫描了),即对角键某列应该维持低电平即为不抖~~~

有空编个程序玩玩~~~
此电路的精妙之处在于真假短路1M电阻以形成电平翻转
hotpower 发表于 2006-11-14 23:41 AVR 单片机 ←返回版面 举报该贴

表面上看只有对角键真正短路了1M电阻.但非对角键却旁路了1M电阻.
效果是一样的.

例如S3键,本应该有内部上拉电阻,R6,R2形成静态分压,当压下键时,却与
R2形成了分压,造成了电平翻转.效果与S4键相同,但触发的列却不同.

至于消抖虽已认定对角键值即为列值,但是菜农还是**3次扫描的方式可靠些.
虽然程序复杂些,但零耗时的消抖解决此问题也并非难事~~~

相关帖子

沙发
hotpower|  楼主 | 2010-8-9 00:07 | 只看该作者
可惜让21ic把图都搞没了!!!

使用特权

评论回复
板凳
yycah| | 2012-3-9 01:43 | 只看该作者
留印学习必须的

使用特权

评论回复
地板
ji7411| | 2012-3-9 12:01 | 只看该作者
图都么了。。。。怎么看啊

使用特权

评论回复
5
ahamao| | 2012-4-10 11:27 | 只看该作者
没有图啊

使用特权

评论回复
发新帖 我要提问
您需要登录后才可以回帖 登录 | 注册

本版积分规则

1460

主题

21619

帖子

506

粉丝