Ingo Electronics


    HOME                                                           Stellaris LM4F120 LaunchPad


  Stellaris LM4F120 LaunchPad.     PWM režimas.                                                                                                            PWM Timer Mode 

Visų, žemiau tekste pavartotų funkcijų vardus ir parametrų reikšmes galima rasti atsidarius Code Composer Studio timer.h failą !!!

Kadangi Stellaris LM4F120 LaunchPad plokštėje esantis mikrovaldiklis turi 12x2 taimerio modulių, teoriškai galima gauti 24 PWM signalus.

Taimeris dirbantis PWM režimu, naudojant papildomą registrą, vadinamą prescaler, dirba kaip 24bitų (16bitų modulis)  arba 48bitų (32bitų modulis)  DOWN skaitiklis.

Taimerio starto reikšmė, kuri taip pat nustato PWM dažnį, yra nustatoma naudojant funkcijas, TimerLoadSet ir TimerPrescaleSet  arba TimerLoadSet64 ir TimerPrescaleSet 

PWM impulso plotis (duty) yra nustatomas  įvedant reikiamą skaitmeninę reikšmę funkcijose:
TimerMatchSet ir TimerPrescaleMatchSet  arba TimerMatchSet64 ir TimerPrescaleMatchSet 

Kadangi PWM režimu, skaitiklis sukasi DOWN, reikšmė įvedama impulso pločiui visada turi būti mažesnė už reikšmę įvedamą PWM dažniui nustatyti.

Taimeris dirbantis PWM režimu, gali generuoti pertraukimų rodykles.

Pertraukimų rodyklės gali būti generuojamos pagal sekančias pasirinktas PWM signalo fronto reikšmes: kylančio fronto, besileidžiančio fronto, arba nuo abiejų frontų (rising edge, falling edge, or both).

Pertraukimų režimas nustatomas funkcijoje TimerControlEvent įvedant vieną iš trijų parametrų:
TIMER_EVENT_POS_EDGE, TIMER_EVENT_NEG_EDGE, TIMER_EVENT_BOTH_EDGES  

Nustatant pertraukimų tipą, funkcijoje TimerIntEnable įvedamas parametras TIMER_CAPA_EVENT

PWM signalas bet kokiu momentu gali buti išjungimas naudojant funkciją TimerDisable

Esant reikalui PWM signalas gali būti invertuojamas panaudojant funkciją TimerControlLevel

Jeigu PWM signalas yra invertuojamas, ir jeigu yra naudojami taimerio fonto pertraukimai t.y panaudota funkcija TimerControlEvent joje esanačius parametrus TIMER_EVENT_POS_EDGE , TIMER_EVENT_NEG_EDGE taip pat reiktų pakeisti. 

Kaip ir periodic režime, PWM režimą, norint gauti ilgesnius laiko išlaikymus, galima sukonfiguruoti pajungiant keletą modulių į grandinę, kai modulis dirba įjungtas įgrandinę, jis laukia signalo iš prieš tai esančio modulio. Taimerio modulis įjungiamas į grandinę panaudojant funkciją TimerControlWaitOnTrigger

Taimeris PWM režimui konfiguruojamas sekančiu eiliškumu:

Konfiguravimo pavyzdys duotas paimant konkretų modulį.

Pasirenkam TIMER0  TIMER_A, pagal mikrokontrolerio LM4F120H5QR pdf aprašymą surandame, kad šio modulio CCP išvadas gali būti prijungtas prie PB6 arba prie PF0. Pasirenkame išvadą PB6.

//***********************************************************************************************************************************

//kadangi pasirinkome PB6, įjungiame PORTB taktavimą
SysCtlPeripheralEnable(SYSCTL_PERIPH_GPIOB);

//konfiguruojam, t.y prijungiam PB6 prie TIMER0  TIMER_A modulio
GPIOPinConfigure(GPIO_PB6_T0CCP0);
GPIOPinTypeTimer(GPIO_PORTB_BASE, GPIO_PIN_6);

//įjungiame taktavimą TIMER0 moduliui
SysCtlPeripheralEnable(SYSCTL_PERIPH_TIMER0);

//konfiguruojame taimerį dirbti PWM režimu
//PWM režimu gali dirbti tik arba modulis A arba B todėl naudojame parametrą
TIMER_CFG_SPLIT_PAIR
TimerConfigure(TIMER0_BASE, TIMER_CFG_SPLIT_PAIR | TIMER_CFG_A_PWM);

//jeigu bus reikalinga pertraukimų funkcija, nustatom pertraukimų režimo kontrolę
//galimi parametrai TIMER_EVENT_POS_EDGE,
TIMER_EVENT_NEG_EDGE, TIMER_EVENT_BOTH_EDGES               
//TimerControlEvent(TIMER0_BASE, TIMER_A, TIMER_EVENT_POS_EDGE);

//jeigu reikalinga, įrašome prescalerio reikšmę
//TimerPrescaleSet(TIMER0_BASE,TIMER_A,0x00);

// konfiguruojame PWM dažnį
TimerLoadSet(TIMER0_BASE, TIMER_A, Period);

// jeigu reikalinga, įvedame prescalerio sutapimo  reikšmę
//TimerPrescaleMatchSet(TIMER0_BASE, TIMER_A,0x00);

// konfigurujame PWM impulsų ilgį
TimerMatchSet(TIMER0_BASE, TIMER_A, dutyCycle);

//leidžiame TIMER0  TIMER_A modulio pertraukimus
//IntEnable(INT_TIMER0A);

//nustatome pertraukimų tipą
//TimerIntEnable(TIMER0_BASE, TIMER_CAPA_EVENT);

//leidžiame mikrovaldikliui reaguoti į pertraukimų rodykles
IntMasterEnable();

//įjungiame TIMER0  TIMER_A modulį (paleidžiame PWM)
TimerEnable(TIMER0_BASE, TIMER_A);

//*********************************************************************************************************************************** 

Taimerio konfiguravimas baigtas. Galime pasirašyti funkciją, kurią vėliau naudoti kaip šabloną taimerio režmo PWM  konfiguravimui:

//***********************************************************************************************************************************

void PWM_init()
{

SysCtlPeripheralEnable(SYSCTL_PERIPH_GPIOB);
GPIOPinConfigure(GPIO_PB6_T0CCP0);
GPIOPinTypeTimer(GPIO_PORTB_BASE, GPIO_PIN_6);

SysCtlPeripheralEnable(SYSCTL_PERIPH_TIMER0);
TimerConfigure(TIMER0_BASE, TIMER_CFG_SPLIT_PAIR | TIMER_CFG_A_PWM);

// konfiguruojame PWM dažnį
TimerLoadSet(TIMER0_BASE, TIMER_A, Period);

//jeigu reikalinga, įrašome prescalerio reikšmę
//TimerPrescaleSet(TIMER0_BASE,TIMER_A,0x00);

// konfigurujame PWM impulsų ilgį
TimerMatchSet(TIMER0_BASE, TIMER_A, dutyCycle);

// jeigu reikalinga, įvedame prescalerio sutapimo  reikšmę

//TimerPrescaleMatchSet(TIMER0_BASE, TIMER_A,0x00);

//įjungiame TIMER0  TIMER_A modulį (paleidžiame PWM)
TimerEnable(TIMER0_BASE, TIMER_A);

}

//*************************************************************************************************

PWM pavyzdžių galima nemažai rasti internete, visi jie standartiški ir labai paprastai konfiguruojami.

Žemiau pateiktame pavyzdyje parodyta kaip panaudoti  PWM pertraukimus. Pertraukimų funkcijos darbo vizualiam stebėjimui panaudotas raudonas šviesos diodas.

Šiame pavyzdyje pasirinktas 32bitų taimerio modulis, kurio parametro pavaizdavimas programos kode turi priešdėlį W, pvz. WTIMER0_BASE.

Mikrovaldiklio taktinis dažnis (F) nustatytas 40Mhz.

Pirmiausia reikia paskaičiuoti periodą. Tarkime norime kad periodas būtų 1sec (T),  period = F/T=40000000/1=40000000. 

Kadangi taimeris keičia savo reikšmę su kiekvienu taktu, tai vienai sekundei reikės 40000000 taktų, hex formatu tai bus (0x02625A00).

Turėdami periodą, galime pasiskaičiuoti impulso ilgį (duty), tarkime norime turėti 50%, tuomet:   duty = (period*100)/50

Žemiau esančiame programos kode galime keisti period ir duty reikšmes , stebėdami kaip į tai reaguoja šviesos diodas.

Reikalingi failiukai parsisiuntimui: Link

//*************************************************************************************************

#include "inc/hw_types.h"
#include "inc/hw_memmap.h"
#include "inc/hw_ints.h"
#include "inc/hw_gpio.h"
#include "driverlib/sysctl.h"
#include "driverlib/gpio.h"
#include "driverlib/timer.h"
#include "driverlib/pin_map.h"
#include "driverlib/interrupt.h"

unsigned int state;
unsigned long period;
unsigned long duty;

//''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''

//interrupt
void Timer0IntHandler(void)
{
// Clear the timer interrupt
TimerIntClear(WTIMER0_BASE, TIMER_CAPA_EVENT);

state = ~state&0x08;
GPIOPinWrite(GPIO_PORTF_BASE, GPIO_PIN_3,state);

}//end interrupt

//''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
void main() {

           // 40 MHz system clock

           SysCtlClockSet(SYSCTL_SYSDIV_5|SYSCTL_USE_PLL| SYSCTL_XTAL_16MHZ|SYSCTL_OSC_MAIN);

           // Turn off LEDs

           SysCtlPeripheralEnable(SYSCTL_PERIPH_GPIOF);

           GPIOPinTypeGPIOOutput(GPIO_PORTF_BASE, GPIO_PIN_3);

           GPIOPinWrite(GPIO_PORTF_BASE,GPIO_PIN_3, 0);

           period = 0x02625A00;

           duty = period/2;

           // Configure timer

           SysCtlPeripheralEnable(SYSCTL_PERIPH_WTIMER0);

           TimerConfigure(WTIMER0_BASE, TIMER_CFG_SPLIT_PAIR|TIMER_CFG_A_PWM );

           TimerLoadSet(WTIMER0_BASE, TIMER_A, period);

           TimerMatchSet(WTIMER0_BASE, TIMER_A, duty);

           //galimi parametrai TIMER_EVENT_POS_EDGE, TIMER_EVENT_NEG_EDGE, TIMER_EVENT_BOTH_EDGES

           TimerControlEvent(WTIMER0_BASE, TIMER_A, TIMER_EVENT_BOTH_EDGES);

           IntEnable(INT_WTIMER0A);

           TimerIntEnable(WTIMER0_BASE, TIMER_CAPA_EVENT);

           IntMasterEnable();

           TimerEnable(WTIMER0_BASE, TIMER_A);

 

           while(1) {}

    

}//end main