Пробуем ШИМ
Быстрая проба ШИМ, основанной на таймере. Для эксперимента будем использовать Timer 4.
Подключим светодиод, как показано на схеме ниже. Пин PB9 можно использовать, как выход PWM (TIM4_CH4).
Выполним простые шаги:
Инициализация ШИМ:
PWM_TIM4_Init(1000 {частота ШИМ});
Установим коэффициент заполнения:
PWM_TIM4_Set_Duty(duty_cycle, _PWM_NON_INVERTED, _PWM_CHANNEL4);
Здесь мы указываем, что сигнал ШИМ не инвертирован, канал таймера - 4.
Запускаем ШИМ на четвертом канале таймера, который физически подключен к PB9:
PWM_TIM4_Start(_PWM_CHANNEL4, @_GPIO_MODULE_TIM4_CH4_PB9);
Максимальное значение коэффициента заполнения (Duty cycle) мы можем получить при вызове функции инициализации.
Period:= PWM_TIM4_Init(1000 {частота ШИМ});
Для каждого значения частоты ШИМ генератора, значение максимального коэффициента заполнения будет разным, чем выше частота, тем меньше разрешение генератора ШИМ.
Для STM32F103C8T6, для стандартных настроек тактирования, отношения частот и разрешения будет таким:
Frequency | Duty cycle |
100 | 65454 |
250 | 57600 |
500 | 48000 |
1000 | 36000 |
5000 | 14400 |
10000 | 7200 |
20000 | 3600 |
50000 | 1440 |
100000 | 720 |
500000 | 144 |
1000000 | 72 |
5000000 | 14 |
10000000 | 7 |
20000000 | 3 |
Применим наш энкодер для регулировки яркости светодиода.
program TestEncoderPWM;
var MenuIndex : Word;
var Period : Word; {Новая переменная!}
var aux_s5 : array[1..5] of Char;
{LCD module connections}
var LCD_RS : sbit at GPIOB_ODR.B10;
var LCD_EN : sbit at GPIOB_ODR.B11;
var LCD_D4 : sbit at GPIOB_ODR.B12;
var LCD_D5 : sbit at GPIOB_ODR.B13;
var LCD_D6 : sbit at GPIOB_ODR.B14;
var LCD_D7 : sbit at GPIOB_ODR.B15;
{End LCD module connections}
Procedure InitTIM2(it2Mode: Byte; it2Edge1, it2Edge2: Byte; it2ARV : Word);
Begin
{ Mode 0 - Encoder mode, use input 1 only
Mode 1 - Encoder mode, use input 2 only
Mode 2 - Encoder mode, use both channels
Mode 3 - Direct counting, use input 1
Mode 4 - Direct counting, use input 2
see below TIM2_CR1.DIR_ for count direction
Edge1 - Rising (0) or falling edge (1) detection for input 1
Edge2 - Rising (0) or falling edge (1) detection for input 2
ARV - Auto reload value for the Timer }
GPIO_Alternate_Function_Enable(@_GPIO_MODULE_TIM2_CH1_PA15);
GPIO_Alternate_Function_Enable(@_GPIO_MODULE_TIM2_CH2_PB3);
GPIO_Set_Pin_Mode(@GPIOA_BASE, _GPIO_PIN_15, _GPIO_CFG_MODE_ALT_FUNCTION);
GPIO_Set_Pin_Mode(@GPIOB_BASE, _GPIO_PIN_3, _GPIO_CFG_MODE_ALT_FUNCTION);
RCC_APB1ENR.TIM2EN := 1; {Enable switching the Timer2}
TIM2_CR1.CEN := 0; {TIM2 disable}
TIM2_CCER.CC1E := 0; {Capture 1 disable}
TIM2_CCER.CC2E := 0; {Capture 2 disable}
If it2Edge1 > 0 then TIM2_CCER.CC1P:= 1 else TIM2_CCER.CC1P:= 0;
If it2Edge2 > 0 then TIM2_CCER.CC2P:= 1 else TIM2_CCER.CC2P:= 0;
TIM2_CR1.DIR_ := 0; {Direction 0 - up, 1- down}
TIM2_CCMR1_Input.CC1S0 := 1; {01: CC1 channel is configured as input, IC1 is mapped on TI1}
TIM2_CCMR1_Input.CC1S1 := 0; {01: CC1 channel is configured as input, IC1 is mapped on TI1}
TIM2_CCMR1_Input.CC2S0 := 1; {01: CC2 channel is configured as input, IC2 is mapped on TI2}
TIM2_CCMR1_Input.CC2S0 := 0; {01: CC2 channel is configured as input, IC2 is mapped on TI2}
Case it2Mode of
0 : begin
TIM2_SMCR.SMS0:= 0;
TIM2_SMCR.SMS1:= 1;
TIM2_SMCR.SMS2:= 0;
end;
1 : begin
TIM2_SMCR.SMS0:= 1;
TIM2_SMCR.SMS1:= 0;
TIM2_SMCR.SMS2:= 0;
end;
2 : begin
TIM2_SMCR.SMS0:= 1;
TIM2_SMCR.SMS1:= 1;
TIM2_SMCR.SMS2:= 0;
end;
3 : begin
TIM2_SMCR.SMS0:= 1;
TIM2_SMCR.SMS1:= 1;
TIM2_SMCR.SMS2:= 1;
TIM2_SMCR.TS0 := 1;
TIM2_SMCR.TS1 := 0;
TIM2_SMCR.TS2 := 1;
end;
4 : begin
TIM2_SMCR.SMS0:= 1;
TIM2_SMCR.SMS1:= 1;
TIM2_SMCR.SMS2:= 1;
TIM2_SMCR.TS0 := 0;
TIM2_SMCR.TS1 := 1;
TIM2_SMCR.TS2 := 1;
end;
end; {Case}
TIM2_ARR := it2ARV; {Value for auto reload the counter}
TIM2_CCMR1_Input.IC1F0 := 1; {Digital filter 00 - %1111}
TIM2_CCMR1_Input.IC1F1 := 1; {Digital filter 00 - %1111}
TIM2_CCMR1_Input.IC1F2 := 1; {Digital filter 00 - %1111}
TIM2_CCMR1_Input.IC1F3 := 1; {Digital filter 00 - %1111}
TIM2_CCMR1_Input.IC2F0 := 1; {Digital filter 00 - %1111}
TIM2_CCMR1_Input.IC2F1 := 1; {Digital filter 00 - %1111}
TIM2_CCMR1_Input.IC2F2 := 1; {Digital filter 00 - %1111}
TIM2_CCMR1_Input.IC2F3 := 1; {Digital filter 00 - %1111}
TIM2_CCER.CC1E := 1; {Capture enable}
TIM2_CCER.CC2E := 1; {Capture enable}
TIM2_CR1.CEN := 1; {TIM2 enable}
End;
begin
Period:= PWM_TIM4_Init(10000); {Частота ШИМ - 10 кГц}
{Инициализируем таймер для энкодера так, чтобы не выйти за границу максимального значения коэффициента заполнения ШИМ}
InitTIM2(1, 1, 1, (Period * 2) + 1);
PWM_TIM4_Set_Duty(0, _PWM_NON_INVERTED, _PWM_CHANNEL4);
PWM_TIM4_Start(_PWM_CHANNEL4, @_GPIO_MODULE_TIM4_CH4_PB9);
Lcd_Init; {Инициализация LCD}
Lcd_Cmd(_LCD_CURSOR_OFF); {Отключаем курсор}
WordToStr(Period, aux_s5);
Lcd_Out(2,1, aux_s5); {Показываем максимальное значение коэффициента заполнения для выбранной частоты}
InitTIM2(1, 1, 1, 39);
While True do begin {Суперцикл}
MenuIndex:= TIM2_CNT div 2; {Значение счетчика делим на два}
{Присваиваем значение положения энкодера значению коэффициента заполнения генератора ШИМ}
PWM_TIM4_Set_Duty(MenuIndex, _PWM_NON_INVERTED, _PWM_CHANNEL4);
WordToStr(MenuIndex, aux_s5); {Преобразуем Word в строку}
Lcd_Out(1,1, aux_s5); {Выводим строку}
end; {Конец суперцикла}
end.
Теперь светодиод изменяет свою яркость в зависимости от положения энкодера.
Комментарии
Отправить комментарий