>
Число комментариев: 1
Просмотров: 177

Уроки программирования STM8. Урок 9. STVD + CXSTM8. Основы работы с таймером TIM4

В данном уроке вы освоите основы работы с таймером TIM4 и пройдете небольшую практику. Суть практической работы заключается в том, чтобы как и в самом начале поморгать светодиодом. Резонно назвать этот практикум "Hello, LED-2". В отличие от первого примитивного примера, где задержка (пауза) осуществлялась зависанием микроконтроллера на количество заданных итераций, здесь микроконтроллер зависать не будет. Он будет "слушать" события. Таймер будет создавать эти события в строго определенный промежуток времени. И по возникновении событий можно будет менять состояние линии порта, на которой висит светодиод. По-прежнему я использую отладочную плату "синяя пуля оптовых оценка STM8 доска" и данный пример будет работать вообще на любом STM8 линеек Value и Acces line.


Начиная с этого занятия разбор кода будет вестись прямо в комментариях к коду. А в конце урока будет даваться теоретическая основа. Таким образом, несложные занятия могут вполне умещаться в рамках одной статьи.

Открывайте все тот же проект из предыдущего занятия и меняйте в нем содержимое файла main.h

@far @interrupt void TIM4_int_handler (void); // Прототип обработчика прерывания TIM4

Меняйте содержимое файла stm8_interrupt_vector.c

 

#include "main.h"
typedef void @far (*interrupt_handler_t)(void);

struct interrupt_vector {
  unsigned char interrupt_instruction;
  interrupt_handler_t interrupt_handler;
};

@far @interrupt void NonHandledInterrupt (void)
{
  // Возникло неожиданное прерывание. Используйте breakpoint
  return;
}

extern void _stext(); /* startup routine */

struct interrupt_vector const _vectab[] = {
  {0x82, (interrupt_handler_t)_stext}, /* reset */
  {0x82, NonHandledInterrupt}, /* trap */
  {0x82, NonHandledInterrupt}, /* irq0 */
  {0x82, NonHandledInterrupt}, /* irq1 */
  {0x82, NonHandledInterrupt}, /* irq2 */
  {0x82, NonHandledInterrupt}, /* irq3 */
  {0x82, NonHandledInterrupt}, /* irq4 */
  {0x82, NonHandledInterrupt}, /* irq5 */
  {0x82, NonHandledInterrupt}, /* irq6 */
  {0x82, NonHandledInterrupt}, /* irq7 */
  {0x82, NonHandledInterrupt}, /* irq8 */
  {0x82, NonHandledInterrupt}, /* irq9 */
  {0x82, NonHandledInterrupt}, /* irq10 */
  {0x82, NonHandledInterrupt}, /* irq11 */
  {0x82, NonHandledInterrupt}, /* irq12 */
  {0x82, NonHandledInterrupt}, /* irq13 */
  {0x82, NonHandledInterrupt}, /* irq14 */
  {0x82, NonHandledInterrupt}, /* irq15 */
  {0x82, NonHandledInterrupt}, /* irq16 */
  {0x82, NonHandledInterrupt}, /* irq17 */
  {0x82, NonHandledInterrupt}, /* irq18 */
  {0x82, NonHandledInterrupt}, /* irq19 */
  {0x82, NonHandledInterrupt}, /* irq20 */
  {0x82, NonHandledInterrupt}, /* irq21 */
  {0x82, NonHandledInterrupt}, /* irq22 */
  {0x82, TIM4_int_handler}, /* irq23 прерывание таймера TIM4 */
  {0x82, NonHandledInterrupt}, /* irq24 */
  {0x82, NonHandledInterrupt}, /* irq25 */
  {0x82, NonHandledInterrupt}, /* irq26 */
  {0x82, NonHandledInterrupt}, /* irq27 */
  {0x82, NonHandledInterrupt}, /* irq28 */
  {0x82, NonHandledInterrupt}, /* irq29 */
};

Меняйте содержимое файла main.c

 

#include <iostm8s103.h> 
int cntTicks = 0; // накопитель событий обновления таймера (тиков) 
@far @interrupt void TIM4_int_handler (void) { // Код обработчика прерывания от таймера TIM4 
  if (cntTicks++ > 60) { // Если кол-во тиков достигло значения 61, то 
    PB_ODR ^= 1<<5; // инвертировать бит 5 порта B 
    cntTicks = 0; // обнулить счетчик тиков 
  } 
  TIM4_SR = 0; // скинуть UIF (update interrupt flag) 
  // если этот флаг не сбросить, то прерывание превратится в бесконечный цикл. 
  return; 
} 
int main(void) { 
  PB_DDR = 0b00100000; // PB5 - Дискретный выход 
  TIM4_PSCR =0b00000111; // TIM4 тактовый предделитель на 128 
  // По-умолчанию, частота тактирования ядра Fmaster = 2 MHz 
  // Частота тактирования таймера будет 2000000/128=15625 Гц 
  TIM4_IER = 1; // Разрешить прерывания от TIM4 
  TIM4_CR1 = 1; // Включить TIM4 
  TIM4_ARR = 255; // Это значение регистра AutoReload 
  // оно такое и по умолчанию, но здесь вы можете его менять 
  // при частоте тактирования 15625 Гц, таймер будет достигать значения 255 
  // каждые 16,32 мсек и вызывать прерывание. 
  // За 1 секунду произойдет 61 прерывание. 
  _asm("rim"); // Разрешить прерывания вообще (по умолчанию запрещены) 
  while(1); // Бесконечный цикл (режим "слушателя") 
}

В микроконтроллерах семейства STM8 содержится несколько системных таймеров и самым простым из них является 8-битный инкрементный TIM4, который может считать от 0 до 255 и вызывать прерывание при обновлении. Таймер этот обновляется в трех случаях:
1) Переполнение, когда счетчик достиг своего предельного значения 255 и при следующем такте обнуляется.
2) Достижение значения регистра TIM4_ARR (по умолчанию таймер обновляется именно так).
3) При программной установке бита UG в регистре TIM4_EGR.

Когда таймер обновляется, то аппаратно выставляется флаг UIF в регистре TIM4_SR (в регистре всего один бит).

Принудительно вызвать обновление можно установкой бита UG в регистре TIM4_EGR, сбросится он аппаратно (в регистре всего один бит).

Прерывание при обновлении разрешается битом UIE в регистре TIM4_IER (в регистре всего один бит).

Регистр предделителя тактовой частоты таймера TIM4_PSCR (в регистре всего три бита)
000 - /1
001 - /2
010 - /4
011 - /8
100 - /16
101 - /32
110 - /64
111 - /128

Значение счетчика таймера, непосредственно, можно прочесть и установить в регистре TIM4_CNTR

Регистр TIM4_CR1 основной конфигурационный

ARPE - разрешить буферизацию регистра TIM4_ARR

OPM - включить режим одиночного импульса. При включенном режиме, таймер отключится (сбросом бита CEN) после первого же обновления.

URS - какое событие вызовет прерывание 1 - только переполнение, 0 - не только переполнение но и достижение значения регистра TIM4_ARR, и программная установка бита UG в регистре TIM4_EGR.

UDIS - обновления 0 - разрешены, 1 - запрещены.

CEN - бит включения таймера.

Этой информации вполне достаточно, чтобы начать использовать таймер TIM4 в своих проектах.