本文整理了基于 N32L40x MCU 的单圈绝对值、多圈计数、全信息及编码器ID协议的示例实现。请求应答时间均在 3µs 以内。

1. 协议帧示例

命令 名称 返回示例 帧长度
0x02 单圈绝对值 02 00 45 23 01 CRC 6 字节
0x8A 多圈计数 8A 00 00 00 00 CRC 6 字节
0x1A 全信息 1A 00 45 23 01 5A 00 00 00 00 CRC 11 字节
0x92 编码器 ID 92 00 5A CRC 4 字节

注:

  • CRC 使用异或校验 (Tamagawa_CRC8)

  • ENID(编码器ID)存储在 tamagawa_data[4]

  • 单圈峰值 0x7FFFFF,到达后下一个值归零

2. 数据结构

// 内部数据数组(9字节)
uint8_t tamagawa_data[9];
// 数据含义
// [0] SF(状态标志)
// [1~3] 单圈值 ABS(23位)
// [4] 编码器ID
// [5~7] 多圈值 ABM(24位)
// [8] 报警标志

预建帧

uint8_t single_resp[SIG_FRAME_LEN];   // 单圈帧 6字节
uint8_t multi_resp[SIG_FRAME_LEN];    // 多圈帧 6字节
uint8_t allinfo_resp[FULL_FRAME_LEN]; // 全信息帧 11字节
uint8_t id_resp[ID_FRAME_LEN];        // 编码器ID帧 4字节

3. 核心函数

CRC 校验

uint8_t Tamagawa_CRC8(uint8_t *data, uint8_t len)
{
    uint8_t xor = 0x00;
    for (uint8_t i = 0; i < len; i++)
        xor ^= data[i];
    return xor;
}

更新数据并重建帧

void Tamagawa_Update_Data(uint32_t abs_position,
                          uint16_t enid,
                          uint32_t multi_turn,
                          uint8_t  alarm)
{
    abs_position &= 0x7FFFFF;  // 23位单圈
    multi_turn   &= 0x00FFFFFF; // 24位多圈

    tamagawa_data[1] = (uint8_t)(abs_position);
    tamagawa_data[2] = (uint8_t)(abs_position >> 8);
    tamagawa_data[3] = (uint8_t)(abs_position >> 16);
    tamagawa_data[4] = (uint8_t)(enid & 0xFF);
    tamagawa_data[5] = (uint8_t)(multi_turn);
    tamagawa_data[6] = (uint8_t)(multi_turn >> 8);
    tamagawa_data[7] = (uint8_t)(multi_turn >> 16);
    tamagawa_data[8] = alarm;

    BuildAllFrames(); // 重建所有应答帧
}

单圈递增(峰值归零)

void Tamagawa_IncreaseSingleTurn(void)
{
    uint32_t cur = (uint32_t)(tamagawa_data[1])
                 | ((uint32_t)(tamagawa_data[2]) << 8)
                 | ((uint32_t)(tamagawa_data[3]) << 16);

    if (cur >= SINGLE_TURN_PEAK) cur = 0;
    else cur++;

    tamagawa_data[1] = (uint8_t)(cur);
    tamagawa_data[2] = (uint8_t)(cur >> 8);
    tamagawa_data[3] = (uint8_t)(cur >> 16);

    // 更新单圈帧
    single_resp[1] = tamagawa_data[0];
    single_resp[2] = tamagawa_data[1];
    single_resp[3] = tamagawa_data[2];
    single_resp[4] = tamagawa_data[3];
    single_resp[5] = Tamagawa_CRC8(single_resp, 5);

    // 同步全信息帧的单圈部分
    allinfo_resp[1] = tamagawa_data[0];
    allinfo_resp[2] = tamagawa_data[1];
    allinfo_resp[3] = tamagawa_data[2];
    allinfo_resp[4] = tamagawa_data[3];
    allinfo_resp[10] = Tamagawa_CRC8(allinfo_resp, 10);
}

4. UART + DMA + RS485

  • GPIO PB6 控制 RS485 收/发

  • UART5 波特率 2.5Mbps,8N1

  • 使用 DMA 加速发送,减少 CPU 占用

中断处理

void UART5_IRQHandler(void)
{
    uint8_t cmd = UART5->DAT;
    if(rs485_dma_tx_busy) return;

    if(cmd == SINGLE_TURN_CMD)
        Tamagawa_IncreaseSingleTurn();

    uint8_t *buf;
    uint16_t len;
    switch(cmd) {
        case SINGLE_TURN_CMD: buf = single_resp; len = SIG_FRAME_LEN; break;
        case MULTI_TURN_CMD:  buf = multi_resp;  len = SIG_FRAME_LEN; break;
        case ALL_INFO_CMD:    buf = allinfo_resp;len = FULL_FRAME_LEN; break;
        case ID_CMD:          buf = id_resp;    len = ID_FRAME_LEN; break;
        default: return;
    }

    rs485_dma_tx_busy = 1;
    RS485_ENABLE_TX();
    USART_ConfigInt(UART5, USART_INT_RXDNE, DISABLE);

    UART5_TX_DMA_CH->MADDR = (uint32_t)buf;
    UART5_TX_DMA_CH->TXNUM = len;
    DMA_ClearFlag(UART5_TX_DMA_CLEAR_FLAGS, DMA);
    USART_ClrFlag(UART5, USART_FLAG_TXC);

    USART_EnableDMA(UART5, USART_DMAREQ_TX, ENABLE);
    DMA_EnableChannel(UART5_TX_DMA_CH, ENABLE);
}

5. 使用示例

int main(void)
{
    RCC_Configuration();
    GPIO_Configuration();
    USART_Configuration();
    DMA_Configuration();

    Tamagawa_Update_Data(0x12345, 0, 0, 0);

    NVIC_Configuration();
    RS485_ENABLE_RX();

    while(1) { } // 主循环
}

6. 总结

  • 支持 单圈 / 多圈 / 全信息 / 编码器ID 四类命令

  • 单圈命令自动递增,峰值归零

  • DMA + 中断方式保证高速响应 (<3µs)

  • RS485 半双工控制,硬件自动完成发送

Logo

免费领 150 小时云算力,进群参与显卡、AI PC 幸运抽奖

更多推荐