十.四轮车驱动开发之三: 巧用编码器获取电机转速信息

本文详细介绍了四轮车驱动控制系统中编码器的应用,包括编码器的工作原理、分类及如何通过软件或硬件方式读取编码器脉冲信号以获取电机转速信息。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

这是”四轮车驱动控制”系列,分多个小节来介绍:

1. 八.四轮车驱动开发之一:正/逆向运动学分析

2. 九.四轮车驱动开发之二: 配置PWM驱动直流电机

3. 十.四轮车驱动开发之三: 巧用编码器获取电机转速信息

4. 十一.四轮车驱动开发之四: 理解直流电机PID控制器

5. 十二.四轮车驱动开发之五: 由浅至深理解6轴陀螺仪姿态解算算法

一.编码器简介

        编码器是一种安装在直流电机同心轴上的将电机转子的角位移或者角速度转换成一连串数字脉冲的旋转式传感器. 因为编码器输出的是标准的方波, 我们可以使用MCU,单片机等直接读取.

        从编码器输出数据类型上分, 可以分为增量式编码器和绝对式编码器。

        从编码器检测原理上来分, 还可以分为光学式、 磁式、 感应式、 电容式。 常见的是光电编码器(光学式) 和霍尔编码器(磁式) 。为判断转动转向, 一般输出两组存在一定相位差的方波信号.

        下图为光电编码器和MCU连接使用示意图:

二. 编码器脉冲信号读取

        如图所示: 编码器除正负电源连接线外,还有A,B两路数字脉冲输出信号, 把这两路信号线对接MCU的两个GPIO输入引脚上.

      对于编码器脉冲信号读取,主要包括电机旋转方向电机转速.

     一般使用 M 法测速确定电机的转速, 即通过测量单位时间内 A 相输出的脉冲数来得到速度信息。而对于B相的输入信号测不用处理.

 1.对于不带编码计数器功能的单片机或使用STM32但timer不够用的情况

        对于两个驱动电机的情况,我们可以通过配置外部GPIO中断读取, 比如把左轮的编码器 A 相输出接到处理器的外部中断输入口, 并通过跳变沿触发中断;把右轮的编码器 A 相输出接到处理器的另一外部中断输入口, 并通过跳变沿触发中断 (注左右轮的B相不用配置中断,仅配置GPIO输入模式即可) . 然后分别在左右轮分A相对应的外部中断服务函数里面, 通过读取 B 相引脚的电平来确定正反转。 如当 A 相来一个跳变沿的时候, 如果 B 相是高电平就认为是正转, 低电平就认为是反转。 并依靠正反转信息对编码器脉冲次数进行累加统计,进而按照一定周期读取此编码器脉冲次数统计值,按照周期时间计算出左右轮的瞬时速度.

        一个大致的代码如下(相关寄存器的配置代码略):

extern uint8_t volatile LeftEncoderCount;
extern int32_t volatile LeftEncoderTotal;
extern int8_t  volatile LeftEncoderDirection;
extern uint8_t volatile  RightEncoderCount;
extern int32_t volatile RightEncoderTotal;
extern int8_t volatile   RightEncoderDirection;

//左轮编码器A相信号中断处理程序, 右轮类似
void EXTIx_IRQHandler(void)  //EXTIx表某中断, 用以处理左轮电机A相脉冲信号
{
    //统计左轮周期内转速,单位周期内读取完毕后务必清0.    右轮类似
    LeftEncoderCount++;
    
    //读取左轮编码器B相相位电平值
    if( GPIOD->IDR & GPIO_Pin_x ){ //若为高电平.   GPIO_Pin_x表某引脚
        LeftEncoderDirection = -1; //标记当前为反向转动,周期性读取后务必清0
        LeftEncoderTotal--;//总编码器个数减1
    }else{
        LeftEncoderDirection = 1; //标记当前为正向转动,周期性读取后务必清0
        LeftEncoderTotal++;//总编码器个数加1
    }

    
    EXTI_ClearITPendingBit(EXTI_Linex);//EXTI_Linex表某中断引脚
}

 2. 对于自带编码器计数接口或利用Timer可实现计数的MCU,如STM32

        对于自带编码器计数接口的MCU,可以直接使用硬件计数器,对编码器脉冲信号进行计数,根据需要确定是否再读取完毕后对计数器进行清0。

        例如下面一个例子,就是对一个Timer进行配置,使其对左轮的编码器A相脉冲方波信号进行计数.(同样因为寄存器差别过大,相关寄存器的配置代码略):

//单位周期内读取编码器计数值. 参数指定读取哪个轮的转速,与定时器一一对应
int Read_Encoder(u8 timerX)
{
    int EncoderCount;    
    switch(timerX)
    {
	    case 2:  
            EncoderCount = (short)TIM2 -> CNT;  //对应左轮编码器计数器值,正负代表旋转方向
            TIM3 -> CNT=0; //因为是统计转速,也为了避免计数器溢出,读取完毕立即清0
            break;	
		case 3:  
            EncoderCount = (short)TIM3 -> CNT;  //对应又轮编码器计数器值,正负代表旋转方向
            TIM4 -> CNT=0;  //同上,读取完毕立即清0
            break;	
		default:  
            EncoderCount = 0;
    }
	
    return EncoderCount;
}

        由于一般MCU的Timer计数寄存器都有长度限制,比如16位,最大计数值为65535,超过会自动清零重装. 所以一般不要使用计数器累计求总编码器值.

       

        综上,有了左右轮的转动方向,编码器脉冲瞬时计数个数,或累计编码器总脉冲个数,还要根据小车的物理结构,做编码器脉冲个数(单位:个)和实际小车位移(单位:m)之间的换算,以及编码器脉冲计数速度(个/秒)和车速(米/秒)之间的换算.  到此, 我们就可以把目标车速和编码器读取值传给PID控制器,对小车的驱动轮进行精准的速度和位移控制.

      

<think>好的,用户想了解如何利用GPIO中断和霍尔编码器获取电机转速。首先,我需要回忆一下霍尔编码器的工作原理。霍尔编码器通常通过检测磁场变化来输出脉冲信号,每个脉冲对应电机的转动角度。所以,脉冲频率和转速成正比。 接下来,用户提到了GPIO中断,这说明需要用到微控制器的外部中断功能来捕获这些脉冲。常见的步骤可能包括硬件连接、中断设置、脉冲计数和时间测量这几个部分。 首先,硬件连接方面,需要确定霍尔编码器的输出信号线连接到哪个GPIO引脚,并且确保该引脚支持外部中断。可能需要使用上拉或下拉电阻,确保信号稳定。这里可能需要查阅具体微控制器的数据手册,确认引脚的中断功能。 然后,配置GPIO为输入模式,并启用中断。这里需要考虑触发方式,比如上升沿、下降沿或双边沿触发。霍尔编码器通常是正交编码,可能有两个信号通道,但用户可能只使用了一个通道,所以可能只需要一个中断。不过,为了更精确,可能需要两个通道来检测方向,但用户的问题可能简化处理。 接下来是中断服务程序(ISR)的设计。每次中断触发时,计数器加一。需要考虑去抖动的问题,不过霍尔编码器通常输出比较干净,可能不需要软件去抖。但如果是低质量的传感器,可能需要添加延时或滤波。 然后,如何将脉冲数转换为转速。通常的方法是计算单位时间内的脉冲数,然后根据编码器的每转脉冲数(PPR)来计算转速。公式应该是转速(RPM)=(脉冲数 / PPR)* (60 / 时间)。这里的单位时间可能是一秒,所以需要定时器来定期计算。 需要考虑定时器的设置,比如每秒触发一次定时器中断,在中断中读取脉冲计数器,并重置计数器。然后将数据通过公式计算得到RPM值。 可能的误差来源包括中断延迟、计数器溢出,或者高频脉冲导致的中断过于频繁,影响系统性能。这时候可能需要使用硬件计数器,或者更高性能的微控制器。另外,如果电机转速很低,单位时间内的脉冲数太少,会导致计算不准确,这时候可能需要延长测量时间或使用其他方法。 用户可能需要具体的代码示例,比如基于Arduino或STM32的代码片段。不过用户没有指定平台,可能需要给出通用的步骤。需要提醒用户注意GPIO的中断优先级,避免丢失脉冲。此外,正交编码器通常有A、B两相,可以检测方向,但用户可能只需要转速,所以可以只使用一个通道的中断,或者结合两个通道来提高精度。 总结步骤应该是:连接霍尔信号到GPIO,配置中断,计数脉冲,定时计算转速,处理数据。可能需要提到每转脉冲数的参数,需要根据实际编码器型号确定。最后,验证方法,比如用已知转速测试系统是否准确。</think>要利用GPIO中断和霍尔编码器获取电机转速,可通过以下步骤实现: --- ### **1. 硬件连接** - **霍尔编码器接口**: 将霍尔编码器的输出信号线(通常为A相或B相)连接到支持外部中断的GPIO引脚(如STM32的EXTI引脚、Arduino的D2/D3等)。 - **电源与接地**: 确保编码器和控制器共地,并为霍尔编码器提供适当电压(通常5V或3.3V)。 --- ### **2. 基本原理** - **霍尔脉冲与转速关系**: 电机每转一圈,霍尔编码器会产生固定数量的脉冲(记为`PPR`, Pulses Per Revolution)。 **转速公式**: $$ \text{RPM} = \frac{\text{脉冲数}}{\text{PPR}} \times \frac{60}{\text{采样时间(秒)}} $$ --- ### **3. 软件实现步骤** #### **步骤1:初始化GPIO中断** - 配置GPIO为输入模式,启用中断(如上升沿/下降沿触发)。 - 示例代码(以STM32 HAL库为例): ```c // 配置GPIO和中断 GPIO_InitTypeDef GPIO_InitStruct = {0}; GPIO_InitStruct.Pin = GPIO_PIN_0; GPIO_InitStruct.Mode = GPIO_MODE_IT_RISING; // 上升沿触发 GPIO_InitStruct.Pull = GPIO_PULLUP; HAL_GPIO_Init(GPIOA, &GPIO_InitStruct); // 使能中断 HAL_NVIC_SetPriority(EXTI0_IRQn, 0, 0); HAL_NVIC_EnableIRQ(EXTI0_IRQn); ``` #### **步骤2:中断服务程序(ISR)** - 在中断中记录脉冲数: ```c volatile uint32_t pulse_count = 0; // 全局变量存储脉冲数 void EXTI0_IRQHandler(void) { if (__HAL_GPIO_EXTI_GET_IT(GPIO_PIN_0) != RESET) { pulse_count++; // 每次中断脉冲数+1 __HAL_GPIO_EXTI_CLEAR_IT(GPIO_PIN_0); } } ``` #### **步骤3:定时采样与计算转速** - 使用定时器定期(如每1秒)读取脉冲数并计算转速: ```c void calculate_rpm(void) { static uint32_t last_pulse_count = 0; uint32_t current_pulse = pulse_count; uint32_t delta_pulse = current_pulse - last_pulse_count; float rpm = (delta_pulse / PPR) * 60.0 / SAMPLE_TIME; // RPM = (脉冲数/PPR) * 60 / 采样时间 last_pulse_count = current_pulse; printf("转速: %.2f RPM\n", rpm); } ``` --- ### **4. 关键注意事项** - **去抖动处理**: 若霍尔信号有噪声,需在硬件(RC滤波)或软件(中断后延时10ms再检测)去抖动。 - **中断响应速度**: 确保中断优先级足够高,避免丢失高速脉冲。 - **脉冲计数器溢出**: 使用`volatile`变量或原子操作防止计数错误。 --- ### **5. 扩展优化** - **正交编码模式**: 若使用双通道霍尔编码器(A/B相),可通过相位差检测旋转方向,并启用硬件编码器接口(如STM32的TIMx_ENCODER模式)。 - **高频脉冲处理**: 对于高速电机,建议使用硬件计数器(如STM32的TIM输入捕获)替代GPIO中断。 --- ### **验证方法** 1. 手动旋转电机,观察脉冲计数是否准确。 2. 用示波器测量霍尔信号频率,验证公式计算结果是否一致。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值