这次看大伙做电赛看到了很多问题
这回就针对串口说一下
对于串口,貌似都没有去做过一个队列的封装(也不算队列,队列读满就不会写入了,这里是会覆盖最旧的,目的是尽量存储新数据
外面的数据进来是通过硬件的,信息上要处理就不要放到中断里!
做一个循环队列的封装!把数据扔到队列里。主循环,再从队列里去匹配
队列一般就描述一下他的起始位置和长度即可。一般一次主循环我们就处理最新的一个或多个消息(不同种类
比如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);
}
}