本帖最后由 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次扫描的方式可靠些.
虽然程序复杂些,但零耗时的消抖解决此问题也并非难事~~~ |
|
|