slamugv使用说明--5.电机编码测速

Paloma ·
更新时间:2024-09-21
· 986 次阅读

电机编码器测速
编码器(encoder)是将信号(如比特流)或数据进行编制、转换为可用以通讯、传输和存储的信号形式的设备。编码器把角位移或直线位移转换成电信号
编码器分类及原理:
按编码器原理分增量式和绝对式
增量式编码器:增量式编码器是将位移转换成周期性的电信号,再把这个电信号转变成计数脉冲,用脉冲的个数表示位移的大小。
增量式编码器通常有A,B,Z三相,A,B相之间延迟1/4的周期(90度)的脉冲输出,根据延时的关系可以区别正反转。而且通过A,B相的上升沿和下降沿可以进行2倍频和4倍频,用来提高精度,Z相为单圈脉冲,我们的直流有刷电机比较便宜,所以没带Z相,所以我就不解释了。想知道的可以自行了解

绝对式编码器:绝对编码器光码盘上有许多道刻线,每道刻线依次以2线、4线、8线、16线。。。。。。编排,这样,

在编码器的每一个位置,通过读取每道刻线的通、暗,获得一组从2的零次方到2的n-1次方的唯一的2进制编码(格雷码),这就称为n位绝对编码器。
直流有刷电机参数:

减速比30 空载电流<400ma 空载转速415rpm 额定扭矩3.9Kg.cm 额定转速350rpm 额定电流 <1.9A 最大扭矩30kg.cm 停转电流11.0A
1.编码器测速cube配置教程
定时器有编码器模式直接配置
![在这里插入图片描述在这里插入图片描述(https://img-blog.csdnimg.cn/20200410221231830.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3dlaXhpbl80MTQwNTQ2Ng==,size_16,color_FFFFFF,t_70)
我之前的定义都定义好了编码器接口对应的引脚和定时器,直接配置就行

然后生成代码
编码器是上升沿触发还是下降沿触发,还是双边沿触发,这个后面生成代码再改

寄存器讲解
选择编码器接口模式时,如果计数器仅在 TI2 边沿处计数,在 TIMx_SMCR 寄存器中写入SMS=001;如果计数器仅在 TI1 边沿处计数,写入 SMS=010;如果计数器在 TI1 和 TI2 边沿处均计数,则写入 SMS=011。通过编程 TIMx_CCER 寄存器的 CC1P 和 CC2P 位,选择 TI1 和 TI2 极性。如果需要,还可对输入滤波器进行编程。在这里插入图片描述
编码器定时器计数的是cnt,debug可以看到,后面我会抽空做一篇关于mdk debug的小技巧 关键代码解读
伪代码:
1. 初始化编码器GPiO引脚
2. 初始化编码器定时器
3. 通过编码器触发中断计数
4. 通过读编码器定时器计算小车轮子的转速 ```c ```c /* 私有变量 ------------------------------------------------------------------*/ __IO uint16_t time_count=0; // 时间计数,每1ms增加一(与滴答定时器频率有关) __IO int32_t CaptureNumber[4]={0}; // 输入捕获数 #define ENCODER 16 // 编码器线数 #define SPEEDRATIO 30 // 电机减速比 #define PPR (SPEEDRATIO*ENCODER*4) // Pulse/r 每圈可捕获的脉冲数 TIM_HandleTypeDef TIM1_Encoder; TIM_HandleTypeDef TIM2_Encoder; TIM_HandleTypeDef TIM3_Encoder; TIM_HandleTypeDef TIM4_Encoder; float Speed1 = 0; float Speed2 = 0; float Speed3 = 0; float Speed4 = 0; __IO int16_t OverflowCount[4] = {0};//定时器溢出次数 void Encoder_Tim1_Init(void) { TIM_Encoder_InitTypeDef EncoderConfig; TIM_MasterConfigTypeDef sMasterConfig; // __HAL_RCC_TIM1_CLK_ENABLE(); /* 定时器基础配置 */ TIM1_Encoder.Instance = TIM1; TIM1_Encoder.Init.Prescaler = 0;//预分频系数 TIM1_Encoder.Init.CounterMode = TIM_COUNTERMODE_UP;//定时器计数方式 TIM1_Encoder.Init.Period = 0xFFFF;//定时器周期 TIM1_Encoder.Init.ClockDivision = TIM_CLOCKDIVISION_DIV1;//时钟分频 TIM1_Encoder.Init.RepetitionCounter = 0;//重复计数器 /* 定时器编码器模式配置 */ EncoderConfig.EncoderMode = TIM_ENCODERMODE_TI12; /* 定时器编码器IC1配置 */ EncoderConfig.IC1Polarity = TIM_ICPOLARITY_RISING; EncoderConfig.IC1Selection = TIM_ICSELECTION_DIRECTTI; EncoderConfig.IC1Prescaler = TIM_ICPSC_DIV1; EncoderConfig.IC1Filter = 0; /* 定时器编码器IC2配置 */ EncoderConfig.IC2Polarity = TIM_ICPOLARITY_RISING; EncoderConfig.IC2Selection = TIM_ICSELECTION_DIRECTTI; EncoderConfig.IC2Prescaler = TIM_ICPSC_DIV1; EncoderConfig.IC2Filter = 0; __HAL_TIM_SET_COUNTER(&TIM1_Encoder,0); /* 初始化编码器接口 */ HAL_TIM_Encoder_Init(&TIM1_Encoder, &EncoderConfig); // __HAL_TIM_CLEAR_IT(&TIM1_Encoder, TIM_IT_UPDATE); //清除更新中断标志位 __HAL_TIM_URS_ENABLE(&TIM1_Encoder); //仅允许计数器溢出才产生更新中断 __HAL_TIM_ENABLE_IT(&TIM1_Encoder,TIM_IT_UPDATE); //使能更新中断 HAL_NVIC_SetPriority(ENCODER_TIM1_IRQn, 1, 3); HAL_NVIC_EnableIRQ(ENCODER_TIM1_IRQn); sMasterConfig.MasterOutputTrigger = TIM_TRGO_RESET; sMasterConfig.MasterSlaveMode = TIM_MASTERSLAVEMODE_DISABLE; HAL_TIMEx_MasterConfigSynchronization(&TIM1_Encoder, &sMasterConfig); } void Encoder_Tim2_Init(void) { // __HAL_RCC_TIM2_CLK_ENABLE(); TIM_Encoder_InitTypeDef EncoderConfig; // TIM_MasterConfigTypeDef sMasterConfig; /* 定时器基础配置 */ TIM2_Encoder.Instance = TIM2; TIM2_Encoder.Init.Prescaler = 0; TIM2_Encoder.Init.CounterMode = TIM_COUNTERMODE_UP; TIM2_Encoder.Init.Period = 0xFFFF; /* 定时器编码器模式配置 */ TIM2_Encoder.Init.ClockDivision = TIM_CLOCKDIVISION_DIV1; /* 定时器编码器IC1配置 */ EncoderConfig.EncoderMode = TIM_ENCODERMODE_TI12; EncoderConfig.IC1Polarity = TIM_ICPOLARITY_RISING; EncoderConfig.IC1Selection = TIM_ICSELECTION_DIRECTTI; EncoderConfig.IC1Prescaler = TIM_ICPSC_DIV1; EncoderConfig.IC1Filter = 0; /* 定时器编码器IC2配置 */ EncoderConfig.IC2Polarity = TIM_ICPOLARITY_RISING; EncoderConfig.IC2Selection = TIM_ICSELECTION_DIRECTTI; EncoderConfig.IC2Prescaler = TIM_ICPSC_DIV1; EncoderConfig.IC2Filter = 0; __HAL_TIM_SET_COUNTER(&TIM2_Encoder,0); /* 初始化编码器接口 */ HAL_TIM_Encoder_Init(&TIM2_Encoder, &EncoderConfig); // __HAL_TIM_CLEAR_IT(&TIM2_Encoder, TIM_IT_UPDATE); //清除更新中断标志位 __HAL_TIM_URS_ENABLE(&TIM2_Encoder); //仅允许计数器溢出才产生更新中断 __HAL_TIM_ENABLE_IT(&TIM2_Encoder,TIM_IT_UPDATE); //使能更新中断 HAL_NVIC_SetPriority(ENCODER_TIM2_IRQn, 1, 3); HAL_NVIC_EnableIRQ(ENCODER_TIM2_IRQn); } void Encoder_Tim3_Init(void) { // __HAL_RCC_TIM3_CLK_ENABLE(); TIM_Encoder_InitTypeDef EncoderConfig; /* 定时器基础配置 */ TIM3_Encoder.Instance = TIM3; TIM3_Encoder.Init.Prescaler = 0; TIM3_Encoder.Init.CounterMode = TIM_COUNTERMODE_UP; TIM3_Encoder.Init.Period = 0xFFFF; TIM3_Encoder.Init.ClockDivision = TIM_CLOCKDIVISION_DIV1; /* 定时器编码器模式配置 */ EncoderConfig.EncoderMode = TIM_ENCODERMODE_TI12; /* 定时器编码器IC1配置 */ EncoderConfig.IC1Polarity = TIM_ICPOLARITY_RISING; EncoderConfig.IC1Selection = TIM_ICSELECTION_DIRECTTI; EncoderConfig.IC1Prescaler = TIM_ICPSC_DIV1; EncoderConfig.IC1Filter = 0; /* 定时器编码器IC2配置 */ EncoderConfig.IC2Polarity = TIM_ICPOLARITY_RISING; EncoderConfig.IC2Selection = TIM_ICSELECTION_DIRECTTI; EncoderConfig.IC2Prescaler = TIM_ICPSC_DIV1; EncoderConfig.IC2Filter = 0; __HAL_TIM_SET_COUNTER(&TIM3_Encoder,0); /* 初始化编码器接口 */ HAL_TIM_Encoder_Init(&TIM3_Encoder, &EncoderConfig); __HAL_TIM_CLEAR_IT(&TIM3_Encoder, TIM_IT_UPDATE); //清除更新中断标志位 __HAL_TIM_URS_ENABLE(&TIM3_Encoder); //仅允许计数器溢出才产生更新中断 __HAL_TIM_ENABLE_IT(&TIM3_Encoder,TIM_IT_UPDATE); //使能更新中断 HAL_NVIC_SetPriority(ENCODER_TIM3_IRQn, 1, 3); HAL_NVIC_EnableIRQ(ENCODER_TIM3_IRQn); } void Encoder_Tim4_Init(void) { // __HAL_RCC_TIM4_CLK_ENABLE(); TIM_Encoder_InitTypeDef EncoderConfig; // TIM_MasterConfigTypeDef sMasterConfig; /* 定时器基础配置 */ /* 定时器基础配置 */ TIM4_Encoder.Instance = TIM4; TIM4_Encoder.Init.Prescaler = 0; TIM4_Encoder.Init.CounterMode = TIM_COUNTERMODE_UP; TIM4_Encoder.Init.Period = 0xFFFF; TIM4_Encoder.Init.ClockDivision = TIM_CLOCKDIVISION_DIV1; /* 定时器编码器模式配置 */ EncoderConfig.EncoderMode = TIM_ENCODERMODE_TI12; /* 定时器编码器IC1配置 */ EncoderConfig.IC1Polarity = TIM_ICPOLARITY_RISING; EncoderConfig.IC1Selection = TIM_ICSELECTION_DIRECTTI; EncoderConfig.IC1Prescaler = TIM_ICPSC_DIV1; EncoderConfig.IC1Filter = 0; /* 定时器编码器IC2配置 */ EncoderConfig.IC2Polarity = TIM_ICPOLARITY_RISING; EncoderConfig.IC2Selection = TIM_ICSELECTION_DIRECTTI; EncoderConfig.IC2Prescaler = TIM_ICPSC_DIV1; EncoderConfig.IC2Filter = 0; __HAL_TIM_SET_COUNTER(&TIM4_Encoder,0); /* 初始化编码器接口 */ HAL_TIM_Encoder_Init(&TIM4_Encoder, &EncoderConfig); // __HAL_TIM_CLEAR_IT(&TIM4_Encoder, TIM_IT_UPDATE); //清除更新中断标志位 __HAL_TIM_URS_ENABLE(&TIM4_Encoder); //仅允许计数器溢出才产生更新中断 __HAL_TIM_ENABLE_IT(&TIM4_Encoder,TIM_IT_UPDATE); //使能更新中断 HAL_NVIC_SetPriority(ENCODER_TIM4_IRQn, 1, 3); HAL_NVIC_EnableIRQ(ENCODER_TIM4_IRQn); } /** * 函数功能: 基本定时器硬件初始化配置 * 输入参数: htim_base:基本定时器句柄类型指针 * 返 回 值: 无 * 说 明: 该函数被HAL库内部调用 */ void HAL_TIM_Encoder_MspInit(TIM_HandleTypeDef* htim_base) { GPIO_InitTypeDef GPIO_InitStruct ; if(htim_base->Instance == ENCODER_TIM1) { __HAL_RCC_TIM1_CLK_ENABLE(); __HAL_RCC_GPIOE_CLK_ENABLE(); __HAL_RCC_GPIOA_CLK_ENABLE(); /**TIM1 GPIO Configuration PE9 ------> TIM1_CH1 PA9 ------> TIM1_CH2 */ GPIO_InitStruct.Pin = GPIO_PIN_9; GPIO_InitStruct.Mode = GPIO_MODE_AF_PP; GPIO_InitStruct.Pull = GPIO_PULLUP; GPIO_InitStruct.Alternate = GPIO_AF1_TIM1; HAL_GPIO_Init(GPIOE, &GPIO_InitStruct); GPIO_InitStruct.Pin = GPIO_PIN_9; GPIO_InitStruct.Mode = GPIO_MODE_AF_PP; GPIO_InitStruct.Pull = GPIO_PULLUP; GPIO_InitStruct.Alternate = GPIO_AF1_TIM1; HAL_GPIO_Init(GPIOA, &GPIO_InitStruct); } else if(htim_base->Instance == ENCODER_TIM2) { __HAL_RCC_TIM2_CLK_ENABLE(); __HAL_RCC_GPIOA_CLK_ENABLE(); __HAL_RCC_GPIOB_CLK_ENABLE(); /**TIM2 GPIO Configuration PA0 ------> TIM2_CH1 PA1 ------> TIM2_CH2 */ GPIO_InitStruct.Pin = GPIO_PIN_0; //PA0 GPIO_InitStruct.Mode = GPIO_MODE_AF_PP; GPIO_InitStruct.Pull = GPIO_PULLUP; GPIO_InitStruct.Alternate = GPIO_AF1_TIM2; HAL_GPIO_Init(GPIOA, &GPIO_InitStruct); GPIO_InitStruct.Pin = GPIO_PIN_1; //PA1 GPIO_InitStruct.Mode = GPIO_MODE_AF_PP; GPIO_InitStruct.Pull = GPIO_PULLUP; GPIO_InitStruct.Alternate = GPIO_AF1_TIM2; HAL_GPIO_Init(GPIOA, &GPIO_InitStruct); } else if(htim_base->Instance == ENCODER_TIM3) { __HAL_RCC_TIM3_CLK_ENABLE(); __HAL_RCC_GPIOA_CLK_ENABLE(); /**TIM3 GPIO Configuration PA6 ------> TIM3_CH1 PA7 ------> TIM3_CH2 */ GPIO_InitStruct.Pin = GPIO_PIN_6|GPIO_PIN_7; GPIO_InitStruct.Mode = GPIO_MODE_AF_PP; GPIO_InitStruct.Pull = GPIO_PULLUP; GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW; GPIO_InitStruct.Alternate = GPIO_AF2_TIM3; HAL_GPIO_Init(GPIOA, &GPIO_InitStruct); } else if(htim_base->Instance == ENCODER_TIM4) { __HAL_RCC_TIM4_CLK_ENABLE(); __HAL_RCC_GPIOD_CLK_ENABLE(); /**TIM4 GPIO Configuration PD12 ------> TIM4_CH1 PD13 ------> TIM4_CH2 */ GPIO_InitStruct.Pin = GPIO_PIN_12|GPIO_PIN_13; //PD12 ,PD13 GPIO_InitStruct.Mode = GPIO_MODE_AF_PP; GPIO_InitStruct.Pull = GPIO_PULLUP; GPIO_InitStruct.Alternate = GPIO_AF2_TIM4; HAL_GPIO_Init(GPIOD, &GPIO_InitStruct); } } /** * 函数功能: 基本定时器硬件反初始化配置 * 输入参数: htim_base:基本定时器句柄类型指针 * 返 回 值: 无 * 说 明: 该函数被HAL库内部调用 */ void HAL_TIM_Encoder_MspDeInit(TIM_HandleTypeDef* tim_encoderHandle) { if(tim_encoderHandle->Instance==TIM1) { /* USER CODE BEGIN TIM1_MspDeInit 0 */ /* USER CODE END TIM1_MspDeInit 0 */ /* 基本定时器外设时钟禁用 */ __HAL_RCC_TIM1_CLK_DISABLE(); /**TIM1 GPIO Configuration PE9 ------> TIM1_CH1 PA9 ------> TIM1_CH2 */ HAL_GPIO_DeInit(GPIOE, GPIO_PIN_9); HAL_GPIO_DeInit(GPIOA, GPIO_PIN_9); } else if(tim_encoderHandle->Instance==TIM2) { /* 基本定时器外设时钟禁用 */ __HAL_RCC_TIM2_CLK_DISABLE(); /**TIM2 GPIO Configuration PA5 ------> TIM2_CH1 PB3 ------> TIM2_CH2 */ HAL_GPIO_DeInit(GPIOA, GPIO_PIN_5); HAL_GPIO_DeInit(GPIOB, GPIO_PIN_3); } else if(tim_encoderHandle->Instance==TIM3) { /* 基本定时器外设时钟禁用 */ __HAL_RCC_TIM3_CLK_DISABLE(); /**TIM2 GPIO Configuration PA6 ------> TIM3_CH1 PA7 ------> TIM3_CH2 */ HAL_GPIO_DeInit(GPIOA, GPIO_PIN_6); HAL_GPIO_DeInit(GPIOA, GPIO_PIN_7); } else if(tim_encoderHandle->Instance==TIM4) { /* USER CODE BEGIN TIM4_MspDeInit 0 */ /* USER CODE END TIM4_MspDeInit 0 */ /* 基本定时器外设时钟禁用 */ __HAL_RCC_TIM4_CLK_DISABLE(); /**TIM4 GPIO Configuration PD12 ------> TIM4_CH1 PD13 ------> TIM4_CH2 */ HAL_GPIO_DeInit(GPIOD, GPIO_PIN_12); HAL_GPIO_DeInit(GPIOD, GPIO_PIN_13); } } void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim) { OSIntEnter(); if(htim == &TIM1_Encoder) { if(__HAL_TIM_IS_TIM_COUNTING_DOWN(htim)) OverflowCount[Encoder_1]--; //向下计数溢出 else OverflowCount[Encoder_1]++; //向上计数溢出 } else if(htim == &TIM2_Encoder) { if(__HAL_TIM_IS_TIM_COUNTING_DOWN(htim)) OverflowCount[Encoder_2]--; //向下计数溢出 else OverflowCount[Encoder_2]++; //向上计数溢出 } else if(htim == &TIM3_Encoder) { if(__HAL_TIM_IS_TIM_COUNTING_DOWN(htim)) OverflowCount[Encoder_3]--; //向下计数溢出 else OverflowCount[Encoder_3]++; //向上计数溢出 } else if(htim == &TIM4_Encoder) { if(__HAL_TIM_IS_TIM_COUNTING_DOWN(htim)) OverflowCount[Encoder_4]--; //向下计数溢出 else OverflowCount[Encoder_4]++; //向上计数溢出 } OSIntExit(); } /************************************************************************** 函数功能:单位时间读取编码器计数 入口参数:定时器 返回 值:速度值 **************************************************************************/ float Read_Encoder(uint16_t TIMX) { int Speed; switch(TIMX) { case 1: CaptureNumber[Encoder_1] = ( int16_t )__HAL_TIM_GET_COUNTER(&TIM1_Encoder)+OverflowCount[Encoder_1]*65535; Speed = (float)CaptureNumber[Encoder_1]/PPR; __HAL_TIM_SET_COUNTER(&TIM1_Encoder,0); break ; case 2: CaptureNumber[Encoder_2] = ( int16_t )__HAL_TIM_GET_COUNTER(&TIM2_Encoder)+OverflowCount[Encoder_2]*65535; Speed = (float)CaptureNumber[Encoder_2]/PPR; __HAL_TIM_SET_COUNTER(&TIM2_Encoder,0); break ; case 3: CaptureNumber[Encoder_3] = ( int16_t )__HAL_TIM_GET_COUNTER(&TIM3_Encoder)+OverflowCount[Encoder_3]*65535; Speed = (float)CaptureNumber[Encoder_3]/PPR; __HAL_TIM_SET_COUNTER(&TIM3_Encoder,0); break ; case 4: CaptureNumber[Encoder_4] = ( int16_t )__HAL_TIM_GET_COUNTER(&TIM4_Encoder)+OverflowCount[Encoder_4]*65535; Speed = (float)CaptureNumber[Encoder_4]/PPR; __HAL_TIM_SET_COUNTER(&TIM4_Encoder,0); break ; } return Speed ; } ```c 在主函数里添加这函数,可以用printf函数打印 int Encoder_A,Encoder_B,Encoder_C,Encoder_D; //编码器的脉冲计数 Encoder_A= Read_Encoder(1); Encoder_A= Read_Encoder(2); Encoder_C= Read_Encoder(3); Encoder_D= Read_Encoder(4); printf("Encoder_A%d",Encoder_A); printf("Encoder_B%d",Encoder_B); printf("Encoder_C%d",Encoder_C); printf("Encoder_D%d",Encoder_D);
作者:傻人爱孤独



编码 电机

需要 登录 后方可回复, 如果你还没有账号请 注册新账号