Вступление.
В двух предыдущих статьях мы генерировали при помощи ШИМ тактовый сигнал нужной нам частоты, получая на светодиоде равный промежутки свечения и его отсутствия. Данная задача имеет место быть на практике (в одной из последующих статей мы с ней точно столкнемся). Но чаще всего ШИМ используют по другому назначению. Одно из самых распространенных — управление яркостью светодиодов или скоростью вращения моторов. Так же при помощи ШИМ можно генерировать звук (о чем будет следующая статья). А в данной статье мне хотелось бы рассказать, как на нашем контроллере можно реализовать управление яркостью светодиода.
Начнем: изменение настроек основного таймера.
За основу мы возьмем проект из этой статьи. На основе функции 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 светодиода не хватает и появляются нежелательные пульсации.
Заключение
В данной статье мы рассмотрели, как можно настроить ШИМ и управлять им. В следующей статье мы попробуем сгенерировать при помощи ШИМ звук.
Файлы проекта к статье.
- href=«http://habrahabr.ru/post/255199/#first_unread»>Переходим с STM32F103 на К1986ВЕ92QI. Или первое знакомство с российским микроконтроллером.
- Переходим с STM32 на российский микроконтроллер К1986ВЕ92QI. Настройка проекта в keil и мигание светодиодом.
- Переходим с STM32 на российский микроконтроллер К1986ВЕ92QI. Системный таймер (SysTick).
- Переходим с STM32 на российский микроконтроллер К1986ВЕ92QI. Настройка тактовой частоты.
- Переходим с STM32 на российский микроконтроллер К1986ВЕ92QI. Практическое применение: Генерируем и воспроизводим звук. Часть первая: генерируем прямоугольный и синусоидальный сигнал. Освоение ЦАП (DAC).
- Переходим с STM32 на российский микроконтроллер К1986ВЕ92QI. Практическое применение: Генерируем и воспроизводим звук. Часть вторая: генерируем синусоидальный сигнал. Освоение DMA.
- Переходим с STM32 на российский микроконтроллер К1986ВЕ92QI. Практическое применение: Генерируем и воспроизводим звук. Часть третья: генерируем синусоидальный сигнал. Простой взгляд на DMA + первое знакомство с таймерами.
- Переходим с STM32 на российский микроконтроллер К1986ВЕ92QI. Практическое применение: Генерируем и воспроизводим звук. Часть четвертая: создаем цифровую часть одноголосной и многоголосой музыкальной открытки.
- Переходим с STM32 на российский микроконтроллер К1986ВЕ92QI. Практическое применение: Опрашиваем клавиши, генерируем ШИМ. Сравнение кода на CMSIS и SPL (PWM+TIM+PORT). Часть первая.
- Переходим с STM32 на российский микроконтроллер К1986ВЕ92QI. Практическое применение: Опрашиваем клавиши, генерируем ШИМ. Сравнение кода на CMSIS и SPL (PWM+TIM+PORT). Часть вторая.
ссылка на оригинал статьи http://habrahabr.ru/post/270887/
Добавить комментарий