Выкладываю пример программных таймеров для AVR. Использую эти таймеры уже несколько лет в своих проектах. Примечание. Подходят скорее для автоматного программирования.
soft_timer.h
Спойлер
Код:
//==================
#ifndef SOFT_TIMERS_H
#define SOFT_TIMERS_H
#include "soft_timers.h"
#include "main_def_func.h"
//==================
//==================
// Выбор: с прерыванием или с опросом флага OCFx.
#define __ST_INTERRUPT__ // __ST_NO_INTERRUPT__ // __ST_INTERRUPT__
// Состав структуры: bool status, u08 sys_tick_prev, u16 cnt, u16 period.
// Итого 6 байтов на один программный таймер. Если убрать элемент period,
// то теперь будет 4 байта на таймер.
#define __ST_PERIOD__ // __ST_PERIOD__ // __ST_NO_PERIOD__
//==================
//==================
#ifdef __IOTINY13_H
#define ST_TCNT TCNT0
#define ST_TIMSK TIMSK0
#define ST_OCIE OCIE0A
#define ST_OCR OCR0A
#define ST_TCCR TCCR0B
#define ST_CS0 CS00
#define ST_CS1 CS01
#define ST_CS2 CS02
#define ST_TIFR TIFR0
#define ST_OCF OCF0A
#endif
#ifdef __IOTINY13A_H
#define ST_TCNT TCNT0
#define ST_TIMSK TIMSK0
#define ST_OCIE OCIE0A
#define ST_OCR OCR0A
#define ST_TCCR TCCR0B
#define ST_CS0 CS00
#define ST_CS1 CS01
#define ST_CS2 CS02
#define ST_TIFR TIFR0
#define ST_OCF OCF0A
#endif
#ifdef __IOM8A_H
#define ST_TCNT TCNT2
#define ST_TIMSK TIMSK
#define ST_TIFR TIFR
#define ST_OCIE OCIE2
#define ST_OCR OCR2
#define ST_TCCR TCCR2
#define ST_CS0 CS20
#define ST_CS1 CS21
#define ST_CS2 CS22
#define ST_TIFR TIFR
#define ST_OCF OCF2
#endif
#ifdef __IOM8535_H
#define ST_TCNT TCNT2
#define ST_TIMSK TIMSK
#define ST_TIFR TIFR
#define ST_OCIE OCIE2
#define ST_OCR OCR2
#define ST_TCCR TCCR2
#define ST_CS0 CS20
#define ST_CS1 CS21
#define ST_CS2 CS22
#define ST_TIFR TIFR
#define ST_OCF OCF2
#endif
#ifdef __IOM32_H
#define ST_TCNT TCNT2
#define ST_TIMSK TIMSK
#define ST_TIFR TIFR
#define ST_OCIE OCIE2
#define ST_OCR OCR2
#define ST_TCCR TCCR2
#define ST_CS0 CS20
#define ST_CS1 CS21
#define ST_CS2 CS22
#define ST_TIFR TIFR
#define ST_OCF OCF2
#endif
//==================
//==================
#define SYS_TICK (F_CPU/64/1000)
//==================
//==================
typedef struct soft_timer
{
bool status;
u08 sys_tick_prev;
u16 cnt; // Counter.
#ifdef __ST_PERIOD__
u16 period; // Period.
#endif
} soft_timer_t;
//==================
//==================
void Init_Soft_Timers (void);
#define Handle_Soft_Timer(a) _Handle_Soft_Timer (&a)
bool _Handle_Soft_Timer (soft_timer_t *ptr_timer);
#ifdef __ST_PERIOD__
#define Set_Soft_Timer(a,b,c) _Set_Soft_Timer (&a, b, c)
void _Set_Soft_Timer (soft_timer_t *ptr_timer, u16 time, u16 period);
#endif
#ifdef __ST_NO_PERIOD__
#define Set_Soft_Timer(a,b) _Set_Soft_Timer (&a, b)
void _Set_Soft_Timer (soft_timer_t *ptr_timer, u16 time);
#endif
#define Reset_Soft_Timer(a) _Reset_Soft_Timer (&a)
void _Reset_Soft_Timer (soft_timer_t *ptr_timer);
void Proc_Sys_Tick (void);
//==================
//==================
__monitor bool Main_Get_Tick (void);
void Set_S_Tick_Flg (bool t);
bool Get_S_Tick_Flg (void);
//==================
#endif
soft_timer.c
Спойлер
Код:
//==================
// Реализация программных таймеров.
// Примечание. Важно!!!!!!!!!!!!!!!
// При смене состояния конечного автомата нужно сбросить
// все таймеры, которые используются в этом состоянии. Иначе может быть
// следующая ситуация: если таймер уже использовался в
// текущем состоянии и флаг EN установлен, то по окончании времени
// выполнится соответствующий код.
//---------- Пример использования ----------
// set_soft_timer (ST_LED_2_BLINK, 50, 50); // Установка таймера.
// if (handle_soft_timer (ST_LED_2_BLINK)) // Проверка таймера.
//==================
//==================
#include "soft_timers.h"
//==================
//==================
static u08 sys_tick;
//==================
//==================
volatile static bool int_s_tick_flg; // Флаг обновления системного таймера
static bool s_tick_flg; // Флаг начала нового системного интервала
//==================
//==================
#ifdef __ST_INTERRUPT__
#pragma vector = TIMER2_COMP_vect
__interrupt void SysTimerComp (void)
{
ST_OCR += SYS_TICK;
sys_tick++;
int_s_tick_flg = true; // Новый системный интервал
}
#endif
//==================
//==================
void Init_Soft_Timers (void)
{
sys_tick = 0;
ST_TCNT = 0;
ST_OCR = SYS_TICK;
int_s_tick_flg = true; // Принудительное обновление
#ifdef __IOTINY13_H
ST_TCCR |= ((1<<ST_CS1) | (1<<ST_CS0));
#endif
#ifdef __IOTINY13A_H
ST_TCCR |= ((1<<ST_CS1) | (1<<ST_CS0));
#endif
#ifdef __IOM8A_H
ST_TCCR |= (1<<ST_CS2);
#endif
#ifdef __IOM8535_H
ST_TCCR |= (1<<ST_CS2);
#endif
#ifdef __IOM32_H
ST_TCCR |= (1<<ST_CS2);
#endif
#ifdef __ST_INTERRUPT__
set_bit (ST_TIMSK, ST_OCIE);
#endif
}
//----------
#ifdef __ST_PERIOD__
void _Set_Soft_Timer (soft_timer_t *ptr_timer, u16 time, u16 period)
#else
void _Set_Soft_Timer (soft_timer_t *ptr_timer, u16 time)
#endif
{
ptr_timer -> status = true;
if (time == 0)
ptr_timer -> sys_tick_prev = ~sys_tick;
else
ptr_timer -> sys_tick_prev = sys_tick;
ptr_timer -> cnt = time;
#ifdef __ST_PERIOD__
ptr_timer -> period = period;
#endif
}
//----------
bool _Handle_Soft_Timer (soft_timer_t *ptr_timer)
{
if (ptr_timer -> status)
{
if (ptr_timer -> sys_tick_prev != sys_tick)
{
ptr_timer -> sys_tick_prev = sys_tick;
if (ptr_timer -> cnt == 0)
{
#ifdef __ST_PERIOD__
if (ptr_timer -> period != 0)
ptr_timer -> cnt = ptr_timer -> period;
#endif
return true;
}
else
{
ptr_timer -> cnt--;
if (ptr_timer -> cnt == 0)
{
#ifdef __ST_PERIOD__
if (ptr_timer -> period == 0)
ptr_timer -> status = false;
else
ptr_timer -> cnt = ptr_timer -> period;
#else
ptr_timer -> status = false;
#endif
return true;
}
}
}
}
return false;
}
//----------
void _Reset_Soft_Timer (soft_timer_t *ptr_timer)
{
ptr_timer -> status = false;
ptr_timer -> sys_tick_prev = 0;
ptr_timer -> cnt = 0;
#ifdef __ST_PERIOD__
ptr_timer -> period = 0;
#endif
}
//----------
#ifdef __ST_NO_INTERRUPT__
void Proc_Sys_Tick (void)
{
static u08 _proc_sys_tick;
switch (_proc_sys_tick)
{
case 0:
Init_Soft_Timers ();
_proc_sys_tick = 1;
break;
case 1:
if (ST_TIFR & (1<<ST_OCF))
{
ST_TIFR = (1<<ST_OCF);
ST_OCR += SYS_TICK;
sys_tick++;
int_s_tick_flg = true; // Новый системный интервал
}
break;
}
}
#endif
//==================
//==================
__monitor bool Main_Get_Tick (void)
{
if(!int_s_tick_flg)
return false; // Проверка нового системного интервала
else
{
int_s_tick_flg = false; // Очистка флага
return true; // Новый системный интервал
}
}
//==================
//==================
void Set_S_Tick_Flg (bool t)
{
s_tick_flg = t;
}
bool Get_S_Tick_Flg (void)
{
return s_tick_flg;
}
//==================