单片机-STM32部分:13-1、编码器
飞书文档https://x509p6c8to.feishu.cn/wiki/BpEywhaX9iqbiLkdqdAcmDnwnab
EC旋转编码器
在产品开发过程中,需要位置闭环的的产品,类似电机类产品来说,编码器至关重要,它不仅可以使我们对带年纪进行精确的速度闭环,位置闭环,还可以通过时间积分,根据运动学关系,获得速度、位置等信息。
本节课,我们使用拨轮滚轮旋转编码器EC11E153440D,带大家了解下编码器如何驱动。
编码器有四根线,A\B是编码输出,S是按钮状态,C是公共端。
那么我们该怎样去使用这个编码器呢,从给出的数据手册上面我们看到一个波形,我们就是通过这个波形去判断编码器是否转动以及编码器转动的方向?
可以从图中可以看出当从CW方向转动的时候,A的波形上升沿比B波形的上升沿快,具体快多少,这里数据手册给出24±3°,当从CCW方向转动的这个时候恰好相反,B的相位上升沿快于A的上升沿。这样可以通过捕获上升沿的顺序来判断编码器的方向。
因此:我们有两种方式来判断编码器转动和方向:
1、设置IOA为上升沿触发中断,在中断中检测B的电平状态,来判断旋转方向,这种方式比较简单。
2、可以同时捕获A项的上升、下降边沿,然后判断A项第一个边沿中断时候获取B和A项的电平,在第二个边沿触发中断的时候捕获B和A项的电平,根据两次捕获B和A项的值就可以知道旋转的方向。
bool is_ccw_end = false;
bool is_cw_end = false;while (1){/* USER CODE END WHILE *//* USER CODE BEGIN 3 */if(is_ccw_end == true){is_ccw_end = false;printf("正转\n");}if(is_cw_end == true){is_cw_end = false;printf("反转\n");}}void HAL_GPIO_EXTI_Callback(uint16_t GPIO_Pin){if(GPIO_Pin == A1_Pin) //判断中断来自哪一条中断线{//进入中断之后,判断B1 PIN的电平来决定哪个方向if(HAL_GPIO_ReadPin(B1_GPIO_Port, B1_Pin) == 0){//CW方向is_cw_end = true;}else{//CCW方向is_ccw_end = true;} }
}
以CW方向为例,第一次捕获A项的的边缘位上升沿,此时A = 1,B = 0;那么第二次就必须捕获下降沿,A = 0,B = 1。假如A第一次没有在边沿捕获到上升沿的时候,捕获的是下降沿,第二次就一定捕获到上升沿。CCW方向也是如此的,这样我们就判断这四种情况,其他的都不用管,这样可以过滤掉干扰,从而实现更准确的控制。
设置PB0和PB1为编码器的A1、B1端口
PB0设置为外部中断,触发模式为上升、下降沿触发
PB1设置为输入模式
同时开启PB0的中断EXTI0
打开USART1作为日志口,方便调试
//CW方向set_cw_status();is_ccw_start = false;}else{//CCW方向set_ccw_status();is_cw_start = false;}}}
}int fputc(int ch, FILE *f)
{HAL_UART_Transmit(&huart1 , (uint8_t *)&ch, 1, 0xFFFF);return ch;
}
/* USER CODE END 4 */
参考工程:
参考飞书文档
STM32的定时器有编码器模式(Encoder Mode)
大大的方便我们的开发。使用STM32cubeMX配置工具,使得这个过程变得无比简单。
如果TI1和TI2分别接编码器的A相和B相的话,那么,当编码器正转的时候,如下图计数器会向上计数,反转的时候会向下计数,注意了这个向下计数并不会出现负的值。 |
配置定时器TIM的编码器模式
设置定时器TIM的Combined Channels的选项为Encoder Mode,编码器模式;
设置定时器TIM相关参数:
PSC:0 ; Counter:65535 (设置计数器的值为65535,最大值);
配置编码器模式相关参数:
在参数配置中的Econder Mode中选择Econder Mode TI1 and TI2;
如果编码模式设置为 Encoder Mode TI1 and TI2 则会默认检测AB相的上升沿与下降沿; |
在TI1、TI2的选项中选择Rising Edge上升沿触发计数;
这个参数的意思是在检测到上升沿的时候就触发encoder捕获AB相的值,而并不是这里设置的是上升沿就只检测AB相的上升沿,下降沿还是同样会计数的。 |
Input Filter:滤波值,起到消抖作用
选择GPIO模式配置,配置定时器两个GPIO引脚模式,全部改成Pull-Up,即上拉模式,主要用于没有外部上拉的编码器读取时,可以确定引脚电平,防止出错;
编写代码
添加定时器3的通道1和通道2的Encoder Mode开启使能函数
/* USER CODE BEGIN 2 */ |
编码器数据的读取使用:
在循环中调用 __HAL_TIM_IS_TIM_COUNTING_DOWN 可以获得当前电机的转向 0为正、1为负;
在循环中调用 __HAL_TIM_GET_COUNTER 获取计数器的计数值,即编码器的脉冲数;
/* Infinite loop *//* USER CODE BEGIN WHILE */while (1){/* USER CODE END WHILE *//* USER CODE BEGIN 3 */int Direction = __HAL_TIM_IS_TIM_COUNTING_DOWN(&htim3); //读取编码器转动方向//若需要检测编码器转了多少格,记得要/4,因为转一格是+4;int CaptureNumber = (short)__HAL_TIM_GET_COUNTER(&htim3)/4; //读取编码器数据printf("Direction is %d \r\n",Direction);printf("CaptureNumber is %d \r\n",CaptureNumber);HAL_Delay(500);}/* USER CODE END 3 *///short的表示范围(-32768-32767),也就是说当读出来的值为(32767, 32768, 32769,…,65535,65536,65537…)的时候会因为溢出而转换为(32767,-32768,-32767,…, -1, ,0, , 1)就这样不断地循环下去。所以我们的电机反转的时候读出的数就是反方向的速度值。