Вступление.

В двух предыдущих статьях мы генерировали при помощи ШИМ тактовый сигнал нужной нам частоты, получая на светодиоде равный промежутки свечения и его отсутствия. Данная задача имеет место быть на практике (в одной из последующих статей мы с ней точно столкнемся). Но чаще всего ШИМ используют по другому назначению. Одно из самых распространенных — управление яркостью светодиодов или скоростью вращения моторов. Так же при помощи ШИМ можно генерировать звук (о чем будет следующая статья). А в данной статье мне хотелось бы рассказать, как на нашем контроллере можно реализовать управление яркостью светодиода.

Начнем: изменение настроек основного таймера.

За основу мы возьмем проект из этой статьи. На основе функции initTimerPWMled создадим функцию initTimerPWMconstPeriod. Параметром функции будет уже не PWM_speed (частота ШИМ-а), а timeEnabledState — время действия импульса. О теории генерации напряжения на выводе методом ШИМ прекрасно рассказывает эта коротенькая статья. Для начала определимся с параметрами:
  • Пусть длительность целого периода функции будет 0xFFFF тиков таймера (можно выбрать любое значение, я выбрал это значение для удобства и чтобы не менять код для следующей статьи о генерации звука ШИМ-ом)
  • Тогда параметр функции timeEnabledState будет показывать сколько тактов из 0xFFFF на выводе присутствует «1». Все остальное время на канале «0». Например, при timeEnabledState = 0x4000, сигнал будет иметь следующий вид.

    При 0x8000 будут почти равны.

    Ну а при 0xF000 сигнал «1» будет почти всегда.
Чем меньше по времени период, тем лучше. Мы выбрали период длинной в 0xFFFF тактов. Для достижения хороших результатов, нам нужно, чтобы частота прохождения этих периодов была максимальна. Для этого выключим делитель тактового сигнала в функции initTimerPWMconstPeriod.
MDR_TIMER1->PSG = 0; // Делитель тактовой частоты отсутствует.
Далее нужно изменить способ формирования сигнала. Как мы помним из предыдущей статьи, за это отвечает группа бит OCCM регистра CH1_CNTRL. Тогда мы выбирали режим инвертирования сигнала REF при CNT == CCR1. Так как CCR было = 0 по умолчанию, то регулируя ARR основного счетчика — мы получали тот же эффект. Сейчас же мы в ARR записываем количество тактов всего периода (0xFFFF), а в CRR будем писать количество тактов единицы на выводе (время действия импульса). А режим выберем 6 (0b110:1, если DIR= 0 (счет вверх), CNT<CCR, иначе 0;).
MDR_TIMER1->ARR = 0xFFFF; // Период постоянный. И дает возможнсоть выбирать период заполнения от 0 до 0xFFFF.
MDR_TIMER1->CCR1 = timeEnabledState; // Канал будет держать 1 до этого значения и 0 - после.
MDR_TIMER1->CH1_CNTRL = 6<<TIMER_CH_CNTRL_OCCM_Pos; // REF = 1, когда CNT < CCR1, 0 - CNT >= CCR1;
По сути, на этом этапе мы уже получили функцию, задающую скважность ШИМ сигнала. Но нужно позаботиться о том, чтобы при смене значения CCR1 счетчик не вышел за пределы. Для этого нужно установить бит CRRRLD в регистре CH1_CNTRL2. Он разрешает смену значения CCR1 и CCR2 лишь при CNT == 0.
MDR_TIMER1->CH1_CNTRL2 = TIMER_CH_CNTRL2_CCRRLD; // CCR1 обновляется лишь при CNT = 0. Чтобы не было глюков.

Закончим: изменение параметров прерывания.

С настройкой ШИМ-а разобрались. Осталось только немного изменить прерывание по опросу клавиш. Зададим новую переменную, характеризующую длительность импульса в периоде. Назовем ее PWM_time. По умолчанию пусть будет 0xFFFF (ШИМ-а при таком значении нет, светодиод горит). А далее посмотрим, с каким интервалом делать шаг при нажатии на клавишу. Для этого разложим число тактов периода на простые множители.
// 65535 = 3·5·17·257. 257 раз пусть будет для нас диапазоном от 0 - не горит до 257 - горит на полную. => шаг 3*5*17 = 255.
Из расчета видим, что шагая с интервалом 255 мы можем пройти всю шкалу от 0 до 257. Так и поступим. Получим следующий код.
// 65535 = 3·5·17·257. 257 раз пусть будет для нас диапазоном от 0 - не горит до 257 - горит на полную. => шаг 3*5*17 = 255.
	if (UP_FLAG == 0) PWM_time+=255; // Проверияем, нажата ли какая-нибудь клавиша. Если нажата - что-то делаем с частотой.
	else if (DOWN_FLAG == 0) PWM_time-=255;			
		else if (LEFT_FLAG == 0) PWM_time-=255;
			else if (RIGHT_FLAG == 0) PWM_time+=255;
	if (PWM_time < 0) PWM_time = 0; // Проверяем, чтобы время "единицы" было не меньше нуля и не больше периода.
		else if (PWM_time > 0xFFFF) PWM_time = 0xFFFF;
Осталось только присвоить новое значение.
MDR_TIMER1->CCR1 = PWM_time; // Меняем частоту.
Еще раз замечу, что период мы не трогаем. Он постоянен. Меняем только длительность импульса. Целиком прерывание будет иметь следующий вид.
int PWM_time = 0xFFFF;											// По началу горит полностью.
void Timer2_IRQHandler (void)
{
	MDR_TIMER2->STATUS  = 0; // Сбрасываем флаг. Обязательно первой коммандой.	
	//LED1_FLAG = !LED1_FLAG; // Показываем, что прерывание было обработано.
	// 65535 = 3·5·17·257. 257 раз пусть будет для нас диапазоном от 0 - не горит до 257 - горит на полную. => шаг 3*5*17 = 255.
	if (UP_FLAG == 0) PWM_time+=255; // Проверияем, нажата ли какая-нибудь клавиша. Если нажата - что-то делаем с частотой.
	else if (DOWN_FLAG == 0) PWM_time-=255;			
		else if (LEFT_FLAG == 0) PWM_time-=255;
			else if (RIGHT_FLAG == 0) PWM_time+=255;
	if (PWM_time < 0) PWM_time = 0; // Проверяем, чтобы время "единицы" было не меньше нуля и не больше периода.
		else if (PWM_time > 0xFFFF) PWM_time = 0xFFFF;
	MDR_TIMER1->CCR1 = PWM_time; // Меняем частоту. 
}
Я намеренно скрыл строку инверсии светодиода, показывающую, что прерывание происходит. Ибо тока на 2 светодиода не хватает и появляются нежелательные пульсации.

Заключение

В данной статье мы рассмотрели, как можно настроить ШИМ и управлять им. В следующей статье мы попробуем сгенерировать при помощи ШИМ звук.
Файлы проекта к статье.
Список предыдущих статей.
  1. Переходим с STM32F103 на К1986ВЕ92QI. Или первое знакомство с российским микроконтроллером.
  2. Переходим с STM32 на российский микроконтроллер К1986ВЕ92QI. Настройка проекта в keil и мигание светодиодом.
  3. Переходим с STM32 на российский микроконтроллер К1986ВЕ92QI. Системный таймер (SysTick).
  4. Переходим с STM32 на российский микроконтроллер К1986ВЕ92QI. Настройка тактовой частоты.
  5. Переходим с STM32 на российский микроконтроллер К1986ВЕ92QI. Практическое применение: Генерируем и воспроизводим звук. Часть первая: генерируем прямоугольный и синусоидальный сигнал. Освоение ЦАП (DAC).
  6. Переходим с STM32 на российский микроконтроллер К1986ВЕ92QI. Практическое применение: Генерируем и воспроизводим звук. Часть вторая: генерируем синусоидальный сигнал. Освоение DMA.
  7. Переходим с STM32 на российский микроконтроллер К1986ВЕ92QI. Практическое применение: Генерируем и воспроизводим звук. Часть третья: генерируем синусоидальный сигнал. Простой взгляд на DMA + первое знакомство с таймерами.
  8. Переходим с STM32 на российский микроконтроллер К1986ВЕ92QI. Практическое применение: Генерируем и воспроизводим звук. Часть четвертая: создаем цифровую часть одноголосной и многоголосой музыкальной открытки.
  9. Переходим с STM32 на российский микроконтроллер К1986ВЕ92QI. Практическое применение: Опрашиваем клавиши, генерируем ШИМ. Сравнение кода на CMSIS и SPL (PWM+TIM+PORT). Часть первая.
  10. Переходим с STM32 на российский микроконтроллер К1986ВЕ92QI. Практическое применение: Опрашиваем клавиши, генерируем ШИМ. Сравнение кода на CMSIS и SPL (PWM+TIM+PORT). Часть вторая.

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