打印
[ZLG-MCU]

经典例程:利用系统节拍定时器SysTick模拟PC键盘按键重复特

[复制链接]
3403|9
手机看帖
扫描二维码
随时随地手机跟帖
跳转到指定楼层
楼主
zlgmcu|  楼主 | 2008-10-20 16:12 | 只看该作者 回帖奖励 |倒序浏览 |阅读模式

  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;
        }
    }
}

相关帖子

沙发
| | 2008-10-21 11:22 | 只看该作者

haode....

使用特权

评论回复
板凳
fm0597| | 2011-5-28 17:29 | 只看该作者

使用特权

评论回复
地板
bit6019| | 2011-5-29 12:36 | 只看该作者
好东西,有想法啊!

使用特权

评论回复
5
ghostzjl| | 2011-5-30 09:32 | 只看该作者
好东西

使用特权

评论回复
6
bairan168| | 2011-5-30 11:09 | 只看该作者
MARK

使用特权

评论回复
7
yulri| | 2011-6-16 10:02 | 只看该作者
好,标记了!!!!

使用特权

评论回复
8
baiyunfei.k.f| | 2011-6-16 11:48 | 只看该作者
:)

使用特权

评论回复
9
爱在2012| | 2011-6-19 18:15 | 只看该作者
:handshake

使用特权

评论回复
10
ccmc| | 2011-6-19 19:15 | 只看该作者
mark~~

使用特权

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

本版积分规则

81

主题

1146

帖子

0

粉丝