STM32 I/O модуль на MODBUS с PWM выходами (Апгрейд2)

Видео в качестве анонса:
Для чего нужен PWM? он нужен для того чтобы управлять чем то при помощи аналогового сигнала который может быть чисто PWM — например для управления яркостью светодиода, либо через интегратор (резистор с конденсатором ) преобразуя в напряжение от 0 до напряжения питания у нас 3.3В для duty цикла от 0 до Максимума равного разрешению таймера соответсвенно.

Причем делается это все плавно с достаточной точность (в примере 15бит), но чем больше бит тем меньше частота т.е. для того чтобы таймер дощелкал до 65535 ему вобщемто надо столько циклов при 24МГц (STM32F100C8T6) — он будет перезаряжаться 366 раз т.е. это будет частота PWM — 366Hz. Обычно эту частоту берут повыше с уменьшением точности (дабы не вешать огромных емкостей в интеграторе) раза в два больше нам будет как раз 732Hz нормально да и 15 бит нехилое разрешение. Во множестве устройств автоматики (особо точные применения не берем) разрядность аналоговых выходов гораздо меньше 8-10 бит т.к. большинство исполнительных устройств типа клапанов из за люфтов и всяких косяков не могут обеспечить даже такую реальную точность. Нус к делу.
Настройка выходов для подцепляния их таймером заключается в объявлении этих пинов выходами и использовании альтернативной функции, ну и как обычно не забываем затактировать нужный порт.
//pa8-11 выходы PWM
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_8|GPIO_Pin_9|GPIO_Pin_10|GPIO_Pin_11;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_InitStructure.GPIO_Mode =GPIO_Mode_AF_PP;//альтернативная функция выход пуш-пул
GPIO_Init(GPIOA, &GPIO_InitStructure);
Есть несколько режимов для PWM повышающих точность выходного сигнала, но именно в нашем применении достаточно для генерации практически статичного сигнала (если его обработать интегратором) мы воспользуемся самым простым вариантом все каналы у нас одной полярности (Правда тут немного все инвернсно получилось, но не суть),N-каналы (компленементарные) не используем хотя почти весь инит для них на всякий случай я оставил. Причем полярность можно настроить не только для таймера но и поканально и у N выходов- это удобно для управления всякими инверторами (как я понимаю).
void Setup_PWM(void)
{
TIM_OCInitTypeDef TIM_OCInitStructure;
TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure;
RCC_APB2PeriphClockCmd(RCC_APB2Periph_TIM1, ENABLE);
/* Time Base configuration */
TIM_TimeBaseStructure.TIM_Prescaler = 0;
TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up;
TIM_TimeBaseStructure.TIM_Period = 32768;//максисмум таймера
TIM_TimeBaseStructure.TIM_ClockDivision = 0;
TIM_TimeBaseStructure.TIM_RepetitionCounter = 0;
TIM_TimeBaseInit(TIM1, &TIM_TimeBaseStructure);
TIM_ARRPreloadConfig ( TIM1,ENABLE);
/* Channel 1, 2,3 and 4 Configuration in PWM mode */
TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_PWM2;//Обратная полярность TIM_OCMode_PWM1 -прямая
TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable;
TIM_OCInitStructure.TIM_OutputNState = TIM_OutputNState_Enable;//это для парных выходов
TIM_OCInitStructure.TIM_Pulse = 0;//Значение мощности для первого канала по умолчанию 0
TIM_OCInitStructure.TIM_OCPolarity = TIM_OCPolarity_Low; //Еще раз обратная полярность :)
TIM_OCInitStructure.TIM_OCNPolarity = TIM_OCNPolarity_Low;//полярность для N выходов
TIM_OCInitStructure.TIM_OCIdleState = TIM_OCIdleState_Set;//что делать в момент ожидания
TIM_OCInitStructure.TIM_OCNIdleState = TIM_OCIdleState_Reset;//для N выходов
TIM_OC1Init(TIM1, &TIM_OCInitStructure);
//все значения структуры у нас одинаковые для всех каналов
TIM_OCInitStructure.TIM_Pulse = 0;//Значение для второго канала
TIM_OC2Init(TIM1, &TIM_OCInitStructure);
TIM_OCInitStructure.TIM_Pulse = 0;//Значение для третьего канала
TIM_OC3Init(TIM1, &TIM_OCInitStructure);
TIM_OCInitStructure.TIM_Pulse = 0;//Значение для четвертого канала
TIM_OC4Init(TIM1, &TIM_OCInitStructure);
/* TIM1 counter enable */
TIM_Cmd(TIM1, ENABLE); //Пуск таймера
/* Main Output Enable */
TIM_CtrlPWMOutputs(TIM1, ENABLE); //Пуск PWM выходов
}
Так как я вроде собирался писать все с помошью стандарных функций (пока) то долго искал как присвоить каналу новое значение, оказалось нет такой функции поэтому пишем просто в соответствующий регистр таймера
TIM1->CCR1 = res_table.regs[5];
TIM1->CCR2 = res_table.regs[6];
TIM1->CCR3 = res_table.regs[7];
TIM1->CCR4 = res_table.regs[8];
Проект для CooCox IDE приложен. Вроде все.
- 0
- 05 сентября 2011, 21:28
- GYUR22
- 1
Файлы в топике:
io_analog_pwm_lt.zip
Комментарии (0)
RSS свернуть / развернуть