单片机工程经验 - 数据逻辑分离

单片机工程经验 - 数据逻辑分离

举例

假设我们有一段程序,程序实现的功能是输入错误代码打印错误字符串。一般实现如下

enum{
	ERR_NONE,
	ERR_INVAL,
	ERR_NOEN,
	ERR_BUSY,
	...
};
char* print_err(char errcode)
{
	if(errcode == ERR_NONE)
	{
		return "No error occurred"
	}
	else if(errcode == ERR_INVAL)
	{
		return "Invalid argument"
	}
	else if(errcode == ERR_NOEN)
	{
		return "No such file or directory"
	}
	else if(errcode == ERR_BUSY)
	{
		return "Device or resource busy"
	}
	...
}

可以看到,虽然上述代码完成了功能,但是代码繁杂,如果需要更改需要寻找大量代码,这时如果我们使用下面程序进行数据和逻辑的分离会有什么效果呢。

解耦数据于逻辑

enum{
	ERR_NONE,
	ERR_INVAL,
	ERR_NOEN,
	ERR_BUSY,
	...
};
const char errStr[]={
	"No error occurred",
	"Invalid argument",
	"No such file or directory",
	"Device or resource busy",
	...
};
char* print_err(char errcode)
{
	char i = 0;
	if( errcode < sizeof(errStr)/sizeof(errStr[0]))
	{
		return errStr[errcode];
	}
	return "Unknow error code";
}

这样我们就完成了数据与逻辑的完全分离,无论怎么增减故障代码,都无需对print_err函数进行更改。核心代码就几行,程序就会变得十分简洁,并且修改故障代码只需在errStr数组中增减即可。

进阶玩法

或许你觉得上述代码很容易就能想到了,那我给大家来个骚操作。
矩阵键盘
矩阵键盘电路相信大家都很熟悉,不懂得可以去看我的
单片机工程经验 - 分层思想这篇文章。
我们假设这里的COL1 ~ COL4连接单片机的PA1 ~ PA4,ROW1 ~ ROW4连接单片机的PB1~PB4。定义一个unsigned long keyValue用16位表示这16个按键是否有按下,按下对应位置1,没按下置0。既(COL数-1)+(ROW数-1)*4位代表(COL,ROW)是否按下,比如(COL3,ROW2)就是keyValue第6位来表示。
那么接下来代码该怎么编写呢,首先我们的逻辑就是轮流扫描ROW,然后依次去读COL的值,对代码而言,COL和ROW的引脚号就是数据,而逻辑是相同的。接下来我们设计代码

const unsigned char col[] = {0xa1,0xa2,0xa3,0xa4};
const unsigned char row[] = {0xb1,0xb2,0xb3,0xb4};
static unsigned long keyValue = 0;
void func_loop()// 轮询
{
   static unsigned char index = 0;
   unsigned char i = 0,j = 0;
   for(i = 0; i < sizeof(row)/sizeof(row[0]);i++)
   {
       pin_write(row[i],1); // 所有ROW先置高
   }
   
   pin_write(row[index ],0);//选中的ROW置低
   
   for(i = 0; i < sizeof(col)/sizeof(col[0]);i++)
   {
       if(pin_read(col[i]) == 0) // col脚被按下
       {
           keyValue |= (1<<(index*sizeof(col)/sizeof(col[0]) + i)); // 对应的位置高
       }
       else
       {
           keyValue &= ~(1<<(index*sizeof(col)/sizeof(col[0]) + i)); // 对应的位置低
       }
   }
   index++; // 下一个row
   if(index >= sizeof(row)/sizeof(row[0]))
   {
       index = 0;
   }
}

注意:pin_readpin_write都是 单片机工程经验 - 分层思想中进行了分层处理的函数。

上述代码非常简单,但他的好处也非常明显,func_loop函数完全不需要更改就可以完全适应32个按键以下的基本上所有的矩阵键盘,而对于不同的矩阵键盘电路,我们只需要更改colrow数组中的值即可,无论是几行几列,都可以使用这套代码,那么程序移植是不是就很方便呢?

这段代码只实现了检测按键是否按下,并没有消抖,双击,长按等判断。为什么呢?因为如果我们将这些逻辑判断再单独写一个button文件,button中有一个get_keyvalue()函数,这个函数只关心按键是否有被按下,然后消抖,双击,长按等逻辑判断全在button中实现,那么无论底层代码是否是矩阵键盘还是独立按键是不是就都可以复用button这个文件了呢?

如果一个项目里面你有80%的代码都可以复用,那摸鱼的时间还不是大把大把!!!

  • 3
    点赞
  • 12
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

蓝忧云枫

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

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

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

打赏作者

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

抵扣说明:

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

余额充值