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

 

posted @   易安yan  阅读(241)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· TypeScript + Deepseek 打造卜卦网站:技术与玄学的结合
· 阿里巴巴 QwQ-32B真的超越了 DeepSeek R-1吗?
· 【译】Visual Studio 中新的强大生产力特性
· 10年+ .NET Coder 心语 ── 封装的思维:从隐藏、稳定开始理解其本质意义
· 【设计模式】告别冗长if-else语句:使用策略模式优化代码结构
点击右上角即可分享
微信分享提示