stm32学习-PWMI模式测量频率占空比

上一篇有讲到输入捕获测量频率的代码,这篇的代码只需要把输入捕获的部分进行升级,设置成两个通道捕获同一个引脚的功能,这样子就同时显示一个通道的频率和占空比了。

更改捕获单元的思路:

(1)把通道初始化部分的代码复制一份,通道1还是直连输入和上升沿触发;通道2配置为交叉输入,下降沿触发。        

(2)利用上一个文章讲到的TIM_PWMIConfig函数配置。

下面我们开始配置。

配置流程

1.RCC开启时钟(打开GPIO和TIM的时钟打开)

(1)void RCC_APB2PeriphResetCmd(uint32_t RCC_APB2Periph, FunctionalState NewState);
(2)void RCC_APB1PeriphResetCmd(uint32_t RCC_APB1Periph, FunctionalState NewState);
根据外设挂载的总线选择使用的函数。

2.GPIO初始化,将GPIO配置为输入模式(一般选择上拉输入或浮空输入)

void GPIO_Init(GPIO_TypeDef* GPIOx, GPIO_InitTypeDef* GPIO_InitStruct);
作用:配置GPIO初始化

3.配置时基单元(使CNT在内部时钟的驱动下自增运行)

这一部分前面文章有写,不懂的可以参考一下上一篇的内容,此处不多赘述了。
                        
原文链接:https://blog.csdn.net/m0_74246768/article/details/139048136

4.配置输入捕获单元(包括滤波器、极性、分频器等参数)

(1)void TIM_ICInit(TIM_TypeDef* TIMx, TIM_ICInitTypeDef* TIM_ICInitStruct);
作用:用结构体配置输入捕获单元的函数

TIMx:选择哪个定时器

TIM_ICInitStruct:包含各个配置的结构体

补充:输入捕获和输出比较都有四个通道,前面文章有写到输出比较的四个通道的库函数,有4个。而输入捕获只有一个函数,是4个通道共用一个函数,在结构体内会额外有个参数去选择配置哪个通道

(2)void TIM_PWMIConfig(TIM_TypeDef* TIMx, TIM_ICInitTypeDef* TIM_ICInitStruct);
和上一个函数一样都是初始化输入捕获单元的,上一个函数只能配置一个通道,这个函数可配置两个通道。使用这个函数,只需要传入一个通道的参数,这个函数会自动把剩下的一个通道初始化成相反的配置。

注意:TIM_PWMIConfig函数只支持通道1和通道2的配置,不能配置通道3和通道4.

5.选择从模式的触发源(触发源选择为TI1FP1,调用一个库函数后直接给一个参数就行了)

void TIM_SelectInputTrigger(TIM_TypeDef* TIMx, uint16_t TIM_InputTriggerSource);
作用:选择输入触发源TRGI。        

6.选择触发之后执行的操作(执行Reset操作,直接调用库函数即可)

void TIM_SelectSlaveMode(TIM_TypeDef* TIMx, uint16_t TIM_SlaveMode);
作用:选择从模式。

7.调用TIM_Cmd函数定时器。

void TIM_Cmd(TIM_TypeDef* TIMx, FunctionalState NewState);
作用:启动定时器。

配置好后,当我们需要读取最新一个周期的频率时,直接读取CCR寄存器,按照fc/N(测周法)计算一下即可。

获取频率

获取输入频率
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);
作用:分别读取四个通道的CCR。和TIM_SetCompare函数作用是一样的,都是读取CCR寄存器。输入比较模式下,CCR是只写,用TIM_SetCompare写入;输入捕获模式下,CCR只读,要用TIM_GetCapture读出。

获取占空比

高电平的计数值存在CCR2里,整个周期的计数值存在CCR1里。用CCR2/CCR1就能得到占空比。

代码显示

IC.c

#include "stm32f10x.h"                  // Device header

void IC_Init(void)
{
	RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM3, ENABLE);
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);
	
	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);
	
	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;		//ARR
	TIM_TimeBaseInitStructure.TIM_Prescaler = 72 - 1;		//PSC
	TIM_TimeBaseInitStructure.TIM_RepetitionCounter = 0;
	TIM_TimeBaseInit(TIM3, &TIM_TimeBaseInitStructure);
	
	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_PWMIConfig(TIM3, &TIM_ICInitStructure);

	TIM_SelectInputTrigger(TIM3, TIM_TS_TI1FP1);
	TIM_SelectSlaveMode(TIM3, TIM_SlaveMode_Reset);
	
	TIM_Cmd(TIM3, ENABLE);
}

uint32_t IC_GetFreq(void)
{
	return 1000000 / (TIM_GetCapture1(TIM3) + 1);
}

uint32_t IC_GetDuty(void)
{
	return (TIM_GetCapture2(TIM3) + 1) * 100 / (TIM_GetCapture1(TIM3) + 1);
	//*100可以直接显示百分比的值,+1是因为实测发现误差相差1,通过+1可以解决这个误差
}

IC.h

#ifndef __IC_H
#define __IC_H

void IC_Init(void);
uint32_t IC_GetFreq(void);
uint32_t IC_GetDuty(void);

#endif
#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");
	OLED_ShowString(2, 1, "Duty:00%");
	
	PWM_SetPrescaler(720 - 1);			//Freq = 72M / (PSC + 1) / 100
	PWM_SetCompare1(50);				//Duty = CCR / 100
	
	while (1)
	{
		OLED_ShowNum(1, 6, IC_GetFreq(), 5);
		OLED_ShowNum(2, 6, IC_GetDuty(), 2);
	}
}

PWM模块与上一节相同,需要的同学可以在前面的文章里面看一下。

原文链接:https://blog.csdn.net/m0_74246768/article/details/139050032

补充:

测频率的范围:

下限:目前代码中给到的预分频器是72-1,所以标准频率是1MHz,那计数器最大只能计到65535,所测到的最低频率是1M/65535,大概是15Hz,信号频率再低就会导致计数器溢出。可通过加大预分频器的值,就可使标准频率降低,所支持的最低频率也就可以更低。

上限:随着待测频率增大,误差也会增大。如果频率超过1MHz,信号频率高于标准频率,误差会很大。(没有实际固定的上限,最大频率根据你对误差的要求决定),提高频率上限可通过降低PSC的值以提高标准频率,就可以提高上限。更高的频率使用测频法(测频法适合高频)

  • 34
    点赞
  • 19
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值