⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 buttons.c

📁 Internet Radio Internet Radio Internet Radio Internet Radio Internet Radio
💻 C
字号:
/*
 * Copyright (C) 2007 by egnite Software GmbH. All rights reserved.
 * Copyright (C) 2008 by egnite GmbH. All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 *
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 * 2. Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in the
 *    documentation and/or other materials provided with the distribution.
 * 3. Neither the name of the copyright holders nor the names of
 *    contributors may be used to endorse or promote products derived
 *    from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
 * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
 * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
 * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
 * THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
 * SUCH DAMAGE.
 *
 * For additional information see http://www.ethernut.de/
 *
 */

/*!
 * \file buttons.c
 * \brief Simple button interface.
 *
 * Handles 3 toggle switches connected to 3 dedicated GPIO lines. It is
 * expected, that the port pin is driven low when the related button is
 * pressed. Auto repeat is supported.
 *
 * The following code sample shows how to use the button interface.
 * \code
 * #include "buttons.h"
 *
 * char key;
 *
 * ButtonInit();
 * key = ButtonRead(500);
 * \endcode
 *
 * \note The macro USE_BUTTONS must be set to 1 to activate this code.
 *
 * \verbatim
 * $Id$
 * \endverbatim
 */

#include <cfg/os.h>
#include <cfg/clock.h>
#include <arch/arm.h>
#include <dev/irqreg.h>

#include <sys/event.h>
#include <sys/timer.h>

#include "buttons.h"

/*! 
 * \def BTN_TC_ID
 * \brief Button scan timer ID.
 *
 * Specifies the timer/counter that will be used to generate periodical 
 * interrupts for scanning the buttons.
 *
 *! \def BTN_PIO_ID
 * \brief PIO ID of the button interface.
 *
 * All buttons must be connected to the same PIO port. 
 *
 * \def BTN_DOWN_BIT
 * \brief PIO bit number of the button labeled DOWN.
 *
 * This button is used to reduce the volume or move to
 * the previous menu item.
 *
 * If not specified, this button will not be available.
 *
 * \def BTN_SELECT_BIT
 * \brief PIO bit number of the button labeled SELECT.
 *
 * This button is used to enter menu mode or to select
 * the currently displayed menu item.
 *
 * If not specified, this button will not be available.
 *
 * \def BTN_UP_BIT
 * \brief PIO bit number of the button labeled UP.
 *
 * This button is used to increase the volume or move to
 * the next menu item.
 *
 * If not specified, this button will not be available.
 */
#if defined(AT91SAM7X_EK)   /* Board */
/* Calypso board configuration. */
#define BTN_TC_ID       TC1_ID
#define BTN_PIO_ID      PIOB_ID
#define BTN_DOWN_BIT    27
//#define BTN_SELECT_BIT    28 //Doesn't work. Reason currently unknown.
#define BTN_UP_BIT      29

#elif defined(AT91SAM9260_EK)
/* Calypso board configuration. */
#define BTN_TC_ID       TC1_ID
#define BTN_PIO_ID      PIOB_ID
#define BTN_DOWN_BIT    8
#define BTN_SELECT_BIT  9
#define BTN_UP_BIT      10

#elif defined(ELEKTOR_IR1)
/* EIR1 configuration. */
#define BTN_TC_ID       TC1_ID
#define BTN_PIO_ID      PIOB_ID
#define BTN_DOWN_BIT    24
#define BTN_SELECT_BIT  25
#define BTN_UP_BIT      26
#endif   /* Board */

#ifndef BTN_SCAN_FREQ
/*!
 *\brief Number of button scans per second. 
 */
#define BTN_SCAN_FREQ       128UL
#endif

#ifndef BTN_REPEAT_FIRST
/*! 
 * \brief Number of scans until the first repeat is triggered. 
 */
#define BTN_REPEAT_FIRST    100
#endif

#ifndef BTN_REPEAT_NEXT
/*! 
 * \brief Number of scans until all following repeats are triggered. 
 */
#define BTN_REPEAT_NEXT     25
#endif

/*!
 * \def BTN_PIO_PE_REG
 * \brief PIO enable register of the button interface.
 *
 * The compiler evaluates \ref BTN_PIO_ID to determine this register.
 *
 * \def BTN_PIO_OD_REG
 * \brief PIO output disable register of the button interface.
 *
 * The compiler evaluates \ref BTN_PIO_ID to determine this register.
 *
 * \def BTN_PIO_PDS_REG
 * \brief Pin data status register of the button interface.
 *
 * The compiler evaluates \ref BTN_PIO_ID to determine this register.
 *
 * \def BTN_PIO_PUE_REG
 * \brief Pull-up enable register of the button interface.
 *
 * The compiler evaluates \ref BTN_PIO_ID to determine this register.
 */
#if BTN_PIO_ID == PIOB_ID
#define BTN_PIO_PE_REG  PIOB_PER
#define BTN_PIO_OD_REG  PIOB_ODR
#define BTN_PIO_PDS_REG PIOB_PDSR
#define BTN_PIO_PUE_REG PIOB_PUER
#elif BTN_PIO_ID == PIOA_ID
#define BTN_PIO_PE_REG  PIOA_PER
#define BTN_PIO_OD_REG  PIOA_ODR
#define BTN_PIO_PDS_REG PIOA_PDSR
#define BTN_PIO_PUE_REG PIOA_PUER
#elif BTN_PIO_ID == PIOC_ID
#define BTN_PIO_PE_REG  PIOC_PER
#define BTN_PIO_OD_REG  PIOC_ODR
#define BTN_PIO_PDS_REG PIOC_PDSR
#define BTN_PIO_PUE_REG PIOC_PUER
#else
#define BTN_PIO_PE_REG  PIO_PER
#define BTN_PIO_OD_REG  PIO_ODR
#define BTN_PIO_PDS_REG PIO_PDSR
#define BTN_PIO_PUE_REG PIO_PUER
#endif

/*! \brief PIO bit mask of the SELECT button. */
#ifdef BTN_SELECT_BIT
#define BTN_SELECT      _BV(BTN_SELECT_BIT)
#else
#define BTN_SELECT      0
#endif

/*! \brief PIO bit mask of the UP button. */
#ifdef BTN_UP_BIT
#define BTN_UP          _BV(BTN_UP_BIT)
#else
#define BTN_UP          0
#endif

/*! \brief PIO bit mask of the DOWN button. */
#ifdef BTN_DOWN_BIT
#define BTN_DOWN        _BV(BTN_DOWN_BIT)
#else
#define BTN_DOWN        0
#endif

/*!
 * \def sig_BTN_TC
 * \brief Interrupt signal of the button scan timer.
 *
 * The compiler evaluates \ref BTN_TC_ID to determine the Nut/OS interrupt signal.
 *
 * \def BTN_TC_CC_REG
 * \brief Channel control register of the button scan timer.
 *
 * The compiler evaluates \ref BTN_TC_ID to determine this register.
 *
 * \def BTN_TC_CM_REG
 * \brief Channel mode register of the button scan timer.
 *
 * The compiler evaluates \ref BTN_TC_ID to determine this register.
 *
 * \def BTN_TC_IE_REG
 * \brief Interrupt enable register of the button scan timer.
 *
 * The compiler evaluates \ref BTN_TC_ID to determine this register.
 *
 * \def BTN_TC_ID_REG
 * \brief Interrupt disable register of the button scan timer.
 *
 * The compiler evaluates \ref BTN_TC_ID to determine this register.
 *
 * \def BTN_TC_S_REG
 * \brief Status register of the button scan timer.
 *
 * The compiler evaluates \ref BTN_TC_ID to determine this register.
 *
 * \def BTN_TC_RC_REG
 * \brief Register C of the button scan timer.
 *
 * The compiler evaluates \ref BTN_TC_ID to determine this register.
 *
 */
#if BTN_TC_ID == TC1_ID
#define sig_BTN_TC      sig_TC1
#define BTN_TC_CC_REG   TC1_CCR
#define BTN_TC_CM_REG   TC1_CMR
#define BTN_TC_IE_REG   TC1_IER
#define BTN_TC_ID_REG   TC1_IDR
#define BTN_TC_S_REG    TC1_SR
#define BTN_TC_RC_REG   TC1_RC
#elif BTN_TC_ID == TC2_ID
#define sig_BTN_TC      sig_TC2
#define BTN_TC_CC_REG   TC2_CCR
#define BTN_TC_CM_REG   TC2_CMR
#define BTN_TC_IE_REG   TC2_IER
#define BTN_TC_ID_REG   TC2_IDR
#define BTN_TC_S_REG    TC2_SR
#define BTN_TC_RC_REG   TC2_RC
#endif

/*!
 * \brief Button event queue.
 *
 * The button scan timer interrupt handler will post an event to this
 * queue whenever a new button had been pressed or the repeat timer
 * elapses with a button still pressed.
 */
static HANDLE btn_que;

/*!
 * \brief Last button code.
 *
 * For each button that had been pressed during the last scan interrupt,
 * the related bit \ref BTN_SELECT, \ref BTN_DOWN or \ref BTN_UP is set.
 */
static volatile u_int btn_pressed;

#if USE_BUTTONS
/*!
 * \brief Button scan timer interrupt handler.
 */
static void ScanTimerInterrupt(void *arg)
{
    static u_int btn_prev;
    static u_int btn_repeat;
    u_int btn_code;

    /* Read the negated GPIO line status. Pressing a button drives the pin low. */
    btn_code = ~inr(BTN_PIO_PDS_REG) & (BTN_DOWN | BTN_SELECT | BTN_UP);
    if (btn_code) {
        /* A button has been or still is pressed. */
        if (btn_code != btn_prev) {
            /* This is a new button. Immediately post an event. */
            btn_pressed = btn_code;
            NutEventPostFromIrq(&btn_que);
            /* Initialize the repeat rate. */
            btn_repeat = BTN_REPEAT_FIRST;
        }
        else if (btn_repeat == 0) {
            /* Button is still pressed and the repeat time elapsed. 
               Post a new event. */
            NutEventPostFromIrq(&btn_que);
            /* Re-initialize the repeat rate. */
            btn_repeat = BTN_REPEAT_NEXT;
        }
        else {
            /* Button is still pressed. Wait until repeat time elapses. */
            btn_repeat--;
        }
    }
    /* Keep the last code, so we are able to distinguish whether the user
       is still pressing the same or selected a new button. */
    btn_prev = btn_code;
}
#endif /* USE_BUTTONS */

/*!
 * \brief Initialize the button interface.
 *
 * Configures and starts a continously running timer interrupt, which scans
 * three GPIO lines. A low level on any line indicates, that the related
 * button has been pressed by the user.
 *
 * The application must call ButtonRead() to read the code of a pressed button.
 */
void ButtonInit(void)
{
#if USE_BUTTONS
    int dummy;

    /* Enable scan timer clock. */
    outr(PMC_PCER, _BV(BTN_TC_ID) | _BV(BTN_PIO_ID));
    /* Disable the Clock Counter */
    outr(BTN_TC_CC_REG, TC_CLKDIS);
    /* Disable all interrupts */
    outr(BTN_TC_ID_REG, 0xFFFFFFFF);
    /* Clear the status register. */
    dummy = inr(BTN_TC_S_REG);
    /* Select divider and compare trigger */
    outr(BTN_TC_CM_REG, TC_CLKS_MCK32 | TC_CPCTRG);
    /* Enable the Clock counter */
    outr(BTN_TC_CC_REG, TC_CLKEN);
    /* Validate the RC compare interrupt */
    outr(BTN_TC_IE_REG, TC_CPCS);

    /* Register timer interrupt handler. */
    NutRegisterIrqHandler(&sig_BTN_TC, ScanTimerInterrupt, 0);
    /* Set to lowest priority. */
    NutIrqSetPriority(&sig_BTN_TC, 0);

    /* Enable timer interrupts */
    NutIrqEnable(&sig_BTN_TC);

    /* Set compare value for specified scan frequency. */
#if defined(AT91_PLL_MAINCK)
    outr(BTN_TC_RC_REG, At91GetMasterClock() / (32 * BTN_SCAN_FREQ));
#else
    outr(BTN_TC_RC_REG, NutGetCpuClock() / (32 * BTN_SCAN_FREQ));
#endif

    /* Initialize GPIO lines for buttons. */
    outr(BTN_PIO_PE_REG, BTN_SELECT | BTN_UP | BTN_DOWN);
    outr(BTN_PIO_OD_REG, BTN_SELECT | BTN_UP | BTN_DOWN);
    outr(BTN_PIO_PUE_REG, BTN_SELECT | BTN_UP | BTN_DOWN);

    /* Software trigger starts the scan timer. */
    outr(BTN_TC_CC_REG, TC_SWTRG);
#endif
}

/*!
 * \brief Wait until the user pressed a button.
 *
 * This routine will not handle concurrently pressed buttons, but
 * return the button with the highest priority. SELECT has the 
 * highest and UP has the lowest priority.
 *
 * \param tmo Maximum number of milliseconds to wait.
 *
 * \return Key code of the button, either \ref KEYCODE_SELECT, 
 *         \ref KEYCODE_DOWN or \ref KEYCODE_UP. If no button had been 
 *         pressed within the given time, then zero is returned.
 */
char ButtonRead(u_long tmo)
{
    /* Wait for a button event from the interrupt handler. */
    if (NutEventWait(&btn_que, tmo) == 0) {
        /* Copy the volatile value to a local variable. */
        u_int pressed = btn_pressed;

        if (pressed & BTN_SELECT) {
            return KEYCODE_SELECT;
        }
        if (pressed & BTN_DOWN) {
            return KEYCODE_DOWN;
        }
        if (pressed & BTN_UP) {
            return KEYCODE_UP;
        }
    }
    return 0;
}

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -