欢迎光临散文网 会员登陆 & 注册

51单片机进阶开发(一)之单片机编程思维

2022-09-09 21:13 作者:落木青云  | 我要投稿

写在前面的P话

明天就中秋节了,祝各位中秋节快乐!各位都有月饼吃了吧?如果没得月饼吃的朋友在评论区留个记号,或许我可以帮上你们。这边肯定也有朋友不想吃月饼或吃腻了的吧,那你们也在后面留个记号,然后大家可以各取所需相互帮助了,这样我应该算帮你们之间都解决了吃月饼的问题了吧。哈哈哈……来我家吃月饼也是可以的。最近一段时间很久都没动静了,发个文证明一下我还活着,也感谢各位老铁一路的支持!其实,今天的这篇文章也是公众号上发了没转过来的,所以我就这么敷衍的搬过来吧。为了表示歉意,明天你们吃月饼,我写文章,内容都想好了,保证很多人没看过,看懂的人对日后计算机相关学习肯定会有180度变化——“老子不学了”。哈哈……

好了,玩笑话就不多扯了,下面先看今天的正文吧 》》》

单片机编程需要什么思维

又很长一段时间没有更新文章了,今天这篇文章其实很久之前就写好开头了,但直到今天才完成,让追更的小伙伴久等了,非常抱歉!看后台数据这段时间有不少小伙伴取关了,但令人欣慰的是总的关注人数没有下降,所以非常感谢各位关注的朋友。当然取关的朋友也是可以理解,毕竟我这里很长时间没更新,学习进度肯定是拖了后腿,有些内容还不如自学的快。之前本来想着没写内容的时候就搬运一些视频过来给大家看看,但后台还是有不知情的朋友询问视频内容相关的一些问题,不是自己做的内容回答起来总有点“欺骗感情”的感觉,所以索性就不搬运了,以后如果看到有非常值得看的视频再搬过来给大家吧,当然在内容中我也会强调视频为搬运(之前其他平台上传的一些搬运视频时我选择的是原创,因为那些平台对填写外网转载的链接不太友好。在微信公众号前期我发的自己的原创视频因为当时还没有获取原创权限也没声明原创,后面开通原创功能后我自己的视频在发布时就都声明为原创了,好在公众号对搬运的视频不用审核转载链接,只要不声明原创就好,所以后面公众号里看到未声明原创的视频大家应该第一时间就要明白是我搬运过来的,大家欣赏一下就好)。总之,在这里我还会继续分享一些实用知识或技能,让看到文章的朋友有所收获。当然写文章,做视频也不会给我带来收入,主要是希望这里能成为一个交流的平台,给需要的人。生活不仅有远方,还要有柴米油盐酱醋茶,所以在我来不及更新的时候,你可以在后台留言或私信你的问题,我看到消息肯定会答复你的疑问。祝大家周末愉快,暑假的朋友假期愉快!哈哈哈,明天我还得继续搬砖,最近在准备一个网页3D项目,因为是第一次接触所以还是需要花足够的功夫,欢迎有经验或有兴趣朋友一起交流。后面空闲时我也做几篇文章分享给大家,接下来进入今日正题。

前面的《51单片机入门基础知识》和《51单片机编程开发》两部分内容我们将51单片机的基本知识做了简单介绍。看过的朋友现在使用51单片机编写一些简单的程序应该是没有问题了吧。当然前面的内容还只是单片机世界的冰山一角,离真正能做项目开发肯定还有一定的距离,说简单来说就是学完前面的内容你能做的都只是一些小玩意,这些代码也不会给你带来啥经济收入。或许部分朋友在此基础上能够制作出一些有趣的“神器”了。那真的恭喜你,继续努力,后面可以制作更多有趣的东西。

之后的文章,我将逐步和大家一起来分享怎么样才能让自己成为一个有项目开发能力的单片机工程师。我会以我个人经验讲解一些作为工程师需要掌握职业技能,当然也欢迎分享你的经验。前面的内容都是让大家像玩玩具一样使用单片机,但项目开发不是做玩具,所以后面我也会介绍一些以后工作岗位上你可能用的上的一些知识。当然如果手头有开发板的朋友,对比你手头上店家提供给你的资料,51单片机基础部分内容中我所写知识点还有一部分是没提及的,比如ADC/DAC(即数模转换),红外传感器,温度传感器,湿度传感器,时钟芯片,电机驱动,外接RAM,外接ROM,IIC、SPI通信协议等等。这些内容考虑到大家使用的开发板可能电路不太一样,或者因为某些内容以后基本用不上,又或者某些内容有更简单的方案了,所以我们就没拿出来单独介绍。其实这些都是在我们前面所讲知识点的基础上衍生出来的一些应用而已,所以对于一些日后使用比较多的知识我后面的文章将会进行补充说明,虽然不会再单独立篇进行介绍,但我会在使用时列出一节内容进行说明,这样方便初学者一次性掌握。

说了这么多题外话,那到底该怎么做我们才能够具备项目开发能力呢?那就不得不说我们应该要掌握的单片机编程思维了,编程思想就像房子的框架,或者人的骨骼,框架结构就决定了房子的外观形状,骨骼确定了人的形态大小。单片机编程思维也一样,它决定了程序的效率,可读性和可移植性。那单片机编程思维需要掌握哪些内容呢?前面我们有点出,但没做具体说明,并且不同的人对这此都有不一样的说法,它更多的是受一个人的编程习惯所影响。在我看来单片机开发需要具备的思维首先是模块化,然后就是多任务化,再有就是面向对象化。当然这几种编编程思维不是独立存在的,也不一定就有时间顺序,在我的职业生涯中他们往往都会同时存在于我的代码中,这些编程思维更像是相互协同的一种编程习惯。当你形成自己的编程思维之后对此肯定也会有自己的认识。

这里先推荐一本书给大家——《时间触发嵌入式系统设计模式》,对于初学者来说可能理解起来需要多花费一些时间,但我还是强烈推荐这本书,希望各位在初学阶段能都形成良好的编程风格。关于编程习惯的参考资料还可以读一读《华为C编程规范和范例》,另外华为的其他一些相关资料也是值得一读的,比如,PCB设计规范,EMC指南等等。站在巨人的肩膀上你会看的更远,所以有时间都可以看一看。当然提升编程能力更重要的是动手,要敢于试错,如果时间允许多看看网络上的开源项目也是不错的一个选择,优秀的开源项目被全世界的开发者盯着看,该规范的都规范了,总比自己闭门造车写出来的代码好看吧。

模块化编程

模块化编程是开发者首先会掌握的一种编程思想,就像前面我们多次提到的把一些特定功能的代码大打包成一个函数,这么一来以后在其他项目中就可以通过复制、粘贴轻松的移植了。这就是最简单的模块化思想了,当然如果要规范一点的话我们需要在函数前做一些必要的注释说明,方便自己日后重新使用这段代码时能很快就可以知道代码的功能。比如下面这段代码:

/*

***********************************************

 * 函数名:led_display

 * 描   述:****

 * 输   入:****

 * 输   出:****

 * 返   回:****

 * 调   用:****

 * 备   注:****

************************************************

*/

void led_display(uint16_t duty ,uint8_t up_rate,uint8_t down_rate)

{

    ****

}

当然也可以不用写这么多注释,注释内容只要能保证可以看懂函数的意思就行,内容根据自己的喜好来确定,比如你也可以这样些:

/**

  * @brief   :****

  * @param : ****

  * @retval  : ****

 **/

甚至你也可以直接就用一句注释说明,比如:

/*    ****   */

或者直接

// ****

只要能保证可以一眼看懂你的说明就行,当然最好是自形成一个统一的格式注释格式,让程序看起来更加美观大方,以后别人读你的程序心情也会好很多,毕竟项目开发不一定是你一个人完成特别是互联网项目,比如一个大型项目就涉及到前端开发者,后端开发者,移动端(或桌面端)开发者,甚至还需要测试人员配合,这种情况虽然不会每个人都需要看你的代码但至少会有人来跟你协同完成应用功能。所以很多公司都会规定注释规范或编程规范。

平时编程时除了善于打包函数将程序模块化,但项目中很多时候我们的程序不止是几个函数,我们项目可能使用了大量的外设,程序中需要大量的函数来完成功能,这时候如果只是打包函数,我们的代码也会变得非常庞大,如果一个文件里面有几千甚至上万行代码,你日后维护起来是不是会崩溃,可能找一个bug都能找半天,这时候我们需要怎么办呢?其实C语言库文件就已经告诉我们做法了,当然其他语言也是一样。这时候我们就可以进行分文件打包程序,就是将相同功能或控制同一个外设的代码放在同一个文件里进行模块化,这样做是不是比单纯使用的函数会更有优势,以后我们如果要重复使用这些代码都不用在代码中查找这些函数的了,直接将整个文件拷贝就可以了,现在我们一起来看看这是怎么实现的。

图片

以上图片中展示的就是这种模块化的做法,在项目中将不同作用的代码放在不同的文件夹下,将不同模块的代码放在不同的***.c文件里面,这样后续修改,调试,移植代码的效率就会大大提高。那这种做法是怎么实现的呢,之前我们在介绍C语言文件时说过C语言文件主要有两种,即.c和.h文件,.c文件我们称它问源文件,.h文件我们称为头文件,在源文件中我们存放各种变量或功能函数的定义等内容,在头文件中声明对应的变量、函数或宏定义等等,所以一般情况下源文件和头文件都是成对出现的。若某个文件需要使用另一个文件中定义的函数时就在该文件头部添加另一个文件对应的头文件,这样就可以实现各部模块程序相互调用了。通过源文件和头文件分离,当你遇到有一些代码文件你不想给别人知道,但又要发布给别人,这种情况下也有对应的处理办法,具体的做法我们后面再介绍。

一般情况下在不同的源文件中我们也会像之前些函数一样对该文件做一些注释描述,比如:

/**** (C) COPYRIGHT  *********

 * 文件名   :****

 * 描述      :****

 * 操作系统 :****

 * 软件平台 :****

 * 硬件基础 :****

 * 库版本    :****

 * 作者       :****

 * 版本编号 :****

 * 修改时间 :****

 * 修改说明 :****

**********************************/

当然你也可以不用写这么多内容,以你能看懂为准。

多任务编程

一般情况下我们在使用 51、AVR、STM32等单片机编程的时候都是在main函数里面用while(1)做一个大循环来完成所有的处理,即应用程序是一个无限的循环,循环中调用相应的函数完成所需的处理。有时候我们也需要用到中断来完成一些功能操作。相对于多任务系统而言,这个就是单任务系统,也称作前后台系统,中断服务函数作为前台程序,大循环while(1)作为后台程序。

图片

类似一下的做法:

void IRQHandler_fun()

{

    flag1 = 1;

}

int main (void)

{

    while(1)

    {

        if (1 = flag1)

        {

            func1();

            flag1 = 0;

        }

    }

}

这种做法在一般项目中是完全没有问题的,但是这种程序结构的一个缺陷是它的前后台系统的实时性不强,前后台系统各个任务(应用程序)都是排队等着轮流执行,不管你这个程序现在有多紧急,没轮到你就只能等着!相当于所有任务(应用程序)的优先级都是一样的。在小项目中前后台系统简单,资源消耗也少,单片机处理起来还得心应手!但在稍微大一点的嵌入式应用中前后台系统对实时性要求较高的应用中就明显力不从心了。这时候就需要进行多任务处理了,就像一下的做法:

void first_task()

{

    while (1)

    {

        if(has_data())

            put_data();

    }

}

void second_task()

{

    while (1)

    {

        if(get_data())

            do_something();

    }

}


int main(void)

{

    create_task(first_task);

    create_task(second_task);

    start_task();

}

相信细心的朋友一眼就能发现,这种做法很明显的不一样就是每个任务函数中都有一个while (1)死循环,是不是我们只要在程序中多使用一些while (1)死循环就OK了呢?简单说可以这么认为吧,当然实际情况肯定不会这么简单。

那多任务编程是怎么实现程序功能的呢?多任务系统把一个大问题“分而治之”,把大任务划分成很多个小问题,逐步的把小任务解决掉,大任务也就随之解决了,这些任务是并发处理的。注意,并不是说同一时刻一起执行很多个任务,毕竟我们单片机项目都是使用单核芯片,任意时刻它也只能存在一个任务占用其内核,它是由于每个任务执行的时间很短,导致看起来像是同一时刻执行了很多个任务一样。

看了以上内容是不是感觉多任务编程非常的难?其实难肯定是难,但也没有那么难,因为现在有非常多开源多任务系统供我们选择,比如freeRTOS,RT-Thread,UC/OS等等,所以就不用我们自己从零写一个多任务系统了,使用时选择一个合适的系统进行移植就能减少很多工作量了。

图片

像以上这个项目,调用freeRTOS来实现程序功能。当然这种编程思维不是一两天就能掌握,需要一定的项目经验,所以初学者理解起来困难并不要紧,要紧的是自己需要把C语言基础掌握好,基础牢固了编程就有感觉了。

面向对象编程

前面介绍C语言基础时我们说过编程语言主要有面向过程和面向对象两种,C语言是典型的面向过程的一种编程语言。你们你可能就会想为什么我们使用C语言开发单片机程序还需要面向对象的编程思维呢,是要使用面向对象的编程语言来开发了吗?当然不是,我们还是使用C语言来编程,只是呢,在编程时我们按面向对象的方式来处理其相关功能,简单的说就是把C语言通过一定的处理技巧封装成像面向对象的编程语言一样来执行程序功能。

对于流程清晰的简单程序,一般只有一条流程主线,很容易被划分成顺序执行的几个步骤,面向对象编程和面向过程编程没有太大差别,并且面向过程编程相对比面向对象编程更加直观高效。

当我们面对一个大型的复杂程序,由于其错综复杂的流程和交互关系,很难将其简单地拆分成一条主线串成的简单步骤,而通常表现为一个网状关系结构。这个时候,面向过程编程的这种流程化和线性化的思维方式就会显得比较吃力,而面向对象编程的优势就比较明显了。

这也是为什么说面向对象的编程语言是更高级的语言的原因之一,面向对象编程风格的代码更容易复用、扩展和维护、更高级、更人性化、更适合大规模复杂程序的开发。在C语言编程的一些操作系统(包括Unix,linux以及Windows等等)中就会用到的面向对象的编程方式,里面有很多的结构体、指针、链表等内容。如果还没有接触到面向对象编程只能说明你做的东西还不够复杂。当然也不是非要掌握这个技能你才能进行项目开发,只是你掌握了这些技能你就能开发更复杂的工程了。你的薪酬肯定也会比其他人高。

我们想来看看一些简单的面向对象编程代码:

图片
图片

以上是STM32某系列芯片官方标准库函数中的部分片段代码。

图片

上图中是freeRTOS中任务创建的函数,对于初学者来说这些咋看都是很深奥的内容,所以这里也不需要你现在就掌握它,以后你有机会接触它们,现在知道有这么回事就好了。现在总不至于哪天面试的时候被人问你一句你是否尝试过面向对象开发单片机程序时自己啥话都说不上来。

图片

这是微软某个版本的某C源文件的某段源码,看起来很复杂吧,说实话这段代码我也没细看,细看也一时不可能看明白,只是刚好看到就这个就贴上来跟大家一起分享一下。

结语:

今天内容是日后走向项目开发的必经之路写的比较多,部分内容现在理解不了也无需担心或害怕,很多东西都是练着练着就熟悉了,所以平时遇到不理解知识点都不用恐惧,哪里不懂就百度哪里,现在遇到的问题多了一个个解决之后将来就不会难倒你了,所以初学时多动手的好处就在于尽早暴露你的不足,助你日后开发项目时轻车熟路,举重若轻。

51单片机进阶开发(一)之单片机编程思维的评论 (共 条)

分享到微博请遵守国家法律