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

1. 协议帧示例

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

注:

  • 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 幸运抽奖

更多推荐