STM32输入捕获详细配置及通过编码器读电机转速

STM32输入捕获详细配置及通过编码器读电机转速

STM32输入捕获工作过程
在这里插入图片描述
通过检测TIMx_CHx上的边沿信号,在边沿信号发生跳变(比如上升沿/下降沿)的时候,将当前定时器的值(TIMx_CNT)存放到对应的捕获/比较寄存器(TIMx_CCRx)里面,完成一次捕获。

STM32输入捕获设置
步骤1:设置输入捕获滤波器
在这里插入图片描述
首先,FDTS的频率由TIMx_CR1的CKD[1:0]的设置决定,为00时,FDTS=FCK_INT。
在这里插入图片描述其次,TIMx_CCMR1的ICF[3:0]这几个为用来设置输入采用频率和数字滤波器的长度,
在这里插入图片描述
在这里插入图片描述

上面N是滤波长度,例如,当N=8时,并设置IC1映射到通道1上,且为上升沿触发,那么捕获到上升沿的时候,再以Fck_int的频率,连续采样到8次通道1的电平,如果都是高电平,则说明是一个有效的触发,就会触发输入捕获中断,这样就可以滤除那些高电平脉宽低于8给采用周期的脉冲信号。不做滤波处理的话,将其设置为0000.

步骤2:设置输入捕获极性
在这里插入图片描述
在这里插入图片描述设置上升沿捕获还是下降沿捕获。

步骤3:设置输入捕获映射通道

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
步骤4:设置输入捕获分频器
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述步骤5:捕获到有效信号可以开启中断‘
在这里插入图片描述寄存器
一:捕获比较模式寄存器CCMR寄存器
在这里插入图片描述在这里插入图片描述在这里插入图片描述
二:捕获比较使能寄存器

在这里插入图片描述三:事件产生寄存器(TIMx_EGR)
在这里插入图片描述
四:中断使能寄存器
在这里插入图片描述在这里插入图片描述

输入捕获(高电平脉宽)函数详解

void TIM5_CH1_Cap_Init(u32 arr,u16 psc)
{		 
	RCC->APB1ENR|=1<<3;   	//TIM5时钟使能
	RCC->AHB1ENR|=1<<0;   	//使能PORTA时钟

	//端口复用
	GPIO_Set(GPIOA,PIN0,GPIO_MODE_AF,GPIO_OTYPE_PP,GPIO_SPEED_100M,GPIO_PUPD_PD);
	GPIO_AF_Set(GPIOA,0,2);	//PA0,AF2
	  
	  //设置自动重装载值与预分频系数
 	TIM5->ARR=arr;  		
	TIM5->PSC=psc;  		

	TIM5->CCMR1|=1<<0;		//CC1S=01 	设置CC1通道为输入,IC1映射到T1上
 	TIM5->CCMR1|=0<<4; 		//IC1F=0000   无滤波
 	TIM5->CCMR1|=0<<10; 	//IC1PS=00 	不分频

	TIM5->CCER|=0<<1; 		//CC1P=0	上升沿捕获
	TIM5->CCER|=1<<0; 		//CC1E=1 	允许捕获计数器的值到捕获寄存器中

//软件控制产生更新时间,使写入预分频器的值立即生效,否则要等到定时器溢出才生效
	TIM5->EGR=1<<0;			
	TIM5->DIER|=1<<1;   	//允许捕获1中断
	TIM5->DIER|=1<<0;   	//允许更新中断
	TIM5->CR1|=0x01;    	//使能定时器2
	MY_NVIC_Init(2,0,TIM5_IRQn,2);//设置抢占优先级2,子优先级0,组2
}

设计一个寄存器,
第7位为捕获完成标志位
第6位为捕获到低电平标志位,
因为要检测高电平脉冲所持续的时间,所以需要判断目前捕获的电平是高电平还是低电平,当高电平来时记录计数器的当前值,将该标志位设置为0,然后将捕获中断改为下降沿捕获,当下降沿来临时再次记录计数器的值,将该标志位置1,通过两次计数器值的差值就可以记录高电平持续时间
第5-0位记录定时器溢出的次数,
因为在如果高电平的持续时间很长,计数器的值会溢出,再用两次当前值相减时需要加上计数器溢出的那几个周期。
在这里插入图片描述


u8  TIM5CH1_CAPTURE_STA=0;	//输入捕获状态				
u32	TIM5CH1_CAPTURE_VAL;	//输入捕获值
//中断服务程序
void TIM5_IRQHandler(void)
{ 		    
	u16 tsr;
	tsr=TIM5->SR;
	 //成功捕获后便不会进入这段程序,只有当主函数把计数值读出来,然后把该寄存器清0后,
 	//才会再次进入该程序,每次的执行过程是一样的,首先是上升沿捕获,然后将第6位标志位置1,
 	//计数器清0,将触发模式改为下降沿捕获,然后进入下降沿捕获,记录成功捕获,
 	//将触发模式改为上升沿,记录计数器的值。
 	//然后便不会进入这段程序,等待主程序将计数器的值读出来,寄存器清0后,再次执行该程序。
 	if((TIM5CH1_CAPTURE_STA&0X80)==0)//没有成功捕获高电平
	{
		if(tsr&0X01)//定时器溢出中断
		{	     
			if(TIM5CH1_CAPTURE_STA&0X40)//已经捕获到高电平
			{
				if((TIM5CH1_CAPTURE_STA&0X3F)==0X3F)//高电平太长,计数器溢出
				{
					TIM5CH1_CAPTURE_STA|=0X80;		//直接标记成功捕获了一次
					TIM5CH1_CAPTURE_VAL=0XFFFFFFFF;
				}else TIM5CH1_CAPTURE_STA++;//每溢出一次加1
			}	 
		}
		if(tsr&0x02)//定时捕获中断发生
		{	
			if(TIM5CH1_CAPTURE_STA&0X40)		//上一次捕获的是上升沿,这一次又发生捕获中断了,表明下降沿到了
			{	  			
				TIM5CH1_CAPTURE_STA|=0X80;		//标记成功捕获了一次高电平脉宽
			    TIM5CH1_CAPTURE_VAL=TIM5->CCR1;	//获取当前计数器的值
	 			TIM5->CCER&=~(1<<1);			//CC1P=0 设置为上升沿捕获
			}else  								//还未开始,第一次捕获上升沿
			{
				TIM5CH1_CAPTURE_STA=0;			//清空
				TIM5CH1_CAPTURE_VAL=0;
				TIM5CH1_CAPTURE_STA|=0X40;		//标记捕获到上升沿
				TIM5->CR1&=~(1<<0)		;    	//使能定时器2
	 			TIM5->CNT=0;					//计数器清空
	 			TIM5->CCER|=1<<1; 				//CC1P=1 设置为下降沿捕获
				TIM5->CR1|=0x01;    			//使能定时器2
			}		    
		}			     	    					   
 	}
	TIM5->SR=0;//清楚中断标志位
}

		if(TIM5CH1_CAPTURE_STA&0X80)		//成功捕获到一次高电平
		{
			temp=TIM5CH1_CAPTURE_STA&0X3F; 
			temp*=0XFFFFFFFF;		 		//溢出时间总和
			temp+=TIM5CH1_CAPTURE_VAL;		//得到总的高电平时间
			printf("HIGH:%lld us\r\n",temp);//打印输出
			TIM5CH1_CAPTURE_STA=0;			//寄存器清空,等待下一次捕获
		}

编码器接口模式:

官方解释
选择编码器接口模式的方法是:如果计数器只在TI2的边沿计数,则置TIMx_SMCR寄存器中的SMS=001;如果只在TI1边沿计数,则置SMS=010;如果计数器同时在TI1和TI2边沿计数,则置SMS=011。
通过设置TIMx_CCER寄存器中的CC1P和CC2P位,可以选择TI1和TI2极性;如果需要,还可以对输入滤波器编程。两个输入TI1和TI2被用来作为增量编码器的接口。假定计数器已经启动(TIMx_CR1寄存器中的CEN=’1’),计数器由每次在TI1FP1或TI2FP2上的有效跳变驱动。TI1FP1和TI2FP2是TI1和TI2在通过输入滤波器和极性控制后的信号;如果没有滤波和变相,则TI1FP1=TI1,TI2FP2=TI2。根据两个输入信号的跳变顺序,产生了计数脉冲和方向信号。依据两个输入信号的跳变顺序,计数器向上或向下计数,同时硬件对TIMx_CR1寄存器的DIR位进行相应的设置。不管计数器是依靠TI1计数、依靠TI2计数或者同时依靠TI1和TI2计数。在任一输入端(TI1或者TI2)的跳变都会重新计算DIR位。
编码器接口模式基本上相当于使用了一个带有方向选择的外部时钟。这意味着计数器只在0到TIMx_ARR寄存器的自动装载值之间连续计数(根据方向,或是0到ARR计数,或是ARR到0计 数)。所以在开始计数之前必须配置TIMx_ARR;同样,捕获器、比较器、预分频器、触发输出特性等仍工作如常。在这个模式下,计数器依照增量编码器的速度和方向被自动的修改,因此计数器的内容始终指示着编码器的位置。计数方向与相连的传感器旋转的方向对应。下表列出了所有可能的组合,假设TI1和TI2不同时变换。
在这里插入图片描述一个外部的增量编码器可以直接与MCU连接而不需要外部接口逻辑。但是,一般会使用比较器将编码器的差动输出转换到数字信号,这大大增加了抗噪声干扰能力。编码器输出的第三个信号表示机械零点,可以把它连接到一个外部中断输入并触发一个计数器复位。
下图是一个计数器操作的实例,显示了计数信号的产生和方向控制。它还显示了当选择了双边沿时,输入抖动是如何被抑制的;抖动可能会在传感器的位置靠近一个转换点时产生。在这个例子中,我们假定配置如下:
● CC1S=’01’ (TIMx_CCMR1寄存器,IC1FP1映射到TI1)
● CC2S=’01’ (TIMx_CCMR2寄存器,IC2FP2映射到TI2)
● CC1P=’0’ (TIMx_CCER寄存器,IC1FP1不反相,IC1FP1=TI1)
● CC2P=’0’ (TIMx_CCER寄存器,IC2FP2不反相,IC2FP2=TI2)
● SMS=’011’ (TIMx_SMCR寄存器,所有的输入均在上升沿和下降沿有效).
● CEN=’1’ (TIMx_CR1寄存器,计数器使能)

在这里插入图片描述
在这里插入图片描述当定时器配置成编码器接口模式时,提供传感器当前位置的信息。使用第二个配置在捕获模式的定时器,可以测量两个编码器事件的间隔,获得动态的信息(速度,加速度,减速度)。指示机械零点的编码器输出可被用做此目的。根据两个事件间的间隔,可以按照固定的时间读出计数器。如果可能的话,你可以把计数器的值锁存到第三个输入捕获寄存器(捕获信号必须是周期的并且可以由另一个定时器产生);也可以通过一个由实时时钟产生的DMA请求来读取它的值。

相关寄存器
1:SMCR寄存器
其中的SMS位用来设置编码器模式,主要影响的是 上面表格《计数方向与编码器信号的关系》 内的计数器的方向。
设置为011时:可理解为一共有两个定时器通道来采集编码器A、B相的脉冲信号,编码器模式3时,会根据另一个通道的电平信号,以及当前通道电平的变化(上升、下降)来决定计数器的计数方向(增加/减少),例如当A相通道(TI1)电平信号为低电平时,B相通道(TI2)的电平跳变成高电平了,此时根据表格,计数器的值下降,编码器模式就是靠这个表格来计数的,这个数对应对应的就是编码器的位置
在这里插入图片描述2:CR1寄存器
编码器模式需要设置位6:5为边沿对齐模式,因为SMCR设置为011,TI1和TI2同时计数情况下,计数器的方向要根据计数器的DIR方向位进行改变,故其设置为00.
在这里插入图片描述

void Encoder_Init_TIM2(void)
{
	RCC->APB2ENR|=1<<0;    //开启辅助时钟
	AFIO->MAPR|=1<<8;      //01部分重映射
	RCC->APB1ENR|=1<<0;     //TIM2时钟使能
	RCC->APB2ENR|=1<<2;    //PORTA时钟使能
	RCC->APB2ENR|=1<<3;    //PORTB时钟使能
	GPIOA->CRH&=0X0FFFFFFF;//PA15
	GPIOA->CRH|=0X40000000;//浮空输入
	
	GPIOB->CRL&=0XFFFF0FFF;//PB3
	GPIOB->CRL|=0X00004000;//浮空输入
	TIM2->DIER|=1<<0;   //允许更新中断
	TIM2->DIER|=1<<6;   //允许触发中断
	MY_NVIC_Init(1,3,TIM2_IRQn,1);
	TIM2->PSC = 0x0;//不分频
	TIM2->ARR = ENCODER_TIM_PERIOD;//设置计数器自动重装载值
	TIM2->CR1 &=~(3<<8);// 时钟分频,不分频
	TIM2->CR1 &=~(3<<5);//选择计数模式,边沿对齐模式
		
	TIM2->CCMR1 |= 1<<0; //CC1S='01' IC1FP1映射到TI1
	TIM2->CCMR1 |= 1<<8; //CC2S='01' IC2FP2映射到TI2
	TIM2->CCER &= ~(1<<1);	 //CC1P='0'	 IC1FP1不反相,ICIFP1=TI1
	TIM2->CCER &= ~(1<<5);	 //CC2P='0'	 IC2FP2不反相,IC2FP2=TI2
//	TIM2->CCMR1 |= 3<<4; //	输入捕获滤波器
  TIM2 -> CNT=0;
	TIM2->SMCR |= 3<<0;	 //计数器同时在TI1和TI2边沿计数
	TIM2->CR1 |= 0x01;    //使能定时器
}

单位时间读取编码器的计数值,可以转化为速度
入口参数:定时器
返回值:速度值

int Read_Encoder(u8 TIMX)
{
    int Encoder_TIM;    
   switch(TIMX)
	 {
	   case 2:  Encoder_TIM= (short)TIM2 -> CNT;   TIM2 -> CNT=0; break;
		 case 3:  Encoder_TIM= (short)TIM3 -> CNT;   TIM3 -> CNT=0; break;
		 case 4:  Encoder_TIM= (short)TIM4 -> CNT;   TIM4 -> CNT=0;  break;	
		 default:  Encoder_TIM=0;
	 }
		return Encoder_TIM;
}

参考:《STM32中文参考手册_V10》
《STM32不完全手册_寄存器版本_V3.1》
《STM32F7中文参考手册》
正点原子官方教程

  • 3
    点赞
  • 106
    收藏
    觉得还不错? 一键收藏
  • 11
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值