ÍNDICE DE CONTEÚDO
Dessa vez vou apresentar rapidamente uma biblioteca contendo rotinas de Timer, Delay e Timeout, e no final do post o código da biblioteca será divulgado por completo.
Ela usa apenas um timer, configurado para contar a cada microssegundo e as funções da biblioteca são ditas rápidas porque aceitam que o registrador contador dê overflow sem fazer uso de código condicional, ou seja, sem “if” para verificar se o contador deu overflow. Isso é feito usando uma subtração que elimina o efeito causado pelo overflow do contador, que é:
1 2 |
/* Elimina o efeito de um overflow, sempre retorna um valor positivo, contanto que as variáveis sejam do tipo unsigned e tenham o mesmo número de bits. */ tempoQuePassou = tempoAgora - tempoAntes; |
Na biblioteca todas as verificações de delay e timeout usam essa subtração, por isso não é gasto tempo extra com verificações e as funções passam a ter um overhead independente do argumento e do valor do contador de tempo. Caso seja necessário saber esse overhead basta medir.
Só existe uma situação onde a subtração pode falhar: overflow duplo, entretanto essa situação é impossível por dois motivos:
- O argumento de uint32_t não permite a espera necessária por um duplo overflow;
- Um duplo overflow levaria: 2 x 2³² micro segundos, ou seja, 2 horas, 23 minutos e 10 segundos.
E conforme prometido, usem e abusem do código abaixo.
timer.h
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 |
#ifndef _TIMER_H_ #define _TIMER_H_ /* Initilize the Timer library */ void delayInit(void); /* Delay Functions, argument in milisecs and microsecs */ void delayMs(uint32_t delayInMs); void delayUs(uint32_t delayInUs); /* Timeout functions */ /* Return a Timeout seed used by the timeoutCheck functions */ uint32_t timeoutInit(void); /* Check if timeouted a initilized seed */ uint32_t timeoutCheck_ms(uint32_t delayInMs, uint32_t seed); uint32_t timeoutCheck_us(uint32_t delayInUs, uint32_t seed); /* Get the system time */ uint32_t getTime_us(void); uint32_t getTime_ms(void); #endif //_TIMER_H_ |
timer.c
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 |
/* #### # # # ## ### # # # # #-# #\ # # # # # # \# #### Author: Felipe de Andrade Neves Lavratti Copyright: There are no restrictions. Use as you want. */ static __inline void _HwTimerInit(void) { /* Setup a 32bits Timer or Ticker to increment each 1us, allow it to overflow */ } static __inline uint32_t _HwTick(void) { /* return the 32bits Timer/Ticker value */ } void delayInit() { _HwTimerInit(); } void delayMs(uint32_t delayInMs) { uint32_t compval = delayInMs*1000; uint32_t start = _HwTick(); while( (_HwTick() - start) < compval); //This comparison tolerates overflow } void delayUs(uint32_t delayInUs) { uint32_t compval = delayInUs; uint32_t start = _HwTick(); while( (_HwTick() - start) < compval); //This comparison tolerates overflow } uint32_t timeoutInit(void) { return _HwTick(); } uint32_t timeoutCheck_ms(uint32_t delayInMs, uint32_t seed) { uint32_t compval = delayInMs*1000; return ( !( (_HwTick() - seed) < compval) ); //This comparison tolerates overflow } uint32_t timeoutCheck_us(uint32_t delayInUs, uint32_t seed) { uint32_t compval = delayInUs; return ( !( (_HwTick() - seed) < compval) ); //This comparison tolerates overflow } uint32_t getTime_us(void) { return _HwTick(); } uint32_t getTime_ms(void) { return (_HwTick()/1000); } |
Olá Felipe. Era exatamente o que eu estava buscando! Por hora estava tentando fazer uma função delayUs utilizando instruções assembly para o meu Cortex-M4F, porém não gostei do resultado. Então passei a usar um Timer32 pra fazer o delayUs, mas essa sua implementação parece mais elegante que a minha, e por isso passarei a usar essa sua. Muito obrigado pelo artigo!
Abraço.