本帖最后由 GrootBrain 于 2023-6-3 20:55 编辑
#有奖活动# #申请原创#
基于AC7802正交编码实现电机测速
正交编码器测速原理
正交编码器是一种通过旋转或移动测量运动位置和速度的传感器。它通常由两个光学传感器(A相和B相)组成,每个传感器的输出波形完全相同,但相位相位差90度(即正交)。当物体被旋转或移动时,两个波形将发生同步变化,使得编码器可以确定方向和速度。
具体而言,在实际应用中,编码器的A和B两条输出线和中心的接地线连接到计数器或控制器电路中。计数器对A和B两种输信进行脉冲计数,并根据两条线之间的相对时间差确定运动速度和方向。如果传感器被旋转,每旋转一次会产生一定数量的脉冲,可以通过这些脉冲来计算旋转角度。
从上来看,以通道A的下降沿作为起始位置:
顺时针是01->00->10->11,也就是10进制的1-0-2-3
逆时针是00->01->11->10,也就是10进制的0-1-3-2
因此,只要知道计数规律,就知道是往哪个方向在转,计算脉冲的频率,就是旋转速度。
AC7802的正交解码功能
AC7802的PWM带正交解码功能,模块的通道0接phase A, 模块的通道1接phase B。7802正对正交编码进行正确记数。
AC7802的正交编码测速方案
硬件接口:
PB0,使用PWM1_CH1功能,用作编码器的phase A输入;
PB1,使用PWM1_CH2功能,用作编码器的phase B输入;
PWM1模块用于正交编码计数。phase A或phase B边沿跳变时计时器加1。正转时计数器增加,反转时计数器减少。
速度计算:
本实验中使用编码器是11线编码器,也就是电机转一圈,A/B两相分别输出11个脉冲,每个脉冲都使解码数值增加的话,电机转一圈是44个脉冲。
本实验电机的输出轴减速比是4.4,也就是电机转4.4圈,电机输出轴才会转一圈。也就是说。输出轴转一圈,脉冲计数器变化11*4*4.4=193.6个脉冲。
本实验每20ms计算一次转速,计算前200ms内转速,假如脉冲数变化为N,则转速rpm(转/分钟)
rpm=[ (N/193.6) / ( 200 / 1000 ) ] * 60
AC7802的正交编码测速编程
测速模块提供初始化接口,速度计算接口以及获取速度接口。
void speed_check_init( void );
void speed_check_task( void );
float speed_check_get_Revolutions_Per_Minute( void );
速度初始化接口speed_check_init(), 用于调用下层正交编码器初始化
void speed_check_init( void )
{
PWM_quadrature_decode_init();
}
速度计算接口speed_check_task(),用于计算转速,必须周期性调用,这里的调用周期是20ms
static void SpeedMeter(int currentPulse)
{
int deltaPulse = 0;
uint8_t i;
for ( i=0; i < (SPEED_METER_BUF_LEN-1) ; ++i ) {
g_pulseRecordTbl[i] = g_pulseRecordTbl[i+1];
}
g_pulseRecordTbl[SPEED_METER_BUF_LEN-1] = currentPulse;
deltaPulse = g_pulseRecordTbl[SPEED_METER_BUF_LEN-1] - g_pulseRecordTbl[0];
if ( -QUAD_CHANGE_NUMBER_MAX_IN_CALC_CYCLE > deltaPulse ) {
// inc pass 0
deltaPulse += (QUAD_ENCODER_NUM_MAX + 1);
} else if ( deltaPulse > QUAD_CHANGE_NUMBER_MAX_IN_CALC_CYCLE ) {
// dec pass 0
deltaPulse -= (QUAD_ENCODER_NUM_MAX + 1);
}
SPEED_TASK_ENTER_CRITICAL();
g_MoterSpeedRPM = deltaPulse / QUAD_ENCODER_NUMBER_IN_A_CYCLE / (SPEED_METER_CYCLE * (SPEED_METER_BUF_LEN-1)/1000.0f) * 60;
SPEED_TASK_EXIT_CRITICAL();
}
void speed_check_task(void)
{
SpeedMeter( PWM_quadrature_decode_get_val() );
}
获取速度接口speed_check_get_Revolutions_Per_Minute(),给外部提供计算后的转速获取接口,正负值表示方向
float speed_check_get_Revolutions_Per_Minute( void )
{
float speed = 0.0f;
SPEED_TASK_ENTER_CRITICAL();
speed = g_MoterSpeedRPM;
SPEED_TASK_EXIT_CRITICAL();
return speed;
}
测速模块会调用下层模块,下层模块提供编码器的初始化和获取编码器数值接口
void PWM_quadrature_decode_init( void );
uint32_t PWM_quadrature_decode_get_val( void );
正交编码器初始化接口PWM_quadrature_decode_init(), 完成PWM底层寄存器配置,端口配置
void PWM_quadrature_decode_init( void )
{
PWM_ConfigType config;
PWM_QuadDecodeConfigType quadDecodeConfig;
PWM_QuadPhaseConfigType quadPhaseAConfig, quadPhaseBConfig;
memset(&config, 0U, sizeof(config));
memset(&quadDecodeConfig, 0U, sizeof(quadDecodeConfig));
memset(&quadPhaseAConfig, 0U, sizeof(quadPhaseAConfig));
memset(&quadPhaseBConfig, 0U, sizeof(quadPhaseBConfig));
GPIO_SetFunc(GPIOB, GPIO_PIN0, GPIO_FUN2); /* PB0--PWM1_CH1.该引脚只在32pin封装上有 */
GPIO_SetFunc(GPIOB, GPIO_PIN1, GPIO_FUN2); /* PB1--PWM1_CH0,该引脚只在32pin封装上有.*/
GPIO_SetPullup(GPIOB, GPIO_PIN0, ENABLE); /*使能上拉*/
GPIO_SetPullup(GPIOB, GPIO_PIN1, ENABLE); /*使能上拉*/
/*通道配置*/
quadPhaseAConfig.polarity = PWM_QUAD_PHASE_NORMAL; /*A相输入极性为正常极性。*/
quadPhaseAConfig.filterEn = DISABLE; /*A相滤波器去能*/
quadPhaseAConfig.filterVal = 0; /*滤波值*/
quadPhaseBConfig.polarity = PWM_QUAD_PHASE_NORMAL; /*B相输入极性为正常极性。*/
quadPhaseBConfig.filterEn = DISABLE; /*B相滤波器去能*/
quadPhaseBConfig.filterVal = 0; /*滤波值*/
quadDecodeConfig.mode = PWM_QUAD_PHASE_ENCODE; /*A相和B相编码模式*/
quadDecodeConfig.phaseAConfig = quadPhaseAConfig; /*A相配置赋值*/
quadDecodeConfig.phaseBConfig = quadPhaseBConfig; /*B相配置赋值*/
quadDecodeConfig.quadEn = ENABLE; /*正交解码使能*/
/*PWM模块配置*/
config.mode = PWM_MODE_QUADRATURE_DECODER; /*PWM模块配置为正交解码模式*/
config.initModeStruct = &quadDecodeConfig; /*正交解码配置赋值*/
config.clkSource = PWM_CLK_SOURCE_APB; /*PWM时钟源配置*/
config.clkPsc = 0; /*PWM时钟源分频*/
config.initValue = 0; /*计数器初始寄存器值*/
config.maxValue = PULSE_PER_REVOLUTION - 1; /*PWM计数器最大值*/
config.overflowInterrupEn = DISABLE; /*计数器溢出中断使能*/
config.cntOverflowFreq = 0; /*CNTOF中断产生的频率与计数器频率的关系(0-127), 0表示每次计数器溢出都产生溢出中断,1表示间隔1次,2表示间隔2次,以此类推。*/
config.interruptEn = DISABLE; /*PWM中断使能*/
config.callBack = NULL; /*PWM中断回调*/
PWM_Init(QUAD_PWM_MODULE, &config); /*配置初始化生效*/
}
正交编码器数值获取接口PWM_quadrature_decode_get_val(),给上层接口提供获取数值的方法uint32_t PWM_quadrature_decode_get_val( void )
{
uint32_t counter = QUAD_PWM_MODULE->CNT & 0xFFFF;
return counter;
}
将速度计算功能嵌入到电机任务中
void motor_Task( void *pvParameters )
{
pvParameters = pvParameters;
adc_motor_ctrl_input_init();
PWM_motor_ctrl_output_init();
speed_check_init();
while (1) {
PWM_motor_ctrl_ouput_duty_val( adc_motor_ctrl_get_adc_Val() );
speed_check_task();
vTaskDelay( pdMS_TO_TICKS(20) );
}
}
在printTask输出电机转速数值
void printf_Task( void *pvParameters )
{
pvParameters = pvParameters;
InitDebug();
while (1) {
//printf( "Hi,I'm a small chip, AC7802.\r\n");
printf("speed(rpm) = %d\r\n", (int)speed_check_get_Revolutions_Per_Minute() );
vTaskDelay( pdMS_TO_TICKS(1000) );
}
}
测试
正转
反转:
结论:电机测速与电机标定值相符,且能计算出电机转动方向。
测试工程
测试工程在linux环境下编译,基于freeRTOS开发。
AC7802_FreeRTOS_motor_speed_meter.zip
(1.56 MB)
|