STM32输入捕获简介
- 格式:docx
- 大小:19.15 KB
- 文档页数:3
STM32Cube学习之八:输入捕获假设已经安装好STM32CubeMX和STM32CubeF4支持包。
Step1.打开STM32CubeMX,点击“New Project”,选择芯片型号,STM32F407ZETx。
Step2. 在Pinout界面下配置晶振输入引脚。
配置TIM2使用内部时钟源,CH1作为输入捕获通道,默认映射到PA0引脚。
配置TIM3使用内部时钟,CH1~CH4为PWM输出通道,默认映射引脚分别为PA6,PA7,PB0,PB1。
配置TIM4使用内部时钟,CH1,CH2为PWM输出通道,映射引脚分别为PD12,PD13。
配置串口,作为信息输出接口。
Step3.在Clock Configuration界面配置时钟源。
使用外部8M晶振作PLL时钟输入,并使用PLL输出作为系统时钟。
为了后面的计算方便,将系统时钟配置成160MHz。
Step4.配置外设参数。
在configuration界面中点击TIM2/ TIM3/ TIM4按钮,可以进入参数配置界面。
TIM2:在Parameter Settings页配置预分频系数为7,其计数时钟就是80MHz/(7+1)=10MHz。
计数周期(自动加载值),转换为十六进制形式,输入32bit最大值0xFFFFFFFF。
注意,TIM2的自动加载寄存器ARR和各个通道的捕获/比较寄存器CCRx都是32bit的。
在NVIC页面使能捕获/比较中断。
在GPIO页面设置捕获输入引脚下拉电阻,设置成上拉也可以,主要是为了使在没有信号输入时在输入引脚上得到稳定的电平。
TIM3:在Parameter页配置预分频系数为7,计数周期(自动加载值)为9999。
其溢出频率就是80MHz/(7+1)/(9999+1)=1kHz,这就是TIM3各通道输出的PWM信号的频率。
各通道输出PWM的占空比参数如上图红框标注,其他参数使用默认值。
按照图中参数,CH1~CH4输出的PWM周期都是1ms,而高电平时间分别是123.4us,234.5us,567.8us,678.9us。
STM32(⼗⼋)输⼊捕获应⽤
输⼊捕获⼀般应⽤在两个⽅⾯:
脉冲跳变沿时间测量
PWM输⼊测量
1、测量频率
当捕获通道TIx.上出现上升沿时,发⽣第⼀次捕获,计数器CNT的值会被锁存到捕获寄存器CCR中,⽽且还会进⼊捕获中断,在中断服务程序中记录⼀-次捕获(可以⽤⼀个标志变量来记录),并把捕获寄存器中的值读取到valuel 中。
当出现第⼆次上升沿时,发⽣第⼆次捕获,计数器CNT的值会再次被锁存到捕获寄存器CCR中,并再次进⼊捕获中断,在捕获中断中,把捕获寄存器的值读取到value3中,并清除捕获记录标志。
利⽤value3和valuel的差值我们就可以算出信号的周期(频率)。
2、测量脉宽
当捕获通道TIx.上出现上升沿时,发⽣第⼀次捕获,计数器CNT的值会被锁存到捕获寄存器CCR中,⽽且还会进⼊捕获中断,在中断服务程序中记录⼀次捕获(可以⽤⼀个标志变量来记录),并把捕获寄存器中的值读取到valuel 中。
然后把捕获边沿改变为下降沿捕获,⽬的是捕获后⾯的下降沿。
当下降沿到来的时候,发⽣第⼆次捕获,计数器CNT的值会再次被锁存到捕获寄存器CCR中,并再次进⼊捕获中断,在捕获中断中,把捕获寄存器的值读取到value3 中,并清除捕获记录标志。
然后把捕获边沿设置为上升沿捕获。
在测量脉宽过程中需要来回的切换捕获边沿的极性,如果测量的脉宽时间⽐较长,定时器就会发⽣溢出,溢出的时候会产⽣更新中断,我们可以在中断⾥⾯对溢出进⾏记录处理。
STM32输入捕获模式
在输入捕获模式下,定时器将统计外部信号的上升沿或下降沿出现的
时间,并将统计结果保存在相关的寄存器中。
用户可以根据需要选择统计
上升沿还是下降沿,并可以选择计数溢出时是否复位计数器。
1.选择定时器和通道:根据实际需求选择合适的定时器和通道。
一般
来说,每个定时器都有多个通道可以配置为输入捕获模式。
2.配置定时器:根据测量的要求配置定时器的工作模式、计数方向和
预分频系数等。
定时器的配置将影响捕获的精度和测量范围。
3.配置输入捕获:选择捕获触发源,可以选择外部信号引脚或其他定
时器的输出作为触发源。
配置捕获触发源时还可以选择捕获的边沿类型
(上升沿或下降沿)和是否复位计数器。
4.开启定时器:配置完成后,通过使能相关的定时器和通道将输入捕
获模式启用。
5.捕获外部信号:当捕获触发源产生触发信号时,定时器将开始计数,当捕获到外部信号的边沿时,定时器会自动将计数值保存在指定的寄存器中。
6.读取测量结果:根据所选择的定时器和通道,从相关的寄存器中读
取测量结果,可以通过计算得到所需的参数,比如周期、脉宽等。
输入捕获模式在很多应用中都是非常常见且重要的。
例如在测量旋转
编码器的位置和速度时,可以使用输入捕获模式来捕获编码器的A相和B
相信号,并通过计算来确定位置和速度。
此外,输入捕获模式还可以用于
测量外部信号的频率、测量脉冲信号的宽度等。
总之,STM32输入捕获模式是一种功能强大且灵活的功能,能够帮助用户实现对外部信号的精确测量和控制。
通过合理配置和使用,可以满足各种不同的应用需求。
stm32PWM输入捕获tm32定时器pwm输入捕获输入捕捉的功能是记录下要捕捉的边沿出现的时刻,如果你仅仅捕捉下降沿,那么两次捕捉的差表示输入信号的周期,即两次下降沿之间的时间。
如果要测量低电平的宽度,你应该在捕捉到下降沿的中断处理中把捕捉边沿改变为上升沿,然后把两次捕捉的数值相减就得到了需要测量的低电平宽度。
如果要的测量低电平太窄,中断中来不及改变捕捉方向时,或不想在中断中改变捕捉方向,则需要使用PWM输入模式,或使用两个TIM某通道,一个通道捕捉下降沿,另一个通道捕捉上升沿,然后对两次捕捉的数值相减。
PWM输入模式也是需要用到两个通道。
使用两个通道时,最好使用通道1和通道2,或通道3和通道4,这样上述功能只需要使用一个I/O管脚,详细请看STM32技术参考手册中的TIM某框图。
//0-----------------------一、概念理解PWM输入捕获模式是输入捕获模式的特例,自己理解如下1.每个定时器有四个输入捕获通道IC1、IC2、IC3、IC4。
且IC1IC2一组,IC3IC4一组。
并且可是设置管脚和寄存器的对应关系。
2.同一个TI某输入映射了两个IC某信号。
3.这两个IC某信号分别在相反的极性边沿有效。
4.两个边沿信号中的一个被选为触发信号,并且从模式控制器被设置成复位模式。
5.当触发信号来临时,被设置成触发输入信号的捕获寄存器,捕获“一个PWM周期(即连续的两个上升沿或下降沿)”,它等于包含TIM时钟周期的个数(即捕获寄存器中捕获的为TIM的计数个数n)。
6.同样另一个捕获通道捕获触发信号和下一个相反极性的边沿信号的计数个数m,即(即高电平的周期或低电平的周期)7.由此可以计算出PWM的时钟周期和占空比了frequency=f(TIM时钟频率)/n。
dutycycle=(高电平计数个数/n),若m为高电平计数个数,则dutycycle=m/n若m为低电平计数个数,则dutycycle=(n-m)/n 注:因为计数器为16位,所以一个周期最多计数65535个,所以测得的最小频率=TIM时钟频率/65535。
输入捕获模式可以用来测量脉冲宽度或者测量频率。
STM32的定时器,除了TIM6和TIM7,其他定时器都有输入捕获功能。
STM32的输入捕获,简单的说就是通过检测TIMx_CHx上的边沿信号,在边沿信号发生跳变(比如上升沿/下降沿)的时候,将当前定时器的值(TIMx_CNT)存放到对应的通道的捕获/比较寄存(TIMx_CCRx)里面,完成一次捕获。
同时还可以配置捕获时是否触发中断/DMA 等. 例如:我们用到TIM5_CH1来捕获高电平脉宽,也就是要先设置输入捕获为上升沿检测,记录发生上升沿的时候TIM5_CNT的值。
然后配置捕获信号为下降沿捕获,当下降沿到来时,发生捕获,并记录此时的TIM5_CNT值。
这样,前后两次TIM5_CNT之差,就是高电平的脉宽,同时TIM5的计数频率我们是知道的,从而可以计算出高电平脉宽的准确时间。
首先TIMx_ARR和TIMx_PSC,这两个寄存器用来设自动重装载值和TIMx的时钟分频。
再来看看捕获/比较模式寄存器1:TIMx_CCMR1,这个寄存器在输入捕获的时候,非常有用;TIMx_CCMR1明显是针对2个通道的配置,低八位[7:0]用于捕获/比较通道1的控制,而高八位[15:8]则用于捕获/比较通道2的控制,因为TIMx还有CCMR2这个寄存器,所以可以知道CCMR2是用来控制通道3和通道4(详见《STM32参考手册》290页,14.4.8节)。
这里用到TIM5的捕获/比较通道1,我们重点介绍TIMx_CMMR1的[7:0]位(其实高8位配置类似)。
再来看看捕获/比较使能寄存器:TIMx_CCER;接下来我们再看看DMA/中断使能寄存器:TIMx_DIER,我们需要用到中断来处理捕获数据,所以必须开启通道1的捕获比较中断,即CC1IE设置为1。
控制寄存器:TIMx_CR1,我们只用到了它的最低位,也就是用来使能定时器的;最后再来看看捕获/比较寄存器1:TIMx_CCR1,该寄存器用来存储捕获发生时,TIMx_CNT的值,我们从TIMx_CCR1就可以读出通道1捕获发生时刻的TIMx_CNT值,通过两次捕获(一次上升沿捕获,一次下降沿捕获)的差值,就可以计算出高电平脉冲的宽度。
理解STM32定时器中的输入捕获滤波器关于STM32定时器中的输入捕获滤波器的功能描述,在中文参考手册中描述如下:我不理解官方的说明,在网上搜了老半天,基本都是下面这几句话:1)当滤波器连续采样到N次个有效电平时,认为一次有效的输入电平。
2)该数字滤波器实际上是个事件计数器,它记录到N个事件后会产生一个输出的跳变。
例如:当f(CK_INT) = 72MHz, CKD[1:0] = 01时,选择f(DTS) = f(CK_INT)/2 = 36MHz;而ETF[3:0] = 0100,则采样频率f(SAMPLI NG) = f(DTS) / 2 = 18MHz, N = 6,此时高于3M Hz的信号将被这个滤波器滤除,这样就有效地屏蔽了高于3MHz的干扰。
看了这些说法,我还是不理解这个数字滤波器到底是如何工作的,问题如下:问题1:当滤波器连续采样到N次个有效电平时,是输出这个电平?还是输出一个跳变?问题2:当滤波器没有连续采样到N次个有效电平时,输出是的什么?带着这两个问题,我们来分析一下,下面以TIM3为例:首先可以肯定输入捕获过程如下:详细信息见参考手册中的14.2节,通用定时器框图TIM3_C H1(PA.6) ----> TI1(外部信号) -------> 输入滤波器I C1F[3:0] -----> IC1(滤波器输出信号) -------> 输入捕获预分频器IC1PSC[1:0] ----> 捕获/比较1寄存器CCR1从上面的过程可以知道,1)发生输入捕获所需要的跳变沿是由滤波器输出产生的。
2)滤波器和预分频器可软件编程,如果IC1F[3:0] = 0x0,则滤波器全通,即TI1 和IC1是同一个信号。
基于STM32CubeMX配置PWM输出和输⼊捕获PWM输出和输⼊捕获1、试验⽬标 1.输出2路PWM脉冲信号 2.捕获1路PWM脉冲信号 本次试验会使⽤到2个定时器,⼀个⾼级定时器⽤于脉冲捕获,⼀个普通定时器⽤于PWM脉冲输出。
2、准备材料 1. STM32F103C8 2. STM32CubeMX2、STM32CubeMX配置 2.1时钟树 系统时钟为72M,APB1 和APB2 的定时器时钟都为72MHZ。
2.2 PWM输出配置 PWM的输出配置⽐较简单,这⾥我们使⽤到了TIM2普通定时器控制输出,具体参数如下图。
在 Parameter Settings 页配置预分频系数为 72-1,计数周期(⾃动加载值)为 10000-1,定时器溢出频率,即PWM的周期,就是72MHz/(71+1)/(9999+1) = 100Hz 2.3 PWM输⼊捕获配置 PWM捕获,本次试验使⽤到了STM32F103C8的⾼级定时器TIM1。
配置如下图。
中断配置勾线这⾥,因为我们需要使⽤中断回调函数来计算频率占空⽐。
2.4 配置中断分组和中断使能2.5串⼝输出2.6⽣成⼯程 这⾥选择分离C.h⽂件,IDE 根据⾃⼰的环境选择,这⾥我使⽤的GUN编译⽅式的IDE所以选择了SW4SEM32。
以上CubeMX的PWM配置就完成了。
配置完毕后,⽣成⼯程打开。
下⾯我们来分析代码和如何使⽤。
3、代码实现 3.1 tim.c 该代码主要配置了Tim1 和Tim2 的相关配置,为什么要这么配置,在接下来的第4⼤点会详细说明。
这⾥主要了解HAL_TIM_IC_CaptureCallback 捕获中断回调函数这⾥函数主要处理计算占空⽐和频率。
/********************************************************************************* @file tim.c* @brief This file provides code for the configuration* of the TIM instances.******************************************************************************* @attention** <h2><center>© Copyright (c) 2021 STMicroelectronics.* All rights reserved.</center></h2>** This software component is licensed by ST under BSD 3-Clause license,* the "License"; You may not use this file except in compliance with the* License. You may obtain a copy of the License at:* /licenses/BSD-3-Clause********************************************************************************//* Includes ------------------------------------------------------------------*/#include "tim.h"/* USER CODE BEGIN 0 *//// 计算占空⽐时使⽤__IO uint16_t IC2Value = 0;__IO uint16_t IC1Value = 0;__IO float DutyCycle = 0;__IO float Frequency = 0;/* USER CODE END 0 */TIM_HandleTypeDef htim1; // ⾼级定时器捕获PWMTIM_HandleTypeDef htim2; // 普通定时器输出PWM/* TIM1 init function */void MX_TIM1_Init(void){TIM_ClockConfigTypeDef sClockSourceConfig = {0};TIM_SlaveConfigTypeDef sSlaveConfig = {0};TIM_MasterConfigTypeDef sMasterConfig = {0};TIM_IC_InitTypeDef sConfigIC = {0};htim1.Instance = TIM1;htim1.Init.Prescaler = 72-1;htim1.Init.CounterMode = TIM_COUNTERMODE_UP; /* 计数⽅式上计数 */htim1.Init.Period = 65535; /* 计数器更新上限值 */htim1.Init.ClockDivision = TIM_CLOCKDIVISION_DIV1; /* 采样时钟分频 */htim1.Init.RepetitionCounter = 0; /* 重装值=0 */htim1.Init.AutoReloadPreload = TIM_AUTORELOAD_PRELOAD_ENABLE; /* ⾃动装载值软件使能 */ if (HAL_TIM_Base_Init(&htim1) != HAL_OK) /* 初始定时器 */{Error_Handler();}sClockSourceConfig.ClockSource = TIM_CLOCKSOURCE_INTERNAL; /* 内部时钟源 */if (HAL_TIM_ConfigClockSource(&htim1, &sClockSourceConfig) != HAL_OK){Error_Handler();}if (HAL_TIM_IC_Init(&htim1) != HAL_OK){Error_Handler();}///选择从模式: 复位模式sSlaveConfig.SlaveMode = TIM_SLAVEMODE_RESET;sSlaveConfig.InputTrigger = TIM_TS_TI1FP1; /* 选择定时器输⼊触发: TI1FP1 */ sSlaveConfig.TriggerPolarity = TIM_INPUTCHANNELPOLARITY_RISING;sSlaveConfig.TriggerFilter = 0;if (HAL_TIM_SlaveConfigSynchro(&htim1, &sSlaveConfig) != HAL_OK){Error_Handler();}sMasterConfig.MasterOutputTrigger = TIM_TRGO_RESET;sMasterConfig.MasterSlaveMode = TIM_MASTERSLAVEMODE_DISABLE;if (HAL_TIMEx_MasterConfigSynchronization(&htim1, &sMasterConfig) != HAL_OK){Error_Handler();}///IC1捕获上升沿触发 TI1FP1sConfigIC.ICPolarity = TIM_INPUTCHANNELPOLARITY_RISING;sConfigIC.ICSelection = TIM_ICSELECTION_DIRECTTI;sConfigIC.ICPrescaler = TIM_ICPSC_DIV1;sConfigIC.ICFilter = 0;if (HAL_TIM_IC_ConfigChannel(&htim1, &sConfigIC, TIM_CHANNEL_1) != HAL_OK){Error_Handler();}///IC2捕获下降沿捕获 TI1FP2sConfigIC.ICPolarity = TIM_INPUTCHANNELPOLARITY_FALLING;sConfigIC.ICSelection = TIM_ICSELECTION_INDIRECTTI;if (HAL_TIM_IC_ConfigChannel(&htim1, &sConfigIC, TIM_CHANNEL_2) != HAL_OK){Error_Handler();}}/* TIM2 init function */void MX_TIM2_Init(void){TIM_ClockConfigTypeDef sClockSourceConfig = {0};TIM_MasterConfigTypeDef sMasterConfig = {0};TIM_OC_InitTypeDef sConfigOC = {0};htim2.Instance = TIM2;/** htim2.Init.Prescaler 分频计算* 定时器时钟源TIMxCLK = 2 * PCLK1* PCLK1 = HCLK / 2* => TIMxCLK = HCLK/2 = SystemCoreClock / 2 *2=72MHz (APB1)* 设定定时器频率为=TIMxCLK/(TIM_Prescaler+1)=10KHz* */htim2.Init.Prescaler = 72-1;htim2.Init.CounterMode = TIM_COUNTERMODE_UP; /* 计数⽅式上升沿有效 */htim2.Init.Period = 10000-1; /* 累计 TIM_Period个后产⽣⼀个更新或者中断当定时器从0计数到10000,即为10000次,为⼀个定时周期*/ htim2.Init.ClockDivision = TIM_CLOCKDIVISION_DIV1;htim2.Init.AutoReloadPreload = TIM_AUTORELOAD_PRELOAD_ENABLE;if (HAL_TIM_Base_Init(&htim2) != HAL_OK){Error_Handler();}sClockSourceConfig.ClockSource = TIM_CLOCKSOURCE_INTERNAL; /* 内部时钟源 */if (HAL_TIM_ConfigClockSource(&htim2, &sClockSourceConfig) != HAL_OK){Error_Handler();}if (HAL_TIM_PWM_Init(&htim2) != HAL_OK){Error_Handler();}sMasterConfig.MasterOutputTrigger = TIM_TRGO_RESET;sMasterConfig.MasterSlaveMode = TIM_MASTERSLAVEMODE_DISABLE;if (HAL_TIMEx_MasterConfigSynchronization(&htim2, &sMasterConfig) != HAL_OK){Error_Handler();}///PWM模式配置sConfigOC.OCMode = TIM_OCMODE_PWM1; /* 配置为PWM模式1*/sConfigOC.Pulse = 5000; /* 默认占空⽐为50%*/sConfigOC.OCPolarity = TIM_OCPOLARITY_HIGH; /* 当定时器计数值⼩于CCR1_Val时为⾼电平*/sConfigOC.OCFastMode = TIM_OCFAST_DISABLE;if (HAL_TIM_PWM_ConfigChannel(&htim2, &sConfigOC, TIM_CHANNEL_1) != HAL_OK) /* 配置PWM通道*/{Error_Handler();}if (HAL_TIM_PWM_ConfigChannel(&htim2, &sConfigOC, TIM_CHANNEL_2) != HAL_OK){Error_Handler();}HAL_TIM_MspPostInit(&htim2); /* 外置GPIO初始化 */}void HAL_TIM_Base_MspInit(TIM_HandleTypeDef* tim_baseHandle){GPIO_InitTypeDef GPIO_InitStruct = {0};if(tim_baseHandle->Instance==TIM1){/* USER CODE BEGIN TIM1_MspInit 0 *//* USER CODE END TIM1_MspInit 0 *//* TIM1 clock enable */__HAL_RCC_TIM1_CLK_ENABLE(); /*定时器时钟使能*/__HAL_RCC_GPIOA_CLK_ENABLE(); /*GPIO时钟使能*//**TIM1 GPIO ConfigurationPA8 ------> TIM1_CH1*/GPIO_InitStruct.Pin = GPIO_PIN_8; /* 36脚的F103 不能改变引脚编号*/GPIO_InitStruct.Mode = GPIO_MODE_INPUT; /* 输⼊模式*/GPIO_InitStruct.Pull = GPIO_NOPULL; /* ⽆上下拉*/HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);/* TIM1 interrupt Init */HAL_NVIC_SetPriority(TIM1_CC_IRQn, 0, 0); /* 配置中断分组*/HAL_NVIC_EnableIRQ(TIM1_CC_IRQn); /* 使能中断*//* USER CODE BEGIN TIM1_MspInit 1 *//* USER CODE END TIM1_MspInit 1 */}else if(tim_baseHandle->Instance==TIM2){/* USER CODE BEGIN TIM2_MspInit 0 *//* USER CODE END TIM2_MspInit 0 *//* TIM2 clock enable */__HAL_RCC_TIM2_CLK_ENABLE();/* USER CODE BEGIN TIM2_MspInit 1 *//* USER CODE END TIM2_MspInit 1 */}}void HAL_TIM_MspPostInit(TIM_HandleTypeDef* timHandle){GPIO_InitTypeDef GPIO_InitStruct = {0};if(timHandle->Instance==TIM2){/* USER CODE BEGIN TIM2_MspPostInit 0 *//* USER CODE END TIM2_MspPostInit 0 */__HAL_RCC_GPIOA_CLK_ENABLE();/**TIM2 GPIO ConfigurationPA0-WKUP ------> TIM2_CH1PA1 ------> TIM2_CH2*/GPIO_InitStruct.Pin = GPIO_PIN_0|GPIO_PIN_1; /* 这⾥定义了2路PMW输出⽤PA0 和PA1*/ GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW;HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);/* USER CODE BEGIN TIM2_MspPostInit 1 *//* USER CODE END TIM2_MspPostInit 1 */}}void HAL_TIM_Base_MspDeInit(TIM_HandleTypeDef* tim_baseHandle){if(tim_baseHandle->Instance==TIM1){/* USER CODE BEGIN TIM1_MspDeInit 0 *//* USER CODE END TIM1_MspDeInit 0 *//* Peripheral clock disable */__HAL_RCC_TIM1_CLK_DISABLE();/**TIM1 GPIO ConfigurationPA8 ------> TIM1_CH1*/HAL_GPIO_DeInit(GPIOA, GPIO_PIN_8);/* TIM1 interrupt Deinit */HAL_NVIC_DisableIRQ(TIM1_CC_IRQn);/* USER CODE BEGIN TIM1_MspDeInit 1 *//* USER CODE END TIM1_MspDeInit 1 */}else if(tim_baseHandle->Instance==TIM2){/* USER CODE BEGIN TIM2_MspDeInit 0 *//* USER CODE END TIM2_MspDeInit 0 *//* Peripheral clock disable */__HAL_RCC_TIM2_CLK_DISABLE();/* USER CODE BEGIN TIM2_MspDeInit 1 *//* USER CODE END TIM2_MspDeInit 1 */}}/* USER CODE BEGIN 1 *//*** @brief Conversion complete callback in non blocking mode 捕获回调函数* @param htim : hadc handle* @retval None*/void HAL_TIM_IC_CaptureCallback(TIM_HandleTypeDef *htim){if (htim->Channel == HAL_TIM_ACTIVE_CHANNEL_1){/* 获取输⼊捕获值 */IC1Value = HAL_TIM_ReadCapturedValue(&htim1,TIM_CHANNEL_1);IC2Value = HAL_TIM_ReadCapturedValue(&htim1,TIM_CHANNEL_2);if (IC1Value != 0){/* 占空⽐计算 */DutyCycle = (float)((IC2Value+1) * 100) / (IC1Value+1);/* 频率计算 */Frequency = 72000000/72/(float)(IC1Value+1);}else{DutyCycle = 0;Frequency = 0;}}}/* USER CODE END 1 *//************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/3.2 main.c ⽤于计算的变量//计算占空⽐时的全局表变量extern __IO uint16_t IC2Value;extern __IO uint16_t IC1Value;extern __IO float DutyCycle;extern __IO float Frequency; 使能和输出PWM/// 使能捕获/⽐较2中断请求HAL_TIM_IC_Start_IT(&htim1,TIM_CHANNEL_1);HAL_TIM_IC_Start_IT(&htim1,TIM_CHANNEL_2);/// 开始输出PWMHAL_TIM_PWM_Start(&htim2,TIM_CHANNEL_1);HAL_TIM_PWM_Start(&htim2,TIM_CHANNEL_2); 打印调试输出while (1){/* USER CODE END WHILE *//* USER CODE BEGIN 3 */printSwo("IC1Value =",IC1Value,LINE_FEED_EN);printSwo("IC2Value =",IC2Value,LINE_FEED_EN);printSwo("占空⽐:",DutyCycle,LINE_FEED_EN);printSwo("频率:",Frequency,LINE_FEED_EN);HAL_Delay(500);}3.3 输出结果短接任意⼀路输出 PA0与PA8 PWM输出与捕获,或 PA1与PA8 PWM输出与捕获。
STM32利用捕获功能完成脉冲宽度测量STM32是一款常见的32位微控制器,它具有强大的功能和灵活性。
通过利用STM32的捕获功能,我们可以实现脉冲宽度测量。
下面是一个详细的说明,包括如何配置STM32的定时器和GPIO引脚,以及如何使用捕获功能进行脉冲宽度测量。
1.配置定时器和GPIO引脚:首先,我们需要配置定时器和GPIO引脚,以确保它们能够正常工作。
在STM32中,使用CubeMX可视化工具来配置硬件资源是一个比较方便的方法。
- 打开CubeMX工具,并选择你正在使用的STM32微控制器型号。
- 在"Pinout & Configuration"选项卡中,选择所需的GPIO引脚进行输入捕获。
将引脚配置为输入模式,并启用上拉或下拉电阻。
-在同一选项卡上,选择所需的定时器。
将其配置为捕获模式,并选择所需的输入通道。
- 在"Generated Code"选项卡中,点击"Project Firmware Structure"下的"Middlewares"文件夹,选择"TIM"文件夹,然后选择"TIM_HandleTypeDef"文件。
复制该文件到你的代码工程文件夹下。
2.配置捕获功能与中断处理函数:- 在自动生成的代码中,找到`HAL_TIM_IC_MspInit`函数。
在该函数中,初始化定时器和GPIO相关的寄存器。
-在主函数中,进行以下配置:```cuint32_t ICValue1 = 0;uint32_t ICValue2 = 0;uint32_t Difference = 0;TIM_HandleTypeDef htim2;```-初始化定时器和GPIO:```cvoid MX_TIM2_Init(void)TIM_MasterConfigTypeDef sMasterConfig = {0};TIM_IC_InitTypeDef sConfigIC = {0};htim2.Instance = TIM2;htim2.Init.Prescaler = 0;htim2.Init.CounterMode = TIM_COUNTERMODE_UP;htim2.Init.Period = 0xFFFFFFFF;htim2.Init.ClockDivision = TIM_CLOCKDIVISION_DIV1; HAL_TIM_IC_Init(&htim2);sConfigIC.ICPolarity = TIM_ICPOLARITY_RISING; sConfigIC.ICSelection = TIM_ICSELECTION_DIRECTTI;sConfigIC.ICPrescaler = TIM_ICPSC_DIV1;sConfigIC.ICFilter = 0;HAL_TIM_IC_ConfigChannel(&htim2, &sConfigIC, TIM_CHANNEL_1);sMasterConfig.MasterSlaveMode = TIM_MASTERSLAVEMODE_DISABLE;HAL_TIMEx_MasterConfigSynchronization(&htim2,&sMasterConfig);```3.启动捕获功能和中断处理:```cvoid HAL_TIM_IC_CaptureCallback(TIM_HandleTypeDef *htim)if (htim->Channel == HAL_TIM_ACTIVE_CHANNEL_1)if (ICValue1 == 0)ICValue1 = HAL_TIM_ReadCapturedValue(htim, TIM_CHANNEL_1);}else if (ICValue2 == 0)ICValue2 = HAL_TIM_ReadCapturedValue(htim, TIM_CHANNEL_1);if (ICValue2 > ICValue1)Difference = ICValue2 - ICValue1;}else if (ICValue1 > ICValue2)Difference = (0xFFFFFFFF - ICValue1) + ICValue2; }elseError_Handler(;}ICValue1 = 0;ICValue2 = 0;}}int main(void)HAL_Init(;SystemClock_Config(;MX_GPIO_Init(;MX_TIM2_Init(;HAL_TIM_IC_Start_IT(&htim2, TIM_CHANNEL_1); while (1)//主循环}```4.测试和读取脉冲宽度:通过使用上述代码配置和启动定时器和GPIO引脚后,STM32将能够使用捕获功能进行脉冲宽度测量。
STM32输入捕获的脉冲宽度及频率计算脉冲宽度的计算:脉冲宽度是指脉冲信号的高电平或低电平持续的时间。
在STM32中,定时器的输入捕获模式可以测量脉冲宽度。
输入捕获模式下,定时器会记录脉冲边沿的时间戳,可以通过计算时间戳之差来得到脉冲宽度。
具体的计算方法如下:1.配置定时器为输入捕获模式,并设置触发边沿(上升沿或下降沿)。
2.当捕获到脉冲边沿时,获取当前的定时器计数器值,作为开始时间戳。
3.当下一个脉冲边沿到来时,再次获取当前的定时器计数器值,作为结束时间戳。
4.计算时间戳之差,即为脉冲宽度。
脉冲频率的计算:脉冲频率是指单位时间内脉冲信号的个数。
脉冲频率的计算可以通过测量脉冲的周期来实现。
在STM32中,定时器的输入捕获模式可以测量脉冲的周期。
具体的计算方法如下:1.配置定时器为输入捕获模式,并设置触发边沿(上升沿或下降沿)。
2.当捕获到脉冲边沿时,获取当前的定时器计数器值,作为开始时间戳。
3.当接收到下一个脉冲边沿时,再次获取当前的定时器计数器值,作为结束时间戳。
4.计算时间戳之差,即为脉冲的周期。
5.频率等于周期的倒数。
需要注意的是,输入捕获功能只能测量单个脉冲的宽度和周期,如果要测量信号源的频率或平均脉冲宽度,需要根据测量的脉冲个数进行统计和计算。
以下是一个示例代码,演示了如何使用STM32的输入捕获功能计算脉冲宽度和频率:```c#include "stm32f4xx.h"//定义输入捕获相关的变量volatile uint32_t startTimestamp = 0;volatile uint32_t endTimestamp = 0;volatile uint32_t pulseWidth = 0;volatile uint32_t pulsePeriod = 0;volatile uint32_t pulseFrequency = 0;void TIM2_IRQHandler(void)if (TIM_GetITStatus(TIM2, TIM_IT_CC1) != RESET)if (startTimestamp == 0)startTimestamp = TIM_GetCapture1(TIM2);} elseendTimestamp = TIM_GetCapture1(TIM2);pulseWidth = endTimestamp - startTimestamp;pulsePeriod = pulseWidth * 2;pulseFrequency = SystemCoreClock / pulsePeriod;startTimestamp = 0;}TIM_ClearITPendingBit(TIM2, TIM_IT_CC1);}int main(void)//初始化定时器2TIM_TimeBaseInitTypeDef TIM_TimeBaseInitStruct;TIM_DeInit(TIM2);TIM_TimeBaseInitStruct.TIM_CounterMode = TIM_CounterMode_Up; // 设置计数器为向上计数模式TIM_TimeBaseInitStruct.TIM_Period = 0xFFFFFFFF; // 设置计数器的溢出值为最大值TIM_TimeBaseInitStruct.TIM_ClockDivision = TIM_CKD_DIV1; // 设置时钟分割TIM_TimeBaseInitStruct.TIM_RepetitionCounter = 0; // 设置重复计数值为0TIM_TimeBaseInit(TIM2, &TIM_TimeBaseInitStruct);//配置输入捕获模式TIM_ICInitTypeDef TIM_ICInitStruct;TIM_ICInitStruct.TIM_Channel = TIM_Channel_1; // 选择定时器通道1TIM_ICInitStruct.TIM_ICPolarity = TIM_ICPolarity_Rising; // 设置捕获参数,上升沿触发TIM_ICInitStruct.TIM_ICSelection = TIM_ICSelection_DirectTI; // 设置输入映射,直接连接至TIM2_IC1管脚TIM_ICInitStruct.TIM_ICPrescaler = TIM_ICPSC_DIV1; // 设置输入分频,不分频TIM_ICInitStruct.TIM_ICFilter = 0; // 不开启滤波器TIM_ICInit(TIM2, &TIM_ICInitStruct);//开启输入捕获中断TIM_ClearITPendingBit(TIM2, TIM_IT_CC1);TIM_ITConfig(TIM2, TIM_IT_CC1, ENABLE);//启动定时器2TIM_Cmd(TIM2, ENABLE);while (1)}```在上述示例代码中,定时器2被配置为输入捕获模式,通过TIM2的通道1测量脉冲输入。
STM32输入捕获简介
输入捕获模式可以用来测量脉冲宽度或者测量频率。
STM32的定时器,除了TIM6和TIM7,其他定时器都有输入捕获功能。
STM32的输入捕获,简单的说就是通过检测TIMx_CHx上的边沿信号,在边沿信号发生跳变(比如上升沿/下降沿)的时候,将当前定时器的值(TIMx_CNT)存放到对应的通道的捕获/比较寄存(TIMx_CCRx)里面,完成一次捕获。
同时还可以配置捕获时是否触发中断/DMA 等.
例如:我们用到TIM5_CH1来捕获高电平脉宽,也就是要先设置输入捕获为上升沿检测,记录发生上升沿的时候TIM5_CNT的值。
然后配置捕获信号为下降沿捕获,当下降沿到来时,发生捕获,并记录此时的TIM5_CNT值。
这样,前后两次TIM5_CNT之差,就是高电平的脉宽,同时TIM5的计数频率我们是知道的,从而可以计算出高电平脉宽的准确时间。
首先TIMx_ARR和TIMx_PSC,这两个寄存器用来设自动重装载值和TIMx的时钟分频。
再来看看捕获/比较模式寄存器1:TIMx_CCMR1,这个寄存器在输入捕获的时候,非常有用;TIMx_CCMR1明显是针对2个通道的配置,低八位[7:0]用于捕获/比较通道1的控制,而高八位[15:8]则用于捕获/比较通道2的控制,因为TIMx还有CCMR2这个寄存器,所以可以知道CCMR2是用来控制通道3和通道4(详见《STM32参考手册》290页,14.4.8节)。
这里用到TIM5的捕获/比较通道1,我们重点介绍TIMx_CMMR1的[7:0]位(其实高8位配置类似)。
再来看看捕获/比较使能寄存器:TIMx_CCER;
接下来我们再看看DMA/中断使能寄存器:TIMx_DIER,我们需要用到中断来处理捕获数据,所以必须开启通道1的捕获比较中断,即CC1IE设置为1。
控制寄存器:TIMx_CR1,我们只用到了它的最低位,也就是用来使能定时器的;
最后再来看看捕获/比较寄存器1:TIMx_CCR1,该寄存器用来存储捕获发生时,TIMx_CNT的值,我们从TIMx_CCR1就可以读出通道1捕获发生时刻的TIMx_CNT值,通过两次捕获(一次上升沿捕获,一次下降沿捕获)的差值,就可以计算出高电平脉冲的宽度。
使能捕获和更新中断(设置TIM5的DIER寄存器)
因为我们要捕获的是高电平信号的脉宽,所以,第一次捕获是上升沿,第二次捕获时下降沿,必须在捕获上升沿之后,设置捕获边沿为下降沿,同时,如果脉宽比较长,那么定时器就会溢出,对溢出必须做处理,否则结果就不准了。
这两件事,我们都在中断里面做,所以必须开启捕获中断和更新中断。
1void init_tim2_cam(u16 psc, u16 arr, u8 way, u8 dir)
2 {
3 RCC->APB1ENR |= 1<<0; //使能定时器2时钟
4 RCC->APB2ENR |= 1<<2; //使能PortA
5
6switch (way)
7 {
8case1:
9 GPIOA->CRL &= 0xfffffff0;
10 GPIOA->CRL |= 0x00000008;
11break;
12case2:
13 GPIOA->CRL &= 0xffffff00;
14 GPIOA->CRL |= 0x00000088;
15break;
16case3:
17 GPIOA->CRL &= 0xfffff000;
18 GPIOA->CRL |= 0x00000888;
19break;
20case4:
21 GPIOA->CRL &= 0xffff0000;
22 GPIOA->CRL |= 0x00008888;
23break;
24 }
25
26 TIMER->PSC = psc;
27 TIMER->ARR = arr;
28
29switch (way)
30 {
31case4:
32 TIMER->CCMR2 |= 1<<8;
33if (dir == 0)
34 TIMER->CCER |= 1<<13; //下降沿捕获
35else
36 TIMER->CCER &= ~(1<<13); //上升沿捕获
37 TIMER->CCER |= 1<<12;
38 TIMER->DIER |= 1<<4;
39case3: //CCR3 PA2
40 TIMER->CCMR2 |= 1<<0;
41if (dir == 0)
42 TIMER->CCER |= 1<<9; //下降沿捕获
43else
44 TIMER->CCER &= ~(1<<9); //上升沿捕获
45 TIMER->CCER |= 1<<8;
46 TIMER->DIER |= 1<<3;
47case2: //CCR2 PA1
48 TIMER->CCMR1 |= 1<<8; //CCR2配置通道方向:输入49if (dir == 0)
50 TIMER->CCER |= 1<<5; //下降沿捕获
51else
52 TIMER->CCER &= ~(1<<5); //上升沿捕获
53 TIMER->CCER |= 1<<4; //CCR2通道捕获使能
54 TIMER->DIER |= 1<<2; //CCR2通道允许捕获中断
55case1: //>CCR1 PA0
56 TIMER->CCMR1 |= 1<<0; //CCR1配置通道方向:输入
57if (dir == 0)
58 TIMER->CCER |= 1<<1; //下降沿捕获
59else
60 TIMER->CCER &= ~(1<<1); //上升沿捕获
61 TIMER->CCER |= 1<<0; //CCR1捕获使能
62 TIMER->DIER |= 1<<1; //CCR1通道允许捕获中断
63break;
64 }
65 TIMER->DIER |= 1<<0; //允许更新中断
66MY_NVIC_Init(1, 2, TIM2_IRQChannel, 2); //中断
67 TIMER->CR1 = 0x01; //使能定时器
68 TIMER->SR &= ~(1<<0);
69 }。