Рейтинг@Mail.ru
STM32. Уроки по программированию STM32F4. Урок № 6. Работа с таймерами TIM7 и TIM1.
Войти
или
Зарегистрироваться
Главная Файлы Видеоматериалы Форум
Карта сайта
Главная -> РУБРИКИ: -> Программирование STM32F4 -> STM32. Уроки по программированию STM32F4. Урок № 6. Работа с таймерами TIM7 и TIM1.

Статья опубликована: 2016-03-09/15:38:22-admin

STM32. Уроки по программированию STM32F4. Урок № 6. Работа с таймерами TIM7 и TIM1.



Начало здесь:


STM32. Уроки по программированию STM32F4. Урок № 0. Вводный. Описание. Установка IDE.


STM32. Уроки по программированию STM32F4. Урок № 1. Система тактирования STM32F4.


STM32. Уроки по программированию STM32F4. Урок № 2. Мигание светодиодом STM32F4.


STM32. Уроки по программированию STM32F4. Урок № 0. Update № 1.Портирование из STM32CubeMX в SW4STM32.


STM32. Уроки по программированию STM32F4. Урок № 3. Системный таймер SysTick STM32F4.


STM32. Уроки по программированию STM32F4. Урок № 4. Программный многозадачный таймер STM32F4.


STM32. Уроки по программированию STM32F4. Урок № 5. Работа с АЦП+DMA + фильтр скользящее среднее.




 

Вместо предисловия.

 

Таймер – одна из самых полезных вещей в микроконтроллере и основная его задача – отсчитывание точных интервалов времени. На отладочной плате STM32F4 Discovery установлен микроконтроллер STM32F407VG, который имеет следующие таймеры:

 

  • Basic timers (TIM6, TIM7) – самый простой таймер, который умеет только генерировать прерывания в заданный промежуток времени, но при этом очень легко настраивается и управляется.
  • General-purpose timers (TIM2-TIM5, TIM9-TIM14) – более продвинутый таймер, позволяющий генерировать ШИМ, считывать состояние ног, обрабатывать данные от энкодера и т.д.
  • Advanced-control timers (TIM1, TIM8) – самый продвинутый таймер, может использоваться как трехфазный ШИМ генератор.

Таблица сравнения таймеров МК STM32F407VGx.

 

Рассмотрим работу таймера на примере TIM7. Настроем его для отсчета временного интервала в 1 с. И по прерыванию от таймера будет инвертировать выход. Для визуализации – выход будет подключен к синему светодиоду, установленному на плате.

 

 Предисловие.

 

Код, который использовался в прошлых уроках, останется практически без изменений. Управление синим светодиодом организуем по прерыванию таймера TIM7. Начнем с изменений в КУБе. Откроем проект из прошлого урока. Внесем изменения, касающиеся таймера TIM7.

 

Включаем таймер TIM7.

 

Не забываем, что данный таймер тактируется от шины ABP1 Timer Clock. Так, что для настройки таймера, необходимо знать частоту тактирования данной шины. Посмотрим на вкладку Clock Configuration.

 

Тактирование шины ABP1.

 

Настройки из прошлых уроков говорят нам, что тактирование таймера TIM7 будет осуществляться с частотой в 84 МГц. Максимально возможное.

 

Далее произведем настройки таймера для генерации прерывания с частотой в 1 с.

 

Настройки прескалера и периода таймера TIM7.

 

Для получения времени между прерываниями в 1 секунду, необходимо установить прескалер в 8400, делитель учитывается как величина прескалера +1, следовательно, значение прескалера 8400-1=8399. С прескалером  получим тактовую частоту таймера в 84 МГц/8400 = 10000 Гц. При установке периода 10000, у нас прерывание будут возникать раз в 1 секунду. Включаем прерывания от таймера TIM7, установкой соответствующей галочки.

 

Здесь все просто и прозрачно. Настроек всего ничего.

 

Исходный код полученной инициализации, а также обработчик прерывания представлен ниже.

 

TIM_HandleTypeDef htim7;

/* TIM7 init function */
void MX_TIM7_Init(void)
{
  TIM_MasterConfigTypeDef sMasterConfig;

  htim7.Instance = TIM7;
  htim7.Init.Prescaler = 8399;
  htim7.Init.CounterMode = TIM_COUNTERMODE_UP;
  htim7.Init.Period = 10000;
  HAL_TIM_Base_Init(&htim7);

  sMasterConfig.MasterOutputTrigger = TIM_TRGO_RESET;
  sMasterConfig.MasterSlaveMode = TIM_MASTERSLAVEMODE_DISABLE;
  HAL_TIMEx_MasterConfigSynchronization(&htim7, &sMasterConfig);

} 
/**
* @brief This function handles TIM7 global interrupt.
*/
void TIM7_IRQHandler(void)
{
  /* USER CODE BEGIN TIM7_IRQn 0 */

  /* USER CODE END TIM7_IRQn 0 */
  HAL_TIM_IRQHandler(&htim7);
  /* USER CODE BEGIN TIM7_IRQn 1 */
  HAL_GPIO_TogglePin(GPIOD,GPIO_PIN_15);
  /* USER CODE END TIM7_IRQn 1 */
}

 

После этого достаточно, запустить таймер TIM7.

 

  /*
   * Для урока №6.
   * Запуск таймера TIM7
   * */
  HAL_TIM_Base_Start_IT(&htim7);

 

Это был пример самого простого таймера, который есть в составе МК. Он прост до безобразия. Считает до определенного значения, генерит прерывание и на этом его функционал заканчивается. Но в МК есть таймеры с более широкими возможностями.

 

Advanced Control таймер TIM1. 

 

Рассмотрим таймер с богатыми возможностями. TIM1 может не только считать и вызывать прерывание по переполнению, но и имеет множество аппаратных возможностей по генерации ШИМ сигнала, режима сравнения, режим захвата и т.д. В данной статье рассмотрим функцию ШИМ.

 

ШИМ- Широтно-импульсная модуляция (ШИМ, англ. pulse-width modulation (PWM)) — процесс управления мощностью, подводимой к нагрузке, путём изменения скважности импульсов, при постоянной частоте.

 

Применение данного режима просто масса. От управления мощности нагрузки, до формирования звуковых рядов. Использование в качестве ЦАПа и т.д.

 

Начнем с простого. Настроим таймер на генерацию ШИМ сигнала с постоянной частотой и скважностью.

 

Настройка таймера TIM1 в режиме ШИМ первого канала.

 

В КУБе настроим источник тактирования таймера, и установим режим ШИМ для первого канала.

 

Тактирование от внутренней шины APB2 с максимальной частотой для таймеров в 168 МГц.

 

В настройках, укажем предделитель и период таймера. Для канала ШИМ укажем скважность, период заполнения.

 

Генерация ШИМ с частотой 20 кГц. Следовательно 168 Мгц/8 = 21 МГц. 8 – предделитель таймера TIM1. 21 МГц/20 кГц = 1050. Это период таймера. Следовательно, если мы будем задавать  период ШИМ от 0 до 1050, то этим и будет регулироваться скважность ШИМ. Получаем полноценный 10-ти битный ШИМ. Для многих нужд, этой точности более чем достаточно.

 

Настройки таймера TIM1.

 

В данном случае скважность ШИМ будет 2. То есть половина периода ШИМ у нас будет высокий уровень на выходе, а половина – низкий.

 

Сгенерим проект. Посмотрим на код.

 

/* TIM1 init function */
void MX_TIM1_Init(void)
{
  TIM_ClockConfigTypeDef sClockSourceConfig;
  TIM_MasterConfigTypeDef sMasterConfig;
  TIM_BreakDeadTimeConfigTypeDef sBreakDeadTimeConfig;
  TIM_OC_InitTypeDef sConfigOC;

  htim1.Instance = TIM1;
  htim1.Init.Prescaler = 7;
  htim1.Init.CounterMode = TIM_COUNTERMODE_UP;
  htim1.Init.Period = 1050;
  htim1.Init.ClockDivision = TIM_CLOCKDIVISION_DIV1;
  htim1.Init.RepetitionCounter = 0;
  HAL_TIM_Base_Init(&htim1);

  sClockSourceConfig.ClockSource = TIM_CLOCKSOURCE_INTERNAL;
  HAL_TIM_ConfigClockSource(&htim1, &sClockSourceConfig);

  HAL_TIM_PWM_Init(&htim1);

  sMasterConfig.MasterOutputTrigger = TIM_TRGO_RESET;
  sMasterConfig.MasterSlaveMode = TIM_MASTERSLAVEMODE_DISABLE;
  HAL_TIMEx_MasterConfigSynchronization(&htim1, &sMasterConfig);

  sBreakDeadTimeConfig.OffStateRunMode = TIM_OSSR_DISABLE;
  sBreakDeadTimeConfig.OffStateIDLEMode = TIM_OSSI_DISABLE;
  sBreakDeadTimeConfig.LockLevel = TIM_LOCKLEVEL_OFF;
  sBreakDeadTimeConfig.DeadTime = 0;
  sBreakDeadTimeConfig.BreakState = TIM_BREAK_DISABLE;
  sBreakDeadTimeConfig.BreakPolarity = TIM_BREAKPOLARITY_HIGH;
  sBreakDeadTimeConfig.AutomaticOutput = TIM_AUTOMATICOUTPUT_DISABLE;
  HAL_TIMEx_ConfigBreakDeadTime(&htim1, &sBreakDeadTimeConfig);

  sConfigOC.OCMode = TIM_OCMODE_PWM1;
  sConfigOC.Pulse = 525;
  sConfigOC.OCPolarity = TIM_OCPOLARITY_HIGH;
  sConfigOC.OCNPolarity = TIM_OCNPOLARITY_HIGH;
  sConfigOC.OCFastMode = TIM_OCFAST_DISABLE;
  sConfigOC.OCIdleState = TIM_OCIDLESTATE_RESET;
  sConfigOC.OCNIdleState = TIM_OCNIDLESTATE_RESET;
  HAL_TIM_PWM_ConfigChannel(&htim1, &sConfigOC, TIM_CHANNEL_1);

}

 

Для запуска ШИМ необходимо вызвать следующую функцию.

 

HAL_TIM_PWM_Start(&htim1,TIM_CHANNEL_1);

 

 

Результатом является генерация ШИМ на выходе со скважностью 2.

 

Сигнал ШИМ. Картинка кликабельна.

 

 

Менять скважность во время работы ШИМ, можно непосредственно записав значение в регистр таймера. Библиотечную функцию в HAL для этого я не нашел.

 

Для задержки в 10 мс, между записи нового значения в регистр инициализируем программный таймер.

 

  OnSwTimer(&TIM[5],SWTIMER_MODE_CYCLE,10);
    TIM[5].Off=0;
    TIM[5].On=1;

 

Код получился такой.

 

//--------------------------------------------------------------
  	  /*
  	   * Урок №6.
  	   * */
	  if (GetStatusSwTimer(&TIM[5])){
		  htim1.Instance->CCR1=i;
		  if (i<1050) i++; else i=0;
	  	  }

 

То есть по срабатыванию программного таймера из урока № 4, производим приращение. Тем самым активное состояние на выходе ШИМа меняется от 0 до 1050.

 

ШИМ + ДМА.

 

В основном, ШИМ используется для генерации какого либо периодического сигнала: треугольник, синусоида и т.д. Для такой рутинной задаче лучше использовать аппаратные возможности МК. ДМА в данном случае. Заполняем массив необходимыми значениями, и с помощью ДМА кладем значения в CCCRx, для изменения скважности и получения сигнала необходимой формы.

 

На этом уроке сгенереруем треугольник с частотой 500 Гц. Частота ШИМ останется 20 кГц. Простой фильтр в виде RC цепочки на выходе обеспечит треугольную форму. Частоту среза фильтра выберем порядка 1 кГц. Расчет ФНЧ на данную частоту произведем из формулы: fср = 1/R*C. Отталкиваться будем от конденсатора. Возьмем С = 1*10-6 Ф, соответственно R  = 1/fср*С = 1/1*10+3*1*10-6 = 1/1*10-3 = 1*10+3 = 1 кОм. Итого R = 1 кОм, С = 1 мкФ.

 

Частота ШИМ 20 кГц. Частота необходимого сигнала  500 Гц. Следовательно, на каждый период треугольного сигнала приходится 20000/500=40 периодов ШИМ. За эти 40 периодов необходимо линейно увеличивать скважность от 0 до максимума и обратно. Следовательно, 20 периодов увеличиваем, 20 периодов уменьшаем.

 

Введем массив из 40 значений и заполним его значениями необходимыми для формирования треугольника.

 

uint16_t pData[40] = {0,52,105,157,210,262,315,367,420,472,525,577,630,682,735,787,
840,892,945,997,1050,997,945,892,840,787,735,682,630,577,525,472,420,367,315,262,
210,157,105,52};

 

Как видно, значения строго симметричны относительно максимума.

 

Для использования ДМА произведем настройки в КУБе.

 

Настройки ДМА.

 

Инициализация таймера TIM1 изменилась.

 

/* Peripheral DMA init*/
  
    hdma_tim1_ch1.Instance = DMA2_Stream1;
    hdma_tim1_ch1.Init.Channel = DMA_CHANNEL_6;
    hdma_tim1_ch1.Init.Direction = DMA_MEMORY_TO_PERIPH;
    hdma_tim1_ch1.Init.PeriphInc = DMA_PINC_DISABLE;
    hdma_tim1_ch1.Init.MemInc = DMA_MINC_ENABLE;
    hdma_tim1_ch1.Init.PeriphDataAlignment = DMA_PDATAALIGN_HALFWORD;
    hdma_tim1_ch1.Init.MemDataAlignment = DMA_MDATAALIGN_HALFWORD;
    hdma_tim1_ch1.Init.Mode = DMA_CIRCULAR;
    hdma_tim1_ch1.Init.Priority = DMA_PRIORITY_LOW;
    hdma_tim1_ch1.Init.FIFOMode = DMA_FIFOMODE_DISABLE;
    hdma_tim1_ch1.Init.FIFOThreshold = DMA_FIFO_THRESHOLD_FULL;
    hdma_tim1_ch1.Init.MemBurst = DMA_MBURST_SINGLE;
    hdma_tim1_ch1.Init.PeriphBurst = DMA_PBURST_SINGLE;
    HAL_DMA_Init(&hdma_tim1_ch1);

    __HAL_LINKDMA(htim_base,hdma[TIM_DMA_ID_CC1],hdma_tim1_ch1);

 

Теперь для запуска ШИМ режима с использованием ДМА для генерации треугольного сигнала необходимо выполнить следующую функцию.

 

HAL_TIM_PWM_Start_DMA(&htim1,TIM_CHANNEL_1, (uint32_t *)pData,40);

 

Код, использованный выше, закомментируем.

 

	  /*
	  if (GetStatusSwTimer(&TIM[5])){
		  htim1.Instance->CCR1=i;
		  if (i<1050) i++; else i=0;
	  	  }
	  	  */

 

Ведь всю работу на себя взял ДМА.

 

Программный таймер TIM[5] теперь тоже не нужен. Закомментируем и его.

 

/*
  OnSwTimer(&TIM[5],SWTIMER_MODE_CYCLE,10);
    TIM[5].Off=0;
    TIM[5].On=1;
    */

 

Архив урока №6, работа с таймерами TIM7 и TIM1 находится здесь.

 

Видео отчет данного урока представлен ниже.

 

 

Заключение.

 

В данном уроке, произведена работа по настройки базового таймера, для отсчета точного временного интервала. Также была рассмотрена работа расширенного таймера в режиме генерации ШИМ сигнала с использованием программного изменения скважности, а также с использованием ДМА для генерации сигнала треугольной формы.

 


Продолжение здесь:



Просмотров: 19952



Комментарии: (7)

Пользователь Anisimov в 2016-06-04 13:40:03 сказал:

Здравствуйте!
Не могли бы пояснить вот эту строчку:

__HAL_LINKDMA(htim_base, hdma[TIM_DMA_ID_CC1], hdma_tim1_ch1);

 

У Вас эту строчку куб сгенерил??? у  меня почему-то нет..
Что линкуется в этой строчке? Как мне понять что мне нужно передавать в этот макросс? (если я просто копирну ваш пример, то на этой строчке компилятор выдаёт мне ошибку).

Не могу разобраьтся...в описании HALа тоже нет ничего про использование этого макросса. Ну либо я не нашёл
 

Ответить

Пользователь admin в 2016-06-07 16:05:46 сказал:

Здравствуйте! Если Вы использовали проект из урока, то данной ошибки не должно быть. Если Вы генерировали проект изКуба, то проверьте тщательно настройки, данную инициализацию ДМА КУБ генерит сам. Простым копипастом не обойдешься. Там много какие дефайны задействованы.

Ответить

Пользователь admin в 2016-06-07 16:06:55 сказал:

А вообще данный линк можно проследить в среде разработки, посмотреть в библиотеки что за параметры туда передаются и что они означают.

Ответить

Пользователь access777 в 2016-12-15 02:15:32 сказал:

Спасибо за статью. Я лишь начинающий. Хотелось бы подробностей о работе в режиме захвата.

Ответить

Пользователь admin в 2017-02-27 13:43:43 сказал:

Здравствуйте! Про режим захвата обязательно будет статья. Вот о времени её выхода пока сказать не смогу.

Ответить

Пользователь Dimaster в 2017-06-29 11:32:16 сказал:

День добрый. Как в примере не заработало вообще ни в какую до тех пор, пока я в коллбеке не начал вызывать HAL_TIM_PWM_Start_DMA повторно. Ну типа отправил одни данные, они отправились, давай другие. Проблема вот в чём. У меня трехфазны ШИМ и мне надо пускать все три канала сразу. Если я вызываю все три функции HAL_TIM_PWM_Start_DMA для трех каналов, то в итоге работает только один, тот который был первым запущен. Как пускать все три правильно? Заранеее спасибо

Ответить

Пользователь admin в 2017-07-08 15:33:43 сказал:

Здравствуйте!

По команде HAL_TIM_PWM_Start_DMA ШИМ должен генерить сигнал без остановки. У Вас закралась ошибка в функции  инициализации ШИМ через ДМА, наверное не правильный указан параметр в структуре.

По поводу 3-х фазного ШИМ помочь не смогу, так как сам еще такое не реализовывал.

Ответить

Оставить комментарий

Да, Я Хочу Всегда Быть В Курсе Новых Событий На Сайте!

Подпишитесь прямо сейчас, и получайте обновления на свой E-Mail:

Ваш E-Mail в безопасности


Рекомендованные статьи:




Данная статья является продолжением цикла видео уроков по изучению МК STM32 на базе STM32F407. На данном уроке разберем модуль АЦП. Его работу и передачу данных с каналов АЦП через DMA в регистры ОЗУ. Дальнейшей фильтрацией по методу скользящего среднего.


РУБРИКИ:








Последняя статья:

Часть I. Статья №6. Верстка подвала – блока футтер

На прошлом уроке мы сверстали основной блок контент. Оформили  статьи, которые отображаются на главной странице. Оформили их стилями, не входящими в макет сайта, но вписывающимися в общий дизайн сайта. На сегодняшнем уроке мы оформим подвал сайта. В данный блок войдут ссылки на стандартные страницы любого сайта, а также копирайт.

Читать далее »


Справка Обратная связь Вопросы и ответы Контакты RSS-лента © 2013-2016, ДРУиД - Дом Рационально-Умный и Душевный
Рейтинг@Mail.ru Яндекс.Метрика