分享PWM输入模式捕捉4路PWM波形的周期和占空比 源码+原理讲解+程序讲解

2019-07-20 23:50发布

前几天分享过一个帖子,因为网速原因没有上传源码,看到有人回复我说实验不成功,那么好吧!这是我的错误,这次就将源码和我的心得体会分享出来,供大家下载测试和成长。我其实也是菜鸟一个,如果讲解的地方有啥不对,或是程序设计的不好,欢迎大家提出意见,让我们一起来学习进步。fficeffice" /> PWM输入是输入捕获的一个特殊应用,输入捕获就是当连接到定时器的引脚上产生电平变化时对应的捕获装置会立即将当前计数值复制到另一个寄存器中。你可以开启捕获中断然后在中断处理函数中读出保存的计数值。 与输入捕获不同的是PWM输入模式会将同一个输入信号(TI1TI2)连接到两个捕获装置(IC1IC2)。这两个捕获装置一个捕获上升沿一个捕获下降沿。TI1FP1TI2FP2它们中的一个被选择为触发输入且从模式控制器被配置为复位模式。 ffice:word" />PWM输入捕获原理和时序图


      1)   当第一次上升沿到达时IC1捕获TIMx_CCR1的值为当前计数值4IC2不会捕获TIMx_CCR2保持不变,计数器复位从0开始计数。
2) 第一个下降沿到达时IC2捕获TIMx_CCR2的值为2表示脉冲宽度。当上升再次到达时TIMx_CCR1的值就表示脉冲周期了(注意:第一次上升沿捕获的是个随机值)。 2)    原理也讲过了,那么下面就是实战了
一、操作步骤: ①将我的源码从论坛里面下载下来 ②用杜邦线将PB7PC6连接起来 ③将编译完成的hex文件下载到开发板 ④打开串口调试助手波特率选9600 ⑤按下开发板的复位键,OK那么你就能看到串口的打印信息。 ⑥用杜邦线依次将PB7PC7PB7PC8PB7PC9连接起来,看串口打印不同占空比和相同周期的信息。 二、主程序讲解 TIM3_PWM_Init(1000-1,72-1);   //1KHz的周期 这个计算相信大部分人应该没有问题原子哥也做过详细的讲解那么我在重复一遍 CPU主频是72MHZ 这里将72MHZ主频72分频,那么就为1MHZ,所以计数器每加1那么就是代表增加1US,我这里设置的是999,因为0-999正好是1000us,所以我设置的周期是1000us 也就是1KHZ TIM_SetCompare1(TIM3,200); 这个函数式设置PWM通道的占空比,因为周期是1000us所以我这里设置的是20%的占空比,这个计算我就算教小白吧  占空比 = 200/1000 我这里设置的是通道1也就是PC6的占空比。下面三个我就不讲了。 TIM4_PWMINPUT_INIT(0xffff,72-1); 这个函数是PWM输入模式初始化,这个我设置的最大计数是0xffff,因为是16位的计数器当然最大也只能这么大了,后面的参数是设置捕捉频率的,我这里还设置为1MHz,这样为了好看实验现象。 While(1){} 主程序那三个打印语句我就不讲了,这个都不会,那么你就该补补了。 三、四路PWM程序讲解 void TIM3_PWM_Init(u16 arr,u16 psc) 这个函数我不讲很多因为原子哥已经将的很清楚了,我就将几个注意的地方和大家说一下, GPIO_PinRemapConfig(GPIO_FullRemap_TIM3, ENABLE); 这个函数式定时器的全映射,将 TIM3定时器的引脚映射到了PC6 C7 C8 C9上了。 四、PWM输入捕捉程序讲解: void TIM4_PWMINPUT_INIT(u16 arr,u16 psc) 这个函数我在源码里面已经注释的很清楚了,有几个点需要大家注意 TIM_SelectInputTrigger(TIM4, TIM_TS_TI2FP2);     这个是选择有效的输入端 ,我这里TIM_TS_TI2FP2选择的PB7,注意:只有TI1FP1TI2FP2连到了从模式控制器,所以PWM输入模式只能使用TIMx_CH1 /TIMx_CH2信号。  TIM_SelectSlaveMode(TIM4, TIM_SlaveMode_Reset);   这个是配置为PWM输入主从复位模式,就是每次输入端有效电平变化的时候定时器计数器就会硬件上置0 中断函数讲解 至于TIM4的中断函数很简单我就不多讲什么了,主要就是将捕捉到的周期和占空比记录下来。   注意:我提醒大家一下,我现在这个捕捉的周期的范围是1-65535us,如果你要捕捉的周期超出这个怎么办,我给大家一点建议①将捕获精度降低,也就是讲捕获频率降下来②这个就是用原子哥那种溢出计数的方法,但是这个有意思的是主从复位模式,每次复位也会产生更新中断,那么如果不加设置的话,可能这种方法是行不通的。但是我已经解决了,看手册介绍,解决的。哈哈,大家有兴趣的话,可以去试着解决,自己做的饭才是最香的。实在是想用第二种方法,但是又解决不了的,就可以回复,但是我想着还是自己解决的好

说了这么多,有的人可能会提出疑问?那你给我们讲这些理论,你自己到底实现了没有?俗话说的好,有图有真相,没图说啥?那么好的上真相,不过是有误差的,但是我认为这个误差在接受范围内。


PB7PC6连接的串口输出情况:实际周期1KHz占空比20%  PB7PC7连接的串口输出情况:实际周期1KHz占空比40% 
PB7
PC8连接的串口输出情况:实际周期1KHz占空比60% 
PB7PC9连接的串口输出情况:实际周期1KHz占空比80% 
 
友情提示: 此问题已得到解决,问题已经关闭,关闭后问题禁止继续编辑,回答。
50条回答
我不后悔
2019-07-25 22:48
我在楼主的基础上 想再添加一些代码用TIM2的CH1来捕获TIM3的CH1,代码如下:
void TIM2_PWMINPUT_INIT(u16 arr,u16 psc) { TIM_TimeBaseInitTypeDef  TIM_TimeBaseStructure; NVIC_InitTypeDef NVIC_InitStructure; TIM_ICInitTypeDef  TIM2_ICInitStructure; GPIO_InitTypeDef GPIO_InitStructure; RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2, ENABLE);     //Open TIM4 clock         RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);
                                       GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0;                               //GPIO??         GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;         GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;         GPIO_Init(GPIOA, &GPIO_InitStructure); TIM_TimeBaseStructure.TIM_Period = arr; //设置在下一个更新事件装入活动的自动重装载寄存   TIM_TimeBaseStructure.TIM_Prescaler =psc; //设置用来作为TIMx时钟频率除数的预分频值   TIM_TimeBaseStructure.TIM_ClockDivision = 0; //设置时钟分割:TDTS = Tck_tim TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up;  //TIM向上计数模式 TIM_TimeBaseInit(TIM2, &TIM_TimeBaseStructure); //根据TIM_TimeBaseInitStruct中指定的参         NVIC_InitStructure.NVIC_IRQChannel = TIM2_IRQn;                              NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0;         NVIC_InitStructure.NVIC_IRQChannelSubPriority = 2;         NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;         NVIC_Init(&NVIC_InitStructure);              TIM2_ICInitStructure.TIM_Channel = TIM_Channel_1;                            TIM2_ICInitStructure.TIM_ICPolarity = TIM_ICPolarity_Rising;                TIM2_ICInitStructure.TIM_ICSelection = TIM_ICSelection_DirectTI;            TIM2_ICInitStructure.TIM_ICPrescaler = TIM_ICPSC_DIV1;  TIM2_ICInitStructure.TIM_ICFilter = 0x0;            TIM_PWMIConfig(TIM2, &TIM2_ICInitStructure);     //PWM输入配置                    TIM_SelectInputTrigger(TIM2, TIM_TS_TI1FP1);     //选择有效输入端                 TIM_SelectSlaveMode(TIM2, TIM_SlaveMode_Reset);  //配置为主从复位模式         TIM_SelectMasterSlaveMode(TIM2, TIM_MasterSlaveMode_Enable);                                                TIM_ITConfig(TIM2, TIM_IT_CC1|TIM_IT_Update, ENABLE);          //中断配置 TIM_ClearITPendingBit(TIM2, TIM_IT_CC1|TIM_IT_Update); //清除中断标志位 TIM_Cmd(TIM2, ENABLE);     } void TIM2_IRQHandler(void) {
if(CollectFlag1) { if (TIM_GetITStatus(TIM2, TIM_IT_CC1) != RESET)//捕获1发生捕获事件 { duty1 = TIM_GetCapture1(TIM2); //采集占空比  period1 = TIM_GetCapture2(TIM2);     //采集周期 } CollectFlag1 = 0; } TIM_ClearITPendingBit(TIM2, TIM_IT_CC1|TIM_IT_Update); //清除中断标志位 }




主函数:
extern void TIM3_PWM_Init(u16 arr,u16 psc); extern void TIM4_PWMINPUT_INIT(u16 arr,u16 psc); extern void TIM2_PWMINPUT_INIT(u16 arr,u16 psc);
extern u16 period; extern u16 duty ; extern u8 CollectFlag ; extern u16 period1; extern u16 duty1 ; extern u8 CollectFlag1 ; //Mini STM32开发板范例代码8
//技术论坛:www.openedv.com    int main(void)  { SystemInit(); delay_init(72);     //延时初始化 NVIC_Configuration();   //中断配置 uart_init(9600); //串口初始化 TIM3_PWM_Init(1000,7200-1);   //1KHZ周期 TIM_SetCompare1(TIM3,200); //设置占空比 TIM_SetCompare2(TIM3,401); //设置占空比 TIM_SetCompare3(TIM3,600); //设置占空比 TIM_SetCompare4(TIM3,800); //设置占空比 TIM4_PWMINPUT_INIT(0xffff,7200-1);   //pwm输入初始化以1M的频率捕捉 TIM2_PWMINPUT_INIT(0xffff,7200-1);
// PWM_Init(900,0); //不分频。PWM频率=72000/900=8Khz while(1) { delay_ms(100);    if(!CollectFlag) { printf("duty   = %d%% ",duty*100/period); //打印占空比 printf("cycle = %dKHz ",1000/period);//打印周期另一种叫法 printf("period  = %dus ",period);    //打印周期 CollectFlag = 1; } delay_ms(10); if(!CollectFlag1) { printf("duty1   = %d%% ",duty1*100/period1); //打印占空比 printf("cycle1 = %dKHz ",1000/period1);//打印周期另一种叫法 printf("period1  = %dus ",period1);    //打印周期 CollectFlag1 = 1; } }  
 }
得出下面的结果:


只有原先楼主的那个测量是准确的 ,能问一下哪错了吗?





一周热门 更多>