PROGCONT.RU

Вход Регистрация
О САЙТЕ ГЛАВНАЯ
 

STM8S Basic timer настройка и использование в SPL.

 Изучение темы таймеры нужно начинать именно с базовых таймеров(Basic timer) которые являются так же частью более продвинутых таймеров таких как Advanced control(расширенный контроль) и General purpose(много целевой).

 Схема таймеров.

нет рисунка

 На схеме показаны два таймера TIM4 и TIM6 отличаются они тем, что второй немного продвинутый так как имеет блок синхронизации(CLOCK/TRIGGER CONTROLLER) через который его можно подключить к остальным таймерам контроллера.

 Эти таймеры состоят из следующих основных элементов:
   Prescaler-входной предделитель;
   Counter-счётчик таймера;
   Auto-reload register-автоматически перегружаемый регистр.
 Из за своей простаты таймеры могут выполнять только функцию подсчёта тактов поступающих на вход счётчика через предделитель и сравнение его с регистром автоматической перегрузки, если значения совпадают то счётчик сбрасывается и генерируется событие, в зависимости от выбранного режима работы таймера будет зависеть остановится он или будет делать это циклически.
Обращаю ваше внимание, что ресурсы данных таймеров очень скудны, это счётчик с максимальным значение 255(256 отсчётов) и предделитель с возможностью нескольких значений 1,2,4,8,16,32,64 и 128.

нет рисунка И не много о том как работают счётчик( Counter) и перегружаемый регистр( Auto-reload register), во время работы таймера счётчик прибавляется и сравнивается с перегружаемым регистром, если значение равно то счётчик будет сброшен и начнёт отсчёт заново в круговом режиме, в однократном таймер отключится.
 Перегружаемый регистр имеет возможность записи в него напрямую нового значения или через вспомогательный теневой регистр данная функция гарантирует отработку всех значений счётчика и исключается ошибка когда будет записано новое значение которое меньше значения в счётчике, что приведет к не отработке.
 Демонстрация работы теневого регистра справа, где показано, что из теневого регистра значение загружается в перегружаемый регистр только после соответствия значения его и счётчика, загрузить новое значение в теневой регистр лучше в обработчике прерывания, по умолчанию таймер настроен для записи на прямую.

 Внимание! Устанавливать нулевое значение в перегружаемый регистр( Auto-reload register) нельзя, приведет к зависанию контроллера и поэтому минимальное значение будет один, что соответствует двум отработанным тактам( установленное значение плюс один).


 Настройка и практика использования TIM4 и TIM6.

 Практиковаться будем на контроллере STM8S903K3 у которого TIM6 настройка которого похожа c TIM4 за исключением дополнительных функций для работы с блоком синхронизации. В примере для визуализации процесса будем использовать светодиод подключенный к порту B выводу 0, который будет мигать.
 Пример №1-Быстрое мигание светодиодом.
 Запускаем контроллер, так как тактирование контроллера 2MHz то после включения светодиод будет мигать с частотой (1/2)/((128*256)/2000000)=30 Hz.

#include "stm8s.h"
int main( void )
{
GPIO_Init( GPIOB, GPIO_PIN_0, GPIO_MODE_OUT_PP_LOW_SLOW);
//Настройка таймера и запуск.
TIM6_TimeBaseInit( TIM6_PRESCALER_128, 255);
TIM6_ClearFlag( TIM6_FLAG_UPDATE);
TIM6_Cmd( ENABLE);

while(1){
//Проверяем переполнение счётчика, если да то меняем состояние светодиода.
while(!TIM6_GetFlagStatus( TIM6_FLAG_UPDATE));
TIM6_ClearFlag( TIM6_FLAG_UPDATE);
GPIO_WriteReverse( GPIOB, GPIO_PIN_0);
}
return 0;
}

#ifdef USE_FULL_ASSERT
void assert_failed(uint8_t* file, uint32_t line)
{
while (1){}
}
#endif

 Пример №2-Мигание светодиодом с использование прерывания.
 Тут мы тоже мигаем светодиодом только замедляем с помощью подсчёта отработок счётчика таймера в прерывании.

#include "stm8s.h"
uint8_t rep=0;//Счётчик отработанных прерываний.
int main( void )
{
//Включаем прерывания.
enableInterrupts();
GPIO_Init( GPIOB, GPIO_PIN_0, GPIO_MODE_OUT_PP_LOW_SLOW);
TIM6_TimeBaseInit( TIM6_PRESCALER_128, 255);
TIM6_ClearFlag( TIM6_FLAG_UPDATE);
//Включаем прерывание от переполнения счётчика.
TIM6_ITConfig( TIM6_IT_UPDATE, ENABLE);
TIM6_Cmd( ENABLE);

while(1){}
return 0;
}

//Обработчик прерываний.
INTERRUPT_HANDLER(TIM6_UPD_OVF_TRG_IRQHandler, 23)
{
if( rep<10){ rep++;}else{ rep=0; GPIO_WriteReverse( GPIOB, GPIO_PIN_0);}
TIM6_ClearFlag( TIM6_FLAG_UPDATE);
}

#ifdef USE_FULL_ASSERT
void assert_failed(uint8_t* file, uint32_t line)
{
while (1){}
}
#endif

 Пример №3-Однократный режим.
 После запуска таймера и переполнения счётчика светодиод зажжётся для эффекта мигания нужно постоянно запускать таймер заново командой TIM6_Cmd( ENABLE).

#include "stm8s.h"
int main( void )
{
enableInterrupts();
GPIO_Init( GPIOB, GPIO_PIN_0, GPIO_MODE_OUT_PP_LOW_SLOW);
TIM6_TimeBaseInit( TIM6_PRESCALER_128, 255);
//Включаем однократный режим.
TIM6_SelectOnePulseMode( TIM6_OPMODE_SINGLE);
TIM6_ClearFlag( TIM6_FLAG_UPDATE);
TIM6_ITConfig( TIM6_IT_UPDATE, ENABLE);
TIM6_Cmd( ENABLE);
while(1){}
return 0;
}

INTERRUPT_HANDLER(TIM6_UPD_OVF_TRG_IRQHandler, 23)
{
GPIO_WriteReverse( GPIOB, GPIO_PIN_0);
TIM6_ClearFlag( TIM6_FLAG_UPDATE);
}

#ifdef USE_FULL_ASSERT
void assert_failed(uint8_t* file, uint32_t line)
{
while (1){}
}
#endif

 Пример №4-Использование теневого регистра. В теле программы включаем теневой регистр а в прерывании будем записывать в него новое значение для отработки, светодиод будет мигать с переменной скоростью.

#include "stm8s.h"
uint8_t inc=1;
int main( void )
{
enableInterrupts();
GPIO_Init( GPIOB, GPIO_PIN_0, GPIO_MODE_OUT_PP_LOW_SLOW);
TIM6_TimeBaseInit( TIM6_PRESCALER_128, inc);
//Включаем теневой регистр.
TIM6_ARRPreloadConfig( ENABLE);
TIM6_ClearFlag( TIM6_FLAG_UPDATE);
TIM6_ITConfig( TIM6_IT_UPDATE, ENABLE);
TIM6_Cmd( ENABLE);

while(1){}
return 0;
}
//Обработчик прерываний.
INTERRUPT_HANDLER(TIM6_UPD_OVF_TRG_IRQHandler, 23)
{
TIM6_ClearFlag( TIM6_FLAG_UPDATE);
GPIO_WriteReverse( GPIOB, GPIO_PIN_0);
if( inc==255){ inc=1;}else{inc++;}
//Записываем в теневой регистр новое значение.
TIM6_SetAutoreload(inc);
}

#ifdef USE_FULL_ASSERT
void assert_failed(uint8_t* file, uint32_t line)
{
while (1){}
}
#endif

 Пример №5-Синхронизация таймеров, включение TIM1 в режиме Trigger gated mode.
 Из за специфики контроллеров STM8S903 TIM6 можно использовать как MASTER то есть будет управлять TIM1 или TIM5. В примере запускаем TIM6 и он одновременно запускает TIM1, в теле программе через задержку включаем и отключаем TIM6, светодиодом управляет TIM1.

#include "stm8s.h"
int main( void )
{
enableInterrupts();
GPIO_Init( GPIOB, GPIO_PIN_0, GPIO_MODE_OUT_PP_LOW_SLOW);
//Настраиваем TIM1 как подчинённый, для включения.
TIM1_TimeBaseInit( 0, TIM1_COUNTERMODE_UP, 65535, 0);
TIM1_SelectInputTrigger( TIM1_TS_TIM6);
TIM1_SelectSlaveMode( TIM1_SLAVEMODE_GATED);
TIM1_SelectMasterSlaveMode( ENABLE);
TIM1_ClearFlag( TIM1_FLAG_UPDATE);
TIM1_ITConfig( TIM1_IT_UPDATE, ENABLE);
TIM1_Cmd( ENABLE);
//Настраиваем TIM6 как мастер, с выходом сигнала от включения.
TIM6_TimeBaseInit( TIM6_PRESCALER_128, 255);
TIM6_SelectOutputTrigger( TIM6_TRGOSOURCE_ENABLE);
TIM6_Cmd( ENABLE);

while(1)
{
for( uint32_t i=0; i<100000; i++);
TIM6_Cmd( ENABLE);
for( uint32_t i=0; i<100000; i++);
TIM6_Cmd( DISABLE);
}
return 0;
}
INTERRUPT_HANDLER(TIM1_UPD_OVF_TRG_BRK_IRQHandler, 11)
{
GPIO_WriteReverse( GPIOB, GPIO_PIN_0);
TIM1_ClearFlag( TIM1_FLAG_UPDATE);
}

#ifdef USE_FULL_ASSERT
void assert_failed(uint8_t* file, uint32_t line)
{
while (1){}
}
#endif

 Пример №6-Синхронизация таймеров, включение TIM1 в режиме Trigger standard mode.
 Похожий пример только TIM1 включается через задержку и запуска TIM6, отключается только программно.

#include "stm8s.h"
int main( void )
{
enableInterrupts();
GPIO_Init( GPIOB, GPIO_PIN_0, GPIO_MODE_OUT_PP_LOW_SLOW);

TIM1_TimeBaseInit( 0, TIM1_COUNTERMODE_UP, 65535, 0);
TIM1_SelectInputTrigger( TIM1_TS_TIM6);
TIM1_SelectSlaveMode( TIM1_SLAVEMODE_TRIGGER);
TIM1_SelectMasterSlaveMode( ENABLE);
TIM1_ClearFlag( TIM1_FLAG_UPDATE);
TIM1_ITConfig( TIM1_IT_UPDATE, ENABLE);

TIM6_TimeBaseInit( TIM6_PRESCALER_128, 255);
TIM6_SelectOutputTrigger( TIM6_TRGOSOURCE_ENABLE);

while(1)
{
for(uint32_t i=0; i<300000; i++);
TIM6_Cmd( ENABLE);
}
return 0;
}
INTERRUPT_HANDLER(TIM1_UPD_OVF_TRG_BRK_IRQHandler, 11)
{
GPIO_WriteReverse( GPIOB, GPIO_PIN_0);
TIM1_ClearFlag( TIM1_FLAG_UPDATE);
}

#ifdef USE_FULL_ASSERT
void assert_failed(uint8_t* file, uint32_t line)
{
while (1){}
}
#endif

 Пример №7-Синхронизация таймеров, использование TIM6 как предделитель для TIM1. TIM6 генерирует сигнал после переполнения своего счётчика, который передаётся TIM1 как тактовый, таким образом с помощью двух таймеров можно отсчитывать большие промежутки времени. В примере светодиод мигает с частотой 32*31250/2000000*2=1Hz.

#include "stm8s.h"
int main( void )
{
enableInterrupts();
GPIO_Init( GPIOB, GPIO_PIN_0, GPIO_MODE_OUT_PP_LOW_SLOW);
//Настраиваем TIM1 для тактирования от внешнего сигнала.
TIM1_TimeBaseInit( 0, TIM1_COUNTERMODE_UP, 31249, 0);
TIM1_SelectInputTrigger( TIM1_TS_TIM6);
TIM1_SelectSlaveMode( TIM1_SLAVEMODE_EXTERNAL1);
TIM1_SelectMasterSlaveMode( ENABLE);
TIM1_ClearFlag( TIM1_FLAG_UPDATE);
TIM1_ITConfig( TIM1_IT_UPDATE, ENABLE);
TIM1_Cmd( ENABLE);
//TIM6 выход настроен для генерации сигнала по переполнению счётчика.
TIM6_TimeBaseInit( TIM6_PRESCALER_1, 31);
TIM6_SelectOutputTrigger( TIM6_TRGOSOURCE_UPDATE);
TIM6_Cmd( ENABLE);

while( 1){ }
return 0;
}
INTERRUPT_HANDLER(TIM1_UPD_OVF_TRG_BRK_IRQHandler, 11)
{
GPIO_WriteReverse( GPIOB, GPIO_PIN_0);
TIM1_ClearFlag( TIM1_FLAG_UPDATE);
}

#ifdef USE_FULL_ASSERT
void assert_failed(uint8_t* file, uint32_t line)
{
while (1){}
}
#endif
Статья №49 Дата:27/02/2020

Комментарии.