打印
[技术问答]

单片机编程思维

[复制链接]
647|0
手机看帖
扫描二维码
随时随地手机跟帖
跳转到指定楼层
楼主
hilahope|  楼主 | 2023-12-13 22:45 | 只看该作者 回帖奖励 |倒序浏览 |阅读模式
模块化编程
模块化编程是开发者首先会掌握的一种编程思想,就像前面我们多次提到的把一些特定功能的代码大打包成一个函数,这么一来以后在其他项目中就可以通过复制、粘贴轻松的移植了。这就是最简单的模块化思想了,当然如果要规范一点的话我们需要在函数前做一些必要的注释说明,方便自己日后重新使用这段代码时能很快就可以知道代码的功能。比如下面这段代码:

/*

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

* 函数名: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源文件的某段源码,看起来很复杂吧,说实话这段代码我也没细看,细看也一时不可能看明白,只是刚好看到就这个就贴上来跟大家一起分享一下。 作者:落木青云 https://www.bilibili.com/read/cv18524298/?from=search&spm_id_from=333.337.0.0 出处:bilibili

使用特权

评论回复
发新帖 我要提问
您需要登录后才可以回帖 登录 | 注册

本版积分规则

26

主题

1096

帖子

0

粉丝