历史上的今天
今天是:2025年01月30日(星期四)
2019年01月30日 | 使用STM32CubeMx配置STM32输入捕获功能
2019-01-30 来源:eefocus
输入捕获原理
在输入捕获模式下,当检测到ICx信号上相应的边沿后,计数器的当前值被锁存到捕获/比较寄存器(TIMx_CCRx)中。当发生捕获事件时,相应的CCxIF标志(TIMx_SR寄存器)被置1,如果开放了中断或者DMA操作,则将产生中断或者DMA请求。如果发生捕获事件时CCxIF标志已经为高,那么重复捕获标志CCxOF(TIMx_SR寄存器)被置1。写CCxIF=0可清除CCxIF,或读取存储在TIMx_CCRx寄存器中的捕获数据也可清除CCxIF。写CCxOF=0可清除CCxOF。
摘自《STM32参考手册中文》
简单解释:定时器一直在计数,如果检测到设置的极性边沿,会把当前的计数值存下来,并触发中断;
比如,定时器设置为TIM2,预分频719,计数周期0xFFFF,则TIM2 10us计数一次,计数到0xFFFF,重装载到0;现在设置的输入捕获极性为上升沿捕获,则当某通道捕获到一次上升沿后,触发中断,并将当前的计数值存在对应通道的CCR值;
所以无论是设置为上升沿捕获还是下降沿捕获,都只能得到整个脉冲的周期时间;如果是想获得高电平占整个周期的百分比呢?
那么我就需要在最开始设置为上升沿捕获,当捕获到一个上升沿后,把极性设置为下降沿捕获,依次类推,这样我们就可以得到高电平时间和周期时间了;注意要设置好标志位
这里的话会出现一个问题,比如我的上升沿时间点在上一个周期,下降沿时间点在下一个周期,那么在下降沿-上升沿之前还要再加上一个定时器周期
以下是我的STM32CubeMx配置



8. 以下是比较重要的代码
/* Private variables ---------------------------------------------------------*/
uint16_t Channel1HighTime, Channel2HighTime, Channel3HighTime, Channel4HighTime;
uint16_t Channel1Period, Channel2Period, Channel3Period, Channel4Period;
uint8_t Channel1Edge = 0, Channel2Edge = 0, Channel3Edge = 0, Channel4Edge = 0;
uint16_t Channel1Percent, Channel2Percent, Channel3Percent, Channel4Percent;
uint16_t Channel1PercentTemp[3] = {0, 0, 0};
uint8_t Channel1TempCount = 0;
uint16_t Channel1RisingTimeLast=0, Channel1RisingTimeNow, Channel1FallingTime;
uint16_t Channel2RisingTimeLast=0, Channel2RisingTimeNow, Channel2FallingTime;
uint16_t Channel3RisingTimeLast=0, Channel3RisingTimeNow, Channel3FallingTime;
uint16_t Channel4RisingTimeLast=0, Channel4RisingTimeNow, Channel4FallingTime;
/* USER CODE END PV */
int main(void)
{
/* USER CODE BEGIN 1 */
/* USER CODE END 1 */
/* MCU Configuration----------------------------------------------------------*/
/* Reset of all peripherals, Initializes the Flash interface and the Systick. */
HAL_Init();
/* USER CODE BEGIN Init */
/* USER CODE END Init */
/* Configure the system clock */
SystemClock_Config();
/* USER CODE BEGIN SysInit */
/* USER CODE END SysInit */
/* Initialize all configured peripherals */
MX_GPIO_Init();
MX_USART1_UART_Init();
MX_TIM2_Init();
/* USER CODE BEGIN 2 */
HAL_TIM_IC_Start_IT(&htim2, TIM_CHANNEL_1);
HAL_TIM_IC_Start_IT(&htim2, TIM_CHANNEL_2);
HAL_TIM_IC_Start_IT(&htim2, TIM_CHANNEL_3);
HAL_TIM_IC_Start_IT(&htim2, TIM_CHANNEL_4);
/* USER CODE END 2 */
/* Infinite loop */
/* USER CODE BEGIN WHILE */
while (1)
{
HAL_GPIO_TogglePin(GPIOB, GPIO_PIN_0);
HAL_Delay(500);
/* USER CODE END WHILE */
/* USER CODE BEGIN 3 */
}
/* USER CODE END 3 */
}
void HAL_TIM_IC_CaptureCallback(TIM_HandleTypeDef *htim)
{
/* Prevent unused argument(s) compilation warning */
UNUSED(htim);
/* NOTE : This function Should not be modified, when the callback is needed,
the __HAL_TIM_IC_CaptureCallback could be implemented in the user file
*/
if(htim->Channel == HAL_TIM_ACTIVE_CHANNEL_1)
{
if(Channel1Edge == 0)
{
Channel1RisingTimeNow = HAL_TIM_ReadCapturedValue(&htim2, TIM_CHANNEL_1);//获取上升沿时间点
__HAL_TIM_SET_CAPTUREPOLARITY(&htim2, TIM_CHANNEL_1, TIM_INPUTCHANNELPOLARITY_FALLING);//切换捕获极性
HAL_TIM_IC_Start_IT(&htim2, TIM_CHANNEL_1);
Channel1Edge = 1;
if(Channel1RisingTimeLast == 0)
{
Channel1Period = 0;
}
else
{
if(Channel1RisingTimeNow > Channel1RisingTimeLast)
{
Channel1Period = Channel1RisingTimeNow - Channel1RisingTimeLast;
}
else
{
Channel1Period = Channel1RisingTimeNow + 0xffff - Channel1RisingTimeLast + 1;
}
}
Channel1RisingTimeLast = Channel1RisingTimeNow;
}
else if(Channel1Edge == 1)
{
Channel1FallingTime = HAL_TIM_ReadCapturedValue(&htim2, TIM_CHANNEL_1);
__HAL_TIM_SET_CAPTUREPOLARITY(&htim2, TIM_CHANNEL_1, TIM_INPUTCHANNELPOLARITY_RISING);
HAL_TIM_IC_Start_IT(&htim2, TIM_CHANNEL_1);
if(Channel1FallingTime < Channel1RisingTimeNow)
{
Channel1HighTime = Channel1FallingTime + 0xffff - Channel1RisingTimeNow + 1;
}
else
{
Channel1HighTime = Channel1FallingTime - Channel1RisingTimeNow;
}
if(Channel1Period != 0)
{
Channel1Percent = (uint8_t)(((float)Channel1HighTime / Channel1Period) * 1000);
printf("Channel1 = %d ", Channel1Percent);
}
Channel1Edge = 0;
}
}
else if(htim->Channel == HAL_TIM_ACTIVE_CHANNEL_2)
{
if(Channel2Edge == 0)
{
Channel2RisingTimeNow = HAL_TIM_ReadCapturedValue(&htim2, TIM_CHANNEL_2);
__HAL_TIM_SET_CAPTUREPOLARITY(&htim2, TIM_CHANNEL_2, TIM_INPUTCHANNELPOLARITY_FALLING);
HAL_TIM_IC_Start_IT(&htim2, TIM_CHANNEL_2);
Channel2Edge = 1;
if(Channel2RisingTimeLast == 0)
{
Channel2Period = 0;
}
else
{
if(Channel2RisingTimeNow > Channel2RisingTimeLast)
{
Channel2Period = Channel2RisingTimeNow - Channel2RisingTimeLast;
}
else
{
Channel2Period = Channel2RisingTimeNow + 0xffff - Channel2RisingTimeLast + 1;
}
}
Channel2RisingTimeLast = Channel2RisingTimeNow;
}
else if(Channel2Edge == 1)
{
Channel2FallingTime = HAL_TIM_ReadCapturedValue(&htim2, TIM_CHANNEL_2);
__HAL_TIM_SET_CAPTUREPOLARITY(&htim2, TIM_CHANNEL_2, TIM_INPUTCHANNELPOLARITY_RISING);
HAL_TIM_IC_Start_IT(&htim2, TIM_CHANNEL_2);
if(Channel2FallingTime < Channel2RisingTimeNow)
{
Channel2HighTime = Channel2FallingTime + 0xffff - Channel2RisingTimeNow + 1;
}
else
{
Channel2HighTime = Channel2FallingTime - Channel2RisingTimeNow;
}
if(Channel2Period != 0)
{
Channel2Percent = (uint8_t)(((float)Channel2HighTime / Channel2Period) * 1000);
printf("Channel2 = %d ", Channel2Percent);
}
Channel2Edge = 0;
}
}
else if(htim->Channel == HAL_TIM_ACTIVE_CHANNEL_3)
{
if(Channel3Edge == 0)
{
Channel3RisingTimeNow = HAL_TIM_ReadCapturedValue(&htim2, TIM_CHANNEL_3);
__HAL_TIM_SET_CAPTUREPOLARITY(&htim2, TIM_CHANNEL_3, TIM_INPUTCHANNELPOLARITY_FALLING);
HAL_TIM_IC_Start_IT(&htim2, TIM_CHANNEL_3);
Channel3Edge = 1;
if(Channel3RisingTimeLast == 0)
{
Channel3Period = 0;
}
else
{
if(Channel3RisingTimeNow > Channel3RisingTimeLast)
{
Channel3Period = Channel3RisingTimeNow - Channel3RisingTimeLast;
}
else
{
Channel3Period = Channel3RisingTimeNow + 0xffff - Channel3RisingTimeLast + 1;
}
}
Channel3RisingTimeLast = Channel3RisingTimeNow;
}
else if(Channel3Edge == 1)
{
Channel3FallingTime = HAL_TIM_ReadCapturedValue(&htim2, TIM_CHANNEL_3);
__HAL_TIM_SET_CAPTUREPOLARITY(&htim2, TIM_CHANNEL_3, TIM_INPUTCHANNELPOLARITY_RISING);
HAL_TIM_IC_Start_IT(&htim2, TIM_CHANNEL_3);
if(Channel3FallingTime < Channel3RisingTimeNow)
{
Channel3HighTime = Channel3FallingTime + 0xffff - Channel3RisingTimeNow + 1;
}
else
{
Channel3HighTime = Channel3FallingTime - Channel3RisingTimeNow;
}
if(Channel3Period != 0)
{
Channel3Percent = (uint8_t)(((float)Channel3HighTime / Channel3Period) * 1000);
printf("Channel3 = %d ", Channel3Percent);
}
Channel3Edge = 0;
}
}
else if(htim->Channel == HAL_TIM_ACTIVE_CHANNEL_4)
{
if(Channel4Edge == 0)
{
Channel4RisingTimeNow = HAL_TIM_ReadCapturedValue(&htim2, TIM_CHANNEL_4);
__HAL_TIM_SET_CAPTUREPOLARITY(&htim2, TIM_CHANNEL_4, TIM_INPUTCHANNELPOLARITY_FALLING);
HAL_TIM_IC_Start_IT(&htim2, TIM_CHANNEL_4);
Channel4Edge = 1;
if(Channel4RisingTimeLast == 0)
{
Channel4Period = 0;
}
else
{
if(Channel4RisingTimeNow > Channel4RisingTimeLast)
{
Channel4Period = Channel4RisingTimeNow - Channel4RisingTimeLast;
}
else
{
Channel4Period = Channel4RisingTimeNow + 0xffff - Channel4RisingTimeLast + 1;
}
}
Channel4RisingTimeLast = Channel4RisingTimeNow;
}
else if(Channel4Edge == 1)
{
Channel4FallingTime = HAL_TIM_ReadCapturedValue(&htim2, TIM_CHANNEL_4);
__HAL_TIM_SET_CAPTUREPOLARITY(&htim2, TIM_CHANNEL_4, TIM_INPUTCHANNELPOLARITY_RISING);
HAL_TIM_IC_Start_IT(&htim2, TIM_CHANNEL_4);
if(Channel4FallingTime < Channel4RisingTimeNow)
{
Channel4HighTime = Channel4FallingTime + 0xffff - Channel4RisingTimeNow + 1;
}
else
{
Channel4HighTime = Channel4FallingTime - Channel4RisingTimeNow;
}
if(Channel4Period != 0)
{
Channel4Percent = (uint8_t)(((float)Channel4HighTime / Channel4Period) * 1000);
printf("Channel4 = %d\n", Channel4Percent);
}
Channel4Edge = 0;
}
}
}
史海拾趣
|
1. 引言1)汽车发动机基本原理和构造当今世界上的汽车发动机工作过程基本上都由四个冲程组成,即进气、压缩、膨胀和排气。利用燃料和空气的混合气在气缸内燃烧产生的高温高压气体的膨胀,发动机借助于曲柄连杆机构通过曲轴对外输出扭矩 ...… 查看全部问答> |
|
不可否认的是,TI还是有钱人~~ 说做MCU,这回又砸向了8位单片机市场: 起价仅 25 美分的 MSP430G2xx 系列 旨在用16位MCU的性能、8位MCU的价格攻城略地。 据称第一批产品现在已经可以提供样片了。昨天还和朋友聊,朋友也觉得:16位机这样的价 ...… 查看全部问答> |
|
企业虚拟化项目十个重要技术问题中国IDC圈 利用虚拟化技术,把软件从硬件当中抽取出来,创建灵活、动态的环境,这样的好处很吸引人。不过能 否成功实施该项技术则取决于所需技能、安全和管理工具以及业务驱动因素是否到位。因为,在有些情 况下 ...… 查看全部问答> |
|
大家好,小弟最近在做一个关于ADC的滑动平均的算法,遇到问题,还请指教。 先说下正常情况,将ADC数据传送到终端的步骤如下: ADC连续转换模式,每转换一个ADC数据,就触发一次中断。随后交给UART送到终端。 但后来发现,当ADC的转换频率为8KHZ ...… 查看全部问答> |
|
大家好,我在往开发板里烧写NK文件的时候在到达99%的时候,超级终端出现了: OEMVerifyMemory FAILED !OEMVERIFYMEMORY: Invalid image 然后烧写进度就停留在了99%,请问是什么错误啊?应该如何修改呢?… 查看全部问答> |
|
请问嵌入式系统移植是怎样的一个概念? 和原来我们所说的单片机对比来说 在系统上编程又有什么不同,如果是否需要学习vc,我只会c 还有驱动编程,又是怎么一回事,和单片机的IO口控制,flash读写,uart控制有什么区别 谢谢各位指导… 查看全部问答> |
|
【我给XILINX资源中心做贡献】设计小技巧--Xilinx公司内部资料 设计小技巧--Xilinx公司内部资料这是一个在设计中常犯的错误列表,这些错误使得你的设计不可靠或者速度较慢。为了提高你的设计性能和提高速度的可靠性,你必须确定你的设计通过所有的这些检查。… 查看全部问答> |




