极速赛车

您好, 登录| 注册|
子站:

看环形行列
浏览: 295 |  回复: 5 楼层中转

2019/05/27 10:56:21
1
lihui710884923[训练版主]
电源币:447 | 积分:1 主题帖:147 | 回复帖:486
LV8
师长

QQ截图20160321155901 【直播】最纯粹的手艺直播!乐云师长教员带你实战电子负载

QQ截图20160321155901 【收费送】 美信MAX17220评价板收费试用收费送


    最质朴的串口数据处置赏罚赏罚机制是数据吸收并原样回发的机制是:告成吸收到一个数,触发进入中止,在中止函数中将数据读取出来,然后急速。这一种数据处置赏罚赏罚机制是“非缓冲中止要领”,虽然这类数据处置赏罚赏罚要领不破费时间,但是这类数据处置赏罚赏罚要领严重的弱点是:数据无缓冲区,假定先前吸收的的数据假定还没有发送完成(处置赏罚赏罚完成),然后串口又吸收到新的数据,新吸收的数据就会把还没有处置赏罚赏罚的数据笼罩,从而招致“数据丢包”。

标签 STM32
2019/05/27 10:57:24
2
lihui710884923[训练版主]
电源币:447 | 积分:1 主题帖:147 | 回复帖:486
LV8
师长

极速赛车  关于“数据丢包”,最质朴的措施就是应用一个数组来吸收数据:每吸收一个数据,数组下标偏移。虽然这样的做法能起到一定的“缓冲效果”,但是数组的空间得不到很好的应用,已处置赏罚赏罚的数据依然会占领原有的数据空间,直到该数组“满载”(数组的每个元素都生涯了有用的数据),将所有数组的数据处置赏罚赏罚完成后,重新清零数组,才干开启新一轮的数据吸收。

 

  那么,有甚么好的数据吸收处置赏罚赏罚机制既能起到“缓冲”效果,又能有用地应用“数组空间”?谜底是:有的,那就是“环形缓冲区”。

 

极速赛车   环形缓冲区就是一个带“头指针”和“尾指针”的数组。“头指针”指向环形缓冲区中可读的数据,“尾指针”指向环形缓冲区中可写的缓冲空间。经由历程移动“头指针”和“尾指针”便可以完成缓冲区的数据读取和写入。在通常情形下,应用法式模范模范读取环形缓冲区的数据仅仅会影响“头指针”,而串口吸收数据仅仅会影响“尾指针”。当串口吸收到新的数组,则将数组生涯到环形缓冲区中,同时将“尾指针”加1,以生涯下一个数据;应用法式模范模范在读取数据时,“头指针”加1,以读取下一个数据。当“尾指针”逾越数组年夜小,则“尾指针”重新指向数组的首元素,从而组成“环形缓冲区”!,有用数据区域在“头指针”和“尾指针”之间。以下图所示。

2019/05/27 11:10:11
3
极速赛车游戏-fqd
电源币:5059 | 积分:15071 主题帖:449 | 回复帖:5059
LV11
统帅
2019/05/27 14:10:48
4
lihui710884923[训练版主]
电源币:447 | 积分:1 主题帖:147 | 回复帖:486
LV8
师长

虽然,环形缓冲区的“头指针”和“尾指针”可以用“头变量”和“尾变量”来取代,由于切换数组的元素空间,除可以用“指针偏移法”以外,还可以用“素组下标偏移法”。当串口吸收到新的数组,则将数组生涯到环形缓冲区中,同时将“尾变量”加一,以生涯下一个数据;应用法式模范模范在读取数据时,“头变量”加一,以读取下一个数据。

 

极速赛车 “环形缓冲区”数据吸收处置赏罚赏罚机制的利益在于:应用了行列的特点,一头进,一头出,互不影响,在数据出来(往里存)的时间,此外一边也能够或许把数据读出来,而读出来的数据,留下的空位,又可以增添多的存储空间,从而防止一边吸收数据且一边处置赏罚赏罚数据会在数据量辘集的时间而招致的损掉落落数据或许数据发生抵触的效果。

 

  假定唯逐一个线程读取环形缓冲区的数据,只需一个串口往环形缓冲区写入数据,则不须要添加互斥掩护机制便可以保证数据的准确性。

极速赛车  

  须要重视的是,假定串口每吸收x个字节的数据才处置赏罚赏罚一次,则环形缓冲区的缓冲数组的年夜小必须是x的N倍,详细N为若干,须要联络详细的数据吸收速率和处置赏罚赏罚速率,适当调治。这就好例如,水壶永世年夜于水杯,这样子水壶才干存放许多杯水。

 

假定以为前文隐晦难明,那么下面我们来一起议论辩说一下环形行列的详细状态和完成。下文构建的环形行列接纳的是极速赛车“头变量”“尾变量”来控制行列的存储和读取。

首先,我们会结构一个结构体,并界说一个结构变量。

 

#define MAX_SIZE  12               //缓冲区年夜小

 

typedef struct 

{

  unsigned char head;        //缓冲区头部职位

  unsigned char tail;         //缓冲区尾部职位

  unsigned char ringBuf[MAX_SIZE]; //缓冲区数组

} ringBuffer_t;

 

ringBuffer_t buffer;                 //界说一个结构体

 

界说一个结构头体则体现新的新闻行列曾经培植完成。新建培植的行列,头指针极速赛车head和尾指针tail都是指向数组的元素0。以下图所示,此时的新闻行列是“空行列”。


2019/05/27 14:12:28
5
lihui710884923[训练版主]
电源币:447 | 积分:1 主题帖:147 | 回复帖:486
LV8
师长

当假定极速赛车l加入行列,则缓冲行列处于满载状态,以下图所示:假定此时,吸收到新的数据并须要生涯,则tail须要归零,将吸收到的数据存到数组的第一个元素空间,假定还没有读取缓冲数组的一个元素空间的数据,则此数据会被新吸收的数据笼罩。同时head须要增添1,修改头节点偏移职位扬弃早期数据。


当新闻行列中的所有数据都读取出来后,此时环形行列是空的,状态以下图所示。从图可以总结得知,假定tail和head相等,则体现缓冲行列是空的。

1.3.1 ringBuffer.c

1. 结构环形缓冲区

 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24

/**********************************************************************************************
形貌   :      环形缓冲读写
作者   :      Jahol Fan
版本   :      V1.0
修改   :      
完成日期: 
Notice    :本法式模范模范只供学习应用,未经作者允许,不得用于其它任何用处。版权所有,盗版必究
***********************************************************************************************/
#include "ringbuffer.h"

#define BUFFER_MAX  36               //缓冲区年夜小

typedef struct 
{
  unsigned char headPosition;        //缓冲区头部职位
  unsigned char tailPositon;         //缓冲区尾部职位
  unsigned char ringBuf[BUFFER_MAX]; //缓冲区数组
} ringBuffer_t;

ringBuffer_t buffer; //界说一个结构体

极速赛车  

首先,须要构建一个结构体ringBuffer_t,假定界说一个结构体变量buffer,则意味着培植一个环形缓冲区。

极速赛车  

2. 往环形缓冲区存数据

 

1
2
3
4
5
6
7
8
9
10
11
12
13
14

/**
* @brief 写一个字节到环形缓冲区
* @param data:待写入的数据
* @return none
*/
void RingBuf_Write(unsigned char data)
{
  buffer.ringBuf[buffer.tailPositon]=data;     //从尾部追加
  if(++buffer.tailPositon>=BUFFER_MAX)         //尾节点偏移
    buffer.tailPositon=0;                      //年夜于数组最年夜长度 归零 组成环形行列
  if(buffer.tailPositon == buffer.headPosition)//假定尾部节点追到头部节点,则修改头节点偏移职位扬弃早期数据
    if(++buffer.headPosition>=BUFFER_MAX)
      buffer.headPosition=0;
}

 

2019/05/27 14:14:18
6
lihui710884923[训练版主]
电源币:447 | 积分:1 主题帖:147 | 回复帖:486
LV8
师长

8行:将数据存放到tailPosition所指向的元素空间。

9行:tailPosition变量自增1,而且断定,假定年夜于最年夜缓冲,则将tailPosition归零。

11行:假定tailPositon与headPosition相等,则体现,数据存入速率年夜于数据取出速率,从到招致“追尾”。此时headPosition须要自增1,以扬弃早期数据,这也就是数据“笼罩情形”,这类情形是禁绝可存在的,处置赏罚赏罚这类情形的措施是将缓冲行列的空间再开年夜点。

极速赛车 13行:假定headPosition也年夜于最年夜数组,则须要将headPosition清零。

 

3. 读取环形缓冲区的数据

 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19

/**
* @brief 读取环形缓冲区的一个字节的数据
* @param *pData:指针,用于生涯读取到的数据
* @return 1体现缓冲区是空的,0体现读取数据告成
*/
u8 RingBuf_Read(unsigned char* pData)
{
  if(buffer.headPosition == buffer.tailPositon)    //假定头尾接触体现缓冲区为空
    {
            return 1;   //前往1,环形缓冲区是空的
    }
  else
  {
    *pData=buffer.ringBuf[buffer.headPosition];    //假定缓冲区非空则取头节点值并偏移头节点
    if(++buffer.headPosition>=BUFFER_MAX)
      buffer.headPosition=0;
    return 0;     //前往0,体现读取数据告成
  }
}

 

极速赛车 8行:首先断定headPosition能否即是tailPositon,假定相等,则注解,此时缓冲区是空的。

10行:缓冲区为空,则直接前往,不推行前面的法式模范模范

极速赛车 12行:假定缓冲区不为空,则条件培植并推行

14行:读取headPosition所指向的环形缓冲行列的元素空间的数据。

极速赛车 15行:headPosition自增1以读取下一个数据。假定headPosition年夜于最年夜值BUFFER_MAX,则将headPosition归零。

极速赛车 17行:前往0,体现读取数据告成。

 

1.3.2 Hal_uart.c

 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16

/**
* @brief 串口1中止函数
* @param none
* @return none
*/
void USART1_IRQHandler(void)
{
  if(USART_GetITStatus(USART1, USART_IT_RXNE) != RESET)  //断定吸收标志位能否为1
  {         
        USART_ClearITPendingBit(USART1,USART_IT_RXNE);       //清晰标志位
        RingBuf_Write(USART_ReceiveData(USART1));
        //壅闭期待直到传输完成
        while (USART_GetFlagStatus(USART1, USART_FLAG_TXE) == RESET);
    
    }
}

极速赛车 11行:数据吸收获功,则将数据存入环形缓冲行列。

 

1.3.3 Main.c

 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37

/**
************************************************************
* @file         main.c
* @brief        MCU entry file
* @author       JaholFan
* @date         2017-11-20
* @version      V010100
* @note         
***********************************************************/
#include "Hal_Led/Hal_Led.h"
#include "Hal_delay/delay.h"
#include "Hal_Key/Hal_Key.h"
#include "Hal_Relay/Hal_Relay.h"
#include "Hal_Usart/hal_uart.h"
#include "ringbuffer.h"
/**
* @brief 法式模范模范出口
* @param none
* @return none
*/
int main(void)
{
    u8 data = 0;
  SystemInit();  //系统时钟初始化
  delayInit(72); //滴答准时器初始化
    uartxInit();
    while(1)
    {
        if(0 == RingBuf_Read(&data))            //从环形缓冲区中读取数据
        {
            USART_SendData(USART1,data);          //读取吸收到的数据并回发数据
        }
        delayMs(1);  //延时1ms:使得处置赏罚赏罚数据的速率小于吸收数据的速率,用于验证吸收缓冲区的“缓冲”特点
        
    }
}

30行:读取环形缓冲的数据,假定环形缓冲行列有数据,则条件培植

极速赛车 32行:将数据原样回发

极速赛车 34行:延时1ms的目的是:使得处置赏罚赏罚数据的速率小于吸收数据的速率,用于验证吸收缓冲区的“缓冲”特点。现实上,在项目工程中,项目代码的推行是消耗一定的CPU时间的,本例法式模范模范用延时1毫秒来等效替换项目代码推行小号的CPU时间。

 

关注我们
官方Q群
联系客服
客服热线
服务时间:周一至周五9:00-18:00
微信关注
收费手艺研究会
取得一手干货分享
editor@netbroad.com
022-58392381
北京pk10-北京pk10新凤凰-凤凰pk10预测 888棋牌游戏-盛大娱乐棋牌平台-棋牌电玩城送彩金 亿酷棋牌-象棋棋牌-棋牌游戏娱乐下载 捕鱼达人3-捕鱼达人3无限金币免费版 银河时时彩-时时彩技巧-老时时彩360 北京pk10开奖-pk10赛车群-pk10开奖首选网上手游 助赢时时彩-韩国时时彩助赢-韩国时时彩助赢计划 幸运五张-幸运五张规则-掌联幸运五张安卓版 新浪棋牌-鑫乐棋牌-盛大棋牌游戏 安徽福彩网-安徽福彩快3网上购买