野火电子论坛

 找回密码
 注册

QQ登录

只需一步,快速开始

楼主: 杰杰

STM32进阶之串口环形缓冲区实现

  [复制链接]
发表于 2020-1-19 11:37:17 | 显示全部楼层
不错,楼主的环形缓冲区,但是楼主的环形缓冲区有个弱点,一次只能写一个字节到缓冲区。

     下面的环形缓冲区可以实现如下功能:
              1、多个环形缓冲区可以共用同一段代码
              2、每个环形缓冲区可以一次性写入多个字节(方便使用DMA接收报文,一次性将接收的字节写入环形缓冲区)
                         虽然可以使用  for 循环分多次写入环形缓冲区,但是会增加串口中断的执行时间,不符合中断服务程序越短越好的原则。

      一、头文件
      [mw_shl_code=c,true]
#define MIN(a,b) ( (a) < (b) ) ? (a)b)


#define RING_MAXLEN             (1280)                typedef struct tagring_buf_struct
{
        uint8_t *buffer;
        uint16_t volatile size;//环形缓冲区长度
        uint16_t volatile rptr;
        uint16_t volatile wptr;
}ring_buf_struct , *ring_buf_struct_ptr;[/mw_shl_code]
回复 支持 反对

使用道具 举报

发表于 2020-1-19 11:40:29 | 显示全部楼层
[mw_shl_code=c,true]

uint8_t GPS_ring_buffer[RING_MAXLEN];
ring_buf_struct ring_struct;
ring_buf_struct_ptr GPS_ring;       



void ringBufferInit(void)
{       
       
        GPS_ring = &ring_struct;               
        GPS_ring->size = RING_MAXLEN;
        GPS_ring->buffer = GPS_ring_buffer;
        memset(GPS_ring->buffer , 0x00 , GPS_ring->size);
        GPS_ring->rptr = 0x00;                       
        GPS_ring->wptr = 0x00;                       
}



BOOL ringBufferEmpty(ring_buf_struct *ring)
{
        if (ring->rptr == ring->wptr)
                return (TRUE);
        return (FALSE);
}



BOOL ringBufferFull(ring_buf_struct *ring)
{
        if (ring->rptr == ((ring->wptr + 1) % ring->size))
                return (TRUE);
        return (FALSE);
}
       


BOOL WriteCharTo_ringBuffer(ring_buf_struct *ring , uint8_t ch)
{
        if (ringBufferFull(ring))
                return (FALSE);
       
        ring->buffer[ring->wptr] = ch;
        ring->wptr++;
        ring->wptr = ring->wptr % ring->size;
        return (TRUE);
}



BOOL ReadCharFrom_ringBuffer(ring_buf_struct *ring , uint8_t *ch)
{
        if (ringBufferEmpty(ring))
                return (FALSE);
       
        *ch = ring->buffer[ring->rptr];
        ring->rptr++;
        ring->rptr = ring->rptr % ring->size;
        return (TRUE);
}



uint16_t ringBufferFilllength(ring_buf_struct *ring)
{
        return ((ring->size + ring->wptr - ring->rptr) % ring->size);
}
       


uint16_t ringBufferFreelength(ring_buf_struct *ring)
{
        return (ring->size - ringBufferFilllength(ring) - 1);
}




//环形缓冲区切记:
//(1)、不一定wptr一定大于rptr
//(2)、不一定rptr一定大于wptr

BOOL WriteBufferTo_ringBuffer(ring_buf_struct *ring , uint8_t *buffer , uint16_t n)
{
        uint16_t i;

       
        if (ringBufferFull(ring))
                return (FALSE);
               
        if (ringBufferFreelength(ring) < n)
                return (FALSE);
       
        i = MIN(n , ring->size - ring->wptr % ring->size);        //从ring->wptr开始到缓冲区结尾的空间
        memcpy(ring->buffer + (ring->wptr % ring->size) , buffer , i);
        if (n > i)
                memcpy(ring->buffer , buffer + i , n - i);                //从缓冲区开始(0)到ring->rptr之前的n-i个有效空间
        ring->wptr = (ring->wptr + n) % ring->size;
       
        return (TRUE);
}




//环形缓冲区切记:
//(1)、不一定wptr一定大于rptr
//(2)、不一定rptr一定大于wptr
///////////////////////////////////////////////////////////////////////////////////////////////
//1.当rptr = 1 , wptr = 0 ,如果环形缓冲区空间=23(RING_MAXLEN=23)字节,则读出22个字节后,则rptr = 0 , wptr = 0(读出的22个字节正确)
//2.当rptr = 2 , wptr = 1 ,如果环形缓冲区空间=23(RING_MAXLEN=23)字节,则读出22个字节后,则rptr = 1 , wptr = 1(读出的22个字节正确)
//3.当rptr = 3 , wptr = 2 ,如果环形缓冲区空间=23(RING_MAXLEN=23)字节,则读出22个字节后,则rptr = 2 , wptr = 2(读出的22个字节正确)
//4.当rptr = 4 , wptr = 3 ,如果环形缓冲区空间=23(RING_MAXLEN=23)字节,则读出22个字节后,则rptr = 3 , wptr = 3(读出的22个字节正确)
//5.当rptr = 5 , wptr = 4 ,如果环形缓冲区空间=23(RING_MAXLEN=23)字节,则读出22个字节后,则rptr = 4 , wptr = 4(读出的22个字节正确)
//6.当rptr =10 , wptr = 9 ,如果环形缓冲区空间=23(RING_MAXLEN=23)字节,则读出22个字节后,则rptr = 9 , wptr = 9(读出的22个字节正确)
//7.当rptr =11 , wptr =10 ,如果环形缓冲区空间=23(RING_MAXLEN=23)字节,则读出22个字节后,则rptr =10 , wptr =10(读出的22个字节正确)
//8.当rptr =12 , wptr =11 ,如果环形缓冲区空间=23(RING_MAXLEN=23)字节,则读出22个字节后,则rptr =11 , wptr =11(读出的22个字节正确)
//9.当rptr =13 , wptr =12 ,如果环形缓冲区空间=23(RING_MAXLEN=23)字节,则读出22个字节后,则rptr =12 , wptr =12(读出的22个字节正确)
//10.当rptr=21 , wptr =20 ,如果环形缓冲区空间=23(RING_MAXLEN=23)字节,则读出22个字节后,则rptr =20 , wptr =20(读出的22个字节正确)
//11.当rptr=22 , wptr =21 ,如果环形缓冲区空间=23(RING_MAXLEN=23)字节,则读出22个字节后,则rptr =21 , wptr =21(读出的22个字节正确)
//12.当rptr= 5 , wptr = 4 ,如果环形缓冲区空间=23(RING_MAXLEN=23)字节,则读出20个字节后,则rptr = 2 , wptr = 4(读出的20个字节正确)(读数据时,折绕正确)
//13.当rptr=10 , wptr = 8 ,如果环形缓冲区空间=23(RING_MAXLEN=23)字节,则读出16个字节后,则rptr = 3 , wptr = 8(读出的16个字节正确)(读数据时,折绕正确)
//14.当rptr= 3 , wptr = 2 ,如果环形缓冲区空间=23(RING_MAXLEN=23)字节,则读出22个字节后,则rptr = 2 , wptr = 2(读出的22个字节正确)(读数据时,折绕正确)
///////////////////////////////////////////////////////////////////////////////////////////////
uint16_t ReadBufferFrom_ringBuffer(ring_buf_struct *ring , uint8_t *buffer , uint16_t n)
{
        uint16_t i;
        uint16_t len;

                     
        len = MIN(n , ringBufferFilllength(ring));                                   
        i = MIN(len , ring->size - ring->rptr % ring->size );      
        memcpy(buffer , ring->buffer + (ring->rptr % ring->size) , i);
        if (len > i)
                memcpy(buffer + i, ring->buffer , len - i);        
        ring->rptr = (ring->rptr + len) % ring->size;
       
    return (len);       
}

[/mw_shl_code]
回复 支持 反对

使用道具 举报

发表于 2020-1-21 09:36:53 | 显示全部楼层
看着很不错
回复 支持 反对

使用道具 举报

发表于 2020-2-3 08:53:24 | 显示全部楼层
FIFO,常用方法,学习下
回复 支持 反对

使用道具 举报

发表于 2020-2-3 11:17:15 | 显示全部楼层
但是在int main中应该怎么把各个函数放进去?
回复 支持 反对

使用道具 举报

发表于 2020-2-5 00:32:40 | 显示全部楼层
不错,正在找相关资料,感谢分享。
回复 支持 反对

使用道具 举报

发表于 2020-2-6 16:09:23 | 显示全部楼层
cool!!!!!!!!!!!!!!!!!!!!
回复

使用道具 举报

发表于 2020-2-22 02:53:19 | 显示全部楼层
可以,学习到了!
回复 支持 反对

使用道具 举报

发表于 2020-2-22 14:58:03 | 显示全部楼层
感谢分享。。。
回复

使用道具 举报

发表于 2020-4-20 22:32:59 | 显示全部楼层
学习中,感谢分享。。。。。。。。。。。。。。。
回复 支持 反对

使用道具 举报

发表于 2020-4-21 07:50:48 | 显示全部楼层
仰望大佬,学习一下
回复 支持 反对

使用道具 举报

发表于 2020-4-30 09:55:42 | 显示全部楼层
谢谢分享
回复

使用道具 举报

发表于 2020-5-1 18:26:04 | 显示全部楼层
谢谢分享
回复

使用道具 举报

发表于 2020-5-2 20:34:17 | 显示全部楼层
学习一下
回复

使用道具 举报

发表于 2020-5-3 10:48:30 来自手机 | 显示全部楼层
哈哈哈哈哈哈哈哈哈
回复 支持 反对

使用道具 举报

发表于 2020-5-20 09:35:33 | 显示全部楼层
挺好的帖子。。
回复 支持 反对

使用道具 举报

发表于 2020-5-20 10:43:54 | 显示全部楼层
volatile unsigned char *queue_in;     //队头
volatile unsigned char *queue_out;   //队尾
void wifi_protocol_init(void)
{
  queue_in = (unsigned char *)wifi_uart_rx_buf;
  queue_out = (unsigned char *)wifi_uart_rx_buf;
}
使用说明 : 在MCU串口接收函数中调用该函数,并将接收到的数据作为参数传入
*****************************************************************************/
void uart_receive_input(unsigned char value)
{       
  if(1 == queue_out - queue_in)
  {
    //数据队列满
      //printf("uart_receive_buf Full !  state 1\r\n");
  }
  else if((queue_in > queue_out) && ((queue_in - queue_out) >= sizeof(wifi_uart_rx_buf)))
  {
    //数据队列满
      //printf("uart_receive_buf Full !  state 2\r\n");
  }
  else
  {
    //队列不满
    if(queue_in >= (unsigned char *)(wifi_uart_rx_buf + sizeof(wifi_uart_rx_buf)))
    {
      queue_in = (unsigned char *)(wifi_uart_rx_buf);
    }
   
    *queue_in ++ = value;
  }
}

看到别人环形队列的应用,它的队尾-队头=1  时;也认为队列满了  if(1 == queue_out - queue_in),是对的吗
回复 支持 反对

使用道具 举报

发表于 2020-5-21 08:47:48 | 显示全部楼层
环形BUFFER比较好用,一直在用,自带缓存
回复 支持 反对

使用道具 举报

发表于 2020-6-11 14:20:23 | 显示全部楼层
不错,谢谢分享。
回复 支持 反对

使用道具 举报

发表于 2020-6-11 18:57:08 | 显示全部楼层
过来学习学习
回复 支持 反对

使用道具 举报

发表于 2021-1-25 11:41:11 | 显示全部楼层
cool~~~~~,nice~~~~~
回复

使用道具 举报

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

本版积分规则

联系站长|手机版|野火电子官网|野火淘宝店铺|野火电子论坛 ( 粤ICP备14069197号 ) 大学生ARM嵌入式2群

GMT+8, 2024-4-28 22:59 , Processed in 0.037742 second(s), 20 queries , Gzip On.

Powered by Discuz! X3.4

Copyright © 2001-2021, Tencent Cloud.

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