通过串口发送数据让单片机执行不同的动作

这里的实现灵感来自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();
	}
}

  • 2
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

入门->放弃

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值