Ingo Electronics


    HOME                                                           Stellaris LM4F120 LaunchPad


  Stellaris LM4F120 LaunchPad.          Išorinių impulsų signalo ilgio skaičiavimo režimas.                        Input Edge Timing Timer Mode  

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

Taimeris šiame režime dirba nuo išorinio impulsų šaltinio, pajungto prie atitinkamo taimerio CCP išvado.

Maksimalus dažnis, kuris gali būti paduodamas į CCP įėjimą yra ¼ mikrokontrolerio taktinio dažnio.

Šiame režime taimerio moduliai TIMER_A  ir  TIMER_B gali dirbti tik atskirai, t.y galima pasirinkti arba TIMER_A  arba TIMER_B 16 arba 32 bitų moduliuose, tai nurodoma funkcijoje  TimerConfigure papildomai įvedant parametrą  TIMER_CFG_SPLIT_PAIR

Taimeris dirbantis Edge Timing Mode režimu, yra sukonfiguruotas kaip 24 arba 48 bitų, UP arba DOWN skaitiklis.

Taimerio prescaler šiame režime yra pridedamas kaip aukščiausių (MSB)  8bitų plėtinys iki 24bitų (16bitų modulis) arba aukščiausių (MSB)  16bitų plėtinys (32bitų modulis) , kaip kad buvo pavaizduota ankstesnėje temoje. Link

Taimeris šiame režime dirba sekančiu principu:

Vos tk paleidžiamas taimeris, funkcijos TimerEnable pagalba, skaitiklis ima suktis ir kai tik yra užfiksuojamas pirmas kylantis arba besileidžiantis signalo frontas, priklausomai nuo funkcijoje TimerControlEvent įvesto parametro, suveikia pertraukimų rodyklė ir taimerio einamoji reikšmė yra fiksuojama ir įrašoma į registrą, kurį galima nuskaityti panaudojant funkcijas:

TimerValueGet (16bitų modulis) arba TimerValueGet64 (32bitų modulis)

Skaitliukas sukasi toliau ir užfiksavęs sekantį signalo frontą, į tą patį registrą vėl yra įrašoma einamoji taimerio skaitiklio reikšmė.  Taigi atsiradus pertraukimų rodyklei, reikia spėti nuskaityti pirmają reikšmę, atsiradus sekačiam pertraukimui, reikšmė  nuskaitoma dar kartą. Šių dviejų reikšmių skirtumas bus laikas tarp dviejų signalo frontų.

Taimerio skaitiklio ribinė (maksimali) reikšmė, įskaitant prescaler reikšmę, dirbant UP režimu yra  0xFFFFFF (16bitų modulis) arba 0xFFFFFFFFFFFF (32bitų modulis)

Taimerio skaitiklio ribinė (minimali) reikšmė, dirbant DOWN režimu, abiejų tipų moduliuose yra 0x00

Jeigu taimerio skaitiklis pasiekia ribinę reikšmę,dirbdamas UP režimu, skaitiklis restartuoja nuo  0x00 reikšmės

Jeigu taimerio skaitiklis pasiekia ribinę reikšmę,dirbdamas DOWN režimu, skaitiklis restartuoja nuo nustatytos taimerio starto pradines reikšmes.

Dirbant Edge Timing Mode režimu, jeigu bus dirbama DOWN, reikia įvesti taimerio starto pradines reikšmes

naudojant funkcijas,  TimerLoadSet ir TimerPrescaleSet (16bitų modulis) arba TimerLoadSet64 ir TimerPrescaleSet (32bitų modulis)

Jeigu bus dirbama režimu UP, visose šiose funkcijose rašoma reikšmė 0x00, arba jos nenaudojamos, nes pagal default šių funkcijų pradinės reikšmės yra 0x00

Dirbant Edge Timing Mode režimu, teimeris gali užfiksuoti trijų tipų reikšmes: tarpas tarp kylančių frontų, tarpas tarp besileidžiančių frontų, arba tarpas tarp kylančio ir besileidžiančio fronto (rising edge, falling edge, or both).

 Dirbant Edge Timing Mode režimu, yra veikiantis, t.y galimas, tik vienas pertraukimas, t.y capture mode event kurio parametras TIMER_CAPA_EVENT arba TIMER_CAPB_EVENT 

 

Taimerio konfiguravimas 

Žemiau  Edge Timing Mode režimo konfiguravimas  aprašytas paimant konkretų mikrovaldiklio taimerį.

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 Edge Timing Mode režime
// galimi parametrai TIMER_CFG_A_CAP_TIME_UP, TIMER_CFG_A_CAP_TIME

TimerConfigure(TIMER0_BASE, TIMER_CFG_SPLIT_PAIR | TIMER_CFG_A_CAP_TIME_UP);

// nustatome, kad taimeris reaguotų į kylantį signalo frontą
// 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);

// jeigu reikalinga, nurodome taimerio reiksme
//TimerLoadSet(TIMER0_BASE, TIMER_A, 200);

// leidziame 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į
TimerEnable(TIMER0_BASE, TIMER_A);

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

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

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

void init_edge_timing_mode ( ) {

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_CAP_TIME_UP);
TimerControlEvent(TIMER0_BASE, TIMER_A, TIMER_EVENT_POS_EDGE);

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

//TimerLoadSet(TIMER0_BASE, TIMER_A, 200);

IntEnable(INT_TIMER0A);

TimerIntEnable(TIMER0_BASE, TIMER_CAPA_EVENT);

IntMasterEnable();

TimerEnable(TIMER0_BASE, TIMER_A);

}

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

Po taimerio konfiguravimo, svarbiausia yra pertraukimų funkcija, kuri bus vykdoma nedelsiant, kai tik suveiks taimerio pertraukimų rodyklė. Šią funkciją kiekvienas programuotojas turi susikurti pagal tai koks uždavinys yra keliamas, įvertinant tai, kad iš pertraukimų funkcijos būtina išeiti kuo greičiau, tam kad išvengti programos darbo konfliktų ir duomenų iškraipymo.

Pertraukimų funkcijoje pirmiausia reikia ištrinti pertraukimų rodyklę funkcijos TimerIntClear pagalba.

Pertraukimų funkcijoje taippat reikia stebėti skaitiklio ribines reikšmes, nes taimeriui restartuojant, pasiekus šią reikšmę, gali būti neteisingai apskaičiuojami reikalingi parametrai.

 Taimerio einamoji (užfiksuota) reikšmė nuskaitoma pertraukimų funkcijoje naudojant funkciją  TimerValueGet (16bitų modulis) arba TimerValueGet64 (32bitų modulis)

 Pvz.:

void timer_interrupt()

{

// Clear the timer interrupt

TimerIntClear(TIMER0_BASE, TIMER_CAPA_EVENT);

//-------------------//

//programinis kodas

//-------------------//

}

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

Žemiau pateiktas programos kodas, skirtas taimerio Edge Timing Mode darbo režimo pavaizdavimui.

Gaunamų reikšmių pavaizdavimui ir debuginimui šiame pavyzdyje panaudotas UART terminalas.

Šiame pavyzdyje įeinanti signalas yra paimamas nuo PD0  išvado, kuris Stellaris LaunchPad plokštėje, per 0om rezistorių, yra sujungtas su šiame pavyzdyje naudojamu taimerio CCP išvadu PB6

Pavyzdys skirtas tik susipažinti su nagrinėjamu taimerio darbo režimu, kuriame galima pabandyti keisti skaitines parametrų reikšmes  ir taimerio konfiguravimą pagal galimus šiam režimui nustatymus.

Taip pat galima bandyti paduoti realų signalą nuo išorinio impulsų šaltinio, redaguojant programos kodą esantį while cikle .

Šio projekto failai 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"
#include "driverlib/uart.h"
#include "driverlib/string.h"
#include "driverlib/stdlib.h"//for ltoa(..);

#define SW1  GPIO_PIN_4

unsigned int state;
unsigned int PD0_state;
unsigned long Period;
unsigned long value_edge1;
unsigned long value_edge2;
unsigned long edge_period;
unsigned long edge_num;

char buf[];

void UARTSend(char *string);

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

//interrupt
void Timer0IntHandler(void)
{

// Clear the timer interrupt
TimerIntClear(TIMER0_BASE, TIMER_CAPA_EVENT);

edge_num ++;

if(edge_num==1){

 value_edge1 = TimerValueGet(TIMER0_BASE,TIMER_A);

}

if(edge_num==2){

 value_edge2 = TimerValueGet(TIMER0_BASE,TIMER_A);

 edge_period = value_edge2-value_edge1;

 if( (0xFFFFFF-edge_period)>edge_period ){

 ltoa(edge_period, buf);

 UARTSend(buf);

 UARTSend("\n");

   }

 edge_num =0;

}

//state = ~state&0x08;

//GPIOPinWrite(GPIO_PORTF_BASE, GPIO_PIN_3,state);

}//end interrupt

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

void main(void) {     

       SysCtlClockSet(SYSCTL_SYSDIV_5|SYSCTL_USE_PLL| SYSCTL_XTAL_16MHZ|SYSCTL_OSC_MAIN);

       SysCtlPeripheralEnable(SYSCTL_PERIPH_GPIOF);

       GPIOPinTypeGPIOOutput(GPIO_PORTF_BASE, GPIO_PIN_3);

       GPIOPinWrite(GPIO_PORTF_BASE, GPIO_PIN_3, 0x00);

       //configure SW1

       GPIOPadConfigSet(GPIO_PORTF_BASE, SW1, GPIO_STRENGTH_8MA,GPIO_PIN_TYPE_STD_WPU);

           //UART initialization

           SysCtlPeripheralEnable(SYSCTL_PERIPH_GPIOD);

           // Unlock PD7

           HWREG(GPIO_PORTD_BASE + GPIO_O_LOCK) = GPIO_LOCK_KEY_DD;

           HWREG(GPIO_PORTD_BASE + GPIO_O_CR) |=  GPIO_PIN_7;

           HWREG(GPIO_PORTD_BASE + GPIO_O_LOCK) = 0;

           SysCtlPeripheralEnable(SYSCTL_PERIPH_UART2);

           // Set GPIO PD6 RX  and PD7 TX as UART pins.

           GPIOPinConfigure(GPIO_PD6_U2RX);

           GPIOPinConfigure(GPIO_PD7_U2TX);

           GPIOPinTypeUART(GPIO_PORTD_BASE, GPIO_PIN_6 | GPIO_PIN_7);

           // Configure the UART for 115,200, 8-N-1 operation.

UARTConfigSetExpClk(UART2_BASE, SysCtlClockGet(), 115200,(UART_CONFIG_WLEN_8 | UART_CONFIG_STOP_ONE |UART_CONFIG_PAR_NONE));

            UARTFIFODisable(UART2_BASE);

          //End UART initialization

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

              //konfiguruojam PD0

               SysCtlPeripheralEnable(SYSCTL_PERIPH_GPIOD);

              GPIOPinTypeGPIOOutput(GPIO_PORTD_BASE, GPIO_PIN_0);

              GPIOPinWrite(GPIO_PORTD_BASE, GPIO_PIN_0, 0x00);

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

            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_CAP_TIME_UP);

            TimerControlEvent(TIMER0_BASE, TIMER_A, TIMER_EVENT_POS_EDGE);

            //jeigu reikalinga, įrašome prescalerio reikšmę

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

            // jeigu reikalinga, nurodome taimerio reiksme

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

            //nurodome taimerio starto reiksme

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

 

       IntEnable(INT_TIMER0A);

       TimerIntEnable(TIMER0_BASE, TIMER_CAPA_EVENT);

       IntMasterEnable();

       TimerEnable(TIMER0_BASE, TIMER_A);

 

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

state = 0x08;

PD0_state=0x01;

edge_num =0;

Period = 300000;

while(1){

                           //Press SW1

                           if( !GPIOPinRead(GPIO_PORTF_BASE, SW1))

                           {

                             SysCtlDelay(500000);

                             Period -=1000;

                             if(Period==0){Period=300000;}

                           }

       SysCtlDelay(Period);

       PD0_state = ~PD0_state&0x01;

       GPIOPinWrite(GPIO_PORTD_BASE, GPIO_PIN_0,PD0_state);

}

}

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

void

UARTSend(char *string)

{

       unsigned long Idx;

       unsigned long string_lenght;

       string_lenght =  strlen(string);

        for(Idx = 0; Idx<string_lenght; Idx++)

                {

               UARTCharPut(UART2_BASE, string[Idx]);

                }

 

}
//'''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''