学习STM32第七天

TIM基础

1、输入捕获

输入捕获(Input Capture, IC),4个输入捕获和输出比较通道共用4个CCR寄存器。对于同一个定时器,输入捕获和输出比较只能使用其中一个,不能同时使用。
当通道输入引脚出现指定电平跳变时(上升沿/下降沿),当前CNT的值将被锁存到CCR中(将当前CNT的值读出来写入到CCR中),高级定时器和通用定时器都有4个输入捕获和输出比较通道。可配置为PWMI模式,用于测量频率和占空比,可配合主从触发模式,实现硬件全自动测量。

PWM测频率
频率测量方法

  • 测频法
    在闸门时间T内,对上升沿计次,得到N,则频率 f x = N / T f_x = N/T fx=N/T,即标准周期与信号周期间关系,适合高频信号,自带均值滤波,得到的结果是平均值且更新慢
  • 测周法
    两个上升沿内,以标准频率 f c f_c fc计次,得到N ,则频率 f x = f c / N f_x = f_c /N fx=fc/N,即标准频率与信号频率间关系,适合低频信号,更新快但易受噪声影响,波动较大
  • 中界频率
    测测频法与测周法误差相等的频率点 f m = f c / N f_m = \sqrt{f_c/N} fm=fc/N

STM32只能测量数字信号的频率,如果是测量正弦波信号的周期,则需要搭建一个信号预处理电路,测量大电压信号则需要用到隔离放大电路,一般是采用运放组建一个比较电路,将正弦波信号转换为方波信号,输入给STM32测量的信号必须是满足TTL协议的信号。频率小于中界频率的信号适合测周法,频率大于中界频率的信号适合测频法。
PWM输入捕获
前三个通道接有三输入异或门是方便作为无刷电机的接口定时器,可从通道1检测无刷电机相位信息。每个通道的输入滤波器和边沿检测器都有两套滤波极性选择,这样一可以灵活切换后续捕获电路的输入二可以把一个引脚的输入同时映射到两个捕获单元,两个通道同时对一个引脚进行捕获即可完成同时对频率和占空比的测量。预分频器对通道输出的信号进行分频,生成触发信号,即触发后面捕获电路。上升沿触发输入捕获,CNT用于计数计时;在完成一次捕获后需要把CNT清0,下次完成捕获所取出的CNT才是两个上升沿的时间间隔,可以用主从触发模式实现自动清0。PWM通道1输入捕获
其中 f D T S f_{DTS} fDTS是滤波器采样时钟来源,通过CCMR寄存器中的ICF位可以控制滤波器的采样频率及数字滤波长度。通过CCER寄存器中的CC1P可以选择边沿检测器输出的极性。最终得到TI1FP1触发信号,进入后续的分频器以及捕获电路。CNT的自动清0是通过从模式控制器进行的。
PWM主从模式触发
主模式可以将定时器内部的信号映射到TRGO引脚,用于触发别的外设;从模式接收其他外设或自身外设的一些信号,用于控制自身定时器运行,被别的信号控制;触发源选择就是选择从模式的触发信号源,映射到TRGI引脚用于触发从模式。从模式下面4个模式用于对时基单元的控制,由函数TIM_SelectSlaveMode(TIM_TypeDef* TIMx, uint16_t TIM_SlaveMode)配置;的上面4个模式是用于编码器接口用的,由其他函数进行配置。
输入捕获基本结构
配置好时基单元后,CNT会在预分频后的时钟(即驱动CNT的标准频率)驱动下不断自增。触发信号在被捕获时,CNT的当前计数值存入CCR1中,同时由触发源选择从模式的复位操作,触发CNT清0。如左上角所示,在第一次上升沿触发时,CCR1保存CNT的当前计数值之后CNT完成清0;CNT从零开始计数,在下一次上升沿触发时,CCR1又保存CNT的当前计数值,之后CNT完成清0。因此整个过程中CCR1的值时钟保持为最新一个周期的计数值,即测周法中的计次N。由于ARR寄存器是16位,因此CNT最大只能计65535个数,频率太低时CNT计数值可能会溢出。从模式的触发源选择只有TI1FP1和TI2FP2,因此只能用通道1和通道2完成自动清0操作,通道3和通道4只能开启捕获中断,在中断里手动清0,这样程序会处于频繁中断状态,比较消耗软件资源。
PWMI基本结构
PWMI模式使用两个通道同时捕获一个引脚,通道1不变,通道2配置为下降沿触发,即CCR1捕获上升沿时刻的CNT,CCR2捕获当前周期下降沿时刻的CNT,由于在CCR1完成上升沿捕获后,CNT立即清0,CCR2的值即为高电平期间的计数值。

二、实验案例

  1. 输入捕获模式测频率
    这里在PA0引脚输出PWM波,通过PA6引脚进行输入捕获测频率。输入捕获模块代码编写如下
//这里使用通用定时器TIM3的通道1
	RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM3, ENABLE);
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);
	//TIM3_CH1在PA6引脚上
	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;		//直接给最大值,防止CNT溢出
	TIM_TimeBaseInitStructure.TIM_Prescaler = 72 - 1;		//标准频率fc = 1MHz
	TIM_TimeBaseInitStructure.TIM_RepetitionCounter = 0;
	TIM_TimeBaseInit(TIM3, &TIM_TimeBaseInitStructure);
	//配置输入捕获单元
	TIM_ICInitTypeDef TIM_ICInitStructure;
	TIM_ICInitStructure.TIM_Channel = TIM_Channel_1;		//选择TIM3通道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);
	//配置主从模式的触发源选择和从模式复位
	TIM_SelectInputTrigger(TIM3, TIM_TS_TI1FP1);//配置TRGI的触发源为TI1FP1
	TIM_SelectSlaveMode(TIM3, TIM_SlaveMode_Reset);//从模式触发实现TIM3的CNT复位
	
	TIM_Cmd(TIM3, ENABLE);
//读取CCR3的值,并计算信号频率
uint32_t IC_GetFreq(void)
{ 	
	//根据公式,信号频率fx = fc / N ,N为计次
	//在通道1,所以使用函数TIM_GetCapture1()
	//计数器是从0开始计数,所以CCR要加1
	return 1000000 / (TIM_GetCapture1(TIM3) + 1);
}
  1. PWMI模式测频率和占空比
    这里同样在PA0引脚给出PWM波,由于测量占空比需要另外一个通道,这里配置CH1通道测量频率,CH2通道测量占空比,即两个通道同时捕获PA0引脚的输出。标准库提供函数TIM_PWMIConfig()可自动配置另一个通道进行占空比的计算。整体代码如下
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;
	//通道1测量频率
	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_PWMIConfig()函数即可完成另外一个通道的配置
//	//通道2测量占空比
//	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);

	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);
}
  • 31
    点赞
  • 18
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值