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=1000.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);
}
}