Sterownik PWM – #1 – Definicja timerów w STM32 do programowych PWM

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:
Timer 2 użyłem do innego celu, służy on do wyzwalania pomiaru ADC. Podczas konfiguracji użyłem funkcji TIM_SelectOutputTrigger(TIM2, TIM_TRGOSource_Update). Wykorzystywana jest ona jako zewnętrzny trigger do pomiaru ADC. Poniższa konfiguracja timera pozwala odczytywać wartość ADC co 200Hz.
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:

Wykorzystanie wspomnianej flagi można zaimplementować do programu w następujący sposób:
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.

Autor artykułu
Mateusz Pluta

Dodaj komentarz

Twój adres e-mail nie zostanie opublikowany.