Xilinx(ZYNQ7000)的vitis库开发时串口发送数据总是上次接收的问题

问题:
Xilinx的ZYNQ-7000,vitis库开发时串口发送数据总是上次接收的问题
UART串口接收的代码总是上一次发送的。无法实现发送本次中断的值是什么原因呢?
代码段:
中断处理:

void uart_intr_aihandler(void *CallBackRef, u32 Event, unsigned int EventData) {
    if (Event == XUARTPS_EVENT_RECV_DATA)
    {
          u8 tmp = XUartPs_RecvByte(XPAR_XUARTPS_0_BASEADDR);//后改的试用;
          if(recv_buf_index >= UART_BUFFER_SIZE-1)//如果超过发送还没有找到尾 重置
          {
            memset(recv_buf, 0, UART_BUFFER_SIZE);
            memset(UartBuff,0,UART_BUFFER_SIZE);
            recv_buf_index = 0;
            IntrDone = 0;
          }
          else if (tmp == UART_TAIL)
          {
            memset(UartBuff,0,UART_BUFFER_SIZE);
            memcpy(UartBuff,recv_buf,strlen((char *)recv_buf));
            recv_buf_index = 0;
            IntrDone = 1;
            memset(recv_buf, 0, UART_BUFFER_SIZE);
          }
          else
          {
            recv_buf[recv_buf_index++] = tmp;
          }
    }
}

int init_uart_intr(XScuGic *InstancePtr, XUartPs *UartInstancePtr, u16 UartIntrId) {
    int Status;
    XScuGic_Config *IntcConfig;
    XUartPs_Config *UartConfig;

    // 初始化 UART 设备
    UartConfig = XUartPs_LookupConfig(UART_DEVICE_ID);
    if (NULL == UartConfig) {
        return XST_FAILURE;
    }
    Status = XUartPs_CfgInitialize(UartInstancePtr, UartConfig, UartConfig->BaseAddress);
    if (Status != XST_SUCCESS) {
        return XST_FAILURE;
    }

    // 初始化中断控制器
    IntcConfig = XScuGic_LookupConfig(INTC_DEVICE_ID);
    if (IntcConfig == NULL) {
        return XST_FAILURE;
    }

    Status = XScuGic_CfgInitialize(InstancePtr, IntcConfig, IntcConfig->CpuBaseAddress);
    if (Status != XST_SUCCESS) {
        return XST_FAILURE;
    }

    // Connect
    Status = XScuGic_Connect(InstancePtr, UartIntrId,
                             (Xil_ExceptionHandler) XUartPs_InterruptHandler,
                             (void *) UartInstancePtr);
    if (Status != XST_SUCCESS) {
        return XST_FAILURE;
    }

    // Open UART Handle
    XUartPs_SetHandler(UartInstancePtr, (XUartPs_Handler)uart_intr_aihandler, UartInstancePtr);
    XUartPs_SetInterruptMask(UartInstancePtr, XUARTPS_IXR_RXOVR | XUARTPS_IXR_TTRIG | XUARTPS_IXR_RXFULL);
    XScuGic_Enable(InstancePtr, UartIntrId);

    // enable Handle
    Xil_ExceptionInit();
    Xil_ExceptionRegisterHandler(XIL_EXCEPTION_ID_INT, (Xil_ExceptionHandler) XScuGic_InterruptHandler, InstancePtr);
    Xil_ExceptionEnable(); 

    return XST_SUCCESS;
}

int main()
{
    while(1) 
    {
          if(IntrDone){
      xil_printf("Recv[%s]\r\n",UartBuff);
      IntrDone = 0;
    }
   }
}

串口端现象

img


怎么才能让串口中断以后马上处理本次发送的数值呢?哪里代码错误了?

先一个字节进行测试,可能是接收到打印不同步引起的!

jiyugpt
根据你提供的代码和描述,推测你可能在发送数据时存在数据缓存未清空的问题。可以尝试在发送数据之前先清空发送数据的缓存,以确保每次发送的都是最新的数据。

具体地,可以在发送数据前使用memset()函数清空缓存区,比如:

memset(send_buf, 0, sizeof(send_buf)); // 清空发送数据缓存
sprintf(send_buf, "Hello world!"); // 向发送数据缓存中写入最新的数据

此外,如果你还没在发送数据之前对串口进行初始化,需要在初始化时将发送缓冲区和接收缓冲区清空,可以使用memset()函数或bzero()函数。

如果以上方法还不能解决问题,可以尝试对串口发送和接收的中断进行调试,查看数据在传输过程中是否存在问题。

在你的代码中,串口中断处理函数 uart_intr_aihandler() 的作用是接收串口数据,如果接收到的数据是 UART_TAIL,则将接收到的数据复制到 UartBuff 中,并将 IntrDone 标志设置为 1,表示数据已经接收完毕。

然而,在你的主函数中,你的代码只有在 IntrDone 被设置为 1 时才会处理 UartBuff 中的数据。因此,如果 IntrDone 没有被设置为 1,则不会处理新接收到的数据,因此你会看到上一次接收到的数据被打印出来。

为了解决这个问题,你需要在中断处理函数中设置一个标志来表示数据已经接收完毕,并在主函数中处理接收到的数据。可以像这样修改代码:


void uart_intr_aihandler(void *CallBackRef, u32 Event, unsigned int EventData) {
    if (Event == XUARTPS_EVENT_RECV_DATA)
    {
          u8 tmp = XUartPs_RecvByte(XPAR_XUARTPS_0_BASEADDR);//后改的试用;
          if(recv_buf_index >= UART_BUFFER_SIZE-1)//如果超过发送还没有找到尾 重置
          {
            memset(recv_buf, 0, UART_BUFFER_SIZE);
            memset(UartBuff,0,UART_BUFFER_SIZE);
            recv_buf_index = 0;
            IntrDone = 0;
          }
          else if (tmp == UART_TAIL)
          {
            memset(UartBuff,0,UART_BUFFER_SIZE);
            memcpy(UartBuff,recv_buf,strlen((char *)recv_buf));
            recv_buf_index = 0;
            IntrDone = 1;
            memset(recv_buf, 0, UART_BUFFER_SIZE);
          }
          else
          {
            recv_buf[recv_buf_index++] = tmp;
            IntrDone = 0; // 数据还未接收完毕
          }
    }
}

int main()
{
    while(1) 
    {
          if(IntrDone){
            // 处理接收到的数据
            xil_printf("Recv[%s]\r\n",UartBuff);
            memset(UartBuff, 0, UART_BUFFER_SIZE);
            IntrDone = 0;
          }
    }
}

这样,每当接收到一个字符时,IntrDone 将被设置为 0,表示数据还没有接收完毕。只有当接收到的数据是 UART_TAIL 时,IntrDone 才会被设置为 1,表示数据已经接收完毕。在主函数中,只要 IntrDone 被设置为 1,就会处理 UartBuff 中的数据。

以下答案由GPT-3.5大模型与博主波罗歌共同编写:
根据你提供的代码,问题可能出现在接收缓冲区(recv_buf)的清零时机上。在函数内部,在数据接收到尾部时,recv_buf被清零,但是在下一个数据接收中,recv_buf并没有被清零,导致上一次接收的数据仍然存在,从而造成发送数据时出现上一次接收的数据的问题。

为了解决这个问题,你可以尝试将清空recv_buf移到函数的开始部分:

void uart_intr_aihandler(void *CallBackRef, u32 Event, unsigned int EventData) {
    if (Event == XUARTPS_EVENT_RECV_DATA)
    {
        memset(recv_buf, 0, UART_BUFFER_SIZE);// 在每个接收到数据的中断函数开始时清空
        u8 tmp = XUartPs_RecvByte(XPAR_XUARTPS_0_BASEADDR);// 后改的试用;
        if(recv_buf_index >= UART_BUFFER_SIZE-1)//如果超过发送还没有找到尾 重置
        {
            memset(UartBuff,0,UART_BUFFER_SIZE);
            recv_buf_index = 0;
            IntrDone = 0;
        }
        else if (tmp == UART_TAIL)
        {
            memcpy(UartBuff,recv_buf,strlen((char *)recv_buf));// 从recv_buf复制到UartBuff
            recv_buf_index = 0;
            IntrDone = 1;
        }
        else
        {
            recv_buf[recv_buf_index++] = tmp;
        }
    }
}

注意,这里的代码只是为了解决上述问题,没有经过完整的测试和优化,可能还存在其他问题。但是,理论上这个修改应该可以解决你遇到的问题。
如果我的回答解决了您的问题,请采纳!

该回答引用ChatGPT
在中断处理函数中,每收到一个字符都会把它放入接收缓冲区中,只有当接收到 UART_TAIL 字符时才会把接收缓冲区中的数据复制到 UartBuff 缓冲区中,并且设置 IntrDone 为 1,表示接收完毕。在主函数中,只有当 IntrDone 被设置为 1 时才会将 UartBuff 中的数据输出。

看起来问题在于中断处理函数是在接收到 UART_TAIL 字符时才会把接收缓冲区清空并把接收到的数据复制到 UartBuff 中。

在这种情况下,如果发送的数据中没包含 UART_TAIL 字符,则在接收下一次数据时之前,之前的数据都会保留在接收缓冲区中。如果需要及时处理发送数据,可以在接收到所有字符时进行处理,而不是只在接收到一个特定字符时进行处理。

修改代码如下:


void uart_intr_aihandler(void *CallBackRef, u32 Event, unsigned int EventData)
{
static u8 recv_buf[UART_BUFFER_SIZE];
static u32 recv_buf_index = 0;
if (Event == XUARTPS_EVENT_RECV_DATA)
{
recv_buf[recv_buf_index++] = XUartPs_RecvByte(XPAR_XUARTPS_0_BASEADDR);
if (recv_buf_index >= UART_BUFFER_SIZE)
{
recv_buf_index = 0;
}
if (recv_buf[recv_buf_index - 1] == UART_TAIL)
{
recv_buf[recv_buf_index - 1] = 0; // 删除 UART_TAIL 字符
IntrDone = 1;
memset(UartBuff, 0, UART_BUFFER_SIZE);
memcpy(UartBuff, recv_buf, UART_BUFFER_SIZE);
recv_buf_index = 0;
memset(recv_buf, 0, UART_BUFFER_SIZE);
}
}
}

int main()
{
while(1)
{
if(IntrDone){
xil_printf("Recv[%s]\r
",UartBuff);
IntrDone = 0;
}
}
}


这样修改后可以实现即时处理接收到的数据,而不是必须等待接收到特定字符后才能处理。