输入捕获模式测频率PWM输入模式(PWMI)测占空比

2024-02-17 22:52

本文主要是介绍输入捕获模式测频率PWM输入模式(PWMI)测占空比,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

一、概念介绍

输出比较:

比较电路输入的CNT、CCR大小关系 ,在通道引脚输出高低电平

二、*频率知识、测量方法补充 *

N/fc得到标准频率的时长,也就是待测频率的周期

测频法代码实现:修改对射式红外传感器计次(上升沿计次)、定时器外部时钟(1s中断) 

测频法:定时器中断,并记录捕获次数;测周法:捕获中断,并记录定时器次数。

三、输入捕获电路分析如何实现测周法:

异或门其实还是为三相无刷电机服务,三个霍尔传感器检测转子位置,根据转子位置进行换相,在前三个通道接上霍尔传感器,这个定时器就作为无刷电机的接口定时器,去驱动换相电路工作

输入滤波器:避免毛刺

3.1设计成交叉状的目的:

TI1FP1(TI1 Filter Polarity 1) -->IC1<--TI2FP1

TI1FP2-->IC2<--TI2FP2

(1)灵活切换后续捕获电路输入 CH1变成CH2   即一个通道切换两个引脚

(2)把一个引脚的输入,同时映射到两个捕获单元(PWMI模式经典结构) 即两个捕获单元捕获一个引脚

举例:

第一个捕获通道?TI1FP1上升沿触发,用来捕获周期

第二个捕获通道TI1FP2下降沿触发,用来捕获占空比

两个通道同时对一个引脚进行捕获

3.2预分频器(测周法实现)&捕获中断

*设置上升沿触发,分频后的触发信号每来一次,CNT就会向CCR转运一次,又因为CNT是内部的标准时钟驱动的,CNT数值就可以记录两个上升沿之间的时间间隔,也就是周期,取倒数得到频率

上升沿用于触发输入捕获,CNT用于计数计时

捕获中断:同时产生捕获事件,这个事件在状态寄存器置标志位,同时也可以产生中断

3.3应用场景:超声波模块检测电路

3.4细节问题

每次捕获后,把CNT清零,这样下次上升沿再捕获,取出的CNT 才是两个上升沿的时间间隔

用主从触发模式自动完成

四、电路执行细节

 注意:

CNT的值是有上限的(65535=ARRmax),若信号频率太低,CNT计数值会溢出

 从模式的触发源选择:TI1FP1 TI2FP2没有3,4 想用从模式自动清零CNT,只能用通道1和通道2,对于通道3和通道4只能开启捕获中断,手动清零

-->Q:能否外部中断? AS:概念不清,外部中断那是CPU了啊,这里是硬件映射主模式,然后配置从模式

 也可以捕获第二个引脚:TI2FP1 TI2FP2

五、函数学习


/*****初始化输入捕获单元******/
void TIM_ICInit(TIM_TypeDef* TIMx, TIM_ICInitTypeDef* TIM_ICInitStruct);//只配置一个通道void TIM_PWMIConfig(TIM_TypeDef* TIMx, TIM_ICInitTypeDef* TIM_ICInitStruct);//配置两个通道(PWMI模式)/*****给输入捕获结构体赋初值*****/
void TIM_ICStructInit(TIM_ICInitTypeDef* TIM_ICInitStruct);*****************************选择从模式*********************************/*****选择从模式输入触发源*****/void TIM_SelectInputTrigger(TIM_TypeDef* TIMx, uint16_t TIM_InputTriggerSource);
/*****选择主模式输出触发源*****/
void TIM_SelectOutputTrigger(TIM_TypeDef* TIMx, uint16_t TIM_TRGOSource);
/*****选择从模式*****/
void TIM_SelectSlaveMode(TIM_TypeDef* TIMx, uint16_t TIM_SlaveMode);/*****配置分频器*****/ 
结构体里也能配置,一个效果void TIM_SetIC1Prescaler(TIM_TypeDef* TIMx, uint16_t TIM_ICPSC);
void TIM_SetIC2Prescaler(TIM_TypeDef* TIMx, uint16_t TIM_ICPSC);
void TIM_SetIC3Prescaler(TIM_TypeDef* TIMx, uint16_t TIM_ICPSC);
void TIM_SetIC4Prescaler(TIM_TypeDef* TIMx, uint16_t TIM_ICPSC);/*****读取CRR*****/
输入捕获模式下只读,输出比较只写(TIM_SetComparex),函数是不一样的
uint16_t TIM_GetCapture1(TIM_TypeDef* TIMx);
uint16_t TIM_GetCapture2(TIM_TypeDef* TIMx);
uint16_t TIM_GetCapture3(TIM_TypeDef* TIMx);
uint16_t TIM_GetCapture4(TIM_TypeDef* TIMx);

Q&AnS

为什么ARR要大一些?

-->防止N过大计数溢出,为了防止cnt到了某个值就重装了

psc也不能给的太小,防止测量的信号频率过低,导致计数器溢出

注意:

1.滤波器 VS分频器

滤波器计次不会改变信号原有频率,因为滤波器采样频率远远高于信号频率,只会滤除高频噪声,使信号更平滑

分频器对信号本身计次,会改变频率

这里用上升沿触发归零,后边用下降沿不触发归零,两个值一减就是占空比。归零一次是一个周期,从0开始计高电平方便得出占空比,不然还得用1再减一下

2.Fc = 72MHz/(psc+1)

 六、输入捕获模式测频率代码分析

main.c 

为什么PWM那里还是 720-1 IC却要改72-1?

#include "stm32f10x.h"    // Device header
#include "Delay.h"
#include "OLED.h"
#include "PWM.h"
#include "IC.h"int main(void)
{OLED_Init();PWM_Init();IC_Init();OLED_ShowString(1,1,"Freq:00000Hz");PWM_SetPreScaler(720-1);             //Freq= 72M / (PSC+1) / 100PWM_SetCompare1(50);                 //Duty = CRR / 100while(1){OLED_ShowNum(1,6,IC_GetFreq(),5);}}

IC.C

#include "stm32f10x.h"                  // Device headervoid IC_Init(void)
{/*****STEP1 开启时钟*****/RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM3,ENABLE);//TIM2要输出PWM 换成3捕获RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA,ENABLE);//TIM3_CH1 在PA6口/*****STEP2 配置GPIO*****/GPIO_InitTypeDef GPIO_InitStructure;GPIO_InitStructure.GPIO_Mode=GPIO_Mode_IPU;						GPIO_InitStructure.GPIO_Pin=GPIO_Pin_6;GPIO_InitStructure.GPIO_Speed=GPIO_Speed_50MHz;GPIO_Init(GPIOA,&GPIO_InitStructure);/*****STEP3 配置时基单元*****/	TIM_InternalClockConfig(TIM3);TIM_TimeBaseInitTypeDef TIM_TimeBaseInitStructure;TIM_TimeBaseInitStructure.TIM_ClockDivision =TIM_CKD_DIV1;TIM_TimeBaseInitStructure.TIM_CounterMode =TIM_CounterMode_Up ;TIM_TimeBaseInitStructure.TIM_Period = 65536 - 1;//ARRTIM_TimeBaseInitStructure.TIM_Prescaler = 72 - 1 ;//PSC 1MHzTIM_TimeBaseInitStructure.TIM_RepetitionCounter = 0;TIM_TimeBaseInit(TIM3,&TIM_TimeBaseInitStructure);/*****STEP 4 输入捕获配置*****/TIM_ICInitTypeDef TIM_ICInitStructure;TIM_ICInitStructure.TIM_Channel = TIM_Channel_1;                     //选择通道TIM_ICInitStructure.TIM_ICFilter = 0xF;                      //配置滤波器参数,数值越大过滤效果越好TIM_ICInitStructure.TIM_ICPolarity = TIM_ICPolarity_Rising;          //极性选择TIM_ICInitStructure.TIM_ICPrescaler = TIM_ICPSC_DIV1;                 //分频器TIM_ICInitStructure.TIM_ICSelection = TIM_ICSelection_DirectTI;     //配置数据选择器TIM_ICInit(TIM3,&TIM_ICInitStructure);/*****STEP 5 配置主从触发模式 *****/TIM_SelectInputTrigger(TIM3,TIM_TS_TI1FP1);         //触发源选择TIM_SelectSlaveMode(TIM3,TIM_SlaveMode_Reset);     //配置从模式/*****STEP6 启动定时器*****/TIM_Cmd(TIM3,ENABLE);
}uint32_t IC_GetFreq(void)
{return 1000000 / TIM_GetCapture1(TIM3);      //Fc = 72MHz/(psc+1)
}

现象

10001Hz 

原因:

计数到1000Hz那个数信号刚好跳变,导致数没记上

有朋友说是因为:读取的是N,但实际上计了N+1个数,因为计数器CNT是从0开始计的,所以这里要加一,错,自行探讨

改进:
uint32_t IC_GetFreq(void)
{
    return 1000000 /( TIM_GetCapture1(TIM3)+1;      //Fc = 72MHz/(psc+1)
}

七、PWMI测占空比代码分析

与上一个代码不同的地方:

1.输入捕获初始化需要升级:

两个通达捕获同一个引脚,比较朴素的想法就是再定义一遍结构体参数

通道1 直连输入,上升沿触发 通道2 交叉输入(通道2相当于通道1 的交叉输入结果)下降沿触发

TIM_ICInitStructure.TIM_Channel = TIM_Channel_2;                     //选择通道TIM_ICInitStructure.TIM_ICFilter = 0xF;                      //配置滤波器参数,数值越大过滤效果越好TIM_ICInitStructure.TIM_ICPolarity = TIM_ICPolarity_Falling;          //极性选择TIM_ICInitStructure.TIM_ICPrescaler = TIM_ICPSC_DIV1;                 //分频器TIM_ICInitStructure.TIM_ICSelection = TIM_ICSelection_IndirectTI;     //配置数据选择器TIM_ICInit(TIM3,&TIM_ICInitStructure);

简单的办法 (只支持通道1、2之间):

	TIM_PWMIConfig(TIM3,&TIM_ICInitStructure);    //自动把剩下的通道配置成相反的配置

2.占空比函数

uint32_t IC_GetDuty(void)
{return (TIM_GetCapture2(TIM3) + 1) * 100 /(TIM_GetCapture1(TIM3) + 1);
}

3.main变动

/***main 变动***/
OLED_ShowString(2,1,"Duty:00%");/***while 变动***/
OLED_ShowNum(2,6,IC_GetDuty(),2);

八、探究测频率性能

测频率范围 

fc 1MHz Nmax = 65535  最低频率是15Hz左右

要是再想降最低频率限制,PSC加大(这里fc=72M/(PSC+1)就是1M,当fc越小,能够测量的信号频率就越小,所以你要想测频率更小的信号,就可以减小fc,也就是增大PSC值)

频率上限,就是标准频率了,再高,没法测,误差(正负一误差=1/计数值)大,提高上限就要降低PSC或者尝试测频法

这篇关于输入捕获模式测频率PWM输入模式(PWMI)测占空比的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/719228

相关文章

在JS中的设计模式的单例模式、策略模式、代理模式、原型模式浅讲

1. 单例模式(Singleton Pattern) 确保一个类只有一个实例,并提供一个全局访问点。 示例代码: class Singleton {constructor() {if (Singleton.instance) {return Singleton.instance;}Singleton.instance = this;this.data = [];}addData(value)

【测试】输入正确用户名和密码,点击登录没有响应的可能性原因

目录 一、前端问题 1. 界面交互问题 2. 输入数据校验问题 二、网络问题 1. 网络连接中断 2. 代理设置问题 三、后端问题 1. 服务器故障 2. 数据库问题 3. 权限问题: 四、其他问题 1. 缓存问题 2. 第三方服务问题 3. 配置问题 一、前端问题 1. 界面交互问题 登录按钮的点击事件未正确绑定,导致点击后无法触发登录操作。 页面可能存在

模版方法模式template method

学习笔记,原文链接 https://refactoringguru.cn/design-patterns/template-method 超类中定义了一个算法的框架, 允许子类在不修改结构的情况下重写算法的特定步骤。 上层接口有默认实现的方法和子类需要自己实现的方法

【iOS】MVC模式

MVC模式 MVC模式MVC模式demo MVC模式 MVC模式全称为model(模型)view(视图)controller(控制器),他分为三个不同的层分别负责不同的职责。 View:该层用于存放视图,该层中我们可以对页面及控件进行布局。Model:模型一般都拥有很好的可复用性,在该层中,我们可以统一管理一些数据。Controlller:该层充当一个CPU的功能,即该应用程序

迭代器模式iterator

学习笔记,原文链接 https://refactoringguru.cn/design-patterns/iterator 不暴露集合底层表现形式 (列表、 栈和树等) 的情况下遍历集合中所有的元素

《x86汇编语言:从实模式到保护模式》视频来了

《x86汇编语言:从实模式到保护模式》视频来了 很多朋友留言,说我的专栏《x86汇编语言:从实模式到保护模式》写得很详细,还有的朋友希望我能写得更细,最好是覆盖全书的所有章节。 毕竟我不是作者,只有作者的解读才是最权威的。 当初我学习这本书的时候,只能靠自己摸索,网上搜不到什么好资源。 如果你正在学这本书或者汇编语言,那你有福气了。 本书作者李忠老师,以此书为蓝本,录制了全套视频。 试

利用命令模式构建高效的手游后端架构

在现代手游开发中,后端架构的设计对于支持高并发、快速迭代和复杂游戏逻辑至关重要。命令模式作为一种行为设计模式,可以有效地解耦请求的发起者与接收者,提升系统的可维护性和扩展性。本文将深入探讨如何利用命令模式构建一个强大且灵活的手游后端架构。 1. 命令模式的概念与优势 命令模式通过将请求封装为对象,使得请求的发起者和接收者之间的耦合度降低。这种模式的主要优势包括: 解耦请求发起者与处理者

springboot实战学习(1)(开发模式与环境)

目录 一、实战学习的引言 (1)前后端的大致学习模块 (2)后端 (3)前端 二、开发模式 一、实战学习的引言 (1)前后端的大致学习模块 (2)后端 Validation:做参数校验Mybatis:做数据库的操作Redis:做缓存Junit:单元测试项目部署:springboot项目部署相关的知识 (3)前端 Vite:Vue项目的脚手架Router:路由Pina:状态管理Eleme

状态模式state

学习笔记,原文链接 https://refactoringguru.cn/design-patterns/state 在一个对象的内部状态变化时改变其行为, 使其看上去就像改变了自身所属的类一样。 在状态模式中,player.getState()获取的是player的当前状态,通常是一个实现了状态接口的对象。 onPlay()是状态模式中定义的一个方法,不同状态下(例如“正在播放”、“暂停

软件架构模式:5 分钟阅读

原文: https://orkhanscience.medium.com/software-architecture-patterns-5-mins-read-e9e3c8eb47d2 软件架构模式:5 分钟阅读 当有人潜入软件工程世界时,有一天他需要学习软件架构模式的基础知识。当我刚接触编码时,我不知道从哪里获得简要介绍现有架构模式的资源,这样它就不会太详细和混乱,而是非常抽象和易