你的浏览器版本过低,可能导致网站不能正常访问!
为了你能正常使用网站功能,请使用这些浏览器。

STM32定时器pwm模式输入捕获方法解析

[复制链接]
STMCU-管管 发布时间:2021-6-18 12:57
STM32定时器pwm模式输入捕获##
STM32中的定时器,除了TIM6和TIM7,其他定时器都有输入捕获功能。这种模式通常用在对输入信号频率frequency、占空比duty、高低脉宽的计算中,具有很广泛的用途。


STM32的输入捕获,简单的说就是通过检测TIMx_CHx上的边沿信号,在边沿信号发生跳变(比如上升沿/下降沿)的时候,将当前定时器的值(TIMx_CNT)存放到对应的通道的捕获/比较寄存(TIMx_CCRx)里面,完成一次捕获。同时还可以配置捕获时是否触发中断/DMA 等。


PWM模式捕获方法:利用TIM3_CH1作PWM输出,TIM2_CH2捕获上述PWM信号,并测出频率和占空比。设置PWM频率为1KHz,占空比50%。
具体步骤:


1、为了实现PWM输入捕获,TIM2占用了2个通道。第2通道的电平变化会被第一通道和第二通道引脚检测到,其中第一通道被设置为从机模式(如何快速判别主从机模式,规则如下:如果设置的是第二通道作为PWM输入捕获,则剩余的第一通道都为从机,反之亦然)。
2、假设输入的PWM从低电平开始跳变,在第一个上升沿到来时,1,2通道同时检测到上升沿。而从机设置为复位模式,所以将TIM2的计数值复位至0,此时不会产生一个中断请求。
3、下一个到来的电平是下降沿,此时通道1发生捕获事件,将计数值存入通道1的CCR1里。
然后是第二个上升沿到来后,此时通道2发生捕获事件,将此时的计数值存入通道2的CCR2里。复位模式此时又将TIM2计数值复位至0,等待第二个下降沿到来。
4、一次捕获过程完成,则PWM的频率f=72M/CCR2;占空比:duty=(CCR1/CCR2) X100%
12.png
注:
PWM输入模式时,用到两个通道(一般用TIMx_CH1或TIMx_CH2),只给其中一个通道分配gpio时钟即可,另一个在内部使用。给一个通道分配gpio时钟后,需要设置另一个为从机且复位模式。(例如使用ch2,ch1就得设置成从机模式)。当一个输入信号(TI1或TI2)来临时,主通道捕获上升沿,从机捕获下降沿。
在CH2通道中:
TI2FP1和TI2FP2都来自同一信号TI2 的边沿检测,信号相同,同一个TIx输入映射了两个ICx信号。
TI2FP1和TI2FP2可以分别由连接到的ICx (IC1或是IC2)相对应的控制寄存器设为上升沿或是下降沿触发,这两个ICx信号分别在相反的极性边沿有效。如果TI2FP2设置为上升沿触发,则TI2FP1设置为下降沿触发,二者极性相反。
CH1,3,4相同。


具体程序:
  1. include “pbdata.h”

  2. void RCC_Configuration(void);
  3. void GPIO_Configuration(void);
  4. void NVIC_Configuration(void);
  5. void TIM2_Configuration(void);
  6. void TIM3_Configuration(void);
  7. void USART_Configuration(void);

  8. int fputc(int ch,FILE *f)
  9. {
  10. USART_SendData(USART1,(u8)ch);
  11. while(USART_GetFlagStatus(USART1,USART_FLAG_TXE)==RESET);
  12. return ch;
  13. }

  14. int main(void)
  15. {
  16. RCC_Configuration(); //配置时钟
  17. GPIO_Configuration();//IO口配置
  18. TIM3_Configuration();
  19. TIM2_Configuration();
  20. NVIC_Configuration();
  21. USART_Configuration();

  22. while(1)
  23. {
  24. if(flag==1)
  25. {
  26. flag=0;
  27. printf(“the duty is %d/r/n”,duty);
  28. printf(“the frequency is %.2fKHz /r/n”,freq);
  29. }
  30. }
  31. }

  32. void RCC_Configuration(void)
  33. {
  34. SystemInit();
  35. RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA|RCC_APB2Periph_USART1,ENABLE);
  36. RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2|RCC_APB1Periph_TIM3,ENABLE);
  37. RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO,ENABLE);
  38. }

  39. void GPIO_Configuration(void)
  40. {
  41. GPIO_InitTypeDef GPIO_InitStructure;
  42. //LED
  43. GPIO_InitStructure.GPIO_Pin=GPIO_Pin_9;//TX
  44. GPIO_InitStructure.GPIO_Speed=GPIO_Speed_50MHz;
  45. GPIO_InitStructure.GPIO_Mode=GPIO_Mode_AF_PP;
  46. GPIO_Init(GPIOA,&GPIO_InitStructure);

  47. GPIO_InitStructure.GPIO_Pin=GPIO_Pin_10;//RX
  48. GPIO_InitStructure.GPIO_Mode=GPIO_Mode_IN_FLOATING;
  49. GPIO_Init(GPIOA,&GPIO_InitStructure);

  50. GPIO_InitStructure.GPIO_Pin=GPIO_Pin_6;//PWM,TIM3_CH1
  51. GPIO_InitStructure.GPIO_Speed=GPIO_Speed_50MHz;
  52. GPIO_InitStructure.GPIO_Mode=GPIO_Mode_AF_PP;
  53. GPIO_Init(GPIOA,&GPIO_InitStructure);

  54. GPIO_InitStructure.GPIO_Pin=GPIO_Pin_1;//TIM2_CH2
  55. GPIO_InitStructure.GPIO_Mode=GPIO_Mode_IN_FLOATING;
  56. GPIO_Init(GPIOA,&GPIO_InitStructure);
  57. }

  58. void TIM2_Configuration(void)
  59. {
  60. TIM_TimeBaseInitTypeDef TIM_TimeBaseStruct;
  61. TIM_ICInitTypeDef TIM_ICInitStructure;

  62. TIM_ICInitStructure.TIM_Channel=TIM_Channel_2;//选择TIM2_CH2,选择输入端 IC2映射到TI2上
  63. TIM_ICInitStructure.TIM_ICPolarity=TIM_ICPolarity_Rising;//上升沿捕获
  64. TIM_ICInitStructure.TIM_ICSelection=TIM_ICSelection_DirectTI;//映射到TI2上
  65. TIM_ICInitStructure.TIM_ICPrescaler=TIM_ICPSC_DIV1;//在捕获输入上每探测到一个边沿执行一次捕获
  66. TIM_ICInitStructure.TIM_ICFilter=0;//滤波设置,经历几个周期跳变认定波形稳定。(采样高电平,只有连续采集到N个电平是高电平时才认为是有效的,否则低于N个时认为是无效的,N取0x0-0xF)
  67. TIM_PWMIConfig(TIM2,&TIM_ICInitStructure);//以上是输入捕获配置
  68. TIM_SelectInputTrigger(TIM2,TIM_TS_TI2FP2);//选择滤波后的TI2FP2输入作为触发源,触发下面程序的复位
  69. TIM_SelectSlaveMode(TIM2,TIM_SlaveMode_Reset);//从模式控制器被设置为复位模式-选中的触发信号上升沿重新初始化计数器并产生一个更新信号(上升沿一到,TIM2->CNT被清零,每次上升沿来到,CNT都会被清零)
  70. TIM_SelectMasterSlaveMode(TIM2,TIM_MasterSlaveMode_Enable);//启动定时器的被动触发
  71. TIM_ITConfig(TIM2,TIM_IT_CC2,ENABLE);//捕获中断打开
  72. TIM_ClearFlag(TIM2,TIM_IT_CC2);//清除标志位
  73. TIM_Cmd(TIM2,ENABLE);//使能定时器2
  74. }

  75. void TIM3_Configuration(void)
  76. {
  77. TIM_TimeBaseInitTypeDef TIM_TimeBaseStruct;
  78. TIM_OCInitTypeDef TIM_OCInitStructure;
  79. TIM_TimeBaseStruct.TIM_Period=72000;//计数初值
  80. TIM_TimeBaseStruct.TIM_Prescaler=0;//分频系数
  81. TIM_TimeBaseStruct.TIM_ClockDivision=0;//时钟分割
  82. TIM_TimeBaseStruct.TIM_CounterMode=TIM_CounterMode_Up;//向上计数模式

  83. TIM_TimeBaseInit(TIM3,&TIM_TimeBaseStruct);

  84. //TIM3_CH1作为pwm输出
  85. TIM_OCInitStructure.TIM_OCMode=TIM_OCMode_PWM1;
  86. TIM_OCInitStructure.TIM_OutputState=TIM_OutputState_Enable;
  87. TIM_OCInitStructure.TIM_Pulse=36000;
  88. TIM_OCInitStructure.TIM_OCPolarity=TIM_OCPolarity_High;

  89. TIM_OC1Init(TIM3,&TIM_OCInitStructure);

  90. TIM_OC1PreloadConfig(TIM3,TIM_OCPreload_Enable);
  91. TIM_ARRPreloadConfig(TIM3,ENABLE);
  92. TIM_Cmd(TIM3,ENABLE);

  93. }

  94. void NVIC_Configuration(void)
  95. {
  96. NVIC_InitTypeDef NVIC_InitStructure;

  97. NVIC_PriorityGroupConfig(NVIC_PriorityGroup_1);

  98. NVIC_InitStructure.NVIC_IRQChannel = TIM2_IRQn;
  99. NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0;
  100. NVIC_InitStructure.NVIC_IRQChannelSubPriority = 1;
  101. NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
  102. NVIC_Init(&NVIC_InitStructure);

  103. }

  104. void USART_Configuration(void)
  105. {
  106. USART_InitTypeDef USART_InitStructure;

  107. USART_InitStructure.USART_BaudRate=115200;
  108. USART_InitStructure.USART_WordLength=USART_WordLength_8b;
  109. USART_InitStructure.USART_StopBits=USART_StopBits_1;
  110. USART_InitStructure.USART_Parity=USART_Parity_No;
  111. USART_InitStructure.USART_HardwareFlowControl=USART_HardwareFlowControl_None;
  112. USART_InitStructure.USART_Mode=USART_Mode_Rx|USART_Mode_Tx;

  113. USART_Init(USART1,&USART_InitStructure);
  114. USART_Cmd(USART1,ENABLE);
  115. USART_ClearFlag(USART1,USART_FLAG_TC);
  116. }

  117. //中断程序
  118. void TIM2_IRQHandler(void)
  119. {
  120. if(TIM_GetITStatus(TIM2,TIM_IT_CC2)==Bit_SET)
  121. {
  122. float IC2Value=0;
  123. float DutyCycle=0;

  124. float Frequency=0;
  125. float pulse=0;

  126. IC2Value=TIM_GetCapture2(TIM2);//获得CCR2的值
  127. pulse=TIM_GetCapture1(TIM2);//获得CCR1的值
  128. DutyCycle=pulse/IC2Value;
  129. Frequency=72000000/IC2Value;
  130. duty=(u32)(DutyCycle*100);
  131. freq=(Frequency/1000);

  132. flag=1;

  133. TIM_ClearITPendingBit(TIM2,TIM_IT_CC2);
  134. }
  135. }

  136. duty和freq是定义的全局变量
  137. extern u32 duty;
  138. extern u16 freq;

  139. u32 duty=0;
  140. u16 freq=0;
复制代码
经调试程序可用。频率和占空比都对。频率的设置不要太高,因为printf函数发数所需时间较多,两次捕获的时间间隔短的话可能使printf不能及时地送出数据,造成数据被刷新。更改方法,使用:USART_SendData();函数发数。


其他应用:
1.测量高电平时间:a,上文中的CCR1就是高电平时间;b,当使用一个通道CH1时,先将触发沿选为为上升沿,产生捕获中断,读取CCR1中的内容,再改变触发沿为下降沿,下降沿到来时捕获,再次读出CCR1的内容,两次相减为高电平时间。
2.测量脉冲个数:a,开启定时器1的捕获中断,捕获信号边沿(上升沿或下降沿)进中断,count++计数,再开启定时器2的更新中断,定时一定时间进更新中断,读取count值,此为脉冲个数。b,开启外部中断,配置沿触发中断,count++计数,再开启定时器x的更新中断,定时一定时间进更新中断,读取count值,此为脉冲个数。
3.计算一路信号的频率,可以选择定时器的CH1或CH2(不可同时计算两路频率,否则计算出的频率是后初始化的那个通道代表的信号频率。当然,要同时也可以,每次得到频率后切换通道,将数据通过DMA取走即可),使用PWM输入捕获模式,使用上升沿触发。而CH3和CH4通道则不行,如图2所示,只有红线所指的4个信号连在了从模式控制器上。所以,对于3和4通道,计数器的值不可能在接受到信号上升沿时候,有复位这个动作。


收藏 评论0 发布时间:2021-6-18 12:57

举报

0个回答

所属标签

关于
我们是谁
投资者关系
意法半导体可持续发展举措
创新与技术
意法半导体官网
联系我们
联系ST分支机构
寻找销售人员和分销渠道
社区
媒体中心
活动与培训
隐私策略
隐私策略
Cookies管理
行使您的权利
官方最新发布
STM32N6 AI生态系统
STM32MCU,MPU高性能GUI
ST ACEPACK电源模块
意法半导体生物传感器
STM32Cube扩展软件包
关注我们
st-img 微信公众号
st-img 手机版