Uma das funções mais usadas em microcontroladores são os temporizadores. Por esse motivo, é muito importante conhecer o modo como é possível implementar de uma maneira otimizada esta função. A maioria dos compiladores para microcontroladores traz funções para fazer a temporização por retardo (delay), mas estes interrompem a execução principal do programa e por isso não são muito práticos.

Quase todos os projetos eletrônicos com microcontroladores fazem uso dos temporizadores para seu funcionamento. Uma das técnicas mais comuns é a utilização de um Timer físico (TIM) do microcontrolador para gerar uma interrupção a cada milissegundo e a partir desta interrupção incrementar o decrementar contadores para gerar os tempos dos temporizadores.

Este método tem um inconveniente quando o projeto usa muitos temporizadores, pois a rotina de interrupção pode usa muito tempo da CPU. Outra técnica é usa temporizadores por retardo (delay), mas estes têm o inconveniente de não se poder ler as entradas do microcontrolador durante sua execução.

Neste artigo descreveremos como usar e codificar temporizadores dinâmicos que eliminam os inconvenientes citados.

 

TEMPORIZADOES DINÂMICOS

Este método usa um contador somente na interrupção do timer físico (TIM) e a partir deste contador, gera todas as interrupções necessárias. O código apresentado neste artigo pode ser adaptado para qualquer microcontrolador ARM de qualquer marca/fabricante ou qualquer microcontrolador de 8/16 bits com boa memória RAM.

O código fonte apresentado neste artigo foi testado no microcontrolador STM32L152RB, um ARM de 32 bits da ST. Na figura 1 podemos observar um diagrama de arquivos fonte para o código apresentado neste artigo.

 

 

Figura 1
Figura 1

 

  O código para a interrupção é o seguinte:

 
extern uint32_t systemTimer;
void TIM3_IRQHandler()
{
if (TIM_GetITStatus(TIM3, TIM_IT_Update) != RESET)
{
TIM_ClearITPendingBit(TIM3, TIM_IT_Update);
 systemTimer++;
}
}

 

  O código para este artigo usa o Timer 3 (TIM3) do microcontrolador, mas pode ser usado qualquer timer que esteja configurado para executar uma interrupção a cada 1 milisegundo.

A seguir, debe-se implementar um arquivo SystemTimer que use o contador systemTimer. O código será:

#include "SystemTimer.h"
uint32_t systemTimer;
******************************************************************/
uint32_t SystemTimer_GetTime()
{
return systemTimer;
}
******************************************************************/
void SystemTimer_Init()
{
systemTimer = 0;
}

 

  Este arquivo fonte usa duas funções: SystemTimer() que retorna o valor do contador systemTimer e a função SystemTimer Init() que inicializa o contador SystemTimer a partir de zero. Esta última função é chamada no reset do microcontrolador.

O arquivo de entrada SystemTimer será:

 

uint32_t SystemTimer_GetTime(void);
void SystemTimer_Init(void);

 

Agora, devemos implementar um arquivo que use as funções do arquivo fonte SystemTimer c para criar os temporizadores dinâmicos. Este arquivo pode ser chamado Timer e seu código será:

#include "Timer.h"
#include "SystemTimer.h"
******************************************************************/
uint32_t Timer_GetTime(Timer *p)
{
uint32_t systemTimer;
uint32_t timeSpan;
if(p->enabled == false)
return 0;
if(p->enabled != true)
return 0;
systemTimer = SystemTimer_GetTime();
if(systemTimer < p->startTime)
{
timeSpan = (0xFFFFFFFF - p->startTime) + systemTimer;
}
else
{
timeSpan = systemTime - p->startTimer;
}
return timeSpan;
}
******************************************************************/
void Timer_SetInterval(Timer *p, uint32_t interval)
{
p->interval = interval;
}
******************************************************************/
void Timer_Start(Timer *p)
{
p->startTime = SystemTimer_GetTime();
p->enabled = true;
}
******************************************************************/
void Timer_Stop(Timer *p)
{
p->enabled = false;
}
******************************************************************/
boolean Timer_Elapsed(Timer *p)
{
uint32_t timeSpan = Timer_GetTime(p);
if(timeSpan == 0)
return false;
if(timeSpan < p->interval)
return false;
Timer_Stop(p);
return true;
}
******************************************************************/
void Timer_Init(Timer *p, uint32_t interval)
{
p->startTime = 0;
p->interval = interval;
p->enabled = false;
}

 

  A função Timer Start() é usada para dar a partida no temporizador dinâmico e a função Timer Stop() é usada para parar o temporizador. A função Timer Init() é usada para inicializar o temporizador e é chamada no reset do microcontrolador.

A função Timer Interval() é usada para programar o intervalo em microssegundos do temporizador. Este intervalo também pode ser programado na função Timer Init();

Para saber quando o temporizador chegou ao seu tempo programado, é utilizada a função Timer Elapsed() a qual retorna “válido” quando o tempo é decorrido. Para usar o Timer do sistema que criamos anteriormente com a interrupção do timer físico 3 e do arquivo fonte SystemTimer c, usamos a função Timer GetTime().

O arquivo de escopo Timer h será:

 

 
typedef struct
{
uint32_t startTime;
uint32_t interval;
boolean enabled;
}Timer;
uint32_t Timer_GetTime(Timer *p);
void Timer_SetInterval(Timer *p, uint32_t interval);
void Timer_Start(Timer *p);
void Timer_Stop(Timer *p);
boolean Timer_Elapsed(Timer *p);
void Timer_Init(Timer *p, uint32_t interval);

 

  A figura 2 mostra o diagrama de blocos de um hardware típico com microcontrolador, onde temos várias entradas e saídas. Na figura 3 podemos observar que, usando estes temporizadores dinâmicos, podemos ler as entradas e executar as temporizações, sem parar o programa principal.

 

 

Figura 2
Figura 2

 

 

 

 

Figura 3
Figura 3

 

No arquivo seguinte fonte main.c podemos ver como utilizar os temporizadores dinâmicos. 

#include "Timer.h"
Timer salida_1_Timer;
Timer salida_2_Timer;
Timer salida_3_Timer;
int main()
{
Init_IO();
Timer_Init(&salida_1_Timer, 3000);
Timer_Init(&salida_2_Timer, 1000);
Timer_Init(&salida_3_Timer, 200);
while(1)
{
if(Timer_Elapsed(&salida_1_Timer))
{
Toggle_Saladia_1();
}
if(Timer_Elapsed(&salida_2_Timer))
{
Toggle_Saladia_2();
}
if(Timer_Elapsed(&salida_3_Timer))
{
Toggle_Saladia_3();
}
}
}

 

  Nos próximos artigos utilizaremos estes temporizadores dinâmicos em exemplos de projetos com microcontroladores.