找回密码
 立即注册

QQ登录

只需一步,快速开始

搜索
查看: 500|回复: 2
打印 上一主题 下一主题
收起左侧

串口发送数据滞后

[复制链接]
跳转到指定楼层
楼主
ID:253030 发表于 2026-6-15 09:56 | 只看该作者 回帖奖励 |倒序浏览 |阅读模式
  while(1)
  {
if(flag==1){
flag = 0;
HAL_UART_Transmit(&huart1, tx, 2, 100);
HAL_Delay(500);
HAL_UART_Receive_IT(&huart1, rx, 2);            
}
  }



void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart){
  if(huart->Instance==USART1){          //RS485接收到从机应答数据信号
flag = 1;
tx[0]=rx[0];
tx[1]=rx[1];
}
}

串口调试助手
[2026-06-15 09:45:12.580]
TX:5689
[2026-06-15 09:45:12.611]
RX:56 89
[2026-06-15 09:45:16.207]
TX:1245
[2026-06-15 09:45:16.233]
RX:56 89
[2026-06-15 09:45:18.217]
TX:1245
[2026-06-15 09:45:18.252]
RX:12 45
[2026-06-15 09:45:25.239]
TX:1245
[2026-06-15 09:45:25.265]
RX:12 45
数据变化时,第一次发送的是旧的值,第二次发送的才是新赋值的数据
分享到:  QQ好友和群QQ好友和群 QQ空间QQ空间 腾讯微博腾讯微博 腾讯朋友腾讯朋友
收藏收藏 分享淘帖 顶顶 踩踩
回复

使用道具 举报

沙发
ID:1175626 发表于 2026-8-20 15:58 | 只看该作者
要彻底解决这个问题,必须将代码改为非阻塞的状态机模式。将“发送”、“等待应答”、“处理数据”解耦。
回复

使用道具 举报

板凳
ID:1175626 发表于 2026-8-20 15:59 | 只看该作者
以下代码供你参考:

// 定义通信状态
typedef enum {
    STATE_IDLE = 0,       // 空闲状态
    STATE_TX_WAIT,        // 等待发送完成
    STATE_RX_WAIT,        // 等待接收应答
    STATE_PROCESS_DATA    // 处理数据
} CommState_t;

volatile CommState_t comm_state = STATE_IDLE;
volatile uint8_t rx_data[2] = {0};
volatile uint8_t tx_data[2] = {0};
volatile uint32_t rx_tick = 0; // 记录接收时间,用于超时判断

// 1. 触发发送的函数(在主循环或定时器中调用)
void Trigger_Send(uint8_t d0, uint8_t d1) {
    if (comm_state == STATE_IDLE) { // 只有空闲时才允许发起新通信
        tx_data[0] = d0;
        tx_data[1] = d1;
        // 使用非阻塞发送
        if (HAL_UART_Transmit_IT(&huart1, (uint8_t*)tx_data, 2) == HAL_OK) {
            comm_state = STATE_TX_WAIT;
        }
    }
}

// 2. 串口发送完成回调
void HAL_UART_TxCpltCallback(UART_HandleTypeDef *huart) {
    if (huart->Instance == USART1) {
        // 发送完成后,立刻开启接收,并记录当前系统时间
        HAL_UART_Receive_IT(&huart1, (uint8_t*)rx_data, 2);
        rx_tick = HAL_GetTick();
        comm_state = STATE_RX_WAIT;
    }
}

// 3. 串口接收完成回调
void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart) {
    if (huart->Instance == USART1) {
        // 收到数据,切换到处理状态
        comm_state = STATE_PROCESS_DATA;
    }
}

// 4. 主循环处理
int main(void) {
    // ... 初始化代码 ...
    comm_state = STATE_IDLE;

    while (1) {
        switch (comm_state) {
            case STATE_IDLE:
                // 在这里判断是否需要发送新数据
                // 例如:if(need_send) Trigger_Send(0x12, 0x45);
                break;

            case STATE_TX_WAIT:
                // 等待发送完成(由中断回调自动切换状态)
                break;

            case STATE_RX_WAIT:
                // 【关键】超时防死机制:如果等待超过100ms还没收到,视为超时
                if ((HAL_GetTick() - rx_tick) > 100) {
                    comm_state = STATE_IDLE; // 超时,回到空闲,准备下一次
                }
                break;

            case STATE_PROCESS_DATA:
                // 在这里处理接收到的 rx_data
                // 处理完毕后,回到空闲状态
                comm_state = STATE_IDLE;
                break;
        }
    }
}
回复

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

小黑屋|51黑电子论坛 |51黑电子论坛6群 QQ 管理员QQ:125739409;技术交流QQ群281945664

Powered by 单片机教程网

快速回复 返回顶部 返回列表