STM32:RS485编码器
RS485编码器
使用RS485读取多个编码器
思路:使用定时器检测数据是否接收完成
CubeMX配置:
配置串口:
配置定时器:
配置485使能脚
代码部分:
初始化部分
SwRS485Mode(RS485_RX_EN); HAL_UART_Receive_IT(&huart2, &Uart2RevByte, 1); HAL_TIM_Base_Start_IT(&htim6);
串口:
// 串口2接收中断回调函数 static void Uart2_RxData_Process(void) { // HAL_UART_Transmit(&huart1, &Uart2RevByte,1,0x1000); Uart2.RxBuf[Uart2.RxLen] = Uart2RevByte; Uart2.RxLen++; encoder_time = 0; // 编码器计时清零 if (Uart2.RxLen > (RX_MAXLEN - 1)) Uart2.RxLen = 0; // 接收数据错误,重新开始接收 HAL_UART_Receive_IT(&huart2, &Uart2RevByte, 1); // 串口中断接收数据 } // 串口接收中断回调函数 void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart) { if (huart->Instance == USART1) { Uart1RxDataProcess(); } if (huart->Instance == USART2) { Uart2_RxData_Process(); } }
定时器部分:串口中断接收中会把encoder_time值清零,在定时器中断检测到未清零,说明一帧数据接收完成,接收完成就可以根据接收的数据判断是哪个编码器发出的
/** * @brief 定时器回调函数 * * @param htim */ void HAL_TIM_RS485_Encoder_Callback(TIM_HandleTypeDef *htim) { if (htim == &htim6) // 500us { encoder_time++; if (encoder_time > 2) { RS485_REV_TIME = 1; } // printf("定时器6中断 :%d\r\n", cnt); } }
向编码器发送指令:
/** * @brief 发送编码器命令 * * @param encoder 编码器 * @param cmd 命令地址 * @param len 命令长度 */ void Send_Cmd_Encoder(RS485_ENCODER_INFOR *encoder) { // 切换485为发送 SwRS485Mode(RS485_TX_EN); // HAL_UART_Transmit_DMA(&huart2, encoder->send_buff, encoder->tx_len); HAL_UART_Transmit(&huart2, encoder->send_buff, encoder->tx_len, 0X100); SwRS485Mode(RS485_RX_EN); }
接收到编码器数据:这里只是发送命令,等待数据接收完成,数据处理看自己用什么方式处理
/** * @brief 发送读取命令,解析接收到的数据 * * @param encoder */ void Get_Encoder_Data(RS485_ENCODER_INFOR *encoder) { unsigned short crc; uint16_t len; // 发送命令:读取命令 或者设置命令 if (RS485_ENCODER[RS485_ENCODER_SET].status == IDLE)//如果设置参数的编码器空闲,发送读取数据的命令 { Send_Cmd_Encoder(encoder); } else if (RS485_ENCODER[RS485_ENCODER_SET].status == SET_PARAMETER)//如果设置参数的编码器在设置参数状态,发送设置的命令 { RS485_ENCODER[RS485_ENCODER_SET].status = IDLE; Encoder_Set_Cmd_Send(&RS485_ENCODER[RS485_ENCODER_SET]); } // 接收数据完成 if (RS485_REV_TIME == 1) // 定时器中断,接收数据完成 { RS485_REV_TIME = 0; // 标识清零 len = Uart2.RxLen; // 获取接收数据的长度 Uart2.RxLen = 0; // 先校验数据是否正确 if (len > 2)//数据长度<2,校验程序会死循环 { crc = do_crc(Uart2.RxBuf, len - 2); // 数据校验 } if (((crc & 0xff00) >> 8 == Uart2.RxBuf[len - 1]) && ((crc & 0xff) == Uart2.RxBuf[len - 2])) // 计算的校验位与接收的校验比较 { // 判断数据是哪个编码器发送的,接收的数据存放到对应的编码器接收buff switch (Uart2.RxBuf[0]) { // case RS485_ENCODER_SET: // memcpy(RS485_ENCODER[RS485_ENCODER_SET].receive_buff, Uart2.RxBuf, len); // RS485_ENCODER[RS485_ENCODER_SET].status = GETDATA; // break; case RS485_ENCODER_1: memcpy(RS485_ENCODER[RS485_ENCODER_1].receive_buff, Uart2.RxBuf, len); RS485_ENCODER[RS485_ENCODER_1].status = GETDATA; break; case RS485_ENCODER_2: memcpy(RS485_ENCODER[RS485_ENCODER_2].receive_buff, Uart2.RxBuf, len); RS485_ENCODER[RS485_ENCODER_2].status = GETDATA; break; case RS485_ENCODER_3: memcpy(RS485_ENCODER[RS485_ENCODER_3].receive_buff, Uart2.RxBuf, len); RS485_ENCODER[RS485_ENCODER_3].status = GETDATA; break; case RS485_ENCODER_4: memcpy(RS485_ENCODER[RS485_ENCODER_4].receive_buff, Uart2.RxBuf, len); RS485_ENCODER[RS485_ENCODER_4].status = GETDATA; break; case RS485_ENCODER_5: memcpy(RS485_ENCODER[RS485_ENCODER_5].receive_buff, Uart2.RxBuf, len); RS485_ENCODER[RS485_ENCODER_5].status = GETDATA; break; default: memcpy(RS485_ENCODER[RS485_ENCODER_SET].receive_buff, Uart2.RxBuf, len); RS485_ENCODER[RS485_ENCODER_SET].status = GETDATA; break; } // 轮询处理编码器数据 for (int i = 0; i < RS485_ENCODER_NUM; i++) { if (RS485_ENCODER[i].status == GETDATA) { RS485_ENCODER[i].mode = RS485_ENCODER[i].receive_buff[1]; RS485_ENCODER[i].status = IDLE; RS485_ENCODER[i].rx_len = len; Encoder_Data_Proc(&RS485_ENCODER[i]); } } } } }
在循环中遍历编码器
/** * @brief 编码器测试函数 * */ void RS485_Encoder_Test(void) { for (int i = 1; i < RS485_ENCODER_NUM; i++) { Updata_ReadCmd(&RS485_ENCODER[i], i, ENCODER_READ_MODE, ENCODER_MODE_REG, (DEV_ADDR_REG - ENCODER_MODE_REG)); // 更新发送命令 Get_Encoder_Data(&RS485_ENCODER[i]); HAL_Delay(30); } }
经测试,3路编码器获取数据,单路数据时间间隔80ms,5路编码器时间间隔200ms
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· TypeScript + Deepseek 打造卜卦网站:技术与玄学的结合
· 阿里巴巴 QwQ-32B真的超越了 DeepSeek R-1吗?
· 【译】Visual Studio 中新的强大生产力特性
· 10年+ .NET Coder 心语 ── 封装的思维:从隐藏、稳定开始理解其本质意义
· 【设计模式】告别冗长if-else语句:使用策略模式优化代码结构