#include "Key.h" /*本文件的函数,主要实现矩阵键盘的功能。矩阵键盘使用PA0到PA7引脚,其中,PA0到PA3固定为推挽输出,PA4到PA7固定为 下拉输入。即,无键按下时,对应PA4到PA7为0,有键按下时,PA4到PA7中,对应的引脚为高。 此程序有一点要注意:要用到的IO口,必须是PX0-PX7,,不能是其他连续的数字。。如果非要改。。如:已经没有连续的0-7的IO口,需要在几个地方修改,请注意!! 此程序带有松手检测。。。。*/ void GPIO_ConfigurationKey ( void ) //初始化矩阵键盘要使用的GPIO口。 { #if key16_def GPIO_InitTypeDef GPIOStru; RCC_APB2PeriphClockCmd ( KEY16_RCC_CONFIG, ENABLE ); GPIOStru.GPIO_Mode = GPIO_Mode_Out_PP; //定义PA0到PA3为推挽输出。 GPIOStru.GPIO_Speed = GPIO_Speed_50MHz; GPIOStru.GPIO_Pin = KEY16_OUTPIN_CONFIG; GPIO_Init ( KEY16_PORT_CONFIG, &GPIOStru ); GPIOStru.GPIO_Mode = GPIO_Mode_IPD; //定义PA4到PA7为下拉输入。 GPIOStru.GPIO_Speed = GPIO_Speed_50MHz; GPIOStru.GPIO_Pin = KEY16_INPIN_CONFIG; GPIO_Init ( KEY16_PORT_CONFIG, &GPIOStru ); #endif } unsigned short ScanKey ( void ) //实现矩阵键盘。返回值为,各按键的键值,此键值由用户自己定义。 { unsigned short KeyVal = 0x0000; //keyVal为最后返回的键值。 GPIO_Write ( KEY16_PORT_CONFIG, ( KEY16_PORT_CONFIG->ODR & 0xfff0 | 0xf ) ); //先让PA0到PA3全部输出高。 if ( ( KEY16_PORT_CONFIG->IDR & 0x00f0 ) == 0x0000 ) //如果,PA4到PA7全为0,则,没有键按下。此时,返回值为-1. return KeyVal; GPIO_Write ( KEY16_PORT_CONFIG, ( KEY16_PORT_CONFIG->ODR & 0xfff0 | 0x1 ) ); //让PA3到PA0输出二进制的0001. KeyVal |= ( ( KEY16_PORT_CONFIG->IDR & 0x00f0 ) >> 4 ) << 0; GPIO_Write ( KEY16_PORT_CONFIG, ( KEY16_PORT_CONFIG->ODR & 0xfff0 | 0x2 ) ); //让PA3到PA0输出二进制的0010. KeyVal |= ( ( KEY16_PORT_CONFIG->IDR & 0x00f0 ) >> 4 ) << 4; GPIO_Write ( KEY16_PORT_CONFIG, ( KEY16_PORT_CONFIG->ODR & 0xfff0 | 0x4 ) ); //让PA3到PA0输出二进制的0100. KeyVal |= ( ( KEY16_PORT_CONFIG->IDR & 0x00f0 ) >> 4 ) << 8; GPIO_Write ( KEY16_PORT_CONFIG, ( KEY16_PORT_CONFIG->ODR & 0xfff0 | 0x8 ) ); //让PA3到PA0输出二进制的1000. KeyVal |= ( ( KEY16_PORT_CONFIG->IDR & 0x00f0 ) >> 4 ) << 12; return KeyVal; } /*tea5767 K11: up+ K12: down- */ /*ds1302 K13: 开机时间复位 K14: 菜单 K15: up+ K16: down- */ pKey Keys[16] = { {0x00, KEY_UP_FLAG, 0, 0, 0, NO_KEY_FLAG}, {0x01, KEY_UP_FLAG, 0, 0, 0, NO_KEY_FLAG}, {0x02, KEY_UP_FLAG, 0, 0, 0, NO_KEY_FLAG}, {0x03, KEY_UP_FLAG, 0, 0, 0, NO_KEY_FLAG}, {0x04, KEY_UP_FLAG, 0, 0, 0, NO_KEY_FLAG}, {0x05, KEY_UP_FLAG, 0, 0, 0, NO_KEY_FLAG}, {0x06, KEY_UP_FLAG, 0, 0, 0, NO_KEY_FLAG}, {0x07, KEY_UP_FLAG, 0, 0, 0, NO_KEY_FLAG}, {0x08, KEY_UP_FLAG, 0, 0, 0, NO_KEY_FLAG}, {0x09, KEY_UP_FLAG, 0, 0, 0, NO_KEY_FLAG}, {0x0A, KEY_UP_FLAG, 0, 0, 0, NO_KEY_FLAG}, {0x0B, KEY_UP_FLAG, 0, 0, 0, NO_KEY_FLAG}, {0x0C, KEY_UP_FLAG, 0, 0, 0, NO_KEY_FLAG}, {0x0D, KEY_UP_FLAG, 0, 0, 0, NO_KEY_FLAG}, {0x0E, KEY_UP_FLAG, 0, 0, 0, NO_KEY_FLAG}, {0x0F, KEY_UP_FLAG, 0, 0, 0, NO_KEY_FLAG} }; //每40ms,进入一次 /* 判断点: 1.down: 400 down<120, == 无效,去抖动 120<=down<400, == 进入2.继续判断 2.down: 400 + up:400 up<400, == 进入3.继续判断 up>400, == 短按 3.down: 400 + up:400 + down: 400 down>1200, == 长按 down<400, == 单击++ */ void KeyHander ( void ) { #if key16_def unsigned short KeyVal = 0; unsigned char i; KeyVal = ScanKey(); for ( i = 0; i < 16; i++ ) { Keys[i].State = KeyVal & ( 1 << Keys[i].ID ) ? KEY_DOWN_FLAG : KEY_UP_FLAG; if ( Keys[i].State == KEY_DOWN_FLAG ) { Keys[i].DnTime++; //超过1.2s,长按 if ( ( Keys[i].DnTime > LONG_KEY_DOWN ) && ( Keys[i].Res != LONG_KEY_FLAG ) ) { Keys[i].Res = LONG_KEY_FLAG; Keys[i].HitNum = 0; } if ( Keys[i].UpTime > 0 ) { Keys[i].UpTime = 0; } } else if ( Keys[i].State == KEY_UP_FLAG ) { Keys[i].UpTime ++; if ( Keys[i].UpTime < CANCEL_KEY_UP ) { //松开0-320ms if ( Keys[i].DnTime > 0 ) { //根据按下时间,判断: if ( Keys[i].DnTime < CANCEL_KEY_DOWN ) //1.抖动 { Keys[i].Res = NO_KEY_FLAG; } else if ( Keys[i].DnTime < SHORT_KEY_DOWN ) //2.单击++ { Keys[i].HitNum ++; } Keys[i].DnTime = 0; } } else if ( Keys[i].UpTime < ( CANCEL_KEY_UP + HANDLE_KEY_TIME ) ) { //松开320-440ms,判断 if ( Keys[i].HitNum > 0 ) //3.判断 { if ( Keys[i].HitNum == 1 ) Keys[i].Res = ONE_HITS_KEY_FLAG; else if ( Keys[i].HitNum == 2 ) Keys[i].Res = TWO_HITS_KEY_FLAG; else if ( Keys[i].HitNum == 3 ) Keys[i].Res = THREE_HITS_KEY_FLAG; Keys[i].HitNum = 0; } } else if ( Keys[i].Res != NO_KEY_FLAG ) { //松开400ms,状态变为, 无按键 Keys[i].Res = NO_KEY_FLAG; } } } #endif }