请选择 进入手机版 | 继续访问电脑版
查看: 1214|回复: 0

【单片机和CPLD/FPGA技术分享】-软件结构

[复制链接]
发表于 2016-6-6 18:00:15 | 显示全部楼层 |阅读模式
前面的帖子不能编辑了,再开个新帖,继续讲软件结构。

说到软件结构,真是有说不完的话。每次DEBUG的时候,都很庆幸自己的好习惯在关键时刻救了自己。在这里把这些知识分享给大家,希望对新手有所帮助,对老手有所启发。

相信大家会经常听到代码风格、程序结构、工程组织等词,在我的印象里,基本上每个涉及到编程的教程都会反复强调这些东西的重要性,那么他们到底是什么呢?且让我一一道来。
由于是开篇,只是介绍一下这些概念,在以后的开发中会经常重复提到。

封装:
曾经,我的桌面类似这个样子

现在它是这样的


是不看起来简洁了很多呢?但是简洁的原因是什么呢?是因为图标少了吗?当然不是。
图标还是那些图标,甚至数目比以前更多了,但是为什么变得简洁了呢?因为图标们不见了,图标们被文件夹装起来了。一般来说,看不见了叫作被隐藏,但是又可以通过文件夹图标找到这些被隐藏的图标,那么这个文件夹图标被叫做接口,整个操作加起来叫作封装
为什么要做封装呢?假设我从来没玩过游戏,不知道魔兽世界,也不认识LOL,有一天室友帮我安装了几款游戏和软件,如果他直接把图标放在桌面上告诉我给我装了游戏,让我自己找到打开玩,但是分不清哪个是游戏,害怕万一按错了电脑会爆炸,所以我只好百度一下多出来的图标到底哪个是游戏。这样做的问题就在于,让一个懂的人去整理,花的时间肯定比一个不懂的人去百度要短。如果室友直接用一个文件夹把游戏装起来,文件夹叫“游戏”,我就可以很轻易的找到游戏图标,这样虽然耗费了他一点点时间,但是省了我很多百度的时间,整体效率会提高很多。这就是封装的初衷,写的工作和用的工作分开,互不干扰,提高总体效率。同样道理,如果有一天他又装了新游戏和新软件,继续扔进文件夹里,还会一样可以节省时间,但是如果从一开始就使用了直接扔桌面这种简单粗暴的方法,后果就是形成恶性循环,随着图标的增多,每次寻找图标需要的时间会越来越多,可能两个人都会弃疗,多么伤感的话题。这就是使用封装技术的好处,便于维护,哪里不要换哪里,简单粗暴,不需要一次改全部,只需要改一次就可以代替很多处修改,代码越多这个优势越明显。

举例:
不同单片机访问寄存器的方法可能不一样,但是如下写法可以让程序更具移植性。
#define LED1_OFF() GpioDataRegs.GPASET.bit.GPIO22 = 1
#define LED1_ON() GpioDataRegs.GPARESETbit.GPIO22 = 1
#define LED1_TOGGLE() GpioDataRegs.GPATOGGLE.bit.GPIO22 = 1
//或者
void LED_Led1On(void){
        GpioDataRegs.GPASET.bit.GPIO22 = 1;
}
// 这样的好处是需要操作LED的时候不用去查看原理图,写起来更符合人的思维,当程序的层级变多后将变得更明显

程序结构:
桌面上的图标被隐藏后,并不是直接扔在文件夹里,如果直接全扔进去其实是自欺欺人的做法,只是表面上看起来好看,并没有提高效率。我桌面上放软件的文件夹是如此分类的


这就像我们的软件,是有结构的,当它规模不大的时候其实不需要考虑结构,但是一旦超过几百行,你会发现下次打开它可能就忘了它是什么意思,当初为什么会这么写。分享一下自己的经验,一般来说习惯分四个层,驱动层,底层,接口层,应用层。
驱动层:PWM_Pwm1ASendPulse(); PWM_Pwm1Isr();
底层:StepMotor_AxisRun();
接口层:Line_RunAsLine();
应用层:主函数、或操作系统
每个层的函数只能被上一层(仅限一层)的函数调用,调用下一层的函数。同层之间不能互相调用,如果需要,由上一层函数调用。
那么有一个问题就是,可能会出现某一层的实现需要借助高一层的实现或者低两层的实现,比如插补函数需要更改中断服务函数的内容。那么可以用回调函数实现,在中断服务函数里调用一个回调函数,通过全局变量或者结构体封装在同一个文件里,同时提供一个访问该函数指针的函数供上层调用,即可解决这个问题。回调函数可以大大提供程序的灵活性,但是要注意平衡内存开销和程序可读性。

暂时写到这里,这些概念以后会体现在我开源的代码中,同时也会做进一步解释,写这两篇是为了让大家了解我想传达给大家的理念,多谢各位的支持!
回复

使用道具 举报

您需要登录后才可以回帖 登录 | 加入因仑

本版积分规则

快速回复 返回顶部 返回列表