IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> 嵌入式 -> 单片机工程经验 - 数据逻辑分离 -> 正文阅读

[嵌入式]单片机工程经验 - 数据逻辑分离

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

举例

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

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%的代码都可以复用,那摸鱼的时间还不是大把大把!!!

  嵌入式 最新文章
基于高精度单片机开发红外测温仪方案
89C51单片机与DAC0832
基于51单片机宠物自动投料喂食器控制系统仿
《痞子衡嵌入式半月刊》 第 68 期
多思计组实验实验七 简单模型机实验
CSC7720
启明智显分享| ESP32学习笔记参考--PWM(脉冲
STM32初探
STM32 总结
【STM32】CubeMX例程四---定时器中断(附工
上一篇文章      下一篇文章      查看所有文章
加:2022-10-08 20:58:04  更:2022-10-08 21:01:18 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年11日历 -2024/11/25 21:49:46-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码