Исходный код библиотеки
Для наглядности я объединил хедер и сишный файл.
//состояния таймера - неработающий, активный, отработавший
enum StateTimer {IDLE, ACTIVE, DONE};
//структура программного таймера
typedef struct{
unsigned int time; //через какое время запустить
unsigned int period; //период повторения
enum StateTimer state; //текущее состояние
void (*pFunc)(void); //указатель на функцию
}SoftTimer;
//максимальное число таймеров
#define MAX_TIMERS 4
//число созданных таймеров
unsigned char AmountTimers = 0;
//массив указателей на таймеры
SoftTimer* SoftTimers[MAX_TIMERS];
//функция создания программного таймера
void CreateTimer(SoftTimer *CurSoftTimer, unsigned int time, unsigned int period , enum StateTimer state, void (*pFunc)(void)){
SoftTimers[AmountTimers] = CurSoftTimer;
CurSoftTimer->time = time;
CurSoftTimer->period = period;
CurSoftTimer->state = state;
CurSoftTimer->pFunc = pFunc;
AmountTimers++;
}
//функция проверки таймеров
void CheckTimer(void){
for(unsigned char i = 0; i < AmountTimers; i++){
if (SoftTimers[i]->state == ACTIVE){
if (SoftTimers[i]->time == 0){
SoftTimers[i]->pFunc();
if (SoftTimers[i]->period != 0) SoftTimers[i]->time = (SoftTimers[i]->period-1);
else SoftTimers[i]->state = DONE;
}
else(SoftTimers[i]->time)--;
}
}
}
Пояснение к коду
- уметь запускаться сразу или через заданное время
- работать в режиме однократного или переодического запуска
- сигнализировать об окончании счета
На основании этих требований определяем структуру SoftTimer.
//состояния таймера - неработающий, активный, отработавший
enum StateTimer {IDLE, ACTIVE, DONE};
//структура программного таймера
typedef struct{
unsigned int time; //через какое время запустить
unsigned int period; //период повторения
enum StateTimer state; //текущее состояние
void (*pFunc)(void); //указатель на функцию
}SoftTimer;
Массив указателей на таймеры
//максимальное число таймеров
#define MAX_TIMERS 4
//число созданных таймеров
unsigned char AmountTimers = 0;
//массив указателей на таймеры
SoftTimer* SoftTimers[MAX_TIMERS];
Создание таймера
void CreateTimer(SoftTimer *CurSoftTimer, unsigned int time, unsigned int period , enum StateTimer state, void (*pFunc)(void)){
SoftTimers[AmountTimers] = CurSoftTimer;
CurSoftTimer->time = time;
CurSoftTimer->period = period;
CurSoftTimer->state = state;
CurSoftTimer->pFunc = pFunc;
AmountTimers++;
}
Функция опроса таймеров
Функция опроса таймеров запускается в прерывании аппаратного таймера/счетчика
//функция проверки таймеров
void CheckTimer(void){
for(unsigned char i = 0; i < AmountTimers; i++){
if (SoftTimers[i]->state == ACTIVE){
if (SoftTimers[i]->time == 0){
SoftTimers[i]->pFunc();
if (SoftTimers[i]->period != 0) SoftTimers[i]->time = (SoftTimers[i]->period-1);
else SoftTimers[i]->state = DONE;
}
else(SoftTimers[i]->time)--;
}
}
}
Тестовый проект
//программирование микроконтроллеров AVR на Си
//тестовый проект с программными таймерами
//Pashgan ChipEnable.ru
#include <ioavr.h>
#include <intrinsics.h>
#include "Timers.h"
#include "bits_macros.h"
//объявляем переменные типа SoftTimer
SoftTimer timer1;
SoftTimer timer2;
SoftTimer timer3;
SoftTimer timer4;
//расписываем функции программных таймеров
void Clk1(void){
InvBit(PORTB, 0);
}
void Clk2(void){
InvBit(PORTB, 1);
}
void Clk3(void){
InvBit(PORTB, 2);
}
void Clk4(void){
InvBit(PORTB, 3);
}
int main( void )
{
//инициализация порта
PORTB = 0x00;
DDRB = 0xff;
//инициализация таймера Т0 - прерывания каждую ms
TIMSK = (1<<OCIE0);
TCCR0=(1<<WGM01)|(0<<WGM00)|(0<<COM01)|(0<<COM00)|(0<<CS02)|(1<<CS01)|(1<<CS00);
TCNT0 = 0;
OCR0 = 0x7d;
//инициализируем таймеры
CreateTimer(&timer1, 0, 1, ACTIVE, Clk1);
CreateTimer(&timer2, 0, 2, ACTIVE, Clk2);
CreateTimer(&timer3, 0, 3, ACTIVE, Clk3);
CreateTimer(&timer4, 0, 4, ACTIVE, Clk4);
//разрешаем прерывания и тупим в цикле
__enable_interrupt();
while(1);
return 0;
}
__interrupt void Timer0CompVect(void)
{
CheckTimer();
}
Заключение
Алгоритм, конечно, расточительный. Во-первых в прерывании запускается функция. Во-вторых перебор таймеров происходит последовательно - чем больше программных таймеров, тем больше времени это займет. В-третьих функции программных таймеров тоже запускаются в прерывании. Как можно оптимизировать? Не использовать много таймеров. Сделать функцию CheckTimer встраиваемой. Период работы аппаратного таймера выбрать большим. Функции программных таймеров сделать короткими.
Файлы
Проект для IARа. Проект для WINAVR.