这里的实现灵感来自C语言中的strstr()函数
问题:
不知各位是否被要求产品在实际生产前,要对一些硬件进行自动化测试(比如led是否可以正常点亮熄灭,对data flash是否可以写入数据等),而这些数据需要通过电脑经过串口发送命令给单片机,而识别这些命令是不是让你很头疼,其实刚开始我也很头疼。
经过不断的整理优化,最终写出了这篇文章,由于这是在没有项目的情况下写的,因此没有在单片机上验证,而只在vs上进行简单的模拟。(如果项目有真正应用,我到时候加上定时器进行测试)
从执行逻辑上来讲,如果在测试命令的开头和结尾添加越多不是命令的数据,命令执行的时间就会越长
#include "stdio.h"
/*
1.不断的向队列中加入数据
2.每次都从队列的头判断到队列的尾
3.每次都要对所有的命令进行比对(虽然速度慢,但是我这里不用关心数据格式)
4.当寻找到一条数据是,就将头指针指到找到这一串数据的末尾,否则将指针复位
5.这里还涉及到定时器,由于是在VS上模拟的,所以也是简单的用累加数字的方法替代一下
*/
#define LEN 255//定义缓存队列的长度
typedef struct
{
unsigned char Rx_data[LEN];
unsigned char front;
unsigned char rear;
}Que;//定义缓存队列
typedef struct
{
const unsigned char tde_len;//命令的长度
const unsigned char* TdeCmd;//指向命令的指针(数组的头)
void(*Fun)();//当前命令需要执行的动作
}TDECMD;
Que queue = {0};
unsigned int time_count = 0;
const unsigned char cmd1[] = "hello";
const unsigned char cmd2[] = {2,3,4,5};
const unsigned char cmd3[] = {3,1,5};
void f1()
{
printf("f1执行\n");
}
void f2()
{
printf("f2执行\n");
}
void f3()
{
printf("f3执行\n");
}
const TDECMD tde[] = //使用了const,是为了将数据写入单片机的flash,减小ram占用
{
{6, cmd1, f1},
{4, cmd2, f2},
{3, cmd3, f3}
};
//模拟数据定时器
unsigned int get_time(void)
{
time_count = 0;
return time_count;
}
unsigned int get_time_interval(void)
{
time_count++;
return time_count;
}
//判断队列是否为空
unsigned char IsEmpty(void)
{
if (queue.front == queue.rear)
{
return 1;
}
return 0;
}
//入队
void InQue(unsigned char val)
{
if (queue.front == (queue.rear + 1) % LEN)
{
queue.Rx_data[queue.rear] = val;
queue.rear = queue.front;
queue.front = (queue.front + 1) % LEN;
}
else
{
queue.Rx_data[queue.rear] = val;
queue.rear = (queue.rear + 1) % LEN;
}
get_time();
}
//出队
unsigned char OutQue(unsigned char *val)
{
if (IsEmpty())
{
return 0;
}
else
{
*val = queue.Rx_data[queue.front];
queue.front = (queue.front + 1) % LEN;
}
return 1;
}
void TDE(void)
{
static unsigned char temp_front = 0;
unsigned char val = 0;
unsigned char flag = 0;
unsigned char i = 0, j = 0;
temp_front = queue.front;
if(IsEmpty() == 1)//如果队列为空,则退出
{
return;
}
for(i = 0; i < sizeof(tde) / sizeof(TDECMD); i++)//依次执行所有的命令
{
while(queue.front != queue.rear)//当队列不为空,则继续进行
{
OutQue(&val);
if(tde[i].TdeCmd[0] == val)//每次从队列中pop出一个数,都会和每一个命令的头进行比对,相等表示找到了头
{
for(j = 1; j < tde[i].tde_len; j ++)//对比该条命令其他的数
{
if(OutQue(&val) == 0)//出队过程为空,退出for循环
{
flag = 1;
queue.front = temp_front;//并将队列头指针复位
break;
}
if(tde[i].TdeCmd[j] != val)//如果数据和命令中数据不同,退出for循环
{
flag = 1;
queue.front = temp_front;//并将队列头指针复位
break;
}
}
if(j == tde[i].tde_len)//如果上面for循环次数j等于数据长度,则表示找到了命令
{
tde[i].Fun();//找到一条命令,头指针不复位
return;
}
}
else//如果pop出的数据和当前对比的命令不相等,则头指针复位
{
queue.front = temp_front;
break;
}
if(flag == 1)//在数据对比中发现不同,则退出当前while循环
{
flag = 0;
break;
}
}
}
//当查完所有的命令,并且串口不再产生中断的时间大于X ms,队列不为空,
//则表示这个字符没有和所有命令对应的头,队列指针往下走一位
if(/*i == sizeof(tde) / sizeof(TDECMD) && */get_time_interval() >= 0x1FFFFFF)
{
if(queue.front != queue.rear)
{
queue.front = (queue.front + 1) % LEN;
}
}
}
int main()
{
//InQue(3);
InQue('h');
InQue('e');
InQue('l');
TDE();
InQue('l');
InQue('o');
InQue('\0');
InQue(2);
InQue(3);
InQue(1);
InQue(5);
InQue(3);
TDE();
InQue(4);
InQue(5);
InQue(2);
InQue(2);
TDE();
InQue(3);
InQue(4);
InQue(5);
InQue(4);
while(1)
{
TDE();
}
}