SPL: прерывание по переполнению таймера

     Краткое описание: При разработке различных проектов с использованием микроконтроллеров, часто требуется иметь привязку к циклограммам (временным диаграммам) по которым работает устройство. Например полив цветов через каждые 12 часов, автоматическая кормушка для питомца которая должна срабатывать каждые 3-6 часов, опрос различных датчиков (давления, температуры...) раз в час и.т.д. 

Работая с циклограммами удобно использовать прерывания по переполнению таймера, как это работает:

1) Настраиваем нужные нам структуры настроек, создаем необходимые переменные: порт ввода вывода, таймер. Переменные которые понадобятся tick_count (счетчик тиков), sec_count(счетчик секунд), min_count(счетчик минут), по аналогии можно добавить счетчик часов.

2) Выставляем пределитель: в коде нашей программы присутствует настройка тактирования от внутреннего источника 8 МГц. Берем частоту тактирования 8МГц делим на пределитель 800, получаем 10 КГц. Рассчитываем один тик таймера 1/10 КГц=100 микросекунд. 

3) Выставляем период таймера: сколько раз должен тикнуть таймер прежде чем сработает прерывание. В нашем случае это значение равно 10. И того 100 микросекунд * 10 = 1 миллисекунда. Прерывание будет происходить раз в миллисекунду.

4) В прерывании выполняем следующее: сперва увеличиваем значение tick_count (счетчик тиков) на единицу, после тысячного срабатывания прерывания (соответственно 1000*1 миллисекунду=1 секунда), выполнится условие и увеличится на единицу sec_count (счетчик секунду) при этом обнулится tick_count (счетчик тиков). Следующее условие это увеличение min_count (счетчика минут) после 60-го значения в счетчике секунд, и обнуление sec_count (счетчика секунд). Можно дописать эту последовательность что бы получить счетчик часов, дней и.т.д. 

     Так или иначе где-то в основном теле программы можно обнулить значение любой выше описанной переменной для получения необходимой циклограммы. 

     Задача: Требуется написать с использованием библиотеки StdPeriph код. Программа должна каждую первую секунду включать зеленый светодиод, а каждую вторую отключать с последующим обнулением счетчика секунд замыкая циклограмму.

#include "stm32f30x.h"
#include "stm32f30x_gpio.h"
#include "stm32f30x_rcc.h"
#include "stm32f30x_exti.h"
#include "stm32f30x_syscfg.h"
#include "stm32f30x_misc.h"
#include "stm32f30x_tim.h"

#define TIMER_PRESCALER 800 //Пределитель
#define TIMER_PERIOD 10 //Период

GPIO_InitTypeDef gpio; //Объявляем переменную gpio типа GPIO_InitTypeDef
TIM_TimeBaseInitTypeDef timer; //Объявляем переменную timer типа TIM_TimeBaseInitTypeDef

int tick_count = 0; //Счетчик тиков
int sec_count = 0; //Счетчик секунд
int min_count = 0; //Счетчик минут

void initAll() //Функция инициализации
{
    RCC_HSICmd(ENABLE); //Включаем тактирование от внутреннего источника
    RCC_SYSCLKConfig(RCC_SYSCLKSource_HSI); //Подаем тактовый сигнал на системную шину
    RCC_AHBPeriphClockCmd(RCC_AHBPeriph_GPIOC, ENABLE); //Включаем тактирование порта С
    RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM4, ENABLE); //Включаем тактирование таймера

    gpio.GPIO_Mode = GPIO_Mode_OUT; //Выбираем режим работы пина: ВЫХОД
    gpio.GPIO_Pin = GPIO_Pin_7; //Выбираем нужный пин
    GPIO_Init(GPIOC, &gpio); //Инициализируем структуру с настройками

    timer.TIM_Prescaler = TIMER_PRESCALER; //Устанавливаем пределитель
    timer.TIM_Period = TIMER_PERIOD; //Устанавливаем период
    TIM_TimeBaseInit(TIM4, &timer); //Инициализируем структуру с настройками
    TIM_ITConfig(TIM4, TIM_IT_Update, ENABLE); //Настраиваем таймер для генерации прерывания по обновлению (переполнению)
    TIM_Cmd(TIM4, ENABLE); //Запускаем таймер
}

int main()
{
    __enable_irq(); //Разрешаем прерывания
    initAll(); //Вызываем функцию инициализации
    NVIC_EnableIRQ(TIM4_IRQn); //Разрешаем прерывание по таймеру

    while (1) {
        if (sec_count == 1) {
            GPIO_SetBits(GPIOC, GPIO_Pin_7); //Включаем красный светодиод досчитав до 1 секунды
        }
        if (sec_count == 2) {
            GPIO_ResetBits(GPIOC, GPIO_Pin_7); //Включаем красный светодиод досчитав до 2-й секунды
            sec_count = 0; //Обнуляем счетчик секунд что бы замкнуть цикл
        }
    }
}

void TIM4_IRQHandler() //Функция обработчика прерываний таймера
{
    TIM_ClearITPendingBit(TIM4, TIM_IT_Update); //Очищаем бит прерывания

    tick_count++; //Увеличиваем значение счетчика тиков на 1

    if (tick_count == 1000)

    {
        tick_count = 0; //Досчитав до 1000 тиков обнуляем значение счетчика тиков
        sec_count++; //Увеличиваем значение счетчика секунд на 1

        if (sec_count == 60) {
            sec_count = 0; //Досчитав до 60 секунд обнуляем значение счетчика секунд
            min_count++; //Увеличиваем значение счетчика минут на 1
        }
    }
}

     Скомпилируйте программу нажав кнопку Build, прошейте микроконтроллер, нажмите RESET. Зеленый светодиод должен мигать раз в секунду. 

     ВНИМАНИЕ: Приведенный листинг кода не является единственной и оптимальной реализацией поставленной задачи. Пример опубликован с демонстрационной целью. Также автор во избежание переписывания чужих статей, пропускает теоретические основы необходимые для понимания примера, связывая это с тем что всю необходимую информацию можно найти в интернете.

Комментариев (0)

Написать комментарий

Имя *
E-mail
Введите комментарий *
Капча
10 + ? = 16