Широтно-импульсная модуляция на STM8
С помощью микроконтроллера STM8 можно генерировать заданную частоту с порта ввода-вывода. Для этого не обязательно вручную переключать туда-сюда пин на порту. Можно воспользоваться одним из таймеров, а именно задействовать в нём функцию PWM. Это режим широтно-импульсной модуляции (ШИМ). В нём можно генерировать заданную частоту и регулировать скважность этой частоты.
Код, приведённый в этой статье относится к компилятору Raisonance.
Для работы с ШИМ я использую следующие макросы (ниже будет показано во что они разворачиваются, так как сложно воспринимать код, написанный в виде макросов):
// timer == TIM2, TIM3 #define InitTimer_PWM(timer) \ timer##_DeInit(); \ timer##_TimeBaseInit(timer##_PRESCALER_1, uPeriod); \ timer##_ARRPreloadConfig(ENABLE); \ timer##_Cmd(ENABLE); #define InitChannel_PWM(timer, channel) \ timer##_OC##channel##Init(timer##_OCMODE_PWM1, timer##_OUTPUTSTATE_ENABLE, \ uPulse, timer##_OCPOLARITY_HIGH); \ timer##_OC##channel##PreloadConfig(ENABLE); #define ChangePulse_PWM(timer, channel) \ timer##->CCR##channel##H = (u8)(uPulse >> 8); \ timer##->CCR##channel##L = (u8)(uPulse); #define DisableChannel_1_PWM(timer) \ timer->CCER1 &= (u8)(~timer##_CCER1_CC1E) #define DisableChannel_2_PWM(timer) \ timer->CCER1 &= (u8)(~timer##_CCER1_CC2E) #define DisableChannel_3_PWM(timer) \ timer->CCER2 &= (u8)(~timer##_CCER2_CC3E)
Последние три макроса нужны на тот случай, если нужно отключить выдачу частоты с канала таймера.
Макрос InitTimer_PWM инициализирует режим PWM для заданного таймера. Вызывать его нужно так: InitTimer_PWM(TIM3); Но, поскольку это макрос, где-то перед ним нужно рассчитать, во-первых, генерируемую частоту, во-вторых, её скважность. Частоту берём из параметра функции uFreq, а скважность будет в переменной uPulse, рассчитанной из параметра fPulse. Параметр fPulse это заполнение в процентах. То есть для скважности 50 % туда надо поместить значение (float)50.
static bool bTimerInitialized = false; void SetFreqChannel_3(u16 uFreq, float fPulse) { u16 uPulse, uPeriod; float fCoeff, fNewPulse; static bool bChannelInitialized = false; uPeriod = (u16)(CLK_GetClockFreq() / uFreq); fCoeff = fPulse / 100.; fNewPulse = (float)uPeriod * fCoeff; uPulse = (u16)( fNewPulse ); if (!bTimerInitialized) { // Таймер ещё не был инициализирован InitTimer_PWM(TIM2); bTimerInitialized = true; } if (!bChannelInitialized) { // Канал ещё не был инициализирован InitChannel_PWM(TIM2, 3); bChannelInitialized = true; } else { // Поменять параметры ШИМ ChangePulse_PWM(TIM2, 3); } }
То есть пишем, например SetFreqChannel_3(200, 45.); и получаем на третьем канале таймера TIM2 частоту 200 Гц и скважность 45 %. Почему у меня в примере функция только для канала 3? А потому, что иначе не получится использовать макрос ChangePulse_PWM, которому во втором параметре нужно именно число (ведь оно подставляется в имя регистра). Модифицировать функцию так, чтобы она работала со всеми каналами сразу, предлагаю вам самостоятельно, если вам это нужно.
Теперь, что касается макросов, они разворачиваются так:
// InitTimer_PWM(TIM2) = TIM2_DeInit(); TIM2_TimeBaseInit(TIM2_PRESCALER_1, uPeriod); TIM2_ARRPreloadConfig(ENABLE); TIM2_Cmd(ENABLE); // InitChannel_PWM(TIM2, 1) = TIM2_OC1Init(TIM2_OCMODE_PWM1, TIM2_OUTPUTSTATE_ENABLE, uPulse, TIM2_OCPOLARITY_HIGH); TIM2_OC1PreloadConfig(ENABLE); // ChangePulse_PWM(TIM2, 1) TIM2->CCR1H = (u8)(uPulse >> 8); TIM2->CCR1L = (u8)(uPulse); // DisableChannel_1_PWM(TIM2) = TIM2->CCER1 &= (u8)(~TIM2_CCER1_CC1E) // DisableChannel_2_PWM(TIM2) = TIM2->CCER1 &= (u8)(~TIM2_CCER1_CC2E) // DisableChannel_3_PWM(TIM2) = TIM2->CCER2 &= (u8)(~TIM2_CCER2_CC3E)
Это — либо обращения к регистрам микроконтроллера, либо вызовы функций библиотеки из состава пакета STM8-RKIT.
Автор: амдф
Дата: 12.10.2012
Избранное
Остальное
Лента atom