当前位置:首页 > > 糖果Autosar
[导读]击上方“果果小师弟”,选择“置顶/星标公众号”干货福利,第一时间送达!摘要:串口是通信中最常用的通信方式,可能写串口的驱动,能写几十种方法,查询方式,中断方式,DMA方式,定时器方式。可能也其中几种方式的组合形式,经典的用法是:发送用查询方式,接收用中断方式,或者DMA+空闲中断...

击上方“果果小师弟”,选择“置顶/星标公众号

干货福利,第一时间送达!

摘要:串口是通信中最常用的通信方式,可能写串口的驱动,能写几十种方法, 查询方式,中断方式,DMA方式,定时器方式。可能也其中几种方式的组合形式,经典的用法是:发送用查询方式,接收用中断方式,或者DMA+空闲中断。本篇不讲串口是啥,现在还在讲串口是啥,估计会被喷。今天来聊一聊串口常用的几种方式,最简单的方法就不说了。

一、经典方法

  1. 查询方式 可靠性很高,要考虑下个数据包覆盖上一个数据包的问题,小数据量,在10个字节以内,可以这样考虑, 很简单,很方便,很可靠。但是在数据量大的时候,程序阻塞的时间特别长,影响其他比较重要的外设的处理。

  2. 中断方式 中断方式 , 不占用系统资源,但是如果数据量大,会频繁中断cpu, 会其他高优先的数据处理造成影响。但是没有DMA不占用资源的好处, 如果没有串口队列的实现,必须通过标志位判断上一个包数据是否发送完成,在把新的数据覆盖到串口的缓冲区。

  3. DMA方式 优点:  不占用系统资源,减少CPU对中断的响应。如何不建立数据包的队列,还是会出现,需要等待阻塞的问题。

二、环形队列

队列这个词在数据局结构中出现的比较多,与之对应的就是堆栈,但是两者的读取方式又完全不同。

FIFO 是First-In First-Out的缩写,它是一个具有先入先出特点的缓冲区。串口设计FIFO的目的是为了提高串口的通讯性能。如果没有FIFO或者说缓冲区的长度只有1字节,那么使用接收中断,就意味着每次收到一个字节的数据就要进一次中断,这样频繁进中断会占用CPU资源。另外如果没有及时读走数据,那么下一个字节数据就会覆盖之前的数据,导致数据丢失,这在通讯速率高的场合很有可能出现。

使用FIFO,可以在连续接收若干个数据后才产生一次中断,然后一起进行处理。这样可以提高接收效率,避免频繁进中断,适用于大数据传输。你可能会想到如果FIFO中的数据没有达到指定长度而无法产生中断怎么办,通常MCU会有接收超时中断,即在一定的时间内没有接收到数据会进入中断,可以利用这个中断把不足FIFO长度的数据最后都读取完。

FIFO类似售票排队窗口,先到的人看到能先买到票,然后先走,后来的人只能后买到票。

在计算机中,每个信息都是存储在存储单元中的,当有大量数据的时候,我们不能存储所有的数据,那么计算机处理数据的时候,只能先处理先来的,那么处理完后呢,就会把数据释放掉,再处理下一个。那么,已经处理的数据的内存就会被浪费掉。因为后来的数据只能往后排队,如过要将剩余的数据都往前移动一次,那么效率就会低下了,肯定不现实,所以,环形队列就出现了。

点击下方视频动态演示出队入队

1、环形队列的实现

在计算机中,是没有环形的内存的,只不过是我们将顺序的内存处理过,让某一段内存形成环形,使他们首尾相连,简单来说,这其实就是一个数组,只不过有两个指针,一个指向列队头,一个指向列队尾。指向列队头的指针是缓冲区可读的数据,指向列队尾的指针是缓冲区可写的数据,通过移动这两个指针即可对缓冲区的数据进行读写操作了,直到缓冲区已满(头尾相接),将数据处理完,可以释放掉数据,又可以进行存储新的数据了。

实现的原理:

视频来自正在一名考研的UP主:秃头少女王某人。计算机专业考研这个是必考点,视频讲的很棒,祝她一战成硕,金榜题名!

串口环形缓冲区收发:在初学单片机的时候我们知道的串口收发都是:接收一个数据,触发中断,然后把数据发回来。这种处理方式是没有缓冲的,当数量太大的时候,亦或者当数据接收太快的时候,我们来不及处理已经收到的数据,那么,当再次收到数据的时候,就会将之前还未处理的数据覆盖掉。那么就会出现丢包的现象了,对我们的程序是一个致命的创伤。

那么如何避免这种情况的发生呢,很显然,上面说的一些队列的特性很容易帮我们实现我们需要的情况。将接受的数据缓存一下,让处理的速度有些许缓冲,使得处理的速度赶得上接收的速度,上面又已经分析了普通队列与环形队列的优劣了,那么我们肯定是用环形队列来进行实现了。下面就是代码的实现:

2、定义一个结构体

typedef struct
{

    uint16_t usWrite;
    uint16_t usRead;
    uint16_t usLenght;
    /* FIFO 结构 */
    uint8_t  ucRing_Buff[RINGBUFF_LEN];

}RingBuff_T;

extern RingBuff_T g_ringBuff;

3、初始化队列

初始化结构体相关信息:使得我们的环形缓冲区是头尾相连的,并且里面没有数据,也就是空的队列,所有元素清0。

void RingBuff_Init(void)
{
    g_ringBuff.usWrite = 0;
    g_ringBuff.usRead = 0;
    g_ringBuff.usLenght = 0;
}

4、数据压入队列

/**
* @brief  Write_RingBuff
* @param  uint8_t _ucWriteData
* @return 0:环形缓冲区已满,写入失败;1:写入成功
* @note   往环形缓冲区写入uint8_t类型的数据
*/

uint8_t Write_RingBuff(uint8_t _ucWriteData)
{
    if(g_ringBuff.usLenght >= RINGBUFF_LEN) /*判断缓冲区是否已满*/
    {
        return 0;
    } 
  g_ringBuff.ucRing_Buff[g_ringBuff.usRead] = _ucWriteData;
    g_ringBuff.usRead = (g_ringBuff.usRead   1) % RINGBUFF_LEN; /*防止越界非法访问*/
    g_ringBuff.usLenght ;
    return 1;
}

5、从队列中读出数据

/**
* @brief  Read_RingBuff
* @param  u8 *rData,用于保存读取的数据
* @return 0:环形缓冲区没有数据,读取失败; 1:读取成功
* @note   从环形缓冲区读取一个uint8_t类型的数据
*/

uint8_t Read_RingBuff(uint8_t *_usReadData)
{
    if(g_ringBuff.usLenght == 0)/*判断非空*/
    {
        return 0;
    }
    *_usReadData = g_ringBuff.ucRing_Buff[g_ringBuff.usWrite];/*先进先出FIFO,从缓冲区头出*/
    g_ringBuff.usWrite = (g_ringBuff.usWrite   1) % RINGBUFF_LEN; /*防止越界非法访问*/
    g_ringBuff.usLenght--;
    return 1;
}
对于读写操作需要注意的地方有两个:

1:判断队列是否为空或者满,如果空的话,是不允许读取数据的,返回0。如果是满的话,也是不允许写入数据的,避免将已有数据覆盖掉。那么如果处理的速度赶不上接收的速度,可以适当增大缓冲区的大小,用空间换取时间。2:防止指针越界非法访问,程序有说明,需要使用者对整个缓冲区的大小进行把握。

四、环形缓冲器

环形缓冲器(ringr buffer),也称作圆形队列(circular queue),循环缓冲区(cyclic buffer),圆形缓冲区(circula buffer),是一种用于表示一个固定尺寸、头尾相连的缓冲区的数据结构,适合缓存数据流。

圆形缓冲区的一个有用特性是:当一个数据元素被用掉后,其余数据元素不需要移动其存储位置。相反,一个非圆形缓冲区(例如一个普通的队列)在用掉一个数据元素后,其余数据元素需要向前搬移。换句话说,圆形缓冲区适合实现先进先出缓冲区,而非圆形缓冲区适合后进先出缓冲区。

那么如何将环形缓冲器ringr buffer应用到串口上面呢?这里我们使用RT-Thread的源码。

1、定义一个结构体

/* ring buffer */
struct rt_ringbuffer
{

    uint8_t *buffer_ptr;
    uint16_t read_mirror : 1;
    uint16_t read_index : 15;
    uint16_t write_mirror : 1;
    uint16_t write_index : 15;
    uint16_t buffer_size;
};

2、初始化ringbuffer

void rt_ringbuffer_init(struct rt_ringbuffer *rb,
                        uint8_t           *pool,
                        uint16_t            size)

{
    RT_ASSERT(rb != NULL);
    RT_ASSERT(size > 0);

    /* initialize read and write index */
    rb->read_mirror = rb->read_index = 0;
    rb->write_mirror = rb->write_index = 0;

    /* set buffer pool and size */
    rb->buffer_ptr = pool;
    rb->buffer_size = RT_ALIGN_DOWN(size, RT_ALIGN_SIZE);
}

3、将数据压入ringbuffer

unsigned long rt_ringbuffer_put(struct rt_ringbuffer *rb,
                            const uint8_t     *ptr,
                            uint16_t           length)

{
    uint16_t size;

    RT_ASSERT(rb != NULL);

    /* whether has enough space */
    size = rt_ringbuffer_space_len(rb);

    /* no space */
    if (size == 0)
        return 0;

    /* drop some data */
    if (size < length)
        length = size;

    if (rb->buffer_size - rb->write_index > length)
    {
        /* read_index - write_index = empty space */
        memcpy(
本站声明: 本文章由作者或相关机构授权发布,目的在于传递更多信息,并不代表本站赞同其观点,本站亦不保证或承诺内容真实性等。需要转载请联系该专栏作者,如若文章内容侵犯您的权益,请及时联系本站删除。
换一批
延伸阅读

特朗普集团近日取消了其新推出的T1智能手机“将在美国制造”的宣传标语,此举源于外界对这款手机能否以当前定价在美国本土生产的质疑。

关键字: 特朗普 苹果 AI

美国总统特朗普在公开场合表示,他已要求苹果公司CEO蒂姆·库克停止在印度建厂,矛头直指该公司生产多元化的计划。

关键字: 特朗普 苹果 AI

4月10日消息,据媒体报道,美国总统特朗普宣布,美国对部分贸易伙伴暂停90天执行新关税政策,同时对中国的关税提高到125%,该消息公布后苹果股价飙升了15%。这次反弹使苹果市值增加了4000多亿美元,目前苹果市值接近3万...

关键字: 特朗普 AI 人工智能 特斯拉

3月25日消息,据报道,当地时间3月20日,美国总统特朗普在社交媒体平台“真实社交”上发文写道:“那些被抓到破坏特斯拉的人,将有很大可能被判入狱长达20年,这包括资助(破坏特斯拉汽车)者,我们正在寻找你。”

关键字: 特朗普 AI 人工智能 特斯拉

1月22日消息,刚刚,新任美国总统特朗普放出重磅消息,将全力支持美国AI发展。

关键字: 特朗普 AI 人工智能

特朗普先生有两件事一定会载入史册,一个是筑墙,一个是挖坑。在美墨边境筑墙的口号确保边境安全,降低因非法移民引起的犯罪率过高问题;在中美科技产业之间挖坑的口号也是安全,美国企业不得使用对美国国家安全构成威胁的电信设备,总统...

关键字: 特朗普 孤立主义 科技产业

据路透社1月17日消息显示,知情人士透露,特朗普已通知英特尔、铠侠在内的几家华为供应商,将要撤销其对华为的出货的部分许可证,同时将拒绝其他数十个向华为供货的申请。据透露,共有4家公司的8份许可被撤销。另外,相关公司收到撤...

关键字: 华为 芯片 特朗普

曾在2018年时被美国总统特朗普称作“世界第八奇迹”的富士康集团在美国威斯康星州投资建设的LCD显示屏工厂项目,如今却因为富士康将项目大幅缩水并拒绝签订新的合同而陷入了僵局。这也导致富士康无法从当地政府那里获得约40亿美...

关键字: 特朗普 富士康

今年5月,因自己发布的推文被贴上“无确凿依据”标签而与推特发生激烈争执后,美国总统特朗普签署了一项行政令,下令要求重审《通信规范法》第230条。

关键字: 谷歌 facebook 特朗普

众所周知,寄往白宫的所有邮件在到达白宫之前都会在他地进行分类和筛选。9月19日,根据美国相关执法官员的通报,本周早些时候,执法人员截获了一个寄给特朗普总统的包裹,该包裹内包含蓖麻毒蛋白。

关键字: 美国 白宫 特朗普
关闭