二、读取编码器数值实现电机测速—3、速读

mobile365sport365 📅 2025-09-17 23:47:06 ✍️ admin 👁️ 6697 ❤️ 564
二、读取编码器数值实现电机测速—3、速读

读取编码器数值实现电机测速

电机系列二、读取编码器数值实现电机测速3、速度;测速原理:采集数据:速度计算思路:

encoder.hencoder.ctimer.htimer.cmain.c

电机系列

二、读取编码器数值实现电机测速

3、速度;

测速原理:

单位时间内,根据脉冲走过的距离计算电机实际速度,这里采用5ms定时器中断。

采集数据:

就是获得到轮子转一圈的编码器个数; 注意电机参数: 减速比:30:1 编码器线数:13线,也称编码器分辨率;

使用四倍频提高测量精度;

代码见下载区。

速度计算思路:

单位时间内获得的编码器脉冲变化数:可以通过代码得到,定为 e 个 ; (反应电机正反转)

单位时间:定时器设定为5ms,即0.005s;

电机转动一圈的脉冲数:n 个

电机轮子半径:R 单位:m(米)

圆周率:PI 单位:无

速度:speed 单位: m/s

此处:

轮子半径 R:0.03m(米);

PI:3.1415926;

手动转一圈的脉冲数 n:1560 个;

e: 通过函数得到;

可得: speed = 0.024166 * e

代码: 结构如下:

encoder.h

将2中部分改为一下代码;

#ifndef __ENCODER_H

#define __ENCODER_H

#include

#include "stm32f10x_tim.h"

/**************************************************************************

作者:chance

**************************************************************************/

#define ENCODER_TIM_PERIOD (u16)(65535) //不可大于65535 因为F103的定时器是16位的。

//定时器编码器初始化;

void Encoder_Init_TIM2(u16 arr,u16 psc);

void Encoder_Init_TIM3(u16 arr,u16 psc);

void Encoder_Init_TIM4(u16 arr,u16 psc);

void Encoder_Init_TIM5(u16 arr,u16 psc);

//5ms 定时器中断服务函数

void TIM7_Int_Init(u16 arr,u16 psc);

//编码器计数函数;

int Read_Encoder_TIM2(void);

int Read_Encoder_TIM3(void);

int Read_Encoder_TIM4(void);

int Read_Encoder_TIM5(void);

int Read_Encoder_test(TIM_TypeDef * TIMx);

//speed

void Get_Motor_Speed(int *A_Speed,int *B_Speed,int *C_Speed,int *D_Speed);

#endif

encoder.c

#include "encoder.h"

#include "stm32f10x_gpio.h"

/**************************************************************************

作者:chance

**************************************************************************/

int Encoder_A,Encoder_B,Encoder_C,Encoder_D; //编码器的脉冲计数

void Encoder_Init_TIM2(u16 arr,u16 psc)

{

//1) 定义相关结构体:

TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure;

TIM_ICInitTypeDef TIM_ICInitStructure;

GPIO_InitTypeDef GPIO_InitStructure;

//2) 使能相关时钟:

RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO,ENABLE);// 需要使能AFIO时钟

RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2, ENABLE);//使能定时器2的时钟

RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);//使能PA端口时钟

RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE);//使能PB端口时钟

GPIO_PinRemapConfig(GPIO_FullRemap_TIM2, ENABLE);

GPIO_PinRemapConfig(GPIO_Remap_SWJ_JTAGDisable , ENABLE); //禁止JTAG功能,把PB3,PB4作为普通IO口使用

//3) 初始化 GPIO:(用于AB相,脉冲计数)

GPIO_InitStructure.GPIO_Pin = GPIO_Pin_15; //端口配置

GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING; //浮空输入

GPIO_Init(GPIOA, &GPIO_InitStructure); //根据设定参数初始化GPIOA

GPIO_InitStructure.GPIO_Pin = GPIO_Pin_3; //端口配置

GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING; //浮空输入

GPIO_Init(GPIOB, &GPIO_InitStructure); //根据设定参数初始化GPIOB

//4) 设置并初始化定时器 TIM2:

TIM_TimeBaseStructInit(&TIM_TimeBaseStructure);

TIM_TimeBaseStructure.TIM_Prescaler = psc; // 预分频器

TIM_TimeBaseStructure.TIM_Period = arr; //设定计数器自动重装值

TIM_TimeBaseStructure.TIM_ClockDivision = TIM_CKD_DIV1;//选择时钟分频:不分频

TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up;////TIM向上计数

TIM_TimeBaseInit(TIM2, &TIM_TimeBaseStructure);

//5) 设置并初始化定时器编码器:

TIM_EncoderInterfaceConfig(TIM2, TIM_EncoderMode_TI12, TIM_ICPolarity_Rising, TIM_ICPolarity_Rising);//使用编码器模式3

TIM_ICStructInit(&TIM_ICInitStructure);

TIM_ICInitStructure.TIM_ICFilter = 10;

TIM_ICInit(TIM2, &TIM_ICInitStructure);

TIM_ClearFlag(TIM2, TIM_FLAG_Update);//清除TIM的更新标志位

TIM_ITConfig(TIM2, TIM_IT_Update, ENABLE);

//Reset counter

TIM_SetCounter(TIM2,0);

//6) 使能定时器:

TIM_Cmd(TIM2, ENABLE);

}

/**************************************************************************

函数功能:把TIM3初始化为编码器接口模式

入口参数:无

返回 值:无

**************************************************************************/

void Encoder_Init_TIM3(u16 arr,u16 psc)

{

TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure;

TIM_ICInitTypeDef TIM_ICInitStructure;

GPIO_InitTypeDef GPIO_InitStructure;

RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM3, ENABLE);//使能定时器3的时钟

RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);//使能PB端口时钟

GPIO_InitStructure.GPIO_Pin = GPIO_Pin_6|GPIO_Pin_7; //端口配置

GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING; //浮空输入

GPIO_Init(GPIOA, &GPIO_InitStructure); //根据设定参数初始化GPIOA

TIM_TimeBaseStructInit(&TIM_TimeBaseStructure);

TIM_TimeBaseStructure.TIM_Prescaler = psc; // 预分频器

TIM_TimeBaseStructure.TIM_Period = arr; //设定计数器自动重装值

TIM_TimeBaseStructure.TIM_ClockDivision = TIM_CKD_DIV1;//选择时钟分频:不分频

TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up;////TIM向上计数

TIM_TimeBaseInit(TIM3, &TIM_TimeBaseStructure);

TIM_EncoderInterfaceConfig(TIM3, TIM_EncoderMode_TI12, TIM_ICPolarity_Rising, TIM_ICPolarity_Rising);//使用编码器模式3

TIM_ICStructInit(&TIM_ICInitStructure);

TIM_ICInitStructure.TIM_ICFilter = 10;

TIM_ICInit(TIM3, &TIM_ICInitStructure);

TIM_ClearFlag(TIM3, TIM_FLAG_Update);//清除TIM的更新标志位

TIM_ITConfig(TIM3, TIM_IT_Update, ENABLE);

TIM_SetCounter(TIM3,0);

TIM_Cmd(TIM3, ENABLE);

}

void Encoder_Init_TIM4(u16 arr,u16 psc)

{

//1) 定义相关结构体:

TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure;

TIM_ICInitTypeDef TIM_ICInitStructure;

GPIO_InitTypeDef GPIO_InitStructure;

//2) 使能相关时钟:

RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM4, ENABLE);//使能定时器4的时钟

RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE);//使能PB端口时钟

//3) 初始化 GPIO:

GPIO_InitStructure.GPIO_Pin = GPIO_Pin_6|GPIO_Pin_7; //端口配置

GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING; //浮空输入

GPIO_Init(GPIOB, &GPIO_InitStructure); //根据设定参数初始化GPIOB

//4) 设置并初始化定时器 TIM4

TIM_TimeBaseStructInit(&TIM_TimeBaseStructure);

TIM_TimeBaseStructure.TIM_Prescaler = psc; // 预分频器

TIM_TimeBaseStructure.TIM_Period = arr; //设定计数器自动重装值

TIM_TimeBaseStructure.TIM_ClockDivision = TIM_CKD_DIV1;//选择时钟分频:不分频

TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up;////TIM向上计数

TIM_TimeBaseInit(TIM4, &TIM_TimeBaseStructure);

//5) 设置并初始化定时器编码器:

TIM_EncoderInterfaceConfig(TIM4, TIM_EncoderMode_TI12, TIM_ICPolarity_Rising, TIM_ICPolarity_Rising);//使用编码器模式 3:CH1、CH2 同时计数,四分频

TIM_ICStructInit(&TIM_ICInitStructure);

TIM_ICInitStructure.TIM_ICFilter = 10;

TIM_ICInit(TIM4, &TIM_ICInitStructure);

TIM_ClearFlag(TIM4, TIM_FLAG_Update);//清除TIM的更新标志位

TIM_ITConfig(TIM4, TIM_IT_Update, ENABLE);

//Reset counter

TIM_SetCounter(TIM4,0);

//6) 使能定时器:

TIM_Cmd(TIM4, ENABLE);

}

void Encoder_Init_TIM5(u16 arr,u16 psc)

{

TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure;

TIM_ICInitTypeDef TIM_ICInitStructure;

GPIO_InitTypeDef GPIO_InitStructure;

RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM5, ENABLE);//使能定时器5的时钟

RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);//使能PA端口时钟

GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0|GPIO_Pin_1; //端口配置

GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING; //浮空输入

GPIO_Init(GPIOA, &GPIO_InitStructure); //根据设定参数初始化GPIOA

TIM_TimeBaseStructInit(&TIM_TimeBaseStructure);

TIM_TimeBaseStructure.TIM_Prescaler = psc; // 预分频器

TIM_TimeBaseStructure.TIM_Period = arr; //设定计数器自动重装值

TIM_TimeBaseStructure.TIM_ClockDivision = TIM_CKD_DIV1;//选择时钟分频:不分频

TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up;////TIM向上计数

TIM_TimeBaseInit(TIM5, &TIM_TimeBaseStructure);

TIM_EncoderInterfaceConfig(TIM5, TIM_EncoderMode_TI12, TIM_ICPolarity_Rising, TIM_ICPolarity_Rising);//使用编码器模式3

TIM_ICStructInit(&TIM_ICInitStructure);

TIM_ICInitStructure.TIM_ICFilter = 10;

TIM_ICInit(TIM5, &TIM_ICInitStructure);

TIM_ClearFlag(TIM5, TIM_FLAG_Update);//清除TIM的更新标志位

TIM_ITConfig(TIM5, TIM_IT_Update, ENABLE);

TIM_SetCounter(TIM5,0);

TIM_Cmd(TIM5, ENABLE);

}

/**************************************************************************

函数功能:单位时间读取编码器计数

入口参数:定时器

返回 值:速度值

**************************************************************************/

int Read_Encoder_test(TIM_TypeDef * TIMx)

{

int Encoder_TIM;

Encoder_TIM = TIMx -> CNT;

if(Encoder_TIM>0xefff)Encoder_TIM=Encoder_TIM-0xffff; //转化计数值为有方向的值,大于 0 正转,小于 0 反转。

//TIM4->CNT 范围为0-0xffff,初值为 0。

TIMx->CNT=0; //读取完后计数清零

return Encoder_TIM; //返回值

}

void Get_Motor_Speed(int *ASpeed,int *BSpeed,int *CSpeed,int *DSpeed)

{

static int AWheelEncoderNow = 0;

static int BWheelEncoderNow = 0;

static int CWheelEncoderNow = 0;

static int DWheelEncoderNow = 0;

static int AWheelEncoderLast = 0;

static int BWheelEncoderLast = 0;

static int CWheelEncoderLast = 0;

static int DWheelEncoderLast = 0;

//记录本次左右编码器数据

AWheelEncoderNow += Read_Encoder_test(TIM2);

BWheelEncoderNow += Read_Encoder_test(TIM3);

CWheelEncoderNow += Read_Encoder_test(TIM4);

DWheelEncoderNow += Read_Encoder_test(TIM5);

//5ms测速 ( *1000 )单位改为mm/s 串口助手读数变化显示更清楚

*ASpeed = (AWheelEncoderNow - AWheelEncoderLast)* 1000*0.024166;

*BSpeed = (BWheelEncoderNow - BWheelEncoderLast)* 1000*0.024166;

*CSpeed = (CWheelEncoderNow - CWheelEncoderLast)* 1000*0.024166;

*DSpeed = (DWheelEncoderNow - DWheelEncoderLast)* 1000*0.024166;

//记录上次编码器数据

AWheelEncoderLast = AWheelEncoderNow;

BWheelEncoderLast = BWheelEncoderNow;

CWheelEncoderLast = CWheelEncoderNow;

DWheelEncoderLast = DWheelEncoderNow;

}

timer.h

#ifndef __TIMER_H

#define __TIMER_H

#include "stm32f10x.h"

void TIM7_Int_Init(u16 arr,u16 psc);

#endif

timer.c

#include "timer.h"

#include "sys.h"

#include "encoder.h"

#include "led.h"

//arr:自动重装值。

//psc:时钟预分频数

//这里使用的是定时器3!

//TIM7_Int_Init(5000-1,7200-1); 500ms

void TIM7_Int_Init(u16 arr,u16 psc)

{

TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure;

NVIC_InitTypeDef NVIC_InitStructure;

RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM7, ENABLE); //时钟使能

TIM_TimeBaseStructure.TIM_Period = arr; //设置在下一个更新事件装入活动的自动重装载寄存器周期的值 计数到5000为500ms

TIM_TimeBaseStructure.TIM_Prescaler =psc; //设置用来作为TIMx时钟频率除数的预分频值 10Khz的计数频率

TIM_TimeBaseStructure.TIM_ClockDivision = 0; //设置时钟分割:TDTS = Tck_tim

TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up; //TIM向上计数模式

TIM_TimeBaseInit(TIM7, &TIM_TimeBaseStructure); //根据TIM_TimeBaseInitStruct中指定的参数初始化TIMx的时间基数单位

TIM_ITConfig( //使能或者失能指定的TIM中断

TIM7, //TIM2

TIM_IT_Update ,

ENABLE //使能

);

NVIC_InitStructure.NVIC_IRQChannel = TIM7_IRQn; //TIM7中断

NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0; //先占优先级0级

NVIC_InitStructure.NVIC_IRQChannelSubPriority = 3; //从优先级3级

NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; //IRQ通道被使能

NVIC_Init(&NVIC_InitStructure); //根据NVIC_InitStruct中指定的参数初始化外设NVIC寄存器

TIM_Cmd(TIM7, ENABLE); //使能TIMx外设

}

main.c

#include "stm32f10x.h"

#include "sys.h"

#include "delay.h"

#include "led.h"

#include "motor.h"

#include "control.h"

#include "usart.h"

#include "encoder.h"

#include "stdio.h"

#include "timer.h"

int ASpeedNow = 0;

int BSpeedNow = 0;

int CSpeedNow = 0;

int DSpeedNow = 0;

int main(void)

{

delay_init(); //=====延时函数初始化

//NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);

MY_NVIC_PriorityGroupConfig(2); //=====设置中断分组

LED_Init(); //=====初始化与 LED 连接的硬件接口

MiniBalance_PWM_Init(7199,0);

Set_Pwm(1000,1000,1000,1000); //驱动电机

USART3_Init(9600);

Encoder_Init_TIM2(0xffff,0); //=====编码器接口

Encoder_Init_TIM3(0xffff,0); //=====编码器接口

Encoder_Init_TIM4(0xffff,0); //=====编码器接口

Encoder_Init_TIM5(0xffff,0); //=====初始化编码器

TIM7_Int_Init(5000-1,7200-1);

while(1)

{

Led_Flash(30);

//Set_Pwm(3000,2000,1000,1000);

printf("$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$\r\n");

//delay_ms(150);

printf("encoder222=%d\r\n",Read_Encoder_test(TIM2));

printf("encoder333=%d\r\n",Read_Encoder_test(TIM3));

printf("encoder444=%d\r\n",Read_Encoder_test(TIM4));

printf("encoder555=%d\r\n",Read_Encoder_test(TIM5));

printf("A=%d,B=%d,C=%d,D=%d\r\n",ASpeedNow,BSpeedNow,CSpeedNow,DSpeedNow);

printf("@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@\r\n");

delay_ms(100); //=====延时

}

}

//5ms 定时器中断服务函数

void TIM7_IRQHandler(void) //TIM7中断

{

if(TIM_GetITStatus(TIM7, TIM_IT_Update) != RESET) //检查指定的TIM中断发生与否:TIM 中断源

{

TIM_ClearITPendingBit(TIM7, TIM_IT_Update); //清除TIMx的中断待处理位:TIM 中断源

Get_Motor_Speed(&ASpeedNow,&BSpeedNow,&CSpeedNow,&DSpeedNow);

Led_Flash(100);

}

}

此时转动电机就可以看到相应的速度了

代码见下载区。

相关推荐

史上十大最强恐龙榜中榜
常见的铑催化反应
大疆有多牛?4600多项专利,打破日本15年垄断,将美公司逼上绝路