STM32F407光栅尺测速

STM32F407光栅尺测速

//TIM5初始化为编码器接口模式,读取光栅尺数值
//分频psc=0;自动重装载值arr根据定时器位数定

void TIM5_Config(u32 arr,u32 psc)
{
	GPIO_InitTypeDef GPIO_InitStructure;
	TIM_TimeBaseInitTypeDef  TIM_TimeBaseStructure;
	TIM_ICInitTypeDef TIM_ICInitStructure;

	RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM5,ENABLE);  	//TIM5时钟使能    
	RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOA, ENABLE); //使能PORTF时钟	
	
	GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0|GPIO_Pin_1; //光栅尺
	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF;//复用功能
	GPIO_InitStructure.GPIO_OType = GPIO_OType_OD; //开漏输出
	GPIO_InitStructure.GPIO_PuPd= GPIO_PuPd_UP; //上拉
	GPIO_InitStructure.GPIO_Speed = GPIO_Speed_100MHz;	//速度100MHz
	GPIO_Init(GPIOA,&GPIO_InitStructure); //初始化PD
	
	GPIO_PinAFConfig(GPIOA,GPIO_PinSource0,GPIO_AF_TIM5); //复用为TIM5
	GPIO_PinAFConfig(GPIOA,GPIO_PinSource1,GPIO_AF_TIM5); //复用为TIM5
	
	TIM_TimeBaseStructInit(&TIM_TimeBaseStructure);  
	TIM_TimeBaseStructure.TIM_Prescaler=psc;  //定时器分频
	TIM_TimeBaseStructure.TIM_Period=arr;   //自动重装载值16位 0xFFFF 65535; 32位0xFFFFFFF
	TIM_TimeBaseStructure.TIM_ClockDivision=TIM_CKD_DIV1; 	//时钟分频
	TIM_TimeBaseStructure.TIM_CounterMode=TIM_CounterMode_Up; //向上计数模式
	TIM_TimeBaseInit(TIM5,&TIM_TimeBaseStructure);  //初始化TIM5
	
  //编码器模式1 – 根据TI1FP1的电平,计数器在TI2FP2的边沿向上/下计数。
	TIM_EncoderInterfaceConfig(TIM5,TIM_EncoderMode_TI12,TIM_ICPolarity_Rising, TIM_ICPolarity_Rising);  //编码器接口模式配置
	TIM_ICStructInit(&TIM_ICInitStructure);  //默认值赋值
	TIM_ICInitStructure.TIM_ICFilter =0x2;   //滤波 0x0~0xF  
	TIM_ICInit(TIM5, &TIM_ICInitStructure);  //初始化

	TIM_ClearFlag(TIM5, TIM_FLAG_Update);//清除标志位
	TIM_ITConfig(TIM5, TIM_IT_Update, ENABLE); //更新中断 
 
	TIM_SetCounter(TIM5,0);  //计数器清零
	TIM_Cmd(TIM5, ENABLE); 
}

//基本定时器6中断初始化
//TIM6时钟为84M
//arr:自动重装值。例5000-1,计数器从0数到4999,即5000次为一个定时器周期
//psc:时钟预分频数。例8400-1,若时钟为84M,则分频后为84M/8400=10KHz 即0.1ms
//定时器溢出时间计算方法:Tout=((arr+1)(psc+1))/Ft us.
//Ft=定时器工作频率,单位:Mhz
//例(100-1,840-1) T=100
0.01ms=1ms

void TIM6_Int_Init(u16 arr,u16 psc)
{	
	TIM_TimeBaseInitTypeDef TIM_TimeBaseInitStructure;
	NVIC_InitTypeDef NVIC_InitStructure;
	
	RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM6,ENABLE);  ///使能TIM6时钟
	
  TIM_TimeBaseInitStructure.TIM_Period = arr; 	//自动重装载值
	TIM_TimeBaseInitStructure.TIM_Prescaler=psc;  //定时器分频
	TIM_TimeBaseInitStructure.TIM_CounterMode=TIM_CounterMode_Up; //向上计数模式
	TIM_TimeBaseInitStructure.TIM_ClockDivision=TIM_CKD_DIV1; 
	TIM_TimeBaseInit(TIM6,&TIM_TimeBaseInitStructure);
	
	TIM_ITConfig(TIM6,TIM_IT_Update,ENABLE); //允许定时器6更新中断
	TIM_Cmd(TIM6,ENABLE); //使能定时器6
	
	NVIC_InitStructure.NVIC_IRQChannel=TIM6_DAC_IRQn;  
	NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority=0x02; //抢占优先级2
	NVIC_InitStructure.NVIC_IRQChannelSubPriority=0x03; //子优先级3
	NVIC_InitStructure.NVIC_IRQChannelCmd=ENABLE;
	NVIC_Init(&NVIC_InitStructure); 									 
}

//定时器6中断服务程序
//每20ms采集一次脉冲值,并计算出当前位置和速度,结果通过串口打印

void TIM6_DAC_IRQHandler(void) //1ms中断一次   定时向伺服发送读取指令
{ 		    		 	
	static vu16 t=0; 
	static int32_t encoderDataLast=0;  //脉冲数
	static int32_t encoderDataNow=0;   //脉冲数
	
	if(TIM_GetITStatus(TIM6,TIM_IT_Update)==SET) //溢出中断
	{ 
		t++; //每1ms加一
		if(t==20) //第20ms
		{
				t=0;
				encoderDataNow=TIM5->CNT;   //读取编码器脉冲数
				encoderData=GetENCODECounter(encoderDataNow);  //脉冲值反方向值处理
				CurrentPos = GetCurrentPosition(encoderData);  //计算当前位置 
	
				CurrentSpeer = EncoderSpeer(encoderDataNow,encoderDataLast,20); //计算速度 20ms
				encoderDataLast=encoderDataNow;   //
			
			  printf("当前位置: %.2fmm; 速度:%.2f mm/s\r\n",CurrentPos,CurrentSpeer); //程序用时3.43ms
		}
	}				   
	TIM_ClearITPendingBit(TIM6,TIM_IT_Update);  //清除中断标志位    
}

encoder.c文件 算法

#include "encoder.h"                  // Device header
#include "stdlib.h"

u32 encoderData; //编码器脉冲数
float  CurrentPos; //当前位置
float  CurrentSpeer;//当前速度
	
//编码器反方向转换
//输入:count脉冲数
//输出0xX0000000  正方向X=0  反方向X=8
//局限性:正向运动输入的脉冲数永远不会超过0X80000000
u32 GetENCODECounter(u32 count)  //编码器反方向数值转换
{
	if(count>0X80000000)     //负方向
	{
		count=0XFFFFFFFF-count;  //
		count=count | 0X80000000 ;			
	}
	return count;
}

//计算当前位置
//输入:count脉冲数   EncoderResolution编码器分辨率:一个脉冲距离/mm
//输出:float当前位置,单位:mm
float GetCurrentPosition(u32 count)  //计算当前位置
{
	int32_t  data;
	
	if(count<0X80000000) 	 data=count;   //正向
	if(count>0X80000000) 	 data=0X80000000-count;   //反向
	
	return data * EncoderResolution;  //编码器分辨率 mm
}
	
//计算当前速度
//输入:encoderDataNow encoderDataLast脉冲数  time间隔时间/ms
//abs() 求绝对值;   EncoderResolution编码器分辨率
//输出:float当前速度,单位:mm/s
float EncoderSpeer(u32 encoderDataNow,u32 encoderDataLast,u8 time) //计算速度
{
	return (abs(encoderDataNow-encoderDataLast))* EncoderResolution*1000/((float)time);   // mm/s
}

encoder.h文件

#ifndef _ENCODER_H
#define _ENCODER_H
#include "sys.h"

#define  EncoderResolution  0.0001     //编码器分辨率

extern 	u32 encoderData; //编码器脉冲数
extern float  CurrentPos; //当前位置
extern float  CurrentSpeer;//当前速度
	
u32 GetENCODECounter(u32 count);  //编码器反方向数值转换
float GetCurrentPosition(u32 count);  //当前位置
float EncoderSpeer(u32 encoderDataNow,u32 encoderDataLast,u8 time); //计算速度

#endif

main.c

int main(void)
{ 
	u16 times=0; 

	//设置系统中断优先级分组2  主优先级0~3 子优先级0~3
	NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);//设置系统中断优先级分组2 
	delay_init(168);   //初始化延时函数
	
	uart_init(115200);	//初始化串口波特率为115200 上位机通信         中断级别中:主1子3

	LED_Init();	//初始化LED 
  	buzzer_Init();	//蜂鸣器初始化LED 	
  	
	//100*(84M/840)=100*0.01ms=1ms 	
	TIM6_Int_Init(100-1,840-1); //初始化基本定时器 定时读取伺服状态   中断级别低:主2子3
	//1000*(84M/8400)=1000*0.1ms=100ms 	
	TIM7_Int_Init(1000-1,8400-1); //初始化基本定时器 控制灯闪烁       中断级别低:主3子3
	
	/*编码器*/
	TIM5_Config(0XFFFFFFFF,0); //光栅尺
	
	printf("控制板开机启动\r\n"); 	  
	delay_ms(100); //等待伺服上电准备

	while(1)
	{
			times++;
		  LED0=!LED0; //闪烁LED,提示系统正在运行
//		  if(times%2==0)  {LED0=!LED0;}//闪烁LED,提示系统正在运行 2*200ms=400ms
		
		
			delay_ms(200);  
	}   
}

你可能感兴趣的:(STM32,stm32,编码器,单片机)