Библиотека "Программных Таймеров" (реализация синхронных и асинхронных задержек в прошивке микроконтроллера)
C
Switch branches/tags
Nothing to show
Clone or download
Fetching latest commit…
Cannot retrieve the latest commit at this time.
Permalink
Failed to load latest commit information.
LICENSE
README.md
celerontimer.c
celerontimer.h

README.md

"CeleronTimer" C library

Библиотека "Программных Таймеров" - реализация синхронных и асинхронных задержек в прошивке микроконтроллера.

Дискретность отсчёта = 1мс. Достаточна для реализации пользовательского интерфейса (и прикладной логики) в устройствах на микроконтроллере.

Документация

API библиотеки описано в "заголовочном файле" в комментариях к макросам и методам (оно простое). А чтобы знать с чего начинать, и чтобы дать представление о концепции библиотеки - смотри пример использования ниже:

<module1.c>

::

#include "celerontimer.h"


// Создать глобальный таймер (выделить память), который будет доступен из всех модулей программы
DELAY_DeclareGlobalTimer(globaltimer1);

// Создать таймер модульного уровня (выделить память), который будет доступен только для функций текущего модуля программы
DELAY_DeclareTimer(moduletimer1);


// Функция "конечного автомата", периодически вызываемая из Суперцикла
foo()
{
    // Создать локальный таймер (выделить статическую память), который будет доступен только из кода текущей функции
    DELAY_DeclareTimer(localtimer1);


    if(произошло_событие_1)
        // Запустить таймер на таймаут в 1сек
        DELAY_SetTimer(localtimer1, 1000);


    // Пока длится таймаут - виляем хвостиком (мигаем LEDиком).
    // (Светодиод на порте LED_ON: 128мс горит и 128мс выключен, 50% заполнение)
    LED_ON = DELAY_IsTimerOn(localtimer1) && 
             (DELAY_SysTick & 0b10000000);


    // За 100мс до окончания таймаута - пикнем бузером.
    // (Бузер с генератором на порте BUZZER_ON)
    BUZZER_ON = DELAY_IsTimerOn(localtimer1) && 
                DELAY_RemainingTime(localtimer1) < 100;


    // Если таймаут истёк?
    if(DELAY_CheckTimer(localtimer1))
    {
        // Важно: в обработчике события необходимо явно, либо выключить сработавший "одиночный таймер", либо перезапустить "периодический таймер" на следующий интервал отсчёта!
        
        // Выключить "одиночный таймер" (событие обработано)
        DELAY_DisableTimer(localtimer1);
        
        // Перезапустить "периодический таймер" на следующий интервал в 1сек (в данном случае это не нужно - код закомментирован)
        //DELAY_SetTimer(localtimer1, 1000);
    }
    
}


// Функции модуля легко шарят "модульные" и "глобальные" таймеры
bar()
{
    DELAY_SetTimer(moduletimer1, 1000);

    DELAY_SetTimer(globaltimer1, 1000);

}

<module1.h>

::

// Декларировать глобальный таймер - расшарить имя для других модулей программы
DELAY_DeclareExternalTimer(globaltimer1)

<module2.c>

::

#include "celerontimer.h"
#include "module1.h"


// Функциям из другого модуля доступны глобальные таймеры (если подключены соответствующие external-декларации)
baz()
{
    if(DELAY_IsTimerOn(globaltimer1))
        return;
        
    // Следующий код выполняется только когда "globaltimer1" неактивен...
}




// И хотя для "глобальных таймеров" доступны любые действия из любого модуля программы, но рекомендую, чисто концептуально, располагать код так, 
// чтобы Таймер декларировался рядом с кодом который его "обслуживает", т.е. включает и выключает по событиям (методы: DELAY_SetTimer, DELAY_CheckTimer, DELAY_DisableTimer).
// А в других "внешних модулях" использовать только наблюдательные действия, не изменяющие состояния таймера (методы: DELAY_IsTimerOn, DELAY_RemainingTime).

qux()
{
    if(DELAY_CheckTimer(globaltimer1))
    {
        DELAY_DisableTimer(globaltimer1);
    }
}

// TODO: рефакторинг, перенести функцию qux() в модуль <module1.c>

Требования

Компилятор Си, совместимый с GCC.

Поддерживаются микроконтроллеры любой разрядности: 8-битные, 32-битные и другие.

Единственное замечание для микроконтроллеров рязрядности ниже 32-бит (в которых реализована фрагментированная арифметика над 32-битными целыми): Обработчик прерывания "Аппаратного Таймера", отсчитывающий 1мс интервалы, и в который вы помещаете вызов DELAY_IncSysTick() - этот обработчик должен иметь "наивысший приоритет" (не перебиваться другими прерываниями) среди других обработчиков, которые также используют обращение к "Программным Таймерам".

ENGLISH:

GCC compatible C compiler.

8-bit and 32-bit microcontrollers are supported!

Just one requirement for 8-bit microcontrollers: 1ms "Hard Timer" interrupt handler, where you place the DELAY_IncSysTick() call, must have highest (or the same) priority among other handlers, which use "Soft Timers"! To avoid fragmentation of DELAY_SysTick variable incrementation process. That is all!

Обоснование

Редкая прошивка обходится без таймеров. "Программные таймеры" - это мощный и универсальный инструмент. Могут быть использованы в любой архитектуре программной прошивки. Но обычно применяются в архитектурах начального уровня сложности: "Суперцикл" и "Конечный/флаговый автомат" - это большинство разрабатываемых прошивок для микроконтроллеров.

  • Вводную теорию "что такое программные таймеры? зачем нужны? и как их применять?" можно почитать в Учебном курсе ["AVR. Учебный Курс. Архитектура Программ" от DI HALT.] (http://easyelectronics.ru/avr-uchebnyj-kurs-arxitektura-programm.html)
  • Ещё одна [реализация программных таймеров] (https://habrahabr.ru/post/273077/) замечена на Хабре.

Но замечу: в библиотеке "CeleronTimer" совсем другая реализация (удобнее и функциональнее API, нетребовательная к ресурсам МК), чем представленные выше!