查看: 2045|回复: 0
收起左侧

第九章:CH32V103应用教程——输入捕获

[复制链接]

  离线 

  • TA的每日心情
    慵懒
    2021-7-23 17:16
  • 签到天数: 17 天

    [LV.4]

    发表于 2021-4-23 00:24:16 | 显示全部楼层 |阅读模式

    有人预言,RISC-V或将是继Intel和Arm之后的第三大主流处理器体系。欢迎访问全球首家只专注于RISC-V单片机行业应用的中文网站

    您需要 登录 才可以下载或查看,没有帐号?立即注册

    x
    本帖最后由 草帽王子 于 2021-9-10 16:27 编辑

    本章教程通过CH32V103开发板PA8引脚检测PWM脉宽和周期,并通过串口调试助手打印显示。


    1、输入捕获简介及相关函数介绍


    输入捕获模式是定时器的基本功能之一,其通常用于测量频率或者测量脉宽。

    输入捕获可对输入信号的上升沿、下降沿或者双边沿进行捕获,其捕获原理为:当发生并捕获信号跳变沿之后,计数器(CNT)值将被锁存到捕获比较寄存器(CCR)中,将前后两次捕获到的CCR寄存器中的值相减,即可计算出频率或者脉宽。如果捕获脉宽时长超过捕获定时器的周期,会发生溢出,此时需要进行额外处理。

    关于定时器输入捕获具体介绍,可参考CH32V103应用手册。输入捕获程序所需函数所在库函数在定时器中断教程中已介绍,本章不做过多介绍。


    2、硬件设计

    本章教程使用输入捕获中PWM输入模式,需要用到两个开发板,一个用于产生PWM输出,一个用于输入捕获。本章教程使用两个CH32V103开发板,一个直接下载CH32V103 EVT中PWM输出例程,一个直接下载本章教程中例程,然后将两个开发板PA8引脚连接起来。


    3、软件设计

    本章教程使用PWM输入模式进行输入捕获,其使用两个通道和两个捕获寄存器,具体实现方式为:当使用PWM输入模式时,PWM信号由输入通道TI1进入,配置滤波后的定时器输入1(TI1FP1)为触发信号并设置上升沿捕获。当上升沿的时候捕获比较通道IC1和IC2同时捕获,计数器CNT清零,到了下降沿的时候,IC2捕获,此时计数器CNT的值被锁存到捕获比较寄存器CCR2中,到了下一个上升沿的时候,IC1捕获,计数器CNT 的值被锁存到捕获比较寄存器CCR1中。其中CCR2+1测量的是脉宽, CCR1+1测量的是周期。这里要注意的是 CCR2 和 CCR1 的值在计算占空比和频率的时候都必须加1,因为计数器是从0开始计数的。

    使用PWM输入模式实现输入捕获具体程序如下:

    capture.h文件
    1. #ifndef __CAPTURE_H
    2. #define __CAPTURE_H

    3. #include "ch32v10x_conf.h"

    4. void Input_Capture_Init( u16 arr, u16 psc );
    5. void TIM1_CC_IRQHandler(void);

    6. #endif
    复制代码
    capture.h文件主要是函数的声明。

    capture.c文件
    1. #include "capture.h"

    2. void TIM1_CC_IRQHandler(void) __attribute__((interrupt("WCH-Interrupt-fast")));

    3. /* ----------------   PWM信号 周期和占空比的计算--------------- */
    4. // arr :自动重装载寄存器的值
    5. // clk_cnt:计数器的时钟,等于 Fck_int / (psc+1) = 72M/(psc+1)
    6. // PWM信号的周期 T = (arr +1)* (1/clk_cnt) = arr*(psc+1) / 72M
    7. // 占空比P=CCR/(arr+1)
    8. /*******************************************************************************
    9. * Function Name  : Input_Capture_Init
    10. * Description    : Initializes TIM1 input capture.
    11. * Input          : arr: the period value.
    12. *                  psc: the prescaler value.
    13. *                  ccp: the pulse value.
    14. * Return         : None
    15. *******************************************************************************/
    16. void Input_Capture_Init( u16 arr, u16 psc )
    17. {
    18.     GPIO_InitTypeDef GPIO_InitStructure;
    19.     TIM_TimeBaseInitTypeDef TIM_TimeBaseInitStructure;
    20.     TIM_ICInitTypeDef TIM_ICInitStructure;
    21.     NVIC_InitTypeDef NVIC_InitStructure;

    22.     RCC_APB2PeriphClockCmd( RCC_APB2Periph_GPIOA | RCC_APB2Periph_TIM1, ENABLE );//使能GPIOA时钟和TIM1时钟

    23.     GPIO_InitStructure.GPIO_Pin = GPIO_Pin_8;
    24.     GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;
    25.     GPIO_Init( GPIOA, &GPIO_InitStructure);
    26.     GPIO_ResetBits( GPIOA, GPIO_Pin_8 );

    27.     //定时器周期,实际就是设定自动重载寄存器 ARR 的值, ARR 为要装载到实际自动重载寄存器(即影子寄存器) 的值, 可设置范围为 0 至 65535。
    28.     TIM_TimeBaseInitStructure.TIM_Period = arr;
    29.     //定时器预分频器设置,时钟源经该预分频器才是定时器计数时钟CK_CNT,它设定 PSC 寄存器的值。
    30.     //计算公式为: 计数器时钟频率 (fCK_CNT) 等于fCK_PSC / (PSC[15:0] + 1),可实现 1 至 65536 分频。
    31.     TIM_TimeBaseInitStructure.TIM_Prescaler = psc;
    32.     //时钟分频,设置定时器时钟 CK_INT 频率与死区发生器以及数字滤波器采样时钟频率分频比。可以选择 1、 2、 4 分频。
    33.     TIM_TimeBaseInitStructure.TIM_ClockDivision = TIM_CKD_DIV1;
    34.     TIM_TimeBaseInitStructure.TIM_CounterMode = TIM_CounterMode_Up; //设置计数模式,向上计数模式
    35.     TIM_TimeBaseInitStructure.TIM_RepetitionCounter =  0x00;        //设置重复计数器的值,0。重复计数器,只有 8 位,只存在于高级定时器。
    36.     TIM_TimeBaseInit( TIM1, &TIM_TimeBaseInitStructure); //初始化

    37.     // 当用作PWM输入捕获模式时,只需要设置触发信号的那一路即可(用于测量周期)
    38.     // 另外一路(用于测量占空比)会由硬件自带设置,不需要再配置

    39.     // TIM_Channel:捕获通道 ICx 选择,可选 TIM_Channel_1、 TIM_Channel_2、TIM_Channel_3 或 TIM_Channel_4 四个通道。
    40.     TIM_ICInitStructure.TIM_Channel = TIM_Channel_1;
    41.     //配置输入捕获预分频器值,如果需要捕获输入信号的每个有效边沿,则设置 1 分频 即可
    42.     TIM_ICInitStructure.TIM_ICPrescaler = TIM_ICPSC_DIV1;
    43.     //输入捕获滤波器设置,可选设置 0x0 至 0x0F。它设定 CHCTLRx 寄存器ICxF[3:0]位的值。一般我们不使用滤波器,即设置为 0
    44.     TIM_ICInitStructure.TIM_ICFilter = 0x0;
    45.     //输入捕获边沿触发选择,可选上升沿触发、下降沿触发或边沿跳变触发。
    46.     TIM_ICInitStructure.TIM_ICPolarity = TIM_ICPolarity_Rising;
    47.     //输入通道选择,捕获通道 ICx 的信号可来自三个输入通道,分别为TIM_ICSelection_DirectTI、 TIM_ICSelection_IndirectTI 或 TIM_ICSelection_TRC
    48.     TIM_ICInitStructure.TIM_ICSelection = TIM_ICSelection_DirectTI;

    49.     TIM_PWMIConfig( TIM1, &TIM_ICInitStructure );

    50.     NVIC_InitStructure.NVIC_IRQChannel = TIM1_CC_IRQn;       //TIM1捕获比较中断
    51.     NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 2;//设置抢占优先级
    52.     NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;       //设置响应优先级
    53.     NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;          //使能通道
    54.     NVIC_Init(&NVIC_InitStructure);

    55.     TIM_ITConfig( TIM1, TIM_IT_CC1 | TIM_IT_CC2, ENABLE ); //使能TIM1捕获中断

    56.     // 选择输入捕获的触发信号
    57.     TIM_SelectInputTrigger(TIM1, TIM_TS_TI1FP1);

    58.     // 选择从模式: 复位模式
    59.     // PWM输入模式时,从模式必须工作在复位模式,当捕获开始时,计数器CNT会被复位
    60.     TIM_SelectSlaveMode(TIM1, TIM_SlaveMode_Reset);
    61.     TIM_SelectMasterSlaveMode(TIM1,TIM_MasterSlaveMode_Enable);
    62.     TIM_Cmd( TIM1, ENABLE );  //定时器使能
    63. }

    64. /*******************************************************************************
    65. * Function Name  : TIM1_CC_IRQHandler
    66. * Description    : This function handles TIM1  Capture Compare Interrupt exception.
    67. * Input          : None
    68. * Output         : None
    69. * Return         : None
    70. *******************************************************************************/
    71. void TIM1_CC_IRQHandler(void)
    72. {

    73.     if( TIM_GetITStatus( TIM1, TIM_IT_CC1 ) != RESET )   //若捕获比较1发生中断
    74.     {
    75.         printf( "cycle:%d\r\n", (TIM_GetCapture1(TIM1)+1) );      //打印得到的捕获比较1寄存器值,其值加1表示周期
    76.         TIM_SetCounter( TIM1, 0 );
    77.     }

    78.     if( TIM_GetITStatus( TIM1, TIM_IT_CC2 ) != RESET )   //若捕获比较2发生中断
    79.     {
    80.         printf( "Pulsewidth:%d\r\n", (TIM_GetCapture2(TIM1)+1) ); //打印得到的捕获比较2寄存器值,其值加1表示脉宽
    81.     }

    82.     TIM_ClearITPendingBit( TIM1, TIM_IT_CC1 | TIM_IT_CC2 ); //清除TIM1捕获比较1和捕获比较2中断挂起位
    83. }

    复制代码


    capture.c文件主要是输入捕获相关函数配置,包括输入捕获相关函数初始化配置和定时器中断服务函数,其具体配置流程如下:


    1、使能GPIOA时钟和TIM1时钟
    1. RCC_APB2PeriphClockCmd( RCC_APB2Periph_GPIOA | RCC_APB2Periph_TIM1, ENABLE );//使能GPIOA时钟和TIM1时钟
    复制代码

    2、GPIO初始化配置
    1. GPIO_InitStructure.GPIO_Pin = GPIO_Pin_8;
    2. GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;
    3. GPIO_Init( GPIOA, &GPIO_InitStructure);
    4. GPIO_ResetBits( GPIOA, GPIO_Pin_8 );
    复制代码

    3、根据TIM_TimeBaseInitStruct中指定的参数初始化TIM1时基单元外围设备。
    1. //定时器周期,实际就是设定自动重载寄存器 ARR 的值, ARR 为要装载到实际自动重载寄存器(即影子寄存器) 的值, 可设置范围为 0 至 65535。
    2.     TIM_TimeBaseInitStructure.TIM_Period = arr;
    3.     //定时器预分频器设置,时钟源经该预分频器才是定时器计数时钟CK_CNT,它设定 PSC 寄存器的值。
    4.     //计算公式为: 计数器时钟频率 (fCK_CNT) 等于fCK_PSC / (PSC[15:0] + 1),可实现 1 至 65536 分频。
    5.     TIM_TimeBaseInitStructure.TIM_Prescaler = psc;
    6.     //时钟分频,设置定时器时钟 CK_INT 频率与死区发生器以及数字滤波器采样时钟频率分频比。可以选择 1、 2、 4 分频。
    7.     TIM_TimeBaseInitStructure.TIM_ClockDivision = TIM_CKD_DIV1;
    8.     TIM_TimeBaseInitStructure.TIM_CounterMode = TIM_CounterMode_Up; //设置计数模式,向上计数模式
    9.     TIM_TimeBaseInitStructure.TIM_RepetitionCounter =  0x00;        //设置重复计数器的值,0。重复计数器,只有 8 位,只存在于高级定时器。
    10.     TIM_TimeBaseInit( TIM1, &TIM_TimeBaseInitStructure); //初始化
    复制代码

    4、输入捕获结构体初始化,配置IC1捕获通道
    1. // TIM_Channel:捕获通道 ICx 选择,可选 TIM_Channel_1、 TIM_Channel_2、TIM_Channel_3 或 TIM_Channel_4 四个通道。
    2.     TIM_ICInitStructure.TIM_Channel = TIM_Channel_1;
    3.     //配置输入捕获预分频器值,如果需要捕获输入信号的每个有效边沿,则设置 1 分频 即可
    4.     TIM_ICInitStructure.TIM_ICPrescaler = TIM_ICPSC_DIV1;
    5.     //输入捕获滤波器设置,可选设置 0x0 至 0x0F。它设定 CHCTLRx 寄存器ICxF[3:0]位的值。一般我们不使用滤波器,即设置为 0
    6.     TIM_ICInitStructure.TIM_ICFilter = 0x0;
    7.     //输入捕获边沿触发选择,可选上升沿触发、下降沿触发或边沿跳变触发。
    8.     TIM_ICInitStructure.TIM_ICPolarity = TIM_ICPolarity_Rising;
    9.     //输入通道选择,捕获通道 ICx 的信号可来自三个输入通道,分别为TIM_ICSelection_DirectTI、 TIM_ICSelection_IndirectTI 或 TIM_ICSelection_TRC
    10.     TIM_ICInitStructure.TIM_ICSelection = TIM_ICSelection_DirectTI;
    复制代码

    5、初始化PWM输入模式
    1. TIM_PWMIConfig( TIM1, &TIM_ICInitStructure );
    复制代码

    6、配置中断优先级
    1. NVIC_InitStructure.NVIC_IRQChannel = TIM1_CC_IRQn;       //TIM1捕获比较中断
    2. NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 2; //设置抢占优先级
    3. NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;            //设置响应优先级
    4. NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;            //使能通道
    5. NVIC_Init(&NVIC_InitStructure);  //NVIC初始化
    复制代码

    7、使能捕获中断
    1. TIM_ITConfig( TIM1, TIM_IT_CC1 | TIM_IT_CC2, ENABLE ); //使能TIM1捕获中断
    复制代码

    8、选择输入捕获触发信号以及主从模式
    1. TIM_SelectInputTrigger( TIM1, TIM_TS_TI1FP1 );                            //选择过滤定时器输入1作为触发源
    2. TIM_SelectSlaveMode( TIM1, TIM_SlaveMode_Reset );                     //TIM1从机模式,所选触发信号(TRGI)的上升沿重新初始化。
    3. TIM_SelectMasterSlaveMode( TIM1, TIM_MasterSlaveMode_Enable );//设置或重置TIM1主从模式,使能定时器与从机之间同步
    复制代码

    9、使能定时器
    1. TIM_Cmd( TIM1, ENABLE );
    复制代码

    10、编写中断服务函数
    1. void TIM1_CC_IRQHandler(void)
    2. {
    3.     if( TIM_GetITStatus( TIM1, TIM_IT_CC1 ) != RESET )   //若捕获比较1发生中断
    4.     {
    5.         printf( "cycle:%d\r\n", (TIM_GetCapture1(TIM1)+1) ); //打印得到的捕获比较1寄存器值,其值加1表示周期
    6.     }
    7.     if( TIM_GetITStatus( TIM1, TIM_IT_CC2 ) != RESET )   //若捕获比较2发生中断
    8.     {
    9.         printf( "Pulsewidth:%d\r\n", (TIM_GetCapture2(TIM1)+1) ); //打印得到的捕获比较2寄存器值,其值加1表示脉宽
    10.     }
    11.     TIM_ClearITPendingBit( TIM1, TIM_IT_CC1 | TIM_IT_CC2 ); //清除TIM1捕获比较1和捕获比较2中断挂起位
    12. }
    复制代码

    capture.c文件主要是进行输入捕获的相关配置以及中断服务函数功能的设置,通过以上配置,即可进行输入捕获并通过中断服务函数打印输出脉宽和周期。

    main.c文件
    1. int main(void)
    2. {
    3.     USART_Printf_Init(115200);
    4.     printf("SystemClk:%d\r\n",SystemCoreClock);

    5.     Input_Capture_Init( 1000-1, 72-1 );

    6.     while(1);
    7. }
    复制代码
    main.c文件主要是相关函数的初始化。


    4、下载验证

    将编译好的程序下载到开发板并复位,将两个开发板PA8引脚连接起来,打开串口调试助手,可看见在不停打印PWM脉宽和周期,具体如下:

    CH32V CH573单片机芯片-第九章:CH32V103应用教程——输入捕获risc-v单片机中文社区(1)

    输入捕获.rar 附件下载
    CH32V CH573单片机芯片-第九章:CH32V103应用教程——输入捕获risc-v单片机中文社区(2) 8、输入捕获.rar (488.51 KB, 下载次数: 14)
    链接:https://pan.baidu.com/s/1L1lF5kzIQfzLbMPJb2nJUg
    提取码:ugio
    复制这段内容后打开百度网盘手机App,操作更方便哦







    上一篇:第八章:CH32V103应用教程——PWM输出
    下一篇:第十章:CH32V103应用教程——ADC
    RISCV作者优文
    全球首家只专注于RISC-V单片机行业应用的中文网站
    回复

    使用道具 举报

    高级模式
    B Color Image Link Quote Code Smilies

    本版积分规则

    关闭

    RISC-V单片机中文网上一条 /2 下一条



    版权及免责声明|RISC-V单片机中文网 |网站地图

    GMT+8, 2024-11-26 09:50 , Processed in 0.526160 second(s), 46 queries .

    快速回复 返回顶部 返回列表