EFM32片内外设--PCNT之External Clock

在官方的Application note中,我们可以看到PCNT的过采样的例程,是以32KHz的时钟源作为参考时钟源的。另外也有一个正交编码,虽然使用的是外部信号作为PCNT模块的时钟,但是我们很少会使用正交编码。

另,我们也只有自己用过,才能比较好的掌握这种功能方式。所以,我们还是用我们的STK,来了解一下PCNT是如何用外部信号作为时钟的。

但是有一点注意的是,就是同步的问题。因为如果外部信号是一个低速信号,而我们又需要修改PCNT的工作方式时,同步会占用很长的时间。

因此,如果是低速信号,还是建议使用32768来过采样外部信号的方式,来数脉冲信号。但是如果是高速外部信号,则可以使用该信号既做信号又做时钟。

另外一个注意的地方就是,G系列的PRS不支持PCNT。而TG系列,PCNT甚至可以数从PRS输过来的脉冲信号。详情看LESense的demo。

而配合定时器Timer,也可以数脉冲的频率。

硬件准备:

使用TG STK。 脉冲信号通过Timer 产生,程序里使用了Timer0的CCP0,location3,指向PD1脚。 而PCNT使用PCNT0的S0输入(切记只有S0上的信号才能作为外部时钟)即PD6脚。具体如下图1所示:

外加一颗LED灯(PD7)脚。

另外,想要完成整体的功能,需要将20pin的扩展口的第6脚和低16脚短接。即连接PD1脚和PD6脚。最终效果就是,你可以看到一盏灯每2秒亮灭一次。

软件准备:

没太多复杂的东西,请直接看例程:

#include "efm32.h"
#include "efm32_cmu.h"
#include "efm32_emu.h"
#include "efm32_gpio.h"
#include "efm32_prs.h"
#include "efm32_system.h"
#include "efm32_timer.h"
#include "efm32_chip.h"
#include "efm32_pcnt.h"

/* Define TOP value */
//默认时钟源为14MHz,timer 256分频
//做成一个10Hz的PWM输出
#define TOP 54687 

/*****************************************************
注意点:
LFA clock默认选择的是LFRCO做为时钟源。但是LFRCO复位之后,
默认是关闭状态。
而初始化PCNT,将其切换到外部时钟信号的操作,仍需要使用
LFRCO作为clock,因此才加入了
CMU_ClockSelectSet(cmuClock_LFA, cmuSelect_LFRCO)
*****************************************************/
void PCNT_Initial(void)
{
   
    CMU_ClockSelectSet(cmuClock_LFA, cmuSelect_LFRCO);
    /* Enabling all necessary clocks */
    CMU_ClockEnable(cmuClock_CORELE, true);     /* Enable CORELE clock */
    CMU_ClockEnable(cmuClock_GPIO, true);       /* Enable clock for GPIO module */
    CMU_ClockEnable(cmuClock_PCNT0, true);      /* Enable clock for PCNT module */
   
    //CMU_PCNTClockExternalSet(0,true);
   
    /* Configure PC4 as intput to drive pulse counter */
    GPIO_PinModeSet(gpioPortD, 6, gpioModeInput, 0);
   
    /* Set configuration for pulse counter */
    PCNT_Init_TypeDef pcntInit =
    {
        .mode       = pcntModeExtSingle,//pcntModeOvsSingle,  //  /* clocked by LFACLK */
        .counter    = 0,                  /* Set initial value to 0 */
        .top        = 9,                  /* Set top to max value */
        .negEdge    = false,              /* positive edges */
        .countDown  = false,              /* up count */
        .filter     = true,               /* filter enabled */
    };
   
    /* Initialize Pulse Counter */
    PCNT_Init(PCNT0, &pcntInit);
   
    /* Enable PCNT overflow interrupt */
    PCNT_IntEnable(PCNT0, 0x2);
   
    /* Enable PCNT1 interrupt vector in NVIC */
    NVIC_EnableIRQ(PCNT0_IRQn);
   
    /* Route PCNT1 input to location 0 -> PCNT1_S0IN on PC4 */ 
    PCNT0->ROUTE = PCNT_ROUTE_LOCATION_LOC3;
}

void Timer_Initial(void)
{
    /* Enable clock for GPIO module */
    CMU_ClockEnable(cmuClock_GPIO, true);
   
    /* Enable clock for TIMER0 module */
    CMU_ClockEnable(cmuClock_TIMER0, true);
   
    /* Set CC0 location 3 pin (PD1) as output */
    GPIO_PinModeSet(gpioPortD, 1, gpioModePushPull, 0);
   
    /* Select CC channel parameters */
    TIMER_InitCC_TypeDef timerCCInit =
    {
        .eventCtrl  = timerEventEveryEdge,
        .edge       = timerEdgeBoth,
        .prsSel     = timerPRSSELCh0,
        .cufoa      = timerOutputActionNone,
        .cofoa      = timerOutputActionNone,
        .cmoa       = timerOutputActionToggle,
        .mode       = timerCCModePWM,
        .filter     = false,
        .prsInput   = false,
        .coist      = false,
        .outInvert  = false,
    };
   
    /* Configure CC channel 0 */
    TIMER_InitCC(TIMER0, 0, &timerCCInit);
   
    /* Route CC0 to location 3 (PD1) and enable pin */ 
    TIMER0->ROUTE |= (TIMER_ROUTE_CC0PEN | TIMER_ROUTE_LOCATION_LOC3);
   
    /* Set Top Value */
    TIMER_TopSet(TIMER0, TOP/10);
   
    /* Set compare value starting at 0 - it will be incremented in the interrupt handler */
    TIMER_CompareBufSet(TIMER0, 0, TOP/20);
   
    /* Select timer parameters */ 
    TIMER_Init_TypeDef timerInit =
    {
        .enable     = true,
        .debugRun   = true,
        .prescale   = timerPrescale256,
        .clkSel     = timerClkSelHFPerClk,
        .fallAction = timerInputActionNone,
        .riseAction = timerInputActionNone,
        .mode       = timerModeUp,
        .dmaClrAct  = false,
        .quadModeX4 = false,
        .oneShot    = false,
        .sync       = false,
    };
   
    /* Configure timer */
    TIMER_Init(TIMER0, &timerInit);
}
/**************************************************************************//**
* @brief  Main function
* Main is called from __iar_program_start, see assembly startup file
*****************************************************************************/
int main(void)

    /* Initialize chip */
    CHIP_Init();
    Timer_Initial();
    PCNT_Initial();
   
    GPIO_PinModeSet(gpioPortD, 7, gpioModePushPull, 0);
   
    while(1)
    {
        /* Go to EM1 */
        EMU_EnterEM1();
    }
   
}

void PCNT0_IRQHandler(void)
{  
    /* Clear PCNT1 overflow interrupt flag */
    PCNT_IntClear(PCNT0, 0x2);
    GPIO_PinOutToggle(gpioPortD, 7);
}

 

 

你可能感兴趣的:(EFM32片内外设--PCNT)