stm32 笔记 PWM输入模式测量脉宽和占空比原理

news2024/11/15 16:02:42

一、PWM 输入模式测量脉宽

1.1 测量脉宽简介

在测量占空比之前,我们先一步一步来,先让 STM32 可以测量脉宽。

TIM3_CH1(tim3 定时器通道 1)捕获模式测量脉宽步骤如下:

1.输入捕获到 PWM 上升沿触发

2.发送中断,通知用户此时被触发,用户获得当前计数器值

3.计数器清零,然后继续计数...

让 STM32 芯片一直重复这三步即可不断地测量出当前的 PWM 脉宽。

1.2 测量脉宽原理

首先我们可以使用 PWM 的复位 Reset 模式,它复合我们之前所要求的功能。具有捕捉上升沿和计数器复位的能力。

如果我们使用 TIM_CH1,可以产生分别是TI1FP1 与TI1FP2 这一对信号。他们的功能是分别是捕捉上升沿和下降沿。

其原理是:

二者都是来自同一 TI1 输入通道,经过输入滤波和边沿检测器后所产生的具有相同特征的信号,然后映射到不同的输入捕捉通道,本质上还是同一路信号。

TI1FP1,是来自于通道TI1,经过滤波器后将接到捕捉比较通道 IC1;

TI1FP2,是来自于通道TI1,经过滤波器后将接到捕捉比较通道 IC2;

由这张图得知,所谓 IC1 就是上升沿信号,TI1FP1会捕获到。IC2 是下降沿信号,TI1FP2 会捕捉到。

1.3 cubeMX 配置

 

①和②在上文已经详细介绍,不再赘述

③我们使用内部时钟

④重点来了!我们捕捉的通道是 TIM_CH1 如果我们走红色这条线,即可用后面的 TI1FP1 捕捉到上升沿。使用直接捕获模式(input capture direct mode)即可。如果需要捕获 TI1FP2 的下降沿则需要使用 重映射输入捕获(input capture direct from remap)。

 

⑤配置分频系数,我的系统时钟是 80mhz,分频 80 则为 1mhz,所以计数速度是 每秒1000000次。

⑥计数器最大值为 65535,所以测量最大的脉宽则为 65536/1000000 = 0.065536 秒。取倒数大约为 15.25hz 所以请不要测量超过这个值的脉宽,否则就会溢出清零,导致测量不准。

⑦默认值,配置为上升沿计数。

1.3 cubeMX 生成的代码解析

/*STM32cubeMX 生成的 TIM3 初始化代码:*/
/* TIM3 init function */
void PWM_TIM3_CHANNEL_1_Init(void)
{

  /* 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};

  /* USER CODE BEGIN TIM3_Init 1 */

  /* USER CODE END TIM3_Init 1 */
  htim3.Instance = TIM3;		//指定需要配置的定时器
  htim3.Init.Prescaler = 79;	//定时器的预分频系数
  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();
  }
  sClockSourceConfig.ClockSource = TIM_CLOCKSOURCE_INTERNAL;	//使用STM32单片机内部时钟
  if (HAL_TIM_ConfigClockSource(&htim3, &sClockSourceConfig) != HAL_OK)
  {
    Error_Handler();
  }
  if (HAL_TIM_IC_Init(&htim3) != 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(&htim3, &sSlaveConfig) != HAL_OK)
  {
    Error_Handler();
  }
  sMasterConfig.MasterOutputTrigger = TIM_TRGO_RESET;
  sMasterConfig.MasterSlaveMode = TIM_MASTERSLAVEMODE_DISABLE;
  if (HAL_TIMEx_MasterConfigSynchronization(&htim3, &sMasterConfig) != HAL_OK)
  {
    Error_Handler();
  }
  sConfigIC.ICPolarity = TIM_INPUTCHANNELPOLARITY_RISING;
  sConfigIC.ICSelection = TIM_ICSELECTION_DIRECTTI;
  sConfigIC.ICPrescaler = TIM_ICPSC_DIV1;
  sConfigIC.ICFilter = 0;
  if (HAL_TIM_IC_ConfigChannel(&htim3, &sConfigIC, TIM_CHANNEL_1) != HAL_OK)
  {
    Error_Handler();
  }
  /* USER CODE BEGIN TIM3_Init 2 */

  /* USER CODE END TIM3_Init 2 */

}

输入GPIO口的配置:

大致是设置复用端口配置、时钟相关配置。比较简单就不全都注释了。

让我困惑的是为什么这个捕获 PWM 的引脚被配置成 GPIO_MODE_AF_PP 复用推挽输出,难道不应该是输入吗?

/*STM32cubeMX 生成的 TIM3 初始化代码:*/
void HAL_TIM_Base_MspInit(TIM_HandleTypeDef* tim_baseHandle)
{

  GPIO_InitTypeDef GPIO_InitStruct = {0};
  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_GPIOB_CLK_ENABLE();
    /**TIM3 GPIO Configuration
    PB4     ------> TIM3_CH1
    */
    GPIO_InitStruct.Pin = GPIO_PIN_4;
    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(GPIOB, &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 */
  }
}

1.4 需要我们写的获取值的代码

经过下降沿后会自动触发中断,在回调函数中判断下是 TIM3通道1发出的,就可以调用HAL_TIM_ReadCapturedValue() 取值了。

HAL_TIM_Base_Start(&htim3);
/* 启动定时器通道输入捕获并开启中断 */
HAL_TIM_IC_Start_IT(&htim3,TIM_CHANNEL_1);	

void HAL_TIM_IC_CaptureCallback(TIM_HandleTypeDef *htim)
{
	
	if(htim->Instance==TIM3)
	{
				if(htim->Channel == HAL_TIM_ACTIVE_CHANNEL_1)
			{
				PWM1_T_Count =  HAL_TIM_ReadCapturedValue(htim,TIM_CHANNEL_1)+1;
			}
	}

}

二、测量占空比

2.1 测量占空比分析

基于之前测量脉宽的逻辑,如果我们把测量上升沿配置成主模式,测量下降沿配置成从模式。STM32将会是这样的逻辑:

1.在上升沿复位两个计数器

2.下降沿暂停下降沿计数器

3.再次上升沿复位两个计数器

不断重复....

在之前测量脉宽我们使用了 TI1FP1 线路测量上升沿,不过测量下降沿则需要 TI1FP2 辅助,将其信号类似“转发”到 TIM_CH2 线路中 (下图红色线路)。也就是说,当我们在 TIM_CH1 同时捕捉上升沿和下降沿,就会占用 TIM_CH2 线路。

2.2 cubeMX 配置

基于之前的配置,我们需要将①通道2配置为从模式;在②中,将这个配置为下降沿触发。

2.3 需要我们写的代码

节约篇幅不再解释 cubeMX 生成的代码,直接贴出我们需要写的代码:

//输入捕获中断回调函数
void HAL_TIM_IC_CaptureCallback(TIM_HandleTypeDef *htim)
{
	
	  if(htim->Instance==TIM3)
  {
				if(htim->Channel == HAL_TIM_ACTIVE_CHANNEL_1)
			{
				PWM1_T_Count =  HAL_TIM_ReadCapturedValue(htim,TIM_CHANNEL_1)+1; //捕获脉宽
				PWM1_Duty = (float)PWM1_D_Count/PWM1_T_Count; //捕获占空比
			}
				else if(htim->Channel == HAL_TIM_ACTIVE_CHANNEL_2)
			{
				PWM1_D_Count =  HAL_TIM_ReadCapturedValue(htim,TIM_CHANNEL_2)+1;//捕获下降沿
			}					
	
	}

}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/175657.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

机器视觉_HALCON_快速向导_2.用HALCON开发程序

文章目录使用HALCON开发应用程序1. 认识HALCON:架构&数据结构1.1. HALCON算子1.2. 参数与数据结构1.2.1. Images 图像1.2.2. Regions 区域1.2.3. XLDS 扩展线1.2.4. Handles 句柄1.2.5. Tuple Mode 元组模式1.3. HALCON与并行编程1.4. HALCON支持计算设备1.5. H…

grant之后要跟着flush privileges吗?

在 MySQL 里面,grant 语句是用来给用户赋权的。不知道你有没有见过一些操作文档里面提到,grant 之后要马上跟着执行一个 flush privileges 命令,才能使赋权语句生效。我最开始使用 MySQL 的时候,就是照着一个操作文档的说明按照这个顺序操作的。 那么,grant 之后真的需要…

33.Isaac教程--操纵运动学

操纵运动学 ISAAC教程合集地址文章目录操纵运动学应用架构实施细节正向运动学逆运动学小码为了控制机器人手臂的运动,需要数学表示法来计算执行器输入并为轨迹规划器表示障碍物。 为实现这一点,操纵运动学 GEM 将铰接式机器人系统表示为连接的刚体&#…

Linux常用命令——sudo命令

在线Linux命令查询工具(http://www.lzltool.com/LinuxCommand) sudo 以其他身份来执行命令 补充说明 sudo命令用来以其他身份来执行命令,预设的身份为root。在/etc/sudoers中设置了可执行sudo指令的用户。若其未经授权的用户企图使用sudo,则会发出警…

pytorch深度学习基础(九)——深入浅析卷积核

深入浅析卷积核引言单通道卷积简单图像边缘检测锐化高斯滤波引言 提到卷积,应该多数人都会想到类似上图的这种示例,可以简单的理解成卷积核与图像中和卷积核相同大小的一块区域与卷积核相乘再求和,通过移动区域产生一个有和组成的新的图像&am…

Python烟花秀

前言 Python跨年烟花表演,具体源码见:Python跨年烟花代码-Python文档类资源-CSDN下载 烟花的粒子类 class particle: #烟花的粒子类 def __init__(self,canvas,num,sums,x,y,x_speed,y_speed,explosion_speed,color,size,max_life): sel…

第四章必备前端基础知识-第二节2:CSS属性

文章目录一:CSS属性一览表二:常用属性详解(1)字体属性(2)文本属性(3)背景属性一:CSS属性一览表 W3C:元素属性 A: align-content规定弹性容器内…

Android studio版本对用的gradle版本和插件版本(注意事项)

简介 Android Studio 构建系统以 Gradle 为基础,并且 Android Gradle 插件添加了几项专用于构建 Android 应用的功能。虽然 Android 插件通常会与 Android Studio 的更新步调保持一致,但插件(以及 Gradle 系统的其余部分)可独立于…

实体店运营:能提高顾客留存率的店铺陈列方式

今天是大年初一,秦丝祝各位商户老板新年快乐,喜迎开门红,赚个盆满钵满!现在还在营业的实体店应该不多了吧?大部分老板都回家团圆了。忙忙碌碌一整年,好不容易到了年关,好好休息是应该的。但是店…

Go存储引擎相关资料汇总

背景 ​ 最近逛知乎的时候看到了这个问题,“Go语言如何写数据库?”。说来我业余时间在这个领域有一些时间精力的投入了,所以想回答一下。我投入的方向是存储引擎方面,所以这篇文章主要是总结一下我看过的一些比较好的Go存储引擎的…

二维费用背包问题

二维费用背包问题一、问题二、思路1、状态表示2、状态转移3、循环设计4、注意三、代码一、问题 二、思路 这道题归根结底还是背包问题的一种,面对背包问题,我们的思路就是面对前i个物品的时候,我们的第i个物品是选还是不选,如果条…

关于ARM的向量中断控制器NVIC

学习或者了解过ARM的朋友应该都会知道NVIC这么个东西,这个东西也是ARM中非常重要的东西,它是ARM不可分离的部分,搭配着内核共同完成着对中断的响应。 1、那到底NVIC是个啥东西呢? NVIC:简称嵌套向量中断控制器。它管理…

【new操作符做了什么 —— js】

🧁个人主页:个人主页 ✌支持我 :点赞👍收藏🌼关注🧡 文章目录new操作符具体做了什么?🎈创建了一个空的对象✨将空对象的原型,指向于构造函数的原型🍧将空对象…

【操作系统】—— Windows卸载与清除工具“ Geek 与 CCleaner ” (带你快速了解)

📜 “作者 久绊A” 专注记录自己所整理的Java、web、sql等,IT技术干货、学习经验、面试资料、刷题记录,以及遇到的问题和解决方案,记录自己成长的点滴。 🍁 操作系统【带你快速了解】对于电脑来说,如果说…

day23-网络编程01

1.网络编程入门 1.1 网络编程概述【理解】 计算机网络 是指将地理位置不同的具有独立功能的多台计算机及其外部设备,通过通信线路连接起来,在网络操作系统,网络管理软件及网络通信协议的管理和协调下,实现资源共享和信息传递的计…

微服务框架需要处理哪些问题?

文章目录简述架构选择统一版本管理基础框架包管理业务框架包管理模型分层全局上下文管理数据结构定义上下文的传播前后端数据格式协定统一数据格式字段规范协定异常处理orm配置公共字段处理分页处理字段加解密缓存key的序列化哪些数据进行缓存消息队列key的规范队列的管理注册中…

34.Isaac教程--操作示例应用程序

操作示例应用程序 ISAAC教程合集地址文章目录操作示例应用程序与 Jupyter Notebook 的简单联合控制Shuffle Box with Simulator与 Jupyter Notebook 的简单联合控制 此示例使用 Jupyter Notebook 提供交互式联合控制。 这是处理用于操作组件(包括 LQR 规划器&#…

PowerShell 执行策略

在使用 SAPIEN 的PowerShell Studio时出现如下错误:无法在当前系统上运行该脚本。有关运行脚本和设置执行策略的详细信息,请参阅 https:/go.microsoft.com/fwlink/?LinkID135170 中的 about_Execution_Policies。 ERROR: 所在位置 行:1 字符: 2 ERROR: …

python基础——函数编程

python基础——函数编程 文章目录python基础——函数编程一、实验目的二、实验原理三、实验环境四、实验内容五、实验步骤一、实验目的 掌握函数编程 二、实验原理 在Python中,定义函数的语法如下: def 函数名([参数列表]): ‘’‘注解’…

【人人都是算法专家】一文搞定AI算法竞赛(全网最详细)

Rocky Ding公众号:WeThinkIn写在前面 【人人都是算法专家】栏目专注于分享Rocky在AI行业中业务/竞赛/研究/产品维度的思考与感悟。欢迎大家一起交流学习💪 大家好,我是Rocky。 之前Rocky总结过很多关于AI算法竞赛的方法论、经验思考以及细节…