Na rozgrzewkę:
W ostatnim czasie pracuję zarówno nad hardwarem jaki i softwarem projektu sterownika, którego wyjścia sterowane są za pomocą PWM. Wspominałem o tym w jednym z wpisów w serii Z życia elektronika – #14 – Metody pomiaru prądu. Na pokładzie sterownika będzie maksymalnie 30 wyjść stąd niezbędna jest taka sama liczba PWM. W procesorze, na którym piszę program czyli STM32F4 istnieje możliwość wygenerowania tylko 16 sprzętowych PWM. Po odrzuceniu opcji wykorzystania sprzętowych PWM chciałem wykorzystać układ scalony PCA9635, lecz we wspomnianym układzie nie ma możliwości obniżenia częstotliwości generowanego sygnału, drugi minus to cena. Ostatnim pomysłem, który został wykorzystany jest generowanie programowych PWM. W tym wpisie opiszę sposób w jaki generuję programowe PWM z wykorzystaniem timerów. Program, nad którym pracuję opiera się na bibliotece StdPeriph.
Zakres wpisu:
- Konfiguracja timerów
- Implementacja funkcji TIM_IT_Update
Konfiguracja timerów:
W projekcie wykorzystałem 3 timery. Timer 2 do wyzwalania pomiaru ADC. Timer 3 do ustalenia stałej częstotliwości generowanego sygnału PWM oraz wypełnienia. Timer 4 do odliczania czasu załączenia danego wyjścia.
Timer 3 oraz 4 zostały skonfigurowane tak samo. W obu timerach skorzystałem z funkcji TIM_ITConfig(TIM3, TIM_IT_Update, ENABLE) dzięki, której otrzymuję flagę o doliczeniu timera do ustalonej wartości.
RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM3, ENABLE); TIM_TimeBaseInitTypeDef tim3; tim3.TIM_CounterMode = TIM_CounterMode_Up; tim3.TIM_Prescaler = 100; tim3.TIM_Period = 83; tim3.TIM_ClockDivision = TIM_CKD_DIV1; tim3.TIM_RepetitionCounter = 0; TIM_TimeBaseInit(TIM3, &tim3); TIM_ITConfig(TIM3, TIM_IT_Update, ENABLE); TIM_Cmd(TIM3, ENABLE);Wszystkie użyte przeze mnie timery są podpięte do linii APB1. Zegar systemowy odlicza z częstotliwością 84MHz. Do wyznaczenia interesującej nas wartości częstotliwości np. 10kHz użyjemy następującego wzoru:
TIM_TimeBaseInitTypeDef tim2; tim2.TIM_CounterMode = TIM_CounterMode_Up; tim2.TIM_Prescaler = 10000; tim2.TIM_Period = 41; tim2.TIM_ClockDivision = TIM_CKD_DIV1; tim2.TIM_RepetitionCounter = 0; TIM_TimeBaseInit(TIM2, &tim2); TIM_Cmd(TIM2, ENABLE); TIM_SelectOutputTrigger(TIM2, TIM_TRGOSource_Update); TIM_ITConfig(TIM2, TIM_IT_Update, ENABLE);
Implementacja funkcji TIM_IT_Update:
if (TIM_GetITStatus(TIM3, TIM_IT_Update) == SET) { TIM_ClearITPendingBit(TIM3, TIM_IT_Update); period--; if(period==0) { period=default_period; } }W powyższej części programu dekrementuję zmienną period co każde wystawienie flagi przez funkcję, czyli doliczenie timera do zdefiniowanej wartości. Na podstawie zmiennej period ustalam częstotliwość pracy wyjść PWM.