离线
TA的每日心情 | 慵懒 2021-7-23 17:16 |
---|
签到天数: 17 天 [LV.4]
|
有人预言,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文件
- #ifndef __CAPTURE_H
- #define __CAPTURE_H
- #include "ch32v10x_conf.h"
- void Input_Capture_Init( u16 arr, u16 psc );
- void TIM1_CC_IRQHandler(void);
- #endif
复制代码 capture.h文件主要是函数的声明。
capture.c文件
- #include "capture.h"
- void TIM1_CC_IRQHandler(void) __attribute__((interrupt("WCH-Interrupt-fast")));
- /* ---------------- PWM信号 周期和占空比的计算--------------- */
- // arr :自动重装载寄存器的值
- // clk_cnt:计数器的时钟,等于 Fck_int / (psc+1) = 72M/(psc+1)
- // PWM信号的周期 T = (arr +1)* (1/clk_cnt) = arr*(psc+1) / 72M
- // 占空比P=CCR/(arr+1)
- /*******************************************************************************
- * Function Name : Input_Capture_Init
- * Description : Initializes TIM1 input capture.
- * Input : arr: the period value.
- * psc: the prescaler value.
- * ccp: the pulse value.
- * Return : None
- *******************************************************************************/
- void Input_Capture_Init( u16 arr, u16 psc )
- {
- GPIO_InitTypeDef GPIO_InitStructure;
- TIM_TimeBaseInitTypeDef TIM_TimeBaseInitStructure;
- TIM_ICInitTypeDef TIM_ICInitStructure;
- NVIC_InitTypeDef NVIC_InitStructure;
- RCC_APB2PeriphClockCmd( RCC_APB2Periph_GPIOA | RCC_APB2Periph_TIM1, ENABLE );//使能GPIOA时钟和TIM1时钟
- GPIO_InitStructure.GPIO_Pin = GPIO_Pin_8;
- GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;
- GPIO_Init( GPIOA, &GPIO_InitStructure);
- GPIO_ResetBits( GPIOA, GPIO_Pin_8 );
- //定时器周期,实际就是设定自动重载寄存器 ARR 的值, ARR 为要装载到实际自动重载寄存器(即影子寄存器) 的值, 可设置范围为 0 至 65535。
- TIM_TimeBaseInitStructure.TIM_Period = arr;
- //定时器预分频器设置,时钟源经该预分频器才是定时器计数时钟CK_CNT,它设定 PSC 寄存器的值。
- //计算公式为: 计数器时钟频率 (fCK_CNT) 等于fCK_PSC / (PSC[15:0] + 1),可实现 1 至 65536 分频。
- TIM_TimeBaseInitStructure.TIM_Prescaler = psc;
- //时钟分频,设置定时器时钟 CK_INT 频率与死区发生器以及数字滤波器采样时钟频率分频比。可以选择 1、 2、 4 分频。
- TIM_TimeBaseInitStructure.TIM_ClockDivision = TIM_CKD_DIV1;
- TIM_TimeBaseInitStructure.TIM_CounterMode = TIM_CounterMode_Up; //设置计数模式,向上计数模式
- TIM_TimeBaseInitStructure.TIM_RepetitionCounter = 0x00; //设置重复计数器的值,0。重复计数器,只有 8 位,只存在于高级定时器。
- TIM_TimeBaseInit( TIM1, &TIM_TimeBaseInitStructure); //初始化
- // 当用作PWM输入捕获模式时,只需要设置触发信号的那一路即可(用于测量周期)
- // 另外一路(用于测量占空比)会由硬件自带设置,不需要再配置
- // TIM_Channel:捕获通道 ICx 选择,可选 TIM_Channel_1、 TIM_Channel_2、TIM_Channel_3 或 TIM_Channel_4 四个通道。
- TIM_ICInitStructure.TIM_Channel = TIM_Channel_1;
- //配置输入捕获预分频器值,如果需要捕获输入信号的每个有效边沿,则设置 1 分频 即可
- TIM_ICInitStructure.TIM_ICPrescaler = TIM_ICPSC_DIV1;
- //输入捕获滤波器设置,可选设置 0x0 至 0x0F。它设定 CHCTLRx 寄存器ICxF[3:0]位的值。一般我们不使用滤波器,即设置为 0
- TIM_ICInitStructure.TIM_ICFilter = 0x0;
- //输入捕获边沿触发选择,可选上升沿触发、下降沿触发或边沿跳变触发。
- TIM_ICInitStructure.TIM_ICPolarity = TIM_ICPolarity_Rising;
- //输入通道选择,捕获通道 ICx 的信号可来自三个输入通道,分别为TIM_ICSelection_DirectTI、 TIM_ICSelection_IndirectTI 或 TIM_ICSelection_TRC
- TIM_ICInitStructure.TIM_ICSelection = TIM_ICSelection_DirectTI;
- TIM_PWMIConfig( TIM1, &TIM_ICInitStructure );
- NVIC_InitStructure.NVIC_IRQChannel = TIM1_CC_IRQn; //TIM1捕获比较中断
- NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 2;//设置抢占优先级
- NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0; //设置响应优先级
- NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; //使能通道
- NVIC_Init(&NVIC_InitStructure);
- TIM_ITConfig( TIM1, TIM_IT_CC1 | TIM_IT_CC2, ENABLE ); //使能TIM1捕获中断
- // 选择输入捕获的触发信号
- TIM_SelectInputTrigger(TIM1, TIM_TS_TI1FP1);
- // 选择从模式: 复位模式
- // PWM输入模式时,从模式必须工作在复位模式,当捕获开始时,计数器CNT会被复位
- TIM_SelectSlaveMode(TIM1, TIM_SlaveMode_Reset);
- TIM_SelectMasterSlaveMode(TIM1,TIM_MasterSlaveMode_Enable);
- TIM_Cmd( TIM1, ENABLE ); //定时器使能
- }
- /*******************************************************************************
- * Function Name : TIM1_CC_IRQHandler
- * Description : This function handles TIM1 Capture Compare Interrupt exception.
- * Input : None
- * Output : None
- * Return : None
- *******************************************************************************/
- void TIM1_CC_IRQHandler(void)
- {
- if( TIM_GetITStatus( TIM1, TIM_IT_CC1 ) != RESET ) //若捕获比较1发生中断
- {
- printf( "cycle:%d\r\n", (TIM_GetCapture1(TIM1)+1) ); //打印得到的捕获比较1寄存器值,其值加1表示周期
- TIM_SetCounter( TIM1, 0 );
- }
- if( TIM_GetITStatus( TIM1, TIM_IT_CC2 ) != RESET ) //若捕获比较2发生中断
- {
- printf( "Pulsewidth:%d\r\n", (TIM_GetCapture2(TIM1)+1) ); //打印得到的捕获比较2寄存器值,其值加1表示脉宽
- }
- TIM_ClearITPendingBit( TIM1, TIM_IT_CC1 | TIM_IT_CC2 ); //清除TIM1捕获比较1和捕获比较2中断挂起位
- }
复制代码
capture.c文件主要是输入捕获相关函数配置,包括输入捕获相关函数初始化配置和定时器中断服务函数,其具体配置流程如下:
1、使能GPIOA时钟和TIM1时钟
- RCC_APB2PeriphClockCmd( RCC_APB2Periph_GPIOA | RCC_APB2Periph_TIM1, ENABLE );//使能GPIOA时钟和TIM1时钟
复制代码
2、GPIO初始化配置
- GPIO_InitStructure.GPIO_Pin = GPIO_Pin_8;
- GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;
- GPIO_Init( GPIOA, &GPIO_InitStructure);
- GPIO_ResetBits( GPIOA, GPIO_Pin_8 );
复制代码
3、根据TIM_TimeBaseInitStruct中指定的参数初始化TIM1时基单元外围设备。
- //定时器周期,实际就是设定自动重载寄存器 ARR 的值, ARR 为要装载到实际自动重载寄存器(即影子寄存器) 的值, 可设置范围为 0 至 65535。
- TIM_TimeBaseInitStructure.TIM_Period = arr;
- //定时器预分频器设置,时钟源经该预分频器才是定时器计数时钟CK_CNT,它设定 PSC 寄存器的值。
- //计算公式为: 计数器时钟频率 (fCK_CNT) 等于fCK_PSC / (PSC[15:0] + 1),可实现 1 至 65536 分频。
- TIM_TimeBaseInitStructure.TIM_Prescaler = psc;
- //时钟分频,设置定时器时钟 CK_INT 频率与死区发生器以及数字滤波器采样时钟频率分频比。可以选择 1、 2、 4 分频。
- TIM_TimeBaseInitStructure.TIM_ClockDivision = TIM_CKD_DIV1;
- TIM_TimeBaseInitStructure.TIM_CounterMode = TIM_CounterMode_Up; //设置计数模式,向上计数模式
- TIM_TimeBaseInitStructure.TIM_RepetitionCounter = 0x00; //设置重复计数器的值,0。重复计数器,只有 8 位,只存在于高级定时器。
- TIM_TimeBaseInit( TIM1, &TIM_TimeBaseInitStructure); //初始化
复制代码
4、输入捕获结构体初始化,配置IC1捕获通道
- // TIM_Channel:捕获通道 ICx 选择,可选 TIM_Channel_1、 TIM_Channel_2、TIM_Channel_3 或 TIM_Channel_4 四个通道。
- TIM_ICInitStructure.TIM_Channel = TIM_Channel_1;
- //配置输入捕获预分频器值,如果需要捕获输入信号的每个有效边沿,则设置 1 分频 即可
- TIM_ICInitStructure.TIM_ICPrescaler = TIM_ICPSC_DIV1;
- //输入捕获滤波器设置,可选设置 0x0 至 0x0F。它设定 CHCTLRx 寄存器ICxF[3:0]位的值。一般我们不使用滤波器,即设置为 0
- TIM_ICInitStructure.TIM_ICFilter = 0x0;
- //输入捕获边沿触发选择,可选上升沿触发、下降沿触发或边沿跳变触发。
- TIM_ICInitStructure.TIM_ICPolarity = TIM_ICPolarity_Rising;
- //输入通道选择,捕获通道 ICx 的信号可来自三个输入通道,分别为TIM_ICSelection_DirectTI、 TIM_ICSelection_IndirectTI 或 TIM_ICSelection_TRC
- TIM_ICInitStructure.TIM_ICSelection = TIM_ICSelection_DirectTI;
复制代码
5、初始化PWM输入模式
- TIM_PWMIConfig( TIM1, &TIM_ICInitStructure );
复制代码
6、配置中断优先级
- NVIC_InitStructure.NVIC_IRQChannel = TIM1_CC_IRQn; //TIM1捕获比较中断
- NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 2; //设置抢占优先级
- NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0; //设置响应优先级
- NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; //使能通道
- NVIC_Init(&NVIC_InitStructure); //NVIC初始化
复制代码
7、使能捕获中断
- TIM_ITConfig( TIM1, TIM_IT_CC1 | TIM_IT_CC2, ENABLE ); //使能TIM1捕获中断
复制代码
8、选择输入捕获触发信号以及主从模式
- TIM_SelectInputTrigger( TIM1, TIM_TS_TI1FP1 ); //选择过滤定时器输入1作为触发源
- TIM_SelectSlaveMode( TIM1, TIM_SlaveMode_Reset ); //TIM1从机模式,所选触发信号(TRGI)的上升沿重新初始化。
- TIM_SelectMasterSlaveMode( TIM1, TIM_MasterSlaveMode_Enable );//设置或重置TIM1主从模式,使能定时器与从机之间同步
复制代码
9、使能定时器
10、编写中断服务函数
- void TIM1_CC_IRQHandler(void)
- {
- if( TIM_GetITStatus( TIM1, TIM_IT_CC1 ) != RESET ) //若捕获比较1发生中断
- {
- printf( "cycle:%d\r\n", (TIM_GetCapture1(TIM1)+1) ); //打印得到的捕获比较1寄存器值,其值加1表示周期
- }
- if( TIM_GetITStatus( TIM1, TIM_IT_CC2 ) != RESET ) //若捕获比较2发生中断
- {
- printf( "Pulsewidth:%d\r\n", (TIM_GetCapture2(TIM1)+1) ); //打印得到的捕获比较2寄存器值,其值加1表示脉宽
- }
- TIM_ClearITPendingBit( TIM1, TIM_IT_CC1 | TIM_IT_CC2 ); //清除TIM1捕获比较1和捕获比较2中断挂起位
- }
复制代码
capture.c文件主要是进行输入捕获的相关配置以及中断服务函数功能的设置,通过以上配置,即可进行输入捕获并通过中断服务函数打印输出脉宽和周期。
main.c文件
- int main(void)
- {
- USART_Printf_Init(115200);
- printf("SystemClk:%d\r\n",SystemCoreClock);
- Input_Capture_Init( 1000-1, 72-1 );
- while(1);
- }
复制代码 main.c文件主要是相关函数的初始化。
4、下载验证
将编译好的程序下载到开发板并复位,将两个开发板PA8引脚连接起来,打开串口调试助手,可看见在不停打印PWM脉宽和周期,具体如下:
输入捕获.rar 附件下载
8、输入捕获.rar
(488.51 KB, 下载次数: 14)
链接:https://pan.baidu.com/s/1L1lF5kzIQfzLbMPJb2nJUg
提取码:ugio
复制这段内容后打开百度网盘手机App,操作更方便哦
完
|
上一篇: 第八章:CH32V103应用教程——PWM输出下一篇: 第十章:CH32V103应用教程——ADC
|