打印
[经验分享]

单片机编程思维

[复制链接]
2227|42
手机看帖
扫描二维码
随时随地手机跟帖
跳转到指定楼层
楼主
youtome|  楼主 | 2025-2-18 04:10 | 只看该作者 回帖奖励 |倒序浏览 |阅读模式
模块化编程
模块化编程是开发者首先会掌握的一种编程思想,就像前面我们多次提到的把一些特定功能的代码大打包成一个函数,这么一来以后在其他项目中就可以通过复制、粘贴轻松的移植了。这就是最简单的模块化思想了,当然如果要规范一点的话我们需要在函数前做一些必要的注释说明,方便自己日后重新使用这段代码时能很快就可以知道代码的功能。比如下面这段代码:
/*
***********************************************
* 函数名: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等等,所以就不用我们自己从零写一个多任务系统了,使用时选择一个合适的系统进行移植就能减少很多工作量了。


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

上图中是freeRTOS中任务创建的函数,对于初学者来说这些咋看都是很深奥的内容,所以这里也不需要你现在就掌握它,以后你有机会接触它们,现在知道有这么回事就好了。现在总不至于哪天面试的时候被人问你一句你是否尝试过面向对象开发单片机程序时自己啥话都说不上来。
这是微软某个版本的某C源文件的某段源码,看起来很复杂吧,说实话这段代码我也没细看,细看也一时不可能看明白,只是刚好看到就这个就贴上来跟大家一起分享一下。

使用特权

评论回复
沙发
plsbackup| | 2025-3-9 20:28 | 只看该作者
ISR 中避免复杂操作(如浮点运算、字符串处理),仅完成快速响应和标志位设置。

使用特权

评论回复
板凳
wangdezhi| | 2025-3-9 20:40 | 只看该作者
合理规划单片机的内存空间,包括RAM和ROM的分配。根据程序的需求,确定不同功能模块所需的内存大小,并确保内存的有效利用。同时,注意内存的访问速度和功耗之间的关系,优化内存访问模式以降低功耗。

使用特权

评论回复
地板
elsaflower| | 2025-3-9 21:27 | 只看该作者
主程序负责轮流调用各个功能模块,实现功能的调度。这种结构增强了模块之间的独立性。

使用特权

评论回复
5
abotomson| | 2025-3-11 13:00 | 只看该作者
深入理解单片机寄存器的功能和用途,包括通用寄存器、状态寄存器、堆栈指针等。明确每个寄存器在程序执行过程中的作用,以及如何通过寄存器实现数据的快速存储和访问。

使用特权

评论回复
6
nomomy| | 2025-3-11 13:45 | 只看该作者
单片机编程需要大量的实践和经验积累。通过实际项目的学习和开发,可以不断提高编程技能和解决问题的能力。

使用特权

评论回复
7
yorkbarney| | 2025-3-11 15:03 | 只看该作者
单片机的资源(如RAM、ROM、处理速度)通常有限,因此编程时需要高效使用这些资源。
需要优化代码大小和执行效率,避免不必要的内存占用和计算。

使用特权

评论回复
8
nomomy| | 2025-3-11 16:49 | 只看该作者
将程序划分为独立的模块或函数,每个模块负责一个特定的功能。
模块化可以提高代码的可读性、可维护性和可重用性。

使用特权

评论回复
9
benjaminka| | 2025-3-11 19:18 | 只看该作者
通过模块化和标准化设计降低长期维护成本。

使用特权

评论回复
10
averyleigh| | 2025-3-12 19:53 | 只看该作者
针对特定的单片机和应用需求,可能需要对代码进行优化,以提高性能。
优化可能包括算法改进、代码结构调整、指令级优化等。

使用特权

评论回复
11
dspmana| | 2025-3-12 22:04 | 只看该作者
对整个系统进行深入分析,明确系统的功能需求和性能要求。将复杂的系统功能分解为多个相对独立的功能模块,每个模块完成特定的任务,如数据采集、数据处理、通信控制等。

使用特权

评论回复
12
wengh2016| | 2025-3-12 22:36 | 只看该作者
模块化设计是将程序划分为多个独立的模块,每个模块负责特定的功能。这种设计方式有助于提高代码的复用性和可测试性。常见的模块包括:

电源管理模块:负责电压检测和处理。
按键扫描模块:负责按键的检测和消抖处理。
开关扫描模块:负责开关状态的检测和处理。
功能处理模块:负责根据按键和开关状态执行相应的功能。
设备操作模块:负责具体设备的操作,如灯、电机、蜂鸣器等。

使用特权

评论回复
13
belindagraham| | 2025-3-14 13:04 | 只看该作者
利用硬件定时器实现精确的延时控制。通过设置定时器的计数值和预分频器的值,可以得到准确的延时时间。硬件延时精度高,但需要占用硬件资源,适用于对时间精度要求较高的场合。

使用特权

评论回复
14
everyrobin| | 2025-3-14 13:33 | 只看该作者
定义清晰的模块接口,包括输入参数、输出结果、函数名称等。确保模块之间通过接口进行有效的通信和协作,同时减少模块之间的耦合度,提高模块的独立性和可移植性。

使用特权

评论回复
15
janewood| | 2025-3-14 14:42 | 只看该作者
最大化利用有限的 内存。              

使用特权

评论回复
16
mikewalpole| | 2025-3-14 15:48 | 只看该作者
了解中断嵌套的概念和实现方式,能够正确处理多重中断的情况。在设计中断服务程序时,注意避免中断嵌套导致的系统异常和数据不一致问题。

使用特权

评论回复
17
lzmm| | 2025-3-15 10:46 | 只看该作者
深入理解中断的概念和原理,包括中断的来源(如外部设备中断、定时器中断等)、中断的触发条件、中断的优先级等。掌握中断服务程序的执行过程,包括中断向量的定位、现场保护、中断处理程序的执行和现场恢复等。

使用特权

评论回复
18
minzisc| | 2025-3-15 11:01 | 只看该作者
提高代码的可复用性和扩展性:通过类和对象的封装,可以实现代码的复用和功能的扩展。
降低复杂度:将复杂的问题抽象为对象,简化了程序的设计和实现。

使用特权

评论回复
19
uptown| | 2025-3-15 11:34 | 只看该作者
熟悉单片机的I/O端口结构,掌握端口的配置方法,包括设置端口的方向(输入或输出)、初始化端口状态等。理解端口的电气特性,如电流驱动能力、电压耐受范围等,以确保端口连接的外部设备能够正常工作。

使用特权

评论回复
20
pentruman| | 2025-3-15 12:12 | 只看该作者
低功耗编程是指在编程时考虑节约功耗的方法,适用于对功耗要求较高的嵌入式系统。

使用特权

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

本版积分规则

41

主题

4046

帖子

2

粉丝