在小型ARM微控制器中实现uart接收缓冲区的正确方法?

在小型ARM微控制器中实现uart接收缓冲区的正确方法?,arm,uart,circular-buffer,Arm,Uart,Circular Buffer,我正在为一个小型应用程序寻找接收缓冲区的想法,该应用程序处理rs485上921.6Kbaud的15字节数据包。我正在考虑使用循环缓冲区作为UART ISR和main之间的接口。因为它是一个微处理器,我想把它 while (uartindex!=localindex) { do stuff } 在 while (;;) {do forever} 部分主要原因,但我被告知这是不可接受的 在类似情况下,人们如何处理UART?如果主循环中从未写入uartindex(在中断被禁用时初始化它除外),

我正在为一个小型应用程序寻找接收缓冲区的想法,该应用程序处理rs485上921.6Kbaud的15字节数据包。我正在考虑使用循环缓冲区作为UART ISR和main之间的接口。因为它是一个微处理器,我想把它

while (uartindex!=localindex) { do stuff } 

while (;;) {do forever} 
部分主要原因,但我被告知这是不可接受的


在类似情况下,人们如何处理UART?

如果主循环中从未写入
uartindex
(在中断被禁用时初始化它除外),并且中断例程从未触及
localindex
,则您建议的方法可能是可行的

我建议您将缓冲区大小设为2的幂,对两个索引使用无符号整数,并允许它们在整个32位大小上自由计数;在“stuff”和“fetch”例程中为缓冲区编制索引时使用位掩蔽。如果你那样做,那么

(unsigned)(uartindex-localindex) 
应该指示缓冲区中有多少个字符,即使缓冲区完全满了,也不需要在缓冲区满的情况下使用特殊的大小写行为,也不限制N字节缓冲区容纳N-1项


请注意,虽然上述表达式中的类型转换不是绝对必要的,但我建议将其包括在内,因为它表明,在减去无符号量时的包装行为是故意的,也是预期的。

ISR应该填充FIFO。我应该用它

下面是一个非常简单的fifo算法:

#define RINGFIFO_SIZE (1024)              /* serial buffer in bytes (power 2)   */
#define RINGFIFO_MASK (RINGFIFO_SIZE-1ul) /* buffer size mask                   */

/* Buffer read / write macros                                                 */
#define RINGFIFO_RESET(ringFifo)      {ringFifo.rdIdx = ringFifo.wrIdx = 0;}
#define RINGFIFO_WR(ringFifo, dataIn) {ringFifo.data[RINGFIFO_MASK & ringFifo.wrIdx++] = (dataIn);}
#define RINGFIFO_RD(ringFifo, dataOut){ringFifo.rdIdx++; dataOut = ringFifo.data[RINGFIFO_MASK & (ringFifo.rdIdx-1)];}
#define RINGFIFO_EMPTY(ringFifo)      (ringFifo.rdIdx == ringFifo.wrIdx)
#define RINGFIFO_FULL(ringFifo)       ((RINGFIFO_MASK & ringFifo.rdIdx) == (RINGFIFO_MASK & (ringFifo.wrIdx+1)))
#define RINGFIFO_COUNT(ringFifo)      (RINGFIFO_MASK & (ringFifo.wrIdx - ringFifo.rdIdx))

/* buffer type                                                                */
typedef struct{
    uint32_t size;
    uint32_t wrIdx;
    uint32_t rdIdx;
    uint8_t data[RINGFIFO_SIZE];
} RingFifo_t;
RingFifo_t gUartFifo;
(必须注意此FIFO算法,大小必须为2的幂)

ISR的行为应如下所示:

void ISR_Handler()
{
    uint8_t c;
    while(UART_NotEmpty()) {
        c = UART_GetByte();
        RINGFIFO_WR(gUartFifo, c);
    }
}
uint8_t ptrToPacket;
uint32_t packetSize;
while(1)
{
    if (!Uart_HasValidPacket()) {
        Uart_GetPacket(&ptrToPacket, &packetSize)
        /* Process packet using ptrToPacket and packetSize */
    }    
}
主要问题是:

while(1)
{
    if (!RINGFIFO_EMPTY(gUartFifo)) {
        /* consume fifo using RINGFIFO_RD */
    }    
}
此算法直接从主循环读取FIFO,您应该使用一个中间层来检查缓冲区中是否有完整的数据包,并对其进行处理,处理方式如下:

void ISR_Handler()
{
    uint8_t c;
    while(UART_NotEmpty()) {
        c = UART_GetByte();
        RINGFIFO_WR(gUartFifo, c);
    }
}
uint8_t ptrToPacket;
uint32_t packetSize;
while(1)
{
    if (!Uart_HasValidPacket()) {
        Uart_GetPacket(&ptrToPacket, &packetSize)
        /* Process packet using ptrToPacket and packetSize */
    }    
}

哈哈,我是一个手臂肌肉发达的人,这让我傻笑出我自己的无知。我将通过观看这段视频来启发自己:)我做过类似的事情,也没有遇到任何问题,所以我很好奇人们会怎么说,以及为什么这是错误的。唯一可能出错的事情是不要理解记忆障碍的概念。