STM32定时器输入捕获

2023-11-13

STM32定时器输入捕获

用STM32F429做定时器捕获PWM波形,测出波形的周期、频率以及占空比、正向脉宽。

基本原理

定时器的输入捕获主要是为了测量输入信号的频率,脉宽,占空比等信息。

需要理解stm32定时器的基本结构

image-20220305195539774

主要理解这些框起来的是重点,都是本人自己的理解,才疏学浅,万一有理解错的还望指正。

至于上半部分的时钟没有太难理解的。下面的通道理解上才比较复杂。

首先一个通用定时器有4个输入通道4个通道,这些通道可以空着也可以复用到对应的GPIO上去,

/*
 	可以输出到GPIO的TIM通道:

	TIM1_CH1, PA8,	PE9,
	TIM1_CH2, PA9,	PE11
	TIM1_CH3, PA10,	PE13
	TIM1_CH4, PA11,	PE14

	TIM2_CH1, PA15 (仅限429,439) 407没有此脚
	TIM2_CH2, PA1,	PB3
	TIM2_CH3, PA2,	PB10
	TIM2_CH4, PA3,	PB11

	TIM3_CH1, PA6,  PB4, PC6
	TIM3_CH2, PA7,	PB5, PC7
	TIM3_CH3, PB0,	PC8
	TIM3_CH4, PB1,	PC9

	TIM4_CH1, PB6,  PD12
	TIM4_CH2, PB7,	PD13
	TIM4_CH3, PB8,	PD14
	TIM4_CH4, PB9,	PD15

	TIM5_CH1, PA0,  PH10
	TIM5_CH2, PA1,	PH11
	TIM5_CH3, PA2,	PH12
	TIM5_CH4, PA3,	PI10

	TIM8_CH1, PC6,  PI5
	TIM8_CH2, PC7,	PI6
	TIM8_CH3, PC8,	PI7
	TIM8_CH4, PC9,	PI2

	TIM9_CH1, PA2,  PE5
	TIM9_CH2, PA3,	PE6

	TIM10_CH1, PB8,  PF6

	TIM11_CH1, PB9,  PF7

	TIM12_CH1, PB14,  PH6
	TIM12_CH2, PB15,  PH9

	TIM13_CH1, PA6,  PF8
	TIM14_CH1, PA7,  PF9

但是一个通道只能配置成一种模式,比如配置成输出模式,就不能配置成输入模式,虽然一个通道有好几个GPIO可以设置,但是设置完一个其他就不能在设置在这个通道了。

因为要捕获输入的信号,所以设置为输入模式,关键看上图左侧的通道关系

TI1到TI4表示4个输入通道,但是输入通道并不是和定时器的通道直接连起来的,经过了输入滤波器和边沿检测器之后,一个输入通道就分成了两个,可以分别送到两个定时器通道去,比如TI1FP1,TI1FP2,这都是第一个输入通道分出来的,可以分别送给IC1和IC2,IC的意思就是输入通道,这样在后边定时器的捕获通道就可以一个捕获上升沿,一个捕获下降沿,这样就可以把一路PWM的频率和占空比都测出来了。

再接下来还有重要的问题是每个定时器的时钟速度。

image-20220305201447912

可以在时钟树上看到APB1和APB2上的定时器的时钟速度是不一样的。

	APB1 定时器有 TIM2, TIM3 ,TIM4, TIM5, TIM6, TIM7, TIM12, TIM13, TIM14 
	APB2 定时器有 TIM1, TIM8 ,TIM9, TIM10, TIM11
	

	APB1 定时器的输入时钟 TIMxCLK = SystemCoreClock / 2; 90M
	APB2 定时器的输入时钟 TIMxCLK = SystemCoreClock; 180M

因此在配置定时器的分频系数,和最后计算信号频率时要注意使用到的定时器的频率。

输入捕获计算信号的频率和占空比的原理是:

假设计数器的计数方向是向上,定时器会按照分频之后的速度,一直向上累加,当遇到设置好的边沿时,就会把当前计数的值存下来,通过读取这个值就可以知道在什么时刻检测到了边沿,通过不同边沿时刻的差值,就可以计算出频率等信息。

代码

使用Cubemx生成代码

image-20220305202250623

这个定时器配置来检测PWM信号。

前两个选项slave mode用来配置TI1FP1触发,而且触发之后的结果是reset,为什么要这么设置,关键是后边代码实现的原理,这么设置的意思是,当TI1FP1触发之后,整个计数器重置,从0开始数,如果前边不设置这么滤波器、分频器的话,TI1FP1就是第一路的输入信号,比如设置为搞电平触发之后,一旦来了高电平,之前全部复位开始计时,这就好比是PWM信号的高电平来了,全部重置,然后第1个定时器通道开始计时,直到遇到下一个上升沿的时候才会记录下数值,而第二路定时器通道也同时开始计时,直到遇到下降沿才记录数值。不难发现,第一路记录的数值就是整个周期的数值,而第二个通道记录的数值是上升沿到下降沿之间的数值,就是PWM正向脉宽的数值,这样就得出了想要的结果,所以要设置成这种模式。

下面两个选项是定时器的两个通道的选择,回到结构框图去看,通道一的输入可以有两个选择,TI1FP1和TI2FP1,那选择第一个就是直连,选择第二个就是非直连,第二路的选择也是同样的道理。硬件配置为通道1的GPIO,所以直接选择通道1直连,通道2非直连。

接下来的配置都比较明白,在下方的参数选择中,一个上升沿触发,一个下降沿触发。

下面主要涉及到3个函数:

TIM_HandleTypeDef htim3;
__IO uint16_t IC2Value = 0;
__IO uint16_t IC1Value = 0;
__IO float DutyCycle = 0;
__IO float Frequency = 0;



void bsp_SetPWMCapture()
{
	  /* USER CODE BEGIN TIM3_Init 0 */

  /* USER CODE END TIM3_Init 0 */

  TIM_ClockConfigTypeDef sClockSourceConfig = {0};
  TIM_SlaveConfigTypeDef sSlaveConfig = {0};
  TIM_MasterConfigTypeDef sMasterConfig = {0};
  TIM_IC_InitTypeDef sConfigIC = {0};
/* 
上面是3个句柄结构体

 */
  /* USER CODE BEGIN TIM3_Init 1 */

  /* USER CODE END TIM3_Init 1 */
  htim3.Instance = TIM3;
  htim3.Init.Prescaler = 90-1;
  htim3.Init.CounterMode = TIM_COUNTERMODE_UP;
  htim3.Init.Period = 65535;
  htim3.Init.ClockDivision = TIM_CLOCKDIVISION_DIV1;
  htim3.Init.AutoReloadPreload = TIM_AUTORELOAD_PRELOAD_DISABLE;
  /* 
上面主要设置了一些分频系数

 */
  if (HAL_TIM_Base_Init(&htim3) != HAL_OK)
  {
    Error_Handler(__FILE__, __LINE__);
  }
  sClockSourceConfig.ClockSource = TIM_CLOCKSOURCE_INTERNAL;
  if (HAL_TIM_ConfigClockSource(&htim3, &sClockSourceConfig) != HAL_OK)
  {
    Error_Handler(__FILE__, __LINE__);
  }
  if (HAL_TIM_IC_Init(&htim3) != HAL_OK)
  {
    Error_Handler(__FILE__, __LINE__);
  }
  sSlaveConfig.SlaveMode = TIM_SLAVEMODE_RESET;
  sSlaveConfig.InputTrigger = TIM_TS_TI1FP1;
  sSlaveConfig.TriggerPolarity = TIM_INPUTCHANNELPOLARITY_RISING;
  sSlaveConfig.TriggerFilter = 0;
  /* 
上面设置的是从模式,比如设置为复位模式,TI1FP1上升沿触发

 */
  if (HAL_TIM_SlaveConfigSynchro(&htim3, &sSlaveConfig) != HAL_OK)
  {
    Error_Handler(__FILE__, __LINE__);
  }
  sMasterConfig.MasterOutputTrigger = TIM_TRGO_RESET;
  sMasterConfig.MasterSlaveMode = TIM_MASTERSLAVEMODE_DISABLE;
/* 
上面这里对于输入捕获来说没有用到

 */
  if (HAL_TIMEx_MasterConfigSynchronization(&htim3, &sMasterConfig) != HAL_OK)
  {
    Error_Handler(__FILE__, __LINE__);
  }
  sConfigIC.ICPolarity = TIM_INPUTCHANNELPOLARITY_RISING;
  sConfigIC.ICSelection = TIM_ICSELECTION_DIRECTTI;
  sConfigIC.ICPrescaler = TIM_ICPSC_DIV1;
  sConfigIC.ICFilter = 0;
  /* 
上面是通道1的配置参数

 */
  if (HAL_TIM_IC_ConfigChannel(&htim3, &sConfigIC, TIM_CHANNEL_1) != HAL_OK)
  {
    Error_Handler(__FILE__, __LINE__);
  }
  sConfigIC.ICPolarity = TIM_INPUTCHANNELPOLARITY_FALLING;
  sConfigIC.ICSelection = TIM_ICSELECTION_INDIRECTTI;
/* 
上面是通道2的配置参数

 */
  if (HAL_TIM_IC_ConfigChannel(&htim3, &sConfigIC, TIM_CHANNEL_2) != HAL_OK)
  {
    Error_Handler(__FILE__, __LINE__);
  }
  /* USER CODE BEGIN TIM3_Init 2 */
	HAL_TIM_IC_Start_IT(&htim3,TIM_CHANNEL_1);
	HAL_TIM_IC_Start_IT(&htim3,TIM_CHANNEL_2);
	/* 
上面是使能两个通道的输入捕获中断,cubemx是不会自动生成这两句的,需要自己手动添加

 */
  /* USER CODE END TIM3_Init 2 */

}
/* 
HAL_TIM_Base_MspInit是HAL库的一个弱定义函数,在这里定义之后就会按照这个定义为准
HAL_TIM_Base_Init会调用这个函数,用来初始化GPIO和中断的参数。
 */
void HAL_TIM_Base_MspInit(TIM_HandleTypeDef* tim_baseHandle)
{

  GPIO_InitTypeDef GPIO_InitStruct = {0};
  if(tim_baseHandle->Instance==TIM1)
  {
  
  }
  else if(tim_baseHandle->Instance==TIM2)
  {

  }
  else if(tim_baseHandle->Instance==TIM3)
  {
  /* USER CODE BEGIN TIM3_MspInit 0 */

  /* USER CODE END TIM3_MspInit 0 */
    /* TIM3 clock enable */
    __HAL_RCC_TIM3_CLK_ENABLE();

    __HAL_RCC_GPIOC_CLK_ENABLE();
    /**TIM3 GPIO Configuration
    PC6     ------> TIM3_CH1
    */
    GPIO_InitStruct.Pin = GPIO_PIN_6;
    GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
    GPIO_InitStruct.Pull = GPIO_NOPULL;
    GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW;
    GPIO_InitStruct.Alternate = GPIO_AF2_TIM3;
    HAL_GPIO_Init(GPIOC, &GPIO_InitStruct);

    /* TIM3 interrupt Init */
    HAL_NVIC_SetPriority(TIM3_IRQn, 0, 0);
    HAL_NVIC_EnableIRQ(TIM3_IRQn);
  /* USER CODE BEGIN TIM3_MspInit 1 */

  /* USER CODE END TIM3_MspInit 1 */
  }

}
/*
//__HAL_TIM_SET_CAPTUREPOLARITY(__HANDLE__, __CHANNEL__, __POLARITY__)可以设置指定定时器和通道的输入触发沿
接下来就是中断服务函数,如果产生了输入捕获中断就会在HAL库的中断服务函数中调用这个回调函数,可以在下面实现自己的代码
*/

void HAL_TIM_IC_CaptureCallback(TIM_HandleTypeDef *htim)
{
	if(TIM3 == htim->Instance)
	{
		if (htim->Channel == HAL_TIM_ACTIVE_CHANNEL_1)
		{
			/* 获取输入捕获值 */
			IC1Value = HAL_TIM_ReadCapturedValue(&htim3,TIM_CHANNEL_1);
			IC2Value = HAL_TIM_ReadCapturedValue(&htim3,TIM_CHANNEL_2);	
			if (IC1Value != 0)
			{
				/* 占空比计算 */
				DutyCycle = (float)((IC2Value+1) * 100) / (IC1Value+1);

				/* 频率计算 */
				Frequency = 90000000/90/(float)(IC1Value+1);
				
			}
			else
			{
				DutyCycle = 0;
				Frequency = 0;
			}

		}
	}
}

另外还需要定义一个大的中断服务函数。

void TIM3_IRQHandler(void)
{
  /* USER CODE BEGIN TIM3_IRQn 0 */

  /* USER CODE END TIM3_IRQn 0 */
  HAL_TIM_IRQHandler(&htim3);//在这个函数中会回调上面自定义的服务函数
  /* USER CODE BEGIN TIM3_IRQn 1 */

  /* USER CODE END TIM3_IRQn 1 */
}

至此配置完成,在主函数中做好初始化,在生成PWM波之后,把输出引脚和输入引脚相连,即可得到波形的数据。

首先设置了一个2k频率,占空比30的PWM波,以下为实验结果:

Snipaste_2022-03-05_19-41-57

DS0006

和示波器测得的数据完全一致。

本文如有错误或者不足,恳请指正。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

STM32定时器输入捕获 的相关文章

  • Android studio安装与配置

    1 首先下载Android studio安装包 下载地址为 http www android studio org 这里采用3 0版本进行演示 对应安装包为android studio ide 171 4408382 windows exe
  • 【微服务】Nacos:发现、配置和管理微服务

    Nacos 发现 配置和管理微服务 Nacos 在阿里巴巴起源于 2008 2008 2008 年五彩石项目 完成微服务拆分和业务中台建设 成长于十年双十一的洪峰考验 沉淀了简单易用 稳定可靠 性能卓越的核心竞争力 随着云计算兴起 2018

随机推荐

  • odoo 附件上传的三种姿势

    odoo 附件上传的三种姿势 因公司业务需要实现上传附件功能 一番折腾找到了三种附件上传的姿势 不过好像用处不大 1 下载 odoo 自带模块 在应用里搜索附件列出以及文档索引 安装模块即可 这样在编辑界面就可以看见附件上传按钮 上传即可
  • 使用微软官方工具MediaCreationTool制作Windows10的U盘系统安装盘

    需要重装系Windows10系统 这里介绍使用微软官方工具MediaCreationTool制作Windows10的U盘安装盘的步骤 1 点击链接https www microsoft com zh cn software download
  • [每日两题系列]刷算法题咯~~

    今日题目 最多能完成排序的块II 统计子矩阵 本系列所选题目均来自力扣或者牛客网站 所选题目主要是以其中的简单题为主 中等题为辅 包含少数困难题 原因是 本人目前能力还不够 开展这个系列的目的是督促自己 在暑假的时间里也要保持有一定的刷题量
  • Docker修改默认数据目录Docker Root Dir

    环境 Docker版本 19 03 12 OS版本 CentOS Linux release 7 7 1908 Core docker 默认数据目录 Docker Root Dir 是 var lib docker 可通过 docker i
  • 数组参数:交换数组中最大值和最小值的位置

    题目 定义一个函数 功能 实现数组中最大值和最小值交换位置 解题思路 定义一个数组参数的函数 首先要先找到数组元素中的最大值和最小值 然后用我们常用的方法来将最大值和最小值进行转换 最后在main函数中调用所定义的f函数 include
  • 【Python游戏】Python各大游戏合集(3):飞翔的小鸟、俄罗斯方块、24点小游戏、吃豆豆小游、扫雷

    相关文件 关注小编 私信小编领取哟 当然别忘了一件三连哟 公众号 Python日志 可以关注小编公众号 会不定时的发布一下Python小技巧 还有很多资源可以免费领取哟 源码领取 加Python学习交流群 773162165 可以领取哟 开
  • 前端面试题---框架篇

    Vue面试题 面试题 Vue2 x 生命周期有哪些 Vue生命周期总共可以分为8个阶段 创建前后 载入前后 更新前后 销毁前销毁后 以及一些特殊场景的生命周期 面试题 第一次进入组件或者页面 会执行哪些生命周期 beforeCreate c
  • 7.20黄金涨势是否会延续?今日如何布局

    近期有哪些消息面影响黄金走势 今日黄金多空该如何研判 黄金消息面解析 国际金价周四 7月20日 徘徊在1984美元 盎司附近 投资者继续押注近期公布的美国经济数据让美联储有理由暂停加息 金价上个交易日触及的5月24日以来新高1985 25美
  • python爬取支付宝基金数据_钱袋子往哪走?教你用Python爬取基金数据

    年关将至 钱袋子往哪走 有人买了定期存款 3年 年利率 3 987 按存50w计算 0 0385 50万 3年息 6万 月息 1666 72元0 039785 50万 3年息 6 21万 月息 1724 53元0 04125 50万 3年息
  • 跳跃游戏(两种详细解答)

    第一种 从前开始 class Solution public boolean canJump int nums 定义reach为能够到达的最远距离 int reach 0 for int i 0 i lt reach i temp表示在下标
  • java调用微信支付接口

    https github com binarywang weixin java pay demo pox xml引入依赖
  • 为何AI无法完全理解人类情感?GPT-4能否理解人类的情绪?

    在科幻小说和电影里 我们经常看到超级AI人工智能机器人可以理解 感知甚至模拟人类的情感 但在现实世界中 我们距离这个目标还有一段相当长的距离 即使是强大的GPT 4甚至未来的GPT 5 过高夸大AI的体验和性能 往往并不利于科技的发展 元宇
  • 华为OD流程走完了

    我机试题地址 传送门 huaweiOD机试题 机试过了后 华为上海部HR一面 耗时30分钟左右 问了些家庭 个人工作经历 包括结婚否 为什么辞职之类的 技术二面 同样 自我介绍结束后 问了些项目相关的细节 该环节完后 面试官共享其试题 限时
  • 猿创征文 |万字长文搞定企业中的mysql数据库部署及使用

    文章目录 Mysql 二进制安装及mycat 读写分离 1 学习环境 2 初始化环境 2 1 关闭selinux 防火墙 2 2 修改主机名 2 3 配置域名解析 2 4 时间同步 3 mysql 安装 3 1 二进制包上传服务器 3 2
  • winCE中实现虚拟串口的方法

    转载请标明是引用于 http blog csdn net chenyujing1234 欢迎大家拍砖 环境 wince6 0 ARM Freescell 一 目的 设计一个读GPS串口数据的驱动 并注册为COM口 二 实现过程 1 COM
  • CSS文字居中对齐学习

    CSS使用text align属性设置文字对齐方式 text align center 这样就设置了文字居中对齐
  • MDK编译生成的HEX、map与htm文件分析

    MDK编译生成的HEX map与htm文件分析 hex文件 Intel HEX文件是记录文本行的ASCII文本文件 在Intel HEX文件中 每一行是一个HEX记录 由十六进制数组成的机器码或者数据常量 Intel HEX文件经常被用于将
  • TCP报文段

    文章目录 什么是TCP TCP报文段 源端口号 目标端口号 序列号 Sequence number 确认号ack 数据偏移 首部长度 保留 8个标志 核心 窗口大小 校验和 可选项 填充 什么是TCP TCP是面向连接的 可靠的 基于字节流
  • Linux常用语法

    文章目录 第一章 Linux概述 第二章 Linux常用命令 第一讲 进入某个路径 第二讲 查看日志 VI 查看静态日志 tail watch 实时日志 tail 搭配使用参数 查看日志目标行 导出日志 查看当前路径下文件 按文件名查找文件
  • STM32定时器输入捕获

    STM32定时器输入捕获 用STM32F429做定时器捕获PWM波形 测出波形的周期 频率以及占空比 正向脉宽 基本原理 定时器的输入捕获主要是为了测量输入信号的频率 脉宽 占空比等信息 需要理解stm32定时器的基本结构 主要理解这些框起