阿里巴巴网站怎么做推广,WordPress SEO中文插件,网站建设二级分销,简述网页与网站的区别背景
旋钮是仪器仪表上一种常见的输入设备#xff0c;它的内部是一个旋转编码器#xff0c;知乎上的这篇科普文章对其工作原理做了深入浅出的介绍。
我们公司的功率分析仪的前面板也用到了该类设备#xff0c;最近前面板的MCU从MSP430切换成了STM32#xff0c;因此我要将…背景
旋钮是仪器仪表上一种常见的输入设备它的内部是一个旋转编码器知乎上的这篇科普文章对其工作原理做了深入浅出的介绍。
我们公司的功率分析仪的前面板也用到了该类设备最近前面板的MCU从MSP430切换成了STM32因此我要将编码器的驱动移植到STM32。
查看MSP430的代码看懂其基本思路是将旋钮的2路输出信号接到2个GPIO管脚并让这2个管脚作为中断源驱动在中断里检测2路输出信号的电平组合并做一些复杂的处理后台循环根据中断的处理结果获悉旋钮的旋转方向以及旋转过了几个刻度。
觉得MSP430的处理逻辑太复杂了而且经过确认app并不需要知道旋转过了几个刻度决定用简单的方法来实现旋钮功能。
移植思路
了解所用旋钮的信号时序
我们用的旋钮是日本帝国通信的XRE系列其原理图 其时序图 可以看到因为增量式旋转编码器的2个信号的波形相差1/4周期因此信号A在跳变时信号B一定处于稳定的高电平或稳定的低电平。
找到信号波形与旋转方向之间的对应关系
根据时序图可以看出当A相处于上升沿时B相总是低电平结合时序图左下角的CLOCKWISE ROTATION注释我们可以得出结论只要在A相的上升沿中断里检测到B相为低电平则说明旋钮在顺时针旋转。
那怎么检测逆时针旋转呢旋钮手册里并没有COUNTER-CLOCKWISE ROTATION的内容其实我们只要从右往左看就是逆时针的时序图 可以看到在逆时针旋转场景里当A相处于上升沿时B相总是高电平因此我们只需要在A相的上升沿检测一次B相的电平高低就能判断出旋转方向
代码编写
STM32的EXTI中断
与MSP430的GPIO自带中断功能不同STM32的GPIO是不具备中断能力的要想当中断管脚用需要搭配EXTI模块。
网上关于EXTI的样例代码较少更多的是用STM32CubeMX生成的整套工程代码我现有的工程就是前任员工基于STM32CubeMX生成的很难将两个工程自动合并。
想到可以将EXTI工程里的有效代码摘出来插入现有工程里尝试了一下可行。
GPIO和EXTI初始化代码
void encoder_init(void)
{GPIO_InitTypeDef GPIO_InitStruct {0};// GPIO initGPIO_InitStruct.Pin encoder_a2_Pin;GPIO_InitStruct.Mode GPIO_MODE_IT_RISING; //A相负责触发中断确定观测时间点GPIO_InitStruct.Pull GPIO_NOPULL;HAL_GPIO_Init(GPIOB, GPIO_InitStruct);GPIO_InitStruct.Pin encoder_b2_Pin;GPIO_InitStruct.Mode GPIO_MODE_INPUT; //软件读取B相的电平高低从而确定方向GPIO_InitStruct.Pull GPIO_NOPULL;HAL_GPIO_Init(GPIOB, GPIO_InitStruct);/* EXTI interrupt init*/HAL_NVIC_SetPriority(EXTI0_IRQn, 0, 0); //encoder_a2_Pin是连接到GPIO_PIN_0的因此对应EXTI的0号中断HAL_NVIC_EnableIRQ(EXTI0_IRQn);
}中断回调代码
void EXTI0_IRQHandler(void)
{/* USER CODE BEGIN EXTI0_IRQn 0 *//* USER CODE END EXTI0_IRQn 0 */HAL_GPIO_EXTI_IRQHandler(encoder_a2_Pin);/* USER CODE BEGIN EXTI0_IRQn 1 *//* USER CODE END EXTI0_IRQn 1 */
}void HAL_GPIO_EXTI_IRQHandler(uint16_t GPIO_Pin)
{/* EXTI line interrupt detected */if (__HAL_GPIO_EXTI_GET_IT(GPIO_Pin) ! 0x00u) // 不用担心多个GPIO共用一个EXTI中断EXTI会做区分{__HAL_GPIO_EXTI_CLEAR_IT(GPIO_Pin);HAL_GPIO_EXTI_Callback(GPIO_Pin);}
}void HAL_GPIO_EXTI_Callback(uint16_t GPIO_Pin)
{uint8_t pin_value;switch (GPIO_Pin){case encoder_a2_Pin:{pin_value HAL_GPIO_ReadPin(encoder_b2_GPIO_Port, encoder_b2_Pin);if (!pin_value) {encoder_msg ENCODERA_LEFT; // 逆时针旋转} else {encoder_msg ENCODERA_RIGH; // 顺时针旋转}break;}default:break;}
}后台循环代码
uint8_t encoder_msg INVALID_MSG;void encoder_process(void)
{uint8_t out_data[6];if (encoder_msg ! INVALID_MSG){data_process(ENCODER_KEY_TYPE, 0, (uint8_t *)encoder_msg, out_data); //将旋钮消息按约定格式封装成out_dataspi_enque_tx_data(out_data); // 将out_data通过SPI总线上报主控板encoder_msg INVALID_MSG; // clear msg}
}总结
我的代码相比老工程在app感知不到功能差异的前提下逻辑大大简化中断占用量还减少了一半值得大家参考。