本帖最后由 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, 下载次数: 11)
|