sobota, 21 czerwca 2014

STM32F429i - PWM + LED

Witajcie!
Jako kontynuację artykułów o STM32F429i przedstawię sposób płynnej
regulacji świecenia diodą led.
Do naszej zabawy będziemy potrzebować przejściówkę FT232, ponieważ
zmodyfikujemy nasz terminal, który wspomoże nas w płynnej regulacji
wypełnienia PWM, oraz diodę led wraz z rezystorem około 300 ohm.

PWM - czyli Pulse Width Modulation -  jest to modulacja szerokości impulsu
utworzonego np: na "wyjściu" naszego timera, który jest tak skonfigurowany aby
generował sygnał prostokątny. My zaś zmieniając parametry modulujemy
tzw. wypełnienie czyli szerokość, tym samym zmieniając wartość średnią
napięcia. Oczywiście nie możemy zapomnieć o bardzo ważnym parametrze
jakim jest częstotliwość naszego przebiegu prostokątnego. Częstotliwość tą
ustawiłem na 1kHz.
Dla lepszego zobrazowania o co chodzi przedstawię screeny z oscyloskopu,
w którym zmienię wartość wypełnienia co z kolei wpłynie na wartość średnią
napięcia na pinie mikrokontrolera.

PWM - 25% -Uavg = 768mV  f= 1kHz
PWM - 50% -Uavg = 1,5V     f= 1kHz

PWM - 75% -Uavg = 2.25V     f= 1kHz


Na oscylogramach widać ładnie jak zmienia się wypełnienie i tym samym wartość
średnia napięcia.
Oczywiście PWM możemy regulować np: prędkość obrotową silnika, nic nie stoi na
przeszkodzie :). W kolejnych cyklach pokażemy sobie jak sterować serwami 
modelarskimi :) co przydaje się każdemu elektronikowi chcącemu zbudować własnego
robota.

Ok najpierw zajmijmy się kodem C# naszego terminala ponieważ dodałem kontrolkę
TrackBara, którą regulujemy płynnie wypełnienie.



 private void trackBar1_Scroll(object sender, EventArgs e)
        {
            serialPort1.Write(trackBar1.Value.ToString() + "\r");
        }
Wygląd naszej formatki powinien wyglądać w taki sposób:

Widzimy że kod jest banalny. W zdarzeniu event_scroll TrackBara za każdym przesunięciem 
wskaźnika wysyłamy wartość na COM od 0 - 512.

Ok to teraz przejdźmy do trudniejszych rzeczy. Przedstawię kod pliku main.c

#include "main.h"

#include "stm32f4xx_gpio.h"
#include "stm32f4xx_rcc.h"
#include "stm32f4xx_tim.h"
#include "stm32_ub_uart.h"
#include "stdlib.h"


void Init(void);
void Delay(volatile uint32_t nCount);
void initPWM(void);

void strreverse(char* begin, char* end);


int main(void)
{
  UART_RXSTATUS_t check;
  char rx_buf[RX_BUF_SIZE];


  SystemInit(); 
  Init();   //inicjalizacja diody - do tego ćwiczenia nie potrzebna
  initPWM();  //inicjalizacja timera 5, który pracuje w trybie PWM
  UB_Uart_Init();   //inicalizacja USARTA

  uint16_t i = 0;

  while(1)
  {
  check=UB_Uart_ReceiveString(COM1,rx_buf); //zapisujemy odebrane dane do bufora

  if(check==RX_READY) {  //sprawdzamy czy dane zostały odebrane 
      
    i = atol(rx_buf);  //konwertujemy dane z bufora czyli ascii na int
       TIM_SetCompare1(TIM5, i); //timer pwm - zapisujemy odebraną wartosc już skonwertowaną do timera

       UB_UART_SendInt(COM1,i,10); //wysylamy spowrotem odebraną wartosc
       //UB_Uart_SendString(COM1,rx_buf); 
       UB_Uart_SendString(COM1,"\r\n"); //wysylamy znak powrotu karetki i nowej lini
  }
       //Delay(5000000);


  }
}

void initPWM()
{
 /* TIM5 włączenie zegara */
 RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM5, ENABLE);

 TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure;

 /* Obliczenie wartoci preskalera */
 uint16_t u16PrescalerValue = (uint16_t) ((SystemCoreClock) / 1000000)- 1;
 TIM_TimeBaseStructure.TIM_Prescaler = u16PrescalerValue; // 1MHz - preskaler
 TIM_TimeBaseStructure.TIM_Period = 500;                  // 1 MHz / 500 /2  = 1kHz (1ms)
 TIM_TimeBaseStructure.TIM_ClockDivision = 0;
 TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up;  //licznik zlicza w góre

 TIM_TimeBaseInit(TIM5, &TIM_TimeBaseStructure); //inicjalizacja struktury Timera 5

 TIM_OCInitTypeDef TIM_OCInitStructure;

 TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_PWM1;  //tryb pwm
 TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable;  //odpalenie timera
 TIM_OCInitStructure.TIM_Pulse = 0; 
 TIM_OCInitStructure.TIM_OCPolarity = TIM_OCPolarity_High;

 /*********************TIM5**************************/
 /* konfiguracja trybu PWM: kanał 1 (GPIOA Pin 0)*/
 TIM_OC1Init(TIM5, &TIM_OCInitStructure);
 TIM_OC1PreloadConfig(TIM5, TIM_OCPreload_Enable );
        TIM_Cmd(TIM5, ENABLE); //odpalenie timera

 ///////////////konfuguracja GPIO ///////////////
 GPIO_InitTypeDef GPIO_PWM;

 RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOA, ENABLE);

 GPIO_PWM.GPIO_Mode = GPIO_Mode_AF;
 GPIO_PWM.GPIO_Speed = GPIO_Speed_50MHz;
 GPIO_PWM.GPIO_OType = GPIO_OType_PP;
 GPIO_PWM.GPIO_PuPd = GPIO_PuPd_UP;

 //PORT A Pin0
 GPIO_PWM.GPIO_Pin = GPIO_Pin_0;
 GPIO_Init(GPIOA, &GPIO_PWM);

 GPIO_PinAFConfig(GPIOA, GPIO_PinSource0, GPIO_AF_TIM5 );

Myślę, że komentarze pomogą w zrozumieniu kodu.

Na koniec zostaje nam pokazanie jak wszystko wspólnie działa. Na filmie będzie
ładnie widać jak płynnie zmienia się wartość PWM a dioda led czerwona zmienia
jasność.

Przyjemnej zabawy :)

Brak komentarzy:

Prześlij komentarz