今天无意间搜到一篇文章。 这位专家(对我来说)谈到了初学者的声音。 我们需要编程思想来指导我们,尤其是程序结构的安排和框架的定制。 这件事是很有经验的。 希望更多的专家写下自己的经验。
以下文章来自写得很好的博客
标题:浅谈微控制器编程中的“分层思维”。 这不是什么神秘的事情。 事实上,许多从事项目的工程师自己都使用它。 看了很多帖子,发现都没有提到这个东西。 不过,层次结构确实是一个非常有用的东西。 了解之后,你会有一种恍然大悟的感觉。 如果我不知道如何驱动 LCD,那很简单。 我可以看看datasheet,参考别人的程序,很快就能做出来。 但如果不了解编程的思维,就会给你在项目过程中带来很多困惑。
我查阅了市面上各种嵌入式书籍,包括MCS-51、AVR、ARM等,但没有找到任何介绍设计思想的书籍,即使有也是凤毛麟角。 写程序并不难,但是如何又好又快地写出程序需要一定的经验。 结构化模块化编程的思想是最基本的要求。 但如何将这个抽象概念应用到工程实践中呢? 需要在做项目的过程中历尽艰辛,总结一些东西,将抽象升华为理论,这对于经验的积累和技术的传播都有很大的好处。 所以我要炫耀一下我的屈辱,总结一些事情。 从我个人的经验来看,有两个设计思路非常重要。
一是“时间片轮的设计思想”,对于实践中解决多任务问题非常有用。 这个东西通常可以用来判断一个人是单片机学习者还是单片机工程师。 这个一定要掌握。 由于网上有很多帖子对此进行介绍,这里不再赘述。
第二个就是我今天要讲的话题:“分层屏蔽的设计思路”。 我们以键盘扫描程序为例来介绍一下今天要讲的内容。
问:单片机学习板为了简单起见,一般都会将按键分配得很好。 比如整个4*4键盘矩阵分配给P1口,有8根控制线,刚刚好。 这样的话,程序也很容易写了。只需要一个简单的
KEY_DAT = P1;
端口数据被读入。诚然,实际上没有什么比这更好的了。 在实际的项目应用中,单片机引脚的复用是相当强大的,这和那些所谓的单片机学习板有很大不同。
另一个原因是,在一般设计中,它是一个“软件匹配硬件”的设计过程。 简单来说就是先确定硬件原理图和硬件接线,最后开发软件,因为修改硬件比较麻烦。 据说修改软件比较容易。 这就是中国传统的阴阳平衡哲学原理。 硬件设计和软件设计本质上是鱼与熊掌的关系,不能两者兼得。 它方便了硬件设计,但可能给软件编写带来很多麻烦。 另一方面,如果软件设计方便的话,硬件设计就会相当麻烦。 如果硬件设计和软件设计都方便的话,就只有两种可能。 一是设计方案非常简单,二是设计者达到了非常高的水平。 我们不考虑那么多情况,只是从常见的实际应用的角度来看待问题。 为了接线方便,硬件常常将IO口分配给不同的端口。 例如,在上面提到的4*4键盘中,8行分别分配给P0 P1 P2 P3。 那么,开发板上的那些键盘扫描程序就见鬼去吧。 如何滑动按钮? 记得刚开始学习的时候,我把它分成了3个非常相似的程序,逐一扫描……也许有人不愿意说,“我花了很长时间学了那些东西,我也用它们”。 “好吧,你怎么能说不用呢?” 虽然有点残酷,但我还是想说,“兄弟,接受现实吧,现实很残酷……”
然而,人类与低等动物的不同之处在于,人类在遇到困难时能够创造并找到解决方案,于是我们开始冥想……然后我们引入了初中数学中的“映射”概念。 来解决问题。 基本思想是将不同端口上的密钥映射到同一端口。
这样,按键扫描程序就分为三个层次。
1)最底层是硬件层,完成端口扫描、20ms延时去抖、将端口数据映射到一个KEY_DAT寄存器。 KEY_DAT 作为上层驱动层的接口。
2)中间层为驱动层,仅对KEY_DAT寄存器的值进行操作。 简单来说,无论底层硬件如何连线,我们都不需要关心驱动层。 我们只需要关心KEY_DAT寄存器的值。 这样做的间接作用就是“屏蔽了底层硬件的差异”,因此驱动层编写的程序可以通用。 驱动层的另一个作用是为上层提供消息接口。 我们使用类似于窗口程序消息的概念。 这里可以提供一些按键消息,例如:按下消息、释放消息、长按消息、长按按键时的步骤消息等。
3)应用层。 下面是根据不同项目分别编写的关键功能程序,是顶层程序。 它使用驱动层提供的消息接口。 在应用层编写程序的思路是,不关心下层如何工作,只关心按键消息。 当关键消息到来时,我执行该函数。 当没有消息传来时,我什么也不做。
下面用一个简单且常用的例子来说明我们的设计思想的使用。 调整秒表时间时,需要按住某个按钮,使时间不断向上增加。 这个东西很实用,在实际家电中有很多用途。 在看下面的事情之前,你可以想一想,这件事难吗? 相信大家都会斩钉截铁地回答:“不难!!”,但我再问:“这东西麻烦吗?” 相信很多人肯定会说“好麻烦!!” 这让我想起了我开始学习单片机的时候。 编写这种按钮的程序结构比较混乱。 不信的话,你可以用51自己写一下,这样你就可以更好地理解本文提到的层次结构的优点。
项目要求:
这两个按钮分配给P10和P20,分别是“加”和“减”按钮。 要求实现按键长按时连续加法、连续减法的功能。
实战:
假设:按钮拉高,无按钮时为高电平,有按钮时为低电平。 另外,为了突出问题,这里就不写延时debounce程序了。 实际项目中需要添加。 C语言中传递函数参数的方法有很多种。 这里以最简单的全局变量为例,用于传递参数。 当然,你也可以使用 unsigned char ReadPort(void) 返回一个读取按键结果,甚至 void ReadPort(unsigned char *pt) 使用指针变量传递地址来直接修改变量。 方法有很多种,具体取决于每个人的编程风格。
1)开始编写硬件层程序并完成映射
#defineKYE_MIN 0X01
#定义KEY_PLUS 0X01
无符号字符KeyDat;
无效读取端口(无效)
如果(P1&KEY_PLUS == 0){
密钥数据 |= 0x01;
如果(P2&KEY_MIN == 0){
密钥数据 |= 0x02;
C语言应该很容易理解吧? 如果按下KEY_PLUS,P10口读到低电平,则P1&KEY_PLUS的结果为0,满足if的条件。 输入KeyDat |= 0x01 是将KeyDat的bit0设置为1,即将KEY_PLUS映射到KeyDat bit0
KEY_MIN 以同样的方式映射到 KeyDat 的 bit1
如果KeyDat的bit0为1,则表示KEY_PLUS被按下,反之亦然。
没有必要认为它很神秘,映射就是这样。 如果还有其他键,使用同样的方法将它们全部映射到KeyDat。
2)驱动层程序编写
如果你把KeyDat想象成P1口,这不就和学习板上的标准扫描程序一样了吗? 是的,这就是底层映射的目的。
3)应用层编程
据消息称
硬件层必须分离,但驱动层和应用层的要求没那么严格。 事实上,对于一些简单的项目来说,没有必要将这两层分开。 可根据实际应用灵活处理。 其实这样写程序对于移植来说是非常方便的。 只需根据不同的板卡适当修改硬件层的ReadPort函数即可。 驱动层和应用层的很多代码无需修改就可以直接使用,可以大大提高开发效率。 当然,这种按钮程序会存在一定的问题,尤其是常闭按钮和触摸按钮一起使用时。 这个就留给大家去思考了。 不管怎样,问题总有解决的办法,尽管方法可能好也可能坏。
结论
本文以按钮为媒介,介绍“分层屏蔽”思想在编程中的原理和应用。 按钮只是一个例子。 事实上,分层的思想在编程中是无处不在的。 如果你细心留意的话,你会发现window、linux、network的tcp/ip结构都是分层的。 这东西不是绣花枕头,而是工程上实际使用的东西。 只是我没有看到太多介绍它的帖子,或者没有人刻意这样总结,或者是经验丰富的工程师将其作为隐藏在心中的法宝。 这是无法接受的。 知道。 但好的东西应该分享,新人应该互相鼓励,让我们一起学会飞翔。