kkzz 发表于 2024-10-31 19:50

串口循环Buffer接收



//串口
#define UART0_RX_BUFF_LEN         (56 * 16)
#define UART0_FRAME_MAX_LEN         (56)          //单帧最长长度

/******************************************    全局变量    *********************************************/
/*串口缓存全局变量初始化*/
volatile unsigned charg_u8Uart0RxDataMem = {0};    //串口0缓存
volatile unsigned short gUart0RxByteNum = 0;                            //已经接收到的字节数量
volatile unsigned short gUart0RxIndex = 0;                              //接收循环写入
volatile unsigned short gUart0RxStartIndex = 0;                         //处理起始位


//串口一个字节一个字节的收
LONG CAudioProcessorDlg::OnCommunication(WPARAM ch, LPARAM port)
{

    unsigned char *pUart0RxDataMem = (unsigned char * )g_u8Uart0RxDataMem;
    unsigned char u8DataLen = 0;                //解析桢字节长度
    CString str;
    str.Format(L"%02X", ch);
    unsigned char u8Temp = { 0 };

    int nRet = 0;
    int i = 0;
    int nRealLen = 0;
    int nRealBeginIndex = 0;
    unsigned char u8UartParaBuf = {0};   //临时变量,每次处理一帧数据

    Unicode_Cstring2char(str, (char*)u8Temp);

    //转换一下
    for (i = 0; i < 4; i++ )
    {
      if (u8Temp >= 'A')
      {
            u8Temp = u8Temp - 55;
      }
      else
      {
            u8Temp = u8Temp - 0x30;
      }
    }

    //按字节接收数据,保证此buf是循环buf
    g_u8Uart0RxDataMem = (u8Temp << 4) | u8Temp;
    gUart0RxIndex = (gUart0RxIndex + 1) % UART0_RX_BUFF_LEN;
    gUart0RxByteNum++;

    //开始解析数据
    while(gUart0RxByteNum) //接收的长度如果大于0
    {
      if(pUart0RxDataMem == 0x55)//第一个帧头字节正确
      {
            break;
      }

      pUart0RxDataMem = 0;
      gUart0RxStartIndex = (gUart0RxStartIndex + 1) % UART0_RX_BUFF_LEN;
      gUart0RxByteNum--;
    }

    if(gUart0RxByteNum >= UART_RX_PROTOCOL_SIZE)      //接收到字节数大于14字节
    {
      if (0xAA == pUart0RxDataMem[((gUart0RxStartIndex + 1) % UART0_RX_BUFF_LEN)])
      {
            //取桢长度
            u8DataLen = pUart0RxDataMem[((gUart0RxStartIndex + 2) % UART0_RX_BUFF_LEN)];

            if((UART_RX_PROTOCOL_SIZE == u8DataLen) || (UART_RX_ExPROTOCOL_SIZE == u8DataLen))
            {
                if(CheckReciveDataCRC(pUart0RxDataMem, u8DataLen))
                {
                  //拷贝一帧数据出来
                  for(i = 0; i < u8DataLen; i++)
                  {
                        //校验通过将数据取出存放到u8UartParaBuf
                        u8UartParaBuf = pUart0RxDataMem;
                        pUart0RxDataMem = 0;
                        gUart0RxStartIndex = (gUart0RxStartIndex + 1) % UART0_RX_BUFF_LEN;
                        gUart0RxByteNum--;
                  }

                  u8DataLen = ProcessingProtocolData(u8UartParaBuf, u8DataLen);
                  CommunicationSend((char *)u8UartParaBuf, u8DataLen);

                }
                else
                {
                  pUart0RxDataMem = 0;
                  gUart0RxStartIndex = (gUart0RxStartIndex + 1) % UART0_RX_BUFF_LEN;
                  gUart0RxByteNum--;
                }
            }
            else
            {
                pUart0RxDataMem = 0;
                gUart0RxStartIndex = (gUart0RxStartIndex + 1) % UART0_RX_BUFF_LEN;
                gUart0RxByteNum--;
            }

      }
      else
      {
            //桢头异常,清除此桢
            pUart0RxDataMem = 0;
            gUart0RxStartIndex = (gUart0RxStartIndex + 1) % UART0_RX_BUFF_LEN;
            gUart0RxByteNum--;
      }
    }


    return 0;
}


yangjiaxu 发表于 2025-1-23 17:28

环形接收么这个是?

macpherson 发表于 2025-2-4 16:25

在中断处理中,尽可能批量处理接收到的数据,减少中断处理时间。

jimmhu 发表于 2025-2-4 17:26

如果系统中使用了多个串口,要考虑不同串口之间的同步问题,避免数据处理混乱。

deliahouse887 发表于 2025-2-4 21:25

设置适当的中断优先级,确保串口中断能够及时响应,尤其是在多中断源的系统中。

pl202 发表于 2025-2-5 08:04

在接收数据前,要确保有足够的空间来存储新接收的数据。可以通过检查缓冲区的剩余空间或者使用硬件提供的缓冲区满标志来判断是否能够继续接收数据。当缓冲区接近满时,要及时处理缓冲区内的数据,以防止新数据覆盖旧数据。

janewood 发表于 2025-2-5 09:41

为了应对可能出现的异常情况,如通信干扰导致的数据突发增加,建议在估算的基础上预留一定的余量 。

caigang13 发表于 2025-2-5 10:08

可以用C语言封装一个FIFO库,网上很多例子。

hearstnorman323 发表于 2025-2-5 11:47

如果使用中断来处理串口数据,确保ISR尽可能短小,避免在ISR中进行复杂的数据处理。
在ISR中只进行必要的缓冲区更新和数据存储。

linfelix 发表于 2025-2-5 12:17

根据串口通信协议,识别数据帧的起始和结束标志,从Buffer中提取完整的数据帧进行处理。

51xlf 发表于 2025-2-5 12:48

定义缓冲区为空或满的条件。通常,当读写指针相同时,缓冲区为空;当写指针追上读指针(考虑循环条件)时,缓冲区为满。

wwppd 发表于 2025-2-5 13:19

要根据实际应用中串口可能接收到的数据量来合理确定缓冲区的大小。如果缓冲区过小,可能会导致数据溢出,造成数据丢失;如果过大,则会浪费系统的内存资源。

sdCAD 发表于 2025-2-5 13:53

如果在多线程环境中使用串口循环 Buffer 接收数据,要注意线程之间的同步问题。不同线程可能同时访问循环 Buffer,需要使用互斥锁、信号量等同步机制来保证数据的一致性和正确性。例如,一个线程负责接收数据并存储到循环 Buffer 中,另一个线程负责从循环 Buffer 中取出数据进行处理,这两个线程在访问循环 Buffer 时需要进行同步操作。

sdCAD 发表于 2025-2-5 16:11

在多线程环境中,需要使用互斥锁(mutexes)或其他同步机制来保护缓冲区访问。

burgessmaggie 发表于 2025-2-5 16:41

可以使用中断方式或DMA方式进行数据接收,并在主循环中及时处理数据

xiaoyaodz 发表于 2025-2-5 17:03

优化数据接收和处理的性能,以确保系统能够实时响应。可以使用 DMA 技术来提高数据传输效率。

uytyu 发表于 2025-2-5 19:43

外部电磁干扰或电源波动可能导致信号失真,影响数据接收。应使用屏蔽电缆、良好的接地和滤波器等措施来减少干扰

earlmax 发表于 2025-2-5 20:14

如果串口接收数据是在中断服务函数中进行的,要确保写入操作的原子性,避免在写入过程中被其他中断打断,导致数据不一致。可以通过关中断或使用互斥锁等方式来实现。

loutin 发表于 2025-2-5 22:25

如果接收的数据包有固定大小,缓冲区大小应至少为数据包大小的整数倍,以避免部分数据包被分割。

janewood 发表于 2025-2-5 22:56

使用两个指针(读指针和写指针)来跟踪缓冲区中的数据位置。写指针指向下一个要写入的位置,读指针指向下一个要读取的位置。
页: [1] 2 3
查看完整版本: 串口循环Buffer接收