串口接收处理不要再乱写了

这次看大伙做电赛看到了很多问题

这回就针对串口说一下

对于串口,貌似都没有去做过一个队列的封装(也不算队列,队列读满就不会写入了,这里是会覆盖最旧的,目的是尽量存储新数据

外面的数据进来是通过硬件的,信息上要处理就不要放到中断里!

做一个循环队列的封装!把数据扔到队列里。主循环,再从队列里去匹配

队列一般就描述一下他的起始位置和长度即可。一般一次主循环我们就处理最新的一个或多个消息(不同种类

比如abc为消息头 消息体第一位用来表示消息类型后面几位为数据,

循环中开始处理消息头的时候,设置一个标志位来暂停中断对缓冲区的写入,避免处理过程中数据受影响

我们从队列的尾巴上开始往前匹配消息头。然后把整段消息截取出来,若第一段没法完整截取,那么先不处理,

然后再往前匹配下一个消息头,如果上一次已经都成功接收过的消息类型,就跳过,如果不是,就整段截取,然后处理,直到匹配完所有有效消息类型或到头,

然后把队列中有效读取的整段置为失效(通过移动下标

#define RxBufferSize 30
#define RxBufferTag "abc"
//假定消息头为abc

//标记哪些已经读了
//比如制定了 0-3.那么我们用0-3位来标记
class ReadedTags
{
    uint_64_t tag;

public:
    void set_1_at(int n)
    {
        tag |= 0x01 << n;
    }
    bool has_tag_at(int n)
    {
        return tag >> n & 0x01;
    }
    void clear()
    {
        tag = 0;
    }
};

class CircleBuffer
{

public:
    char buff[RxBufferSize];
    char index; //下一个写入位置
    char len;   //已经记录长度

    //读时须确保在长度内,否则为无效值
    char at(int index1)
    {
        index1 %= RxBufferSize;
        if (index1 < 0)
        {
            index1 += RxBufferSize;
        }
        return buff[index1];
    }
    //从begin开始比较n位
    bool cmp_n_at(char *str, int n, int begin)
    {
        for (int i = 0; i < n; i++)
        {
            if (at(begin + i) != str[i])
            {
                return false;
            }
        }
        return true;
    }
    void push(char value)
    {
        buff[index] = value;
        index++;
        if (index == RxBufferSize)
        {
            index = 0;
        }
    }
};

class RxBuffer
{
private:
    bool (*callback)(ReadedTags &tags, CircleBuffer &cb, int begin, int len);
    CircleBuffer cb;
    bool handling;

public:
    ReadedTags tags;
    RxBuffer(/* args */)
    {

        handling = false;
    }
    bool set_callback(
        void (*callback1)(ReadedTags &tags, CircleBuffer &cb, int begin, int len))
    {
        callback = callback1;
    }
    void handle()
    {
        //前三个字节不可能有效
        int index = cb.index - sizeof(RxBufferTag);
        int len1 = cb.len - sizeof(RxBufferTag); //未分析长度
        int len2 = sizeof(RxBufferTag) - 1;      //当前扫描位置到上一个结束点长度
        bool firstTime = true;
        int len_clearTo;
        while (len1)
        {
            //匹配到关键字
            if (cb.cmp_n_at(RxBufferTag,
                            sizeof(RxBufferTag) - 1, index))
            {
                //回调分析后续内容
                bool succ = callback(cb, index + (sizeof(RxBufferTag) - 1), len2 - (sizeof(RxBufferTag) - 1));
                if (firstTime)
                {

                    if (succ)
                    {
                        len_clearTo = 0;
                    }
                    else
                    { //数据没全,保留下来,
                        index_clearTo = len2;
                    }
                }

                len2 = 0;
            }
            len1--;
            index--;
            len2++;
            firstTime = false;
        }
        //执行清除。本质就是改变长度和下标
        cb.len = len_clearTo;
        tags.clear();
    }
    void push(char value)
    {
        if (!handling) //保证处理时不干涉
        {
            cb.push(value);
        }
    }
};

RxBuffer rxBuffer;

// 中断函数调用
void interrupt(char a)
{
    rxBuffer.push(a);
}

//主函数处理
void main()
{
    rxBuffer.set_callback(
        [](ReadedTags &tags, CircleBuffer &cb, int begin, int len) -> bool
        {
            char id = cb.at(begin);
            //未读过则读取
            if (!tags.has_tag_at(id))
            {
                if (/*读取成功*/) //读取成功就做标记,下次不读取了
                {
                    tags.set_1_at(id)
                }
            }
        });

    while (1)
    {
        rxBuffer.handle();

        delay(1);
    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值