Как и в МК других производителей в STM32 ШИМ генерируется таймерами, которых в STM32F030F4P6 содержится 5 штук не считая системного таймера, часов и сторожевых таймеров. TIM1 и TIM3 относятся к таймерам общего назначения и они многофункциональные - содержат по 4 канала захвата/сравнения и имеют множество других функций. Таймеры TIM14, TIM16 и TIM17 базовые и они попроще и имеют только 1 канал захвата/сравнения. Более подробно о таймерах и их возможностях можно узнать например из статей о таймерах общего назначения и базовых.
Базовые таймеры.
16-битный счётчик с автоперезагрузкой.
16-битный программируемый делитель частоты: с 1 по 65535.
Схема синхронизации для запуска АЦП/ЦАП.
Захват сигнала (input capture).
Сравнение вывода (output compare).
Генерация сигнала ШИМ (выровненного по границе или по центру).
Генерация одиночных импульсов.
Генерация прерывания и/или запроса DMA по переполнению счётчика.Таймеры общего назначения.
16-битный счётчик с автоперезагрузкой.
16-битный программируемый делитель частоты: с 1 по 65535.
Схема синхронизации для запуска АЦП/ЦАП.
Захват сигнала (input capture).
Сравнение вывода (output compare).
Генерация сигнала ШИМ (выровненного по границе или по центру).
Генерация одиночных импульсов.
Генерация прерывания и/или запроса DMA по переполнению счётчика.
Схемы синхронизации для управления таймерами при помощи внешних сигналов и для соединения нескольких таймеров друг с другом.
Комплементарные выходы с программируемым dead-time.
Счётчик повторений.
Вход BRK для сброса выходов таймера или выставления их в известное состояние.
Поддерживают инкрементальные (квадратурные) энкодеры и датчики Холла.
Генерация прерывания или запроса DMA по следующим событиям:
* Обновление: переполнение счётчика.
* Событие-триггер: старт, остановка, инициализация счётчика или его обновление внутренним или внешним триггером.
* Захват сигнала.
* Сравнение (output compare).
* Включение BRK.
Вернемся к рассматриваемой теме - генерации ШИМ.
Схема тестового устройства.
С выводом PB1 к которому подключен светодиод, соединены каналы TIM1, TIM3 и TIM14.
Для генерации ШИМ будем использовать таймер TIM14 как наиболее простой из перечисленных.
Тестовый код.
#include "stm32f0xx_conf.h" void GPIO_Conf(void) // Конфигурация портов ввода / вывода. { GPIO_InitTypeDef s; RCC_AHBPeriphClockCmd(RCC_AHBPeriph_GPIOB, ENABLE); // Включаем тактирование порта PB. s.GPIO_Pin = GPIO_Pin_1; // Настройка вывода PB1. s.GPIO_Mode = GPIO_Mode_AF; // Вывод настроен на одну из альтернативных функций. s.GPIO_OType = GPIO_OType_PP; // Двухтактный выход (т. е. не открытый сток). s.GPIO_PuPd = GPIO_PuPd_NOPULL; // Подтягивающие резисторы отключены. s.GPIO_Speed = GPIO_Speed_50MHz; GPIO_Init(GPIOB, &s); // Инициализация порта. GPIO_PinAFConfig(GPIOB, GPIO_PinSource1, GPIO_AF_0); // PB1 это выход таймера TIM 14. } void Tim14_Conf(void) // Конфигурация таймера. { TIM_TimeBaseInitTypeDef Tim; TIM_OCInitTypeDef Pwm; RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM14, ENABLE); // Включаем тактирование таймера 14. Tim.TIM_ClockDivision = TIM_CKD_DIV1; // Выключаем предварительный делитель частоты таймера. Tim.TIM_CounterMode = TIM_CounterMode_Up; // Значение в счетном регистре увеличивается. Tim.TIM_Period = 65535; // Значение до которого досчитав таймер обнулится (максимум 65535). Tim.TIM_Prescaler = 0; // На сколько нужно делить частоту (максимум 65535). Tim.TIM_RepetitionCounter = 0; TIM_TimeBaseInit(TIM14, &Tim); // Инициализация таймера. // Настройка ШИМ. TIM_OCStructInit(&Pwm); // Загрузка в структуру настроек таймера по умолчанию. Pwm.TIM_OCMode = TIM_OCMode_PWM1; // Режим ШИМ 1. Pwm.TIM_OutputState = TIM_OutputState_Enable; Pwm.TIM_Pulse = 1000; //32768; TIM_OC1Init(TIM14, &Pwm); TIM_Cmd(TIM14, ENABLE); // Запуск таймера. } int main(void) { GPIO_Conf(); // Конфигурация портов ввода / вывода. Tim14_Conf(); // Конфигурация таймера. while(1) { } }
Программа довольно простая. В функции main() вызываются функции настройки порта и таймера, после чего МК зацикливается до тех пор пока питание не выключат.
В функции GPIO_Conf() производится настройка вывода PB1 к которому подключен светодиод. Сперва включается тактирование порта GPIOB, которое по умолчанию выключено. Затем вывод порта настраивается на использование альтернативной функции. Какой именно зависит от этой строки.
GPIO_PinAFConfig(GPIOB, GPIO_PinSource1, GPIO_AF_0); // PB1 это выход таймера TIM 14.
Может показаться непонятно как здесь указывается что вывод PB1 должен быть соединен именно с выходом TIM14. Ответ на это можно найти в даташите на МК STM32F030F4P6 в котором есть таблица альтернативных функций для портов.
Для порта GPIOB.
Из таблицы следует что нулевая альтернативная функция PB1 это выход таймера TIM14. А если бы нам потребовалось генерировать ШИМ третьим каналом таймера TIM1 и выводить его на PB1, то нужно было бы настроить вывод порта на вторую альтернативную функцию.
Функция Tim14_Conf() настраивает таймер TIM14. В ней в первую очередь включается тактирование таймера, а затем настраиваются основные параметры таймера, такие как предварительное деление частоты, значение после которого таймер обнулится и т. д.
Затем производится настройка первого канала таймера, так чтобы он генерировал ШИМ. Чтобы не заполнять все поля структуры, вызывается функция TIM_OCStructInit(), которая записывает в структуру настройки по умолчанию. После чего нужно изменить лишь те поля которые отличаются от тех что по умолчанию. Необходимо выбрать решим ШИМ, разрешить работу выхода канала и задать длительность импульса. Последнее необязательно, ведь длительность можно изменить позже.
После всех настроек разрешается работа таймера функцией TIM_Cmd().
Если прошить эту программу в МК, то при подаче питания светодиод будет слабо светится. Почему слабо? Потому что длительность импульса равна примерно 1/65 длительности периода ШИМ (в поле TIM_Period значение 65535, а в поле TIM_Pulse значение 1000). Т. к. частота поступающая на счетчик таймера равна 48 МГц и предделители отключены, а таймер обнуляется каждые 65536 импульсов, то частота ШИМ составит 48000000 / 65536 = 732.42 Гц.
Проверим это логическим анализатором.
Длительность импульса 20 мкс, период ШИМ 1.36 мс и частота 732.22 Гц. Результат близок к расчетному. Небольшое отличие видимо из-за того что частота кварцевого резонатора не ровно 8 МГц, а немного меньше.
Но не всегда нужен 16-ти битный ШИМ. Обычно нужна частота побольше. Уменьшим значение поля TIM_Period, скажем до 4000.
Длительность импульса осталась прежней, а период и частота изменились. Светодиод начал светить намного ярче.
Теперь добавим в цикл код, изменяющий длительность импульса во время работы программы. Функция main() будет выглядеть таким образом.
int main(void) { uint16_t x=0; volatile uint16_t i; GPIO_Conf(); // Конфигурация портов ввода / вывода. Tim14_Conf(); // Конфигурация таймера. while(1) { TIM_SetCompare1(TIM14, x); // Изменяем длительность импульса. x=x+100; for (i=0; i<30000; i++); // Небольшая задержка. } }
Запустив этот код, можно увидеть как светодиод плавно увеличивает яркость до максимума, а потом гаснет и все начинается сначала.