ARM7MODA: PWM Blinker @ KEIL

В рамках примера кода для модуля ARM7MODA продолжим выкладывать примеры кодов. Что такое ШИМ (PWM) Вы можете прочитать тут — http://en.wikipedia.org/wiki/Pulse-width_modulation. Визуально, если изменять скважность сигнала, на осциллографе это выглядит примерно так:

ШИМ  ШИМ

Картинки взяты с сайта: http://myrobot.ru/stepbystep/rce_pwm.php и http://www.pcports.ru/articles/avr3.php

Как Вы видите смысл заключается в том, что меняется длительность логического «1» к логической «0» (иногда, наоборот). А если быть еще точнее, то меняется длиительность импульса, по отношению к всему периоду, это соотношение называется — «скважность».

Режим ШИМ можно реализовать на базе AT91SAM7S, благодаря внутреннему аппартному контроллеру.

Представляю вашему вниманию модернизированный фрагмент программы в которой продемонстрирован режим работы периферии ШИМ (PWM). В данном примере осуществляется не просто мигание светодиодами на пинах GPIO0..2, и мигание плавно загорающееся.

Этот пример основан на базе экземпла от Keil v4.10.

 

Код:

#include "AT91SAM7S64.H"    /* AT91SAMT7S64 definitions  */
#include "Board.h"
//#include "AT91SAM7S64.h"

// Simple program that runs PWM channel 0
// connect the output (PA11) to an LED

//#define  PORT_PWM              11
#define  PORT_PWM0              0
#define  PORT_PWM1              1
#define  PORT_PWM2              2

#define  PORT_MASK(nBit) (1 < < nBit)
#define  TRUE                   1
#define  FALSE                  0 

typedef  unsigned char       BOOL;
typedef  unsigned char       BYTE;   

//#define  PORT_PWM             11
#define  PORT_PWM0              0
#define  PORT_PWM1              1
#define  PORT_PWM2              2

#define  PORT_MASK(nBit) (1 << nBit)

#define  TRUE                   1
#define  FALSE                  0

typedef  unsigned char       BOOL;
typedef  unsigned char       BYTE;

// ------------------------------------------------------------
// Init() initializes the Flash, the watchdog timer, the Power
// Management Controller (PMC), and the PIO port.
// See the steps outlined in the section titled "Programming
// Sequence" of the Atmel AT91SAM7S data sheet (Section 26.7 )
// to program the PMC.
// ------------------------------------------------------------
void Init(void)
{
AT91PS_PMC pPMC;
AT91PS_PIO pPIO;

// --- set flash memory parameters ---
// MCK will be set to 47.92 MHz (approximately 48MHz) below
// so set FMCN=48.  Add minimal wait states since we are above 40 MHz.
 AT91C_BASE_MC->MC_FMR = ( (AT91C_MC_FMCN) & (48 < < 16) ) |
                            AT91C_MC_FWS_1FWS ;

// --- disable the watchdog timer ---
 AT91C_BASE_WDTC->WDTC_WDMR = AT91C_WDTC_WDDIS;

// --- program the Power Management Controller (PMC) ---
// steps are as given in Section 26.7 "Programming Sequence"

 pPMC = AT91C_BASE_PMC;

// 1. start the "main oscillator" (Section 25.3.3)
// slow clock frequency = 32.768 KHz
// slow clock period = 30.5176 microseconds
// Start up time = 8*7*30.5176 = 1708.984375 microseconds or 1.709 milliseconds
 pPMC->PMC_MOR = ( AT91C_CKGR_OSCOUNT & (0x07 < < 8 ) ) |
                   AT91C_CKGR_MOSCEN;

// 2. check the main oscillator frequency (optional)
// skipped

// wait the master clock to settle
 while( !(pPMC->PMC_SR & AT91C_PMC_MOSCS) );

// 3. set the PLL and the divider
// main clock or (crystal) frequency = 18.432MHz)
// use: USBDIV=1, DIV=5, MUL=25, and OUT=0, which yields,
// (18.432/5)*(25+1)=95,8464MHz
// for a LOCK time of 1000 microseconds (1 milliseconds),
// set PLLCOUNT to 1000/30.5176=33
 pPMC->PMC_PLLR = ( (AT91C_CKGR_DIV & 5) |
                    (AT91C_CKGR_PLLCOUNT & (33 < < 8)) |
					(AT91C_CKGR_MUL & (25 << 16)) |
					(AT91C_CKGR_USBDIV & (1 << 28)) );

// wait for the PLL to stabalize
 while ( !(pPMC->PMC_SR & AT91C_PMC_LOCK) );
// wait for the "master clock ready" flag
 while ( !(pPMC->PMC_SR & AT91C_PMC_MCKRDY) );

// 4. select the master clock source and the prescalar
// source    = the PLL clock
// prescalar = 2
 pPMC->PMC_MCKR = AT91C_PMC_CSS_PLL_CLK |
//                  AT91C_PMC_PRES_CLK_2;
                  AT91C_PMC_PRES_CLK;
 while( !(pPMC->PMC_SR & AT91C_PMC_MCKRDY) );

// 5. select programmable clocks
// (programmable clocks are not used in this application)

// 6. enable the peripheral clock used by PIOA and PWMC
 pPMC->PMC_PCER = ( 1 < < AT91C_ID_PIOA) |
                  ( 1 << AT91C_ID_PWMC );

// initializ the port defined as PORT_LED as an output port.

 pPIO = AT91C_BASE_PIOA;
//configure the PIO register used by the PWM channel 0
/*
 pPIO->PIO_PDR = PORT_MASK(PORT_PWM0); // PWM port is controlled by the peripheral
 //pPIO->PIO_BSR = PORT_MASK(PORT_PWM); // PWM port is peripheral B (multiplexed with PA11)
 pPIO->PIO_ASR = PORT_MASK(PORT_PWM0); // PWM port is peripheral A (multiplexed with PA2)
*/
// PWM port is controlled by the peripheral
 pPIO->PIO_PDR = PORT_MASK(PORT_PWM0)|PORT_MASK(PORT_PWM1)|PORT_MASK(PORT_PWM2);
// PWM port is peripheral A (multiplexed with PA0..2)
 pPIO->PIO_ASR = PORT_MASK(PORT_PWM0)|PORT_MASK(PORT_PWM1)|PORT_MASK(PORT_PWM2);
}
// ------------------------------------------------------------
/*
BOOL GetPort(BYTE bPort)
{
AT91PS_PIO pPio;

 pPio = AT91C_BASE_PIOA;
 return( ( pPio->PIO_PDSR & PORT_MASK(bPort) )?TRUE:FALSE );  // return BOOL
}
// ------------------------------------------------------------
void SetPort(BYTE bPort, BOOL bState)
{
AT91PS_PIO pPio;

 pPio = AT91C_BASE_PIOA;
 if (bState) pPio->PIO_SODR = PORT_MASK(bPort);
    else pPio->PIO_CODR = PORT_MASK(bPort);
}
*/
// ------------------------------------------------------------
int main(void)
{
AT91PS_PWMC     pPwmc;
AT91PS_PWMC_CH  pPwmCh0;
AT91PS_PWMC_CH  pPwmCh1;
AT91PS_PWMC_CH  pPwmCh2;

//volatile int     n = 0, nDC = 0;
volatile int     n = 0;
//volatile int     nDC = 0;
volatile unsigned int  nDC = 0;
volatile unsigned int  nDC0 = 0;
volatile unsigned int  nDC1 = 0;
volatile unsigned int  nDC2 = 0;

// perform initialization tasks
 Init();

// enable pwm channel 0 -- no interrupts
 pPwmc = AT91C_BASE_PWMC;
 //pPwmc->PWMC_MR = 0x00000fff; // preB-divB-preA-divA
 pPwmc->PWMC_ENA = 0x07;  // enable pwm channel 0-2

 pPwmCh0             = AT91C_BASE_PWMC_CH0;
 pPwmCh0->PWMC_CMR   = 0x030A; // polarity 1 (start high), PWM_CLK = MCK/1024
 pPwmCh0->PWMC_CPRDR = 0x100;  // period
 pPwmCh0->PWMC_CDTYR = 0x0;   // duty cycle

 pPwmCh1             = AT91C_BASE_PWMC_CH1;
 pPwmCh1->PWMC_CMR   = 0x030A; // polarity 1 (start high), PWM_CLK = MCK/1024
 pPwmCh1->PWMC_CPRDR = 0x100;  // period
 pPwmCh1->PWMC_CDTYR = 0x0;   // duty cycle

 pPwmCh2             = AT91C_BASE_PWMC_CH2;
 pPwmCh2->PWMC_CMR   = 0x030A; // polarity 1 (start high), PWM_CLK = MCK/1024
 pPwmCh2->PWMC_CPRDR = 0x100;  // period
 pPwmCh2->PWMC_CDTYR = 0x30;   // duty cycle

 nDC0 = (100/3)*3;
 nDC1 = (100/3)*2;
 nDC2 = (100/3)*1;

// endless loop blinks the LED
 while(TRUE)
  {
   for(n=0; n<0x80000; n++);	// delay between iterations

   nDC0++;
   if ( 0x50 > nDC0 )
     pPwmCh0->PWMC_CUPDR=nDC0;
   else nDC0=0;

   nDC1++;
   if ( 0x50 > nDC1 )
     pPwmCh1->PWMC_CUPDR=nDC1;
   else nDC1=0;

   nDC2++;
   if ( 0x50 > nDC2 )
     pPwmCh2->PWMC_CUPDR=nDC2;
   else nDC2=0;
  }
}
// -------------------------------------------------------------
// end of module main
// -------------------------------------------------------------

 

Добавить комментарий