历史上的今天
今天是:2024年11月26日(星期二)
2021年11月26日 | STM32输入捕获--“PWM输入模式”(可拓展多路同时捕获)
2021-11-26 来源:eefocus
前言
博文基于STM32F103ZET6和标准固件库V3.5.0在MDK5环境下开发;
本博文只讨论输入捕获的PWM输入模式,这个模式是STM32输入捕获检测脉宽和频率的一种硬件处理机制,说白了就是STM32芯片专门用来进行对PWM进行捕获的一个功能;此方法相比较于传统的PWM的捕获方法,大大减小了代码量,提高了检测效率,而实际上对于PWM信号的检测还有其他方法(下面我会介绍,就是原子教程提供的方法),并且关于繁琐的寄存器的介绍这里就不多说了,有兴趣的话可以直接去我的另外一个博客里去看: https://blog.csdn.net/wuyuzun/article/details/73135662 ;(备注:此链接里的博客里有一个配套的例程,例程的思想来自于源子教程,然而本博客是向突出介绍“PWM输入模式”这种我认为更好的方法)
本片博文只介绍单路(一个定时器)的PWM输入模式的,如果想实现多路PWM同时检测,只需要对其他具有输入捕获功能的定时器相同配置即可(我会在另外一个博客里进行介绍);
如有不足之处,多指教;
什么是PWM输入模式以及相应配置流程

(截图来自《STM32中文参考手册_V10》第216页)
介绍:(我们通过比较原子提供的思路来分析一下“PWM输入模式的比较模式”)
原子的思路:

如图为某个引脚输入的PWM波,把它分为4~5的阶段进行编程:
① 此时设置好上升沿为触发中断,以及其他定时器配置;
② 此时产生了上升沿,进行捕获操作,CNT内的值捕获到CCR内,此时使CNT=0,CNT继续开始计数;当完成捕获,并且修改捕捉极性为下降沿捕获,当下降沿来到时,将会再次触发此中断函数;
③ 此时产生了下降沿,触发了中断函数;
④ 清0 TIMx_SR寄存器中CCxOF和CCxIF位。
PWM输入模式:

(图片中为定时器输入捕获模式涉及到的功能模块,来自《STM32中文使用手册》P200页)
如图,举一个输入引脚为例(但是只能举TIMx_CH1和TIMx_CH2,因为TIMx_CH3和TIMx_CH4没有今天所要讨论的PWM输入模式这个功能,),假设这里对TIMx_CH1输入的信号同原子思路中的一样;那么我们同样可以用上面那种图来分析①~⑤五个步骤:
①:配置相对应的输入捕获引脚TIMx_CH1和GPIO管脚的映射关系;
②:选择TIMx_CCR1为有效输入:置TIMx_CCMR1寄存器的CC1S=01(这步的配置决定了此时的CCR1寄存器是输入用的还是输出用的,因为每个可以执行捕获和比较功能的定时器同一时间,只能执行捕获或者输出,两者不能同时进行);

③:选择TI1FP1的有效极性(用来捕获数据到TIMx_CCR1和清除计数器CNT),置CC1P=0(上升沿有效)

④:选择TIMx_CCR2的有效输入:置TIMx_CCMR1寄存器的CC2S=10(选中TI1)。(这里是需要特别注意的一个地方,从下图的配置选择或者从上面电路方框图的绿色剪头可以看出来,其实IC1和IC2配置时选择的输入信号都是来自于CH1通道进来的信号)

⑤:选择TI1FP2的有效极性(捕获CNT的数据到TIMx_CCR2);置CC2P=1(下降沿有效)。(图片参考了CC1P的配置,这里可以注意到一个现象就是IC2选择下降沿触发捕获,而IC1选择的是信号上升沿触发捕获)

⑥:选择有效的触发输入信号:置TIMx_SMCR寄存器中的TS = 101(选择TI1FP1);

⑦:配置从模式寄存器为复位模式:置TIMx_SMCR中的SMS=100;(这一步决定每次上升沿出现,CNT就被清零)

⑧:使能捕获:配置TIMx_CCER寄存器中CC1E=1且CC2E=1;
从波形的角度分析工作原理

①:在一处完成上述配置(当然,上述的配置只是简单地寄存器配置,并没写中断函数等等,这个工作,可以放在后续):
②:一条路上的CH1,TI1,TI1FP1,TI1FP2的上升沿同时产生,CNT内的值被捕获到了CCR1内并且CNT被清零,从新开始计数;
③:一条路上的CH1,TI1,TI1FP1,TI1FP2的下降沿同时产生,CNT内的值被捕获到了CCR2内,不清零CNT;
④~⑤:在编写的中断函数内即可进行逻辑操作,获取此时CCR1(周期)和CCR2(高电平时间),即可计算占空比 = CCR2/CCR1;
下面即使相对应的代码:
/*---------------PWM输入对应管脚配置-----------------*/
static void PWM_Intput_GPIO_Config(void)
{
GPIO_InitTypeDef GPIO_InitStructure;
// TIM1 对应 PA8
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_8;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING; //浮空输入模式;
GPIO_Init(GPIOA, &GPIO_InitStructure);
}
/*-------------中断嵌套配置------------*/
static void PWM_Intput_NVIC_Config(void)
{
NVIC_InitTypeDef NVIC_InitStructure;
NVIC_PriorityGroupConfig(NVIC_PriorityGroup_0);
NVIC_InitStructure.NVIC_IRQChannel = TIM1_CC_IRQn;
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0;
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
NVIC_Init(&NVIC_InitStructure);
}
/*-------------TIM1模式配置------------*/
static void PWM_Intput_Mode_Config(void)
{
RCC_APB2PeriphClockCmd(RCC_APB2Periph_TIM1,ENABLE);
/*--------------------时基结构初始化-------------------------*/
TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure;
TIM_TimeBaseStructure.TIM_Period=0xffff; //ARR=65535us
TIM_TimeBaseStructure.TIM_Prescaler= 72-1; //PSC = 1M = 1us;
TIM_TimeBaseStructure.TIM_ClockDivision=TIM_CKD_DIV1; //分频因子为0,即不分频;
TIM_TimeBaseStructure.TIM_CounterMode=TIM_CounterMode_Up; //CNT为向上计数模式;
TIM_TimeBaseStructure.TIM_RepetitionCounter=0;
TIM_TimeBaseInit(TIM1, &TIM_TimeBaseStructure);
/*-------------------输入捕获结构体初始化------------------*/
TIM_ICInitTypeDef TIM_ICInitStructure;
//配置CH1
TIM_ICInitStructure.TIM_Channel = TIM_Channel_1;
TIM_ICInitStructure.TIM_ICPolarity = TIM_ICPolarity_Rising; //上升沿触发
TIM_ICInitStructure.TIM_ICSelection = TIM_ICSelection_DirectTI; //IC1直接连接TI1FP1
TIM_ICInitStructure.TIM_ICPrescaler = TIM_ICPSC_DIV1; //对输入的PWM信号不分频
TIM_ICInitStructure.TIM_ICFilter = 0x0;
TIM_PWMIConfig(TIM1, &TIM_ICInitStructure);
//配置CH2
TIM_ICInitStructure.TIM_Channel = TIM_Channel_2;
TIM_ICInitStructure.TIM_ICPolarity = TIM_ICPolarity_Falling; //下降沿触发;
TIM_ICInitStructure.TIM_ICSelection = TIM_ICSelection_IndirectTI; //IC2间接连接TI1FP2
TIM_ICInitStructure.TIM_ICPrescaler = TIM_ICPSC_DIV1; //对输入的PWM信号不分频
TIM_ICInitStructure.TIM_ICFilter = 0x0;
TIM_PWMIConfig(TIM1, &TIM_ICInitStructure);
//选择输入捕获的触发信号;
TIM_SelectInputTrigger(TIM1, TIM_TS_TI1FP1);
// 选择从模式
// PWM输入模式时,从模式必须工作在复位模式,当捕获开始时,计数器CNT被复位清零;
TIM_SelectSlaveMode(TIM1, TIM_SlaveMode_Reset);
TIM_SelectMasterSlaveMode(TIM1,TIM_MasterSlaveMode_Enable);
// 使能捕获中断,这个中断主要针对的是主捕获通道(TI1FP1)
TIM_ITConfig(TIM1, TIM_IT_CC1, ENABLE);
// 清除中断标志位
TIM_ClearITPendingBit(TIM1, TIM_IT_CC1);
// 计数器开始计数
TIM_Cmd(TIM1, ENABLE);
}
/*---------------PWM输入对应管脚配置-----------------*/
static void PWM_Intput_GPIO_Config(void)
{
GPIO_InitTypeDef GPIO_InitStructure;
// TIM1 对应 PA8
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_8;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING; //浮空输入模式;
GPIO_Init(GPIOA, &GPIO_InitStructure);
}
/*-------------中断嵌套配置------------*/
static void PWM_Intput_NVIC_Config(void)
{
NVIC_InitTypeDef NVIC_InitStructure;
NVIC_PriorityGroupConfig(NVIC_PriorityGroup_0);
NVIC_InitStructure.NVIC_IRQChannel = TIM1_CC_IRQn;
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0;
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
NVIC_Init(&NVIC_InitStructure);
}
void TIM1_CC_IRQHandler(void)
{
uint8_t IC1_CCR1,IC2_CCR2;
TIM_ClearITPendingBit(TIM1, TIM_IT_CC1);
IC1_CCR1 = TIM_GetCapture1(TIM1); //获取周期值CCR1
IC2_CCR2 = TIM_GetCapture2(TIM1); //获取高电平时间CCR2
/*逻辑代码*/
}
/*-------------TIM1模式配置------------*/
static void PWM_Intput_Mode_Config(void)
{
RCC_APB2PeriphClockCmd(RCC_APB2Periph_TIM1,ENABLE);
/*--------------------时基结构初始化-------------------------*/
TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure;
TIM_TimeBaseStructure.TIM_Period=0xffff; //ARR=65535us
TIM_TimeBaseStructure.TIM_Prescaler= 72-1; //PSC = 1M = 1us;
TIM_TimeBaseStructure.TIM_ClockDivision=TIM_CKD_DIV1; //分频因子为0,即不分频;
TIM_TimeBaseStructure.TIM_CounterMode=TIM_CounterMode_Up; //CNT为向上计数模式;
TIM_TimeBaseStructure.TIM_RepetitionCounter=0;
TIM_TimeBaseInit(TIM1, &TIM_TimeBaseStructure);
/*-------------------输入捕获结构体初始化------------------*/
TIM_ICInitTypeDef TIM_ICInitStructure;
//配置CH1
TIM_ICInitStructure.TIM_Channel = TIM_Channel_1;
TIM_ICInitStructure.TIM_ICPolarity = TIM_ICPolarity_Rising; //上升沿触发
TIM_ICInitStructure.TIM_ICSelection = TIM_ICSelection_DirectTI; //IC1直接连接TI1FP1
TIM_ICInitStructure.TIM_ICPrescaler = TIM_ICPSC_DIV1; //对输入的PWM信号不分频
TIM_ICInitStructure.TIM_ICFilter = 0x0;
TIM_PWMIConfig(TIM1, &TIM_ICInitStructure);
//配置CH2
TIM_ICInitStructure.TIM_Channel = TIM_Channel_2;
TIM_ICInitStructure.TIM_ICPolarity = TIM_ICPolarity_Falling; //下降沿触发;
TIM_ICInitStructure.TIM_ICSelection = TIM_ICSelection_IndirectTI; //IC2间接连接TI1FP2
TIM_ICInitStructure.TIM_ICPrescaler = TIM_ICPSC_DIV1; //对输入的PWM信号不分频
TIM_ICInitStructure.TIM_ICFilter = 0x0;
TIM_PWMIConfig(TIM1, &TIM_ICInitStructure);
//选择输入捕获的触发信号;
TIM_SelectInputTrigger(TIM1, TIM_TS_TI1FP1);
// 选择从模式
// PWM输入模式时,从模式必须工作在复位模式,当捕获开始时,计数器CNT被复位清零;
TIM_SelectSlaveMode(TIM1, TIM_SlaveMode_Reset);
TIM_SelectMasterSlaveMode(TIM1,TIM_MasterSlaveMode_Enable);
// 使能捕获中断,这个中断主要针对的是主捕获通道(TI1FP1)
TIM_ITConfig(TIM1, TIM_IT_CC1, ENABLE);
// 清除中断标志位
TIM_ClearITPendingBit(TIM1, TIM_IT_CC1);
// 计数器开始计数
TIM_Cmd(TIM1, ENABLE);
}
史海拾趣
|
面向未来的IC设计方案随着集成电路制造业的飞速发展,传统的设计方法越来越受到严峻的挑战。每年设计技术的进步大约滞后制造技术20%。在器件的特征线宽进入深亚微米以后,这个矛盾显得越发的突出。主要表现在系统的集成度越来越高,使得单个芯片的 ...… 查看全部问答> |
|
FROM....TO....约束关于from to 的约束是一个比较实用,也比较好用的约束。 尤其在跨时钟域处理中的应用,特别有效。 举例: 设计中有两个时钟,一个是PLL的输入,一个是PLL的输出,当设计中有数据在该两个时钟域中传递时, 又没有用到fifo隔离, ...… 查看全部问答> |
|
在workbench3.0中建立了一个downloadable Kernel Module Project(一个简单的hello world程序),在vxworks6.x simulator里面运行通过了,也显示了hello world。可是连接8548板子后,选择连接vxworks6.x target server却去下载不进去,显示错误:Po ...… 查看全部问答> |
|
【求助】“阻塞(pend)”与“挂起(suspend)”的区别? 这两个词的英文意思差不多,看孔祥营书也没搞明白这两种任务状态的区别。 google的结果不尽相同。有说阻塞是位于主存,挂起位于外存;有说阻塞占用CPU,挂起不占用CPU…… 书上说:挂起(suspend)状态主要用于调试,不会约束状态转换,仅仅约束 ...… 查看全部问答> |
|
CString str = \"D:\\\\zxh\\\\111\\\\res\\\\sa.bmp\"; HBITMAP bim = (HBITMAP)LoadImage(AfxGetInstanceHandle(), str, IMAGE_BITMAP, 0,0,0); if(bim == NULL) { DWORD errno = GetLastError(); return; } 总 ...… 查看全部问答> |
|
最近好象很多人都在问关于DFU文件的使用问题,正好我们刚研究过,给大家讲讲我们的用法。第一步,准备好要转换的文件,bmp和wav格式,ST原版的DEMO就是这两种格式,后缀改为.bin(也可不改,只是选文件类型过滤选ALL Files(*.*)).第二步 ...… 查看全部问答> |
|
应该如何开始学习啊,主要是要做一些工业控制,F2812,是不是从写header file和.cmd文件开始写起?应该如何写呢?望大虾指教 Orz… 查看全部问答> |




