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 é:
/* 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
#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
/*
#### #
# #
## ### # # #
# #-# #\ # #
# # # # \# ####
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.