Debouncing de teclas usando Soft Timers

debouncing
Este post faz parte da série Soft Timers

Introdução

Aqui no Portal Embarcados já tivemos alguns artigos abordando o problema de debouncing de chaves em sistemas embarcados. Nosso colaborador Rodrigo Almeida escreveu um artigo excelente no ano passado descrevendo o que é debouncing e os seus efeitos em sistemas embarcados. E neste artigo demonstraremos a implementação de soft timers para debouncing de teclas.

Para isso usaremos o kit Connected Launchpad, da Texas Instruments, e suas teclas de usuário, que sofrerão o processo de debouncing. Para implementar o time delay utilizamos alguns soft timers, disponibilizados pela biblioteca Soft Timers. Como compilador, utilizamos o MDK Keil 5.0 da ARM.

Hardware Utilizado para Debouncing

A Connected Launchpad é um kit bem interessante, veja na Figura 1. Pensado para o mercado de IoT, ele vem equipado com um microcontrolador TIVA TM4C1294, conectividade ethernet com MAC e PHY integrado, USB 2.0, 4 LEDs de uso geral, 2 chaves de uso geral e conectores para as placas de expansão Booster XL da Texas. Acabei adquirindo esta placa pois o seu preço é extremamente baixo.

Soft Timers para Debouncing: Connected Launchpad
Figura 1 – Connected Launchpad da Texas Instruments

Aplicação de Soft Timers para Debouncing

O projeto demo (veja aqui o seu repositório) que irei demonstrar aqui realiza basicamente duas operações:

  • leitura das teclas USR_SW1/USR_SW2 com a respectiva atualização dos LEDs D1 e D2 e;
  • atualização de um LED que pode ser interpretado como um LED de Keep-Alive.

Essas duas tarefas são realizadas através de tasks gerenciadas por soft timers.

A função main() tem a função somente de inicializar o hardware, criar os soft timers e entrar em um laço infinito que só serve para manter o programa rodando e aguardando interrupções.

int main()
{   
    uint32_t dwTimerHandle;
    
    SetSystemClock();  /* configure the system clock  */    
    
    TTimerCfgTimeOut( 500 );  /* initialize the ttimer engine  */
    
    BrdLedsInit();  /* initialize the board leds engine */
    BrdKeyInit();   /* initialize the board keys engine */
    
    BrdLedsSetState( USR_LED0, 0 );
    BrdLedsSetState( USR_LED1, 0 );
    BrdLedsSetState( USR_LED2, 0 );
    BrdLedsSetState( USR_LED3, 0 );

    // create a periodic timer to execute TaskMain
    TTimerRegisterCallBack( TTIMER_1MS_INTERVAL, TimerPeriodic, TaskMain, NULL, &dwTimerHandle );
    TTimerStart( dwTimerHandle );

    // create a periodic timer to execute TaskBlink
    TTimerRegisterCallBack( TTIMER_1SEC_INTERVAL, TimerPeriodic, TaskBlink, NULL, &dwTimerHandle );
    TTimerStart( dwTimerHandle );
    
    for( ;; );
}

As tasks iniciadas pela função main() são responsáveis pela operação de alterar o status dos LEDs D1 e D2 quando as teclas USR_SW1 ou USR_SW2 forem pressionadas e também pela função de pisca-pisca realizado no LED D4.

Abaixo segue o código da task TaskMain(), que é a responsável por controlar os LEDs D1 e D2:

uint32_t TaskMain( void* lpParam )
{
    struct STSwStatus
    {
        uint8_t bCurrentStatus;
        uint8_t bPrevStatus;
    };
    
    uint8_t bCounter;
    static uint8_t bLedStatus=0;
    static UsrLedType tUsrLed[] = {USR_LED0, USR_LED1};
    static struct STSwStatus stSwStatus[] = 
    {
        [0] = 
        {
            .bCurrentStatus = 0,
            .bPrevStatus    = 0,
        },
        [1] = 
        {
            .bCurrentStatus = 0,
            .bPrevStatus    = 0,
        }
    };
    
    for ( bCounter = 0; bCounter < GET_ARRAY_LEN( stSwStatus ); bCounter++ )
    {
        stSwStatus[bCounter].bPrevStatus = stSwStatus[bCounter].bCurrentStatus;
        stSwStatus[bCounter].bCurrentStatus = BrdKeyRead( (UsrSwType)bCounter );
        
        if( (stSwStatus[bCounter].bPrevStatus == 0) && (stSwStatus[bCounter].bCurrentStatus == 1) )
        {
            bLedStatus ^= (1<<bCounter);
            BrdLedsSetState( tUsrLed[bCounter], (bLedStatus & (1<<bCounter)) == (1<<bCounter) ); 
        }
    }
    
    return 0;
}

A “mágica” é realizada dentro do módulo BoardKeys (arquivo Board/BoardKeys.c). Ele é responsável por realizar a leitura das teclas e determinar se o seu status é ON ou OFF. Para isso também utilizamos uma task gerenciada por um soft timer que somente realiza a leitura das chaves e armazena o estado em uma struct que é utilizada internamente pelo módulo (struct STSwStatus stSwStatus).

uint32_t UserSwitchTask( void* lpParam )
{
    static  UsrSwType lblButton = USR_SW1;  //! local variable to control the current key to be read
    struct STGpioInputStatus* pSwitchStatus = &stSwitchStatus[lblButton];
    const struct STGpioConfig* pSwitchConfig = &stSwitchConfig[lblButton];
    
    bBusy = 1;

    switch( lblButton )
    {
        case USR_SW1: 
            lblButton = USR_SW2;
            break;
        
        case USR_SW2:
            lblButton = USR_SW1;
            break;
    }

    // save the previous state
    pSwitchStatus->bPrevState = pSwitchStatus->bState;
    
    // get the new switch status
    pSwitchStatus->bState = (GPIOPinRead( pSwitchConfig->dwBASE, pSwitchConfig->dwPin ) ? 0 : 1);

    bBusy = 0;

    return 0;
}

Atentem-se que, como as tasks são executadas em contexto de interrupção, as tarefas executadas por elas devem ser as mais breves possíveis. Se o usuário colocar um loop infinito em um soft timer o sistema não funcionará a contento. Pensem que é um sistema colaborativo.

O código é bastante simples e pode ser portável para qualquer outra arquitetura de microcontrolador, só necessitando reescrever os drivers para os timers e GPIOs.

O código fonte do projeto de debouncing no ambiente Keil está disponível no github.

Soft Timers

Biblioteca de Soft Timers
Licença Creative Commons Esta obra está licenciada com uma Licença Creative Commons Atribuição-CompartilhaIgual 4.0 Internacional.
Comentários:
Notificações
Notificar
3 Comentários
recentes
antigos mais votados
Inline Feedbacks
View all comments
Rogerio
Rogerio
04/08/2015 13:19
phfbertoleti
phfbertoleti
03/08/2015 22:52

Muito bom post!

Rafael Dias
Rafael Dias
Reply to  phfbertoleti
04/08/2015 08:50

obrigado!

Home » Software » Firmware » Debouncing de teclas usando Soft Timers

EM DESTAQUE

WEBINARS

VEJA TAMBÉM

JUNTE-SE HOJE À COMUNIDADE EMBARCADOS

Talvez você goste: