wtorek, 18 października 2016

[22] STM32F4 - Programowy PWM

Ten post chciałbym poświęcić na przygotowanie programu pozwalającego na wygenerowanie sygnału PWM programowo. Pozwoli to na generację tego sygnału z każdej dostępnej nogi mikrokontrolera. Do poprawnego ustawienia sygnału będzie wykorzystywany licznik Systick.

Program


Program demonstracyjny będzie miał za zadanie ustawienie odpowiedniego sygnału PWM na każdym z dostępnych diod wbudowanych.

W przykładzie sygnał będzie generowany razem z wywołaniem obsługi przerwania od Systicka, czyli co 1ms.

Poniżej cześć inicjalizacji Systicka wraz z delayem.

  1. volatile uint16_t time_delay = 0;
  2. uint8_t SYSTICK_ON()
  3. {
  4.    if (SysTick_Config(SystemCoreClock / 1000))
  5.    {   while (1);  }
  6. }
  7. void delay_ms(uint16_t delay)
  8. {
  9.     time_delay = delay;
  10.     while(time_delay) { }
  11. }

PWM programowy opiera się na zastosowaniu odpowiedniego czasu załączenia i wyłączenia poprzez dobór wartości w pętlach, co pozwoli na sterowanie częstotliwości generowanego sygnału.

  1. uint16_t PWM_LICZNIK = 0;
  2. uint16_t PWM_PART_1 = 10;
  3. uint16_t PWM_PART_2 = 25;
  4. void PWM_GENERATE(void)
  5. {
  6.     if(PWM_LICZNIK >= PWM_PART_2)
  7.     {
  8.         PWM_LICZNIK = 0;
  9.         GPIOD->BSRRL = GPIO_Pin_15;
  10.     }
  11.     else if(PWM_LICZNIK == PWM_PART_1)
  12.     {
  13.         PWM_LICZNIK++;
  14.         GPIOD->BSRRH = GPIO_Pin_15;
  15.     }
  16.     else {  PWM_LICZNIK++; }
  17. }

Funkcja działa następująca, w pierwszej kolejności sprawdzane jest czy została przekroczona maksymalna wartość zmiennej PWM_PART_2, gdy została to zmienna zostaje zresetowana i na wybranym pinie ustawiany jest stan wysoki, gdy natomiast wartość PWM_PART_1 osiągnie wartość określoną w deklaracji, to jej stan jest zmieniany z wysokiego na niski, dalej gdy zmienna znajduje się pomiędzy wartościami zdefiniowanymi to licznik zostaje zwiększony, podczas gdy stan niski jest ciągle utrzymywany na linii. Dzięki temu podczas zmiany wartości PWM_PART_1 oraz PWM_PART_2 można otrzymać różne rodzaje wypełnienia oraz częstotliwości.

Zaletą zdecydowanie jest możliwość wygenerowania sygnału na każdym wyprowadzeniu mikrokontrolera.

Poniżej program pozwalający na generowanie różnych wartości wypełnienia z wykorzystaniem standardowo jednej z diod wbudowanych.

Aby tego dokonać należy lekko zmodyfikować funkcje zgodnie z poniższym wzorem:

  1. uint16_t PWM_LICZNIK = 0;
  2. volatile uint16_t PWM_PART_1 = 0;
  3. const uint16_t PWM_PART_2 = 100;
  4. void delay_simple(int time)
  5. {
  6.     int i=0;
  7.     for(i=0; i<=time; i++) { __NOP(); }
  8. }
  9. void PWM_GENERATE(void)
  10. {
  11.     if(PWM_LICZNIK >= PWM_PART_2)
  12.     {
  13.         PWM_LICZNIK = 0;
  14.         GPIOD->BSRRL = GPIO_Pin_15;
  15.         PWM_A++;
  16.     }
  17.     else if(PWM_Counter == PWM_PART_1)
  18.     {
  19.         PWM_LICZNIK++;
  20.         PIOD->BSRRH = GPIO_Pin_15;
  21.     }
  22.     else
  23.     { PWM_LICZNIK++; }
  24.    
  25.     if(PWM_A > PWM_B) { PWM_A = 0; }
  26.    
  27.     delay_simple(100);
  28. }