PC按键具有如下特性:当按下某个键时,系统立即响应,如果未松手,则键值会重复出现,直到松手时才停止。如附图所示的Windows键盘属性设置,有两个重要的按键参数:重复延迟和重复率。重复延迟是指从按下键不松手开始,到第1次键值重复开始时的时间间隔;重复率是指以后连续重复的速率,每两次重复之间的时间间隔越短重复越快。
以下程序是系统节拍定时器SysTick的一个应用,利用其定时中断扫描按键KEY的输入,并模拟出PC按键的重复特性,结果通过UART输出。在程序里,SysTick设置的定时中断周期是10ms,可自动地消除按键抖动,同时还能保证每秒100次的按键采样速率。重复延时参数是KEY_DELAY,即按下KEY后若不松手则等待10×KEY_DELAY毫秒后开始重复。重复速率参数是KEY_SPEED,即开始重复后每两次重复之间的时间间隔为10×KEY_SPEED毫秒。
在SysTick中断服务函数SysTick_ISR( )里,采用状态处理的方法,实现了预定的功能,并没有出现任何无谓的等待。
#include <hw_types.h> #include <hw_memmap.h> #include <hw_ints.h> #include <hw_sysctl.h> #include <hw_gpio.h> #include <hw_uart.h> #include <interrupt.h> #include <systick.h> #include <sysctl.h> #include <gpio.h> #include <uart.h>
// 将较长的标识符定义成较短的形式 #define SysCtlPeriEnable SysCtlPeripheralEnable #define SysCtlPeriDisable SysCtlPeripheralDisable #define GPIOPinTypeIn GPIOPinTypeGPIOInput #define GPIOPinTypeOut GPIOPinTypeGPIOOutput #define GPIOPinTypeOD GPIOPinTypeGPIOOutputOD
// 定义KEY #define KEY_PERIPH SYSCTL_PERIPH_GPIOD #define KEY_PORT GPIO_PORTD_BASE #define KEY_PIN GPIO_PIN_1
// 设置KEY重复延迟和重复速率参数 #define KEY_DELAY 75 #define KEY_SPEED 10
// 定义按键缓冲区 char KEY_Buf = '\0';
// UART初始化 void uartInit(void) { SysCtlPeriEnable(SYSCTL_PERIPH_UART0); // 使能UART模块 SysCtlPeriEnable(SYSCTL_PERIPH_GPIOA); // 使能RX/TX所在的GPIO端口
GPIOPinTypeUART(GPIO_PORTA_BASE, // 配置RX/TX所在管脚为 GPIO_PIN_0 | GPIO_PIN_1); // UART收发功能
UARTConfigSet(UART0_BASE, // 配置UART端口 9600, // 波特率:9600 UART_CONFIG_WLEN_8 | // 数据位:8 UART_CONFIG_STOP_ONE | // 停止位:1 UART_CONFIG_PAR_NONE); // 校验位:无
UARTEnable(UART0_BASE); // 使能UART端口 }
// 主函数(程序入口) int main(void) { SysCtlClockSet(SYSCTL_USE_OSC | // 系统时钟设置 SYSCTL_OSC_MAIN | // 采用主振荡器 SYSCTL_XTAL_6MHZ | // 外接6MHz晶振 SYSCTL_SYSDIV_1); // 不分频
uartInit(); // UART初始化
SysCtlPeriEnable(KEY_PERIPH); // 使能KEY1所在的GPIO端口 GPIOPinTypeIn(KEY_PORT, KEY_PIN); // 设置KEY1所在管脚为输出
SysTickPeriodSet(10 * (SysCtlClockGet() / 1000)); // 设置SysTick周期,定时10ms SysTickIntEnable(); // 使能SysTick中断 IntMasterEnable(); // 使能处理器中断 SysTickEnable(); // 使能SysTick计数器
for (;;) { if (KEY_Buf != '\0') // 如果KEY缓冲区不空 { UARTCharPut(UART0_BASE, KEY_Buf); // 显示KEY值 KEY_Buf = '\0'; // 清空KEY缓冲区 } } }
// SysTick计数器的中断服务函数 void SysTick_ISR(void) { static tBoolean bStatus = false; // KEY状态:false松开,true按下 static unsigned short usDelayCnt = 0; // 重复延时计数器 static unsigned short usSpeedCnt = 0; // 重复速率计数器
if (bStatus) // 如果原先KEY是按下的 { if (GPIOPinRead(KEY_PORT, KEY_PIN) == 0x00) // 如果KEY仍为按下状态 { if (usDelayCnt == 0) // 如果重复延时已经结束 { if (--usSpeedCnt == 0) // 执行重复动作 { usSpeedCnt = KEY_SPEED; KEY_Buf = 'K'; } } else { usDelayCnt--; } } else // 如果KEY已松开 { bStatus = false; } } else // 如果原先KEY是松开的 { if (GPIOPinRead(KEY_PORT, KEY_PIN) == 0x00) // 如果KEY按下 { bStatus = true; KEY_Buf = 'K'; usDelayCnt = KEY_DELAY; usSpeedCnt = KEY_SPEED; } } } |