Широтно-импульсная модуляция на 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
Избранное
Остальное
По вопросам сотрудничества и другим вопросам по работе сайта пишите на cleogroup[собака]yandex.ru