TMR定时器捕捉(Capture)

前言:
在CH579官方例程中,已经有了通过定时器翻转IO口、定时器产生PWM输出、定时器产生CAP捕捉(DMA通道)、定时器产生计数器的相关例程。本篇博客主要是通过定时器1产生CAP捕获功能并作讲解。

一、操作
使用CH579芯片进行定时器的CAP捕捉,首先需要注意的是引脚功能,PA10是作为低频振荡器的输入端。使用该引脚进行捕捉,需要释放该引脚原先的功能,所以第一步是启用芯片内部32K,同时程序中关闭外部低频晶振引脚功能。

PWR_UnitModCfg( DISABLE, UNIT_SYS_LSE );     // 注意此引脚是LSE晶振引脚,要保证关闭才能使用其他功能

CH579的定时器是26位,所以最大超时为3FFFFFF。在捕捉时我们可以自由设置超时时间。如下图,设置超时为FFFF,则在打印时我们将红框里的数据全部相加,然后将所得值除以主频,便得到了捕获的值((0x0000ffff×6 + 1a84) / 40M ,结果如下图可见)。如果,设置超时时间为默认值即3FFFFFF,则会打印为00061a7e,将得到的值除以40M,结果是一样的(0x00061a7e / 40M)。详细讲解见CH579的芯片手册。

 

二、程序

/*程序:(使用40M的时钟进行CAP捕捉。需注意开启PLL电源控制位)*/
UINT32 capbuf[200];
UINT16 caplen = 0;
void DebugInit(void) //配置串口1打印
{
    GPIOA_SetBits(GPIO_Pin_9);
  GPIOA_ModeCfg(GPIO_Pin_8, GPIO_ModeIN_PU);
  GPIOA_ModeCfg(GPIO_Pin_9, GPIO_ModeOut_PP_5mA);
  UART1_DefInit();
}
int main()
{    
  SetSysClock(CLK_SOURCE_PLL_40MHz);  //R8_HFCK_PWR_CTRL |= RB_CLK_PLL_PON;  //打开PLL电源控制位
  DebugInit(); //配置串口调试
#if 1       /* 定时器3,PWM输出 */   //此为被捕捉的方波,由定时器产生
  GPIOA_ResetBits( GPIO_Pin_2 );            // 配置PWM口 PA2
  GPIOA_ModeCfg( GPIO_Pin_2, GPIO_ModeOut_PP_5mA );
  TMR3_PWMInit( High_Level, PWM_Times_1 );
  TMR3_PWMCycleCfg( 400000 ); // 周期 10ms
  TMR3_Disable();
  TMR3_PWMActDataWidth( 200000 ); // 占空比设置 , 修改占空比必须暂时关闭定时器
  TMR3_Enable();
  while(1);
#endif  

#if 1
    PWR_UnitModCfg( DISABLE, UNIT_SYS_LSE );                  // 注意此引脚是LSE晶振引脚,要保证关闭才能使用其他功能
    GPIOA_ResetBits( GPIO_Pin_10 );                           // 配置PWM口 PA10
    GPIOA_ModeCfg( GPIO_Pin_10, GPIO_ModeIN_PU );
    TMR1_CapInit( FallEdge_To_FallEdge );                   //下降沿到下降沿  & 计数下降沿
    TMR1_CAPTimeoutCfg( 0xFFFF );                         // 设置捕捉超时时间,最大为3FFFFFF(定时器为26位)
    TMR1_ITCfg(ENABLE,RB_TMR_IE_DATA_ACT|RB_TMR_IE_CYC_END);       //配置中断使能寄存器
    NVIC_EnableIRQ( TMR1_IRQn );                        //开启定时器1中断
    mDelaymS(3);
    while(1)                                    //中断中产生的数据在这里打印出来
    {    
      if(caplen > 200)                              //一次打印200个,可根据需求增减
        {
            NVIC_DisableIRQ( TMR1_IRQn );                   //打印时关闭中断,防止继续捕获
            TMR1_ITCfg(DISABLE,RB_TMR_IE_DATA_ACT|RB_TMR_IE_CYC_END);  //打印时关闭中断,防止继续捕获
            for(caplen = 0; caplen < 200; caplen++)
            {
              printf( "capbuf = %08lx\n", capbuf[caplen]);        //打印CAP捕捉值
            }
      }
    }
#endif
}
 
void TMR1_IRQHandler( void )                    // TMR1 定时中断
{
  UINT16 i ;
    if( TMR1_GetITFlag(RB_TMR_IF_DATA_ACT) )        //进入普通捕捉(普通与超时:有且仅有二选一)
  {
      capbuf[caplen] = R32_TMR1_FIFO;            //采集的值放在FIFO寄存器中
    caplen++;                         //设置捕捉次数,本次为200(可增减)
    TMR1_ClearITFlag( RB_TMR_IF_DATA_ACT );        // 清除中断标志  
  }
  if( TMR1_GetITFlag( RB_TMR_IF_CYC_END ) )       //进入超时捕捉(普通与超时:有且仅有二选一)
  {
    capbuf[caplen] = R32_TMR1_CNT_END;          //计数终值寄存器,即设置捕捉超时的时间
    caplen++;
    TMR1_ClearITFlag( RB_TMR_IF_CYC_END );         // 清除中断标志  
  }
}

CH592捕捉:

CH592捕获定时器产生PWM波形

#include "CH59x_common.h"
__attribute__((aligned(4))) uint32_t CapBuf[200];
volatile UINT32 capbuf[200];
volatile UINT16 caplen = 0;
volatile uint8_t capFlag = 0;;

void DebugInit(void){
    GPIOB_SetBits(GPIO_Pin_7);
    GPIOB_ModeCfg(GPIO_Pin_4, GPIO_ModeIN_PU);
    GPIOB_ModeCfg(GPIO_Pin_7, GPIO_ModeOut_PP_5mA);
    UART0_DefInit();
}

int main(){
    SetSysClock(CLK_SOURCE_PLL_60MHz);
    DebugInit();
    UART0_BaudRateCfg(1500000);
    PRINT("Start @ChipID=%02X\n", R8_CHIP_ID);

/* 定时器3,PWM输出 */
    GPIOB_ResetBits(GPIO_Pin_22); // 配置PWM口 PB22
    GPIOB_ModeCfg(GPIO_Pin_22, GPIO_ModeOut_PP_5mA);
    TMR3_PWMInit(High_Level, PWM_Times_1);
    TMR3_PWMCycleCfg(60 * 10); // 周期 100us  最大67108864
    TMR3_PWMActDataWidth(30 * 10); // 占空比 50%, 修改占空比必须暂时关闭定时器
    TMR3_PWMEnable();
    TMR3_Enable();
//xxx 捕获
    mDelaymS(3000);
    PWR_UnitModCfg(DISABLE, UNIT_SYS_LSE); // 注意此引脚是LSE晶振引脚,要保证关闭才能使用其他功能
    GPIOA_ResetBits(GPIO_Pin_10);          // 配置PWM口 PA10
    GPIOA_ModeCfg(GPIO_Pin_10, GPIO_ModeIN_PU);

    TMR1_CapInit(Edge_To_Edge);
    TMR1_CAPTimeoutCfg(0xFFF); // 设置捕捉超时时间
    TMR1_DMACfg(ENABLE, (uint16_t)(uint32_t)&CapBuf[0], (uint16_t)(uint32_t)&CapBuf[100], Mode_Single);
    TMR1_ITCfg(ENABLE, TMR1_2_IT_DMA_END); // 开启DMA完成中断
    PFIC_EnableIRQ(TMR1_IRQn);

    while(1){
        if(capFlag == 1){
            capFlag = 0;
            for(uint8_t i = 0; i < 100; i++)
            {
                PRINT("%08lx\n", CapBuf[i]& 0x3ffffff); // 26bit, 最高位表示 高电平还是低电平
            }printf("\n");
        }
    }
    while(1);
}

__attribute__((interrupt("WCH-Interrupt-fast")))
__attribute__((section(".highcode")))
void TMR1_IRQHandler(void) // TMR0 定时中断
{
    printf("IRQ\n");
    if(TMR1_GetITFlag(TMR1_2_IT_DMA_END))
    {
        TMR1_ITCfg(DISABLE, TMR1_2_IT_DMA_END);//使用单次DMA功能+中断,注意完成后关闭此中断使能,否则会一直上报中断。
        TMR1_ClearITFlag(TMR1_2_IT_DMA_END);    // 清除中断标志
        capFlag = 1;
    }
}

26bit为高代表捕捉到高电平,为低代表低电平。

0x12c是波形长度,为300,与PWM边沿吻合。

posted @ 2022-03-21 15:43  SweetTea_lllpc  阅读(760)  评论(0编辑  收藏  举报