嵌入式C语言之结构体封装函数

news2024/10/22 19:45:07

嵌入式C语言之结构体封装函数

  • Chapter1 嵌入式C语言之结构体封装函数
    • 结构体封装函数的作用
    • 结构体封装函数的应用
    • 结构体封装函数的好处
    • 举例1
    • 举例2
    • 举例3


Chapter1 嵌入式C语言之结构体封装函数

原文链接:https://blog.csdn.net/qq_43416206/article/details/131405313

说明:

在嵌入式系统中,结构体封装函数可以用于对于嵌入式硬件资源进行抽象和封装,从而提高软件的可维护性和可移植性。结构体封装函数通常包含数据和行为,并提供了对数据的访问和操作方法。

比如可以将硬件驱动函数封装在结构体中,方便对外提供统一的API接口,同时也便于代码的移植和扩展。另外,结构体封装函数还可以用于实现状态机、任务调度等复杂的系统功能。

在C语言中,结构体不仅可以封装数据,还可以封装函数指针。这种方式可以用于实现回调函数、状态机等,提高代码的复用性和可维护性。特别是在嵌入式当中,应用是非常多的。

结构体封装函数的作用

  1. 将函数指针和参数打包成一个结构体,实现了代码的模块化和可复用性。
  2. 在结构体中可以定义多个函数指针,实现了对函数的分类管理和调用。
  3. 结构体可以作为函数的参数或返回值,传递和返回函数指针和参数。

结构体封装函数的应用

在这里插入图片描述

  • 回调函数:将函数指针和参数打包成一个结构体,传递给API函数,在API函数内部执行该函数。

  • 状态机:将每个状态对应的处理函数封装成一个结构体,根据当前状态调用相应的处理函数。

  • 事件驱动:将事件处理函数封装成一个结构体,通过事件触发调用相应的处理函数。

  • 线程池:将任务处理函数封装成一个结构体,加入任务队列后由线程池调用执行

结构体封装函数的好处

  • 更好的隐藏实现细节:结构体封装函数使得函数的实现细节被封装在结构体内部,只有结构体暴露给外部的函数指针,实现了良好的封装和信息隐藏。

  • 更加灵活的函数调用:函数指针可以被动态修改,从而实现动态的函数调用。例如,在状态机中,根据不同的状态,可以将相应的处理函数指针赋值给一个函数指针变量,从而实现状态的转换和函数的调用。

  • 更加方便的扩展性:结构体封装函数可以轻松地添加新的函数指针,从而扩展功能。在需要添加新功能时,只需要定义一个新的函数指针,并添加到结构体中,就可以实现功能的扩展,而不需要修改原有的代码。

  • 更加通用的代码:结构体封装函数可以使用于各种不同的编程范式,例如面向对象编程(OOP)和函数式编程(FP),从而实现通用的代码。例如,在OOP中,结构体可以被看作是一个对象,函数指针可以被看作是对象的方法,从而实现OOP编程的思想。

  • 更加易于维护:结构体封装函数使得代码更加清晰、易于维护和修改。由于函数指针的定义和使用都在结构体内部,因此修改或调整代码时,只需要修改结构体中的函数指针定义或调用方式,而不需要修改其他部分的代码,从而使得代码更加健壮、易于维护和修改

  • 模块化:通过结构体封装函数,可以将多个函数和数据结构组合成一个模块,以便于模块化设计和维护。这种方法可以将代码的复杂性分解到不同的模块中,降低了代码的耦合性,提高了代码的可读性和可维护性。

  • 代码复用:结构体封装的函数可以通过传递结构体的方式重用同一个函数。这种方式可以大大减少代码量,提高代码的复用性和可维护性。

  • 可扩展性:当需要增加新的功能时,只需增加新的函数和数据结构,而不需要修改现有代码。这种方式可以大大减少代码的修改和调试时间,提高代码的可扩展性和可维护性。

  • 保护数据:通过结构体封装函数,可以将数据和函数封装在一个结构体中,防止外部代码对数据的非法访问和修改。

  • 提高安全性:将函数和数据封装在一个结构体中,可以防止其他函数对数据的非法操作,从而提高程序的安全性。

举例1

 1/* 定义封装函数结构体由外部调用*/
 2typedef struct {
 3    int x;
 4    int y;
 5    void (*move_up)(int steps);
 6    void (*move_down)(int steps);
 7    void (*move_left)(int steps);
 8    void (*move_right)(int steps);
 9} Point;
10
11// 定义结构体中的函数
12void move_up(int steps) {
13    // 向上移动steps个单位
14    // ...
15}
16
17void move_down(int steps) {
18    // 向下移动steps个单位
19    // ...
20}
21
22void move_left(int steps) {
23    // 向左移动steps个单位
24    // ...
25}
26
27void move_right(int steps) {
28    // 向右移动steps个单位
29    // ...
30}
31
32int main() {
33    // 初始化结构体
34    Point point = {
35        .x = 0,
36        .y = 0,
37        .move_up = move_up,
38        .move_down = move_down,
39        .move_left = move_left,
40        .move_right = move_right
41    };
42
43    // 调用结构体中的函数
44    point.move_up(10);
45    point.move_right(5);
46
47    return 0;
48}

在上面的示例代码中,我们定义了一个结构体Point,其中包含了两个整型变量x和y,以及四个函数指针move_up、move_down、move_left和move_right。每个函数指针指向一个移动函数,用于在平面坐标系中移动点的位置。通过使用结构体封装函数,我们可以将函数和数据封装在一起,方便地进行操作和管理。

在main()函数中,我们首先通过初始化的方式,将结构体中的成员变量和函数指针初始化。然后,我们使用结构体中的函数指针,调用了move_up()和move_right()函数,分别将点向上移动10个单位和向右移动5个单位。

值得注意的是,在实际应用中,我们需要根据实际情况修改函数的实现,以及结构体中的成员变量和函数指针的数量和类型。同时避免滥用。

举例2

 1typedef struct {
 2    void (*init)(void);
 3    void (*write)(uint8_t data);
 4    uint8_t (*read)(void);
 5} spi_t;
 6
 7void spi_init(void) {
 8    /* SPI初始化代码 */
 9}
10
11void spi_write(uint8_t data) {
12    /* SPI写入数据 */
13}
14
15uint8_t spi_read(void) {
16    /* SPI读取数据 */
17}
18
19int main(void) {
20    spi_t spi = {spi_init, spi_write, spi_read};
21
22    spi.init();
23    spi.write(0xAA);
24    uint8_t data = spi.read();
25
26    return 0;
27}

在举例2这个例子中,我们定义了一个spi_t类型的结构体,它包含了三个成员函数指针,分别对应SPI总线的初始化、写入和读取操作。在main函数中,我们定义了一个spi结构体变量,并且初始化它的函数指针成员。接下来,我们通过spi结构体变量的函数指针成员,分别调用了SPI总线的初始化、写入和读取操作。

使用结构体封装函数可以使代码更加清晰明了,减少了代码的冗余和重复,同时也方便代码的扩展和维护。

举例3

假设我们需要控制一个LED灯的亮度,可以使用PWM(脉冲宽度调制)技术来实现。为了方便控制,我们可以使用一个结构体来封装控制LED灯的函数和变量。

 1typedef struct {
 2    uint8_t duty_cycle;     // 占空比
 3    void (*set_duty_cycle)(uint8_t duty_cycle);  // 设置占空比的函数指针
 4    void (*start)(void);    // 启动PWM输出的函数指针
 5    void (*stop)(void);     // 停止PWM输出的函数指针
 6} pwm_control_t;
 7
 8// 设置占空比
 9void set_duty_cycle(uint8_t duty_cycle) {
10    // 设置占空比的代码
11}
12
13// 启动PWM输出
14void start_pwm(void) {
15    // 启动PWM输出的代码
16}
17
18// 停止PWM输出
19void stop_pwm(void) {
20    // 停止PWM输出的代码
21}
22
23int main(void) {
24    pwm_control_t pwm;
25
26    pwm.duty_cycle = 50;   // 设置占空比为50%
27    pwm.set_duty_cycle = set_duty_cycle;
28    pwm.start = start_pwm;
29    pwm.stop = stop_pwm;
30
31    pwm.set_duty_cycle(pwm.duty_cycle);  // 设置占空比
32    pwm.start();  // 启动PWM输出
33
34    while (1) {
35        // 循环执行其他任务
36    }
37}

在上面的代码中,我们定义了一个名为pwm_control_t的结构体,其中包含了一个占空比成员变量duty_cycle和三个函数指针set_duty_cycle、start和stop。set_duty_cycle函数用于设置占空比,start函数用于启动PWM输出,stop函数用于停止PWM输出。

在main函数中,我们创建了一个pwm_control_t类型的结构体变量pwm,并分别给结构体的成员变量和函数指针赋值。接着,我们调用了set_duty_cycle和start函数来设置占空比和启动PWM输出。

结构体封装函数的好处在于,我们可以通过创建不同的结构体变量来控制多个LED灯,而且不同的LED灯可以使用不同的PWM参数。此外,如果需要修改PWM输出的实现方式,只需要修改start和stop函数即可,而不需要修改每个LED灯。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2213498.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

spring:Springboot3使用模版引擎thymeleaf

文章目录 介绍语法1、文本替换2、属性替换3、条件判断4. 列表循环5. 表单处理 基本示例视图解析机制视图解析器的默认配置为什么用Controller可以,用RestController就只是返回字符串 介绍 Thymeleaf 是一个现代的服务器端 Java 模板引擎,用于在服务器端…

掌握这几款在线音频剪辑工具,轻松成为音频处理达人!

在数字时代,音频剪辑已经成为一项必备技能。无论是制作短视频、播客,还是进行音乐创作,一款好用的音频剪辑工具都能助你事半功倍。今天,我们就来为大家推荐几款实用的在线音频剪辑工具,让你轻松成为音频处理达人&#…

救命!后悔没早点读,自学Python,这本书永远的神,经典又好懂!

这是一本对新手来说很友好的入门书,这本是今年才出的新版,之前的两个版本在某瓣都是9分以上了。专为初学者设计,同时也适合有编程经验的读者。该书由Eric Matthes编写,内容涵盖Python基础语法、编程概念以及丰富的实践项目。 全书…

【工具变量】文明城市评选DID(2000-2023年)

数据简介: 随着城市化的不断推进和全球城际竞争的日益激烈,城市品牌成为争夺优质资源、推动城市可持续发展的重要战略工具。通过关注城市品牌建设,不仅可以刺激本地企业家更多地进行创新活动,为企业家创新活动提供更好的营商环境…

自回溯天线:实现波束自动跟踪的智能天线系统

自回溯天线:实现波束自动跟踪的智能天线系统 1. 引言 自回溯天线是一种能够自动将接收到的信号发射回信号源方向的智能天线系统。它基于相位共轭原理,无需复杂的信号处理和控制系统,就能实现波束的自动跟踪。 自回溯天线技术依靠纯模拟方式实现,通过共轭模块对入射…

vue3中如何更改当前类的文件名称

首先&#xff0c;使用script指定文件名称 <template><div class"person"><h2>姓名&#xff1a;{{ name }}</h2><h2>年龄&#xff1a;{{ age }}</h2><button click"showTel">查看联系方式</button><bu…

【含文档】基于Springboot+Vue的招投标管理系统(含源码+数据库+lw)

1.开发环境 开发系统:Windows10/11 架构模式:MVC/前后端分离 JDK版本: Java JDK1.8 开发工具:IDEA 数据库版本: mysql5.7或8.0 数据库可视化工具: navicat 服务器: SpringBoot自带 apache tomcat 主要技术: Java,Springboot,mybatis,mysql,vue 2.视频演示地址 3.功能 系统定…

如何恢复误删除的照片?能恢复多少?

最近在旅行时不小心删除了相机里之前拍摄的照片&#xff0c;我尝试在相机上恢复&#xff0c;但是没有找到恢复选项。我还能恢复这些照片吗&#xff1f;求助&#xff01; 一、照片恢复的可能性 照片恢复的可能性取决于多个因素&#xff0c;包括数据是否被覆盖、存储介质的类型、…

C语言笔记 10

求前n项之和 程序设计 f(n)1… 起点终点数字已知&#xff0c;用for循环最合适 #include <stdio.h>int main() {int n;int i;double sum 0.0;scanf("%d", &n);for ( i1; i<n; i ) {sum 1.0/i;}pritnf("f(%d)%f\n", n, sum);return 0; } i…

宿舍离人自动断电控制系统的功能要求是什么?

宿舍离人自动断电系统&#xff0c;由石家庄光大远通电气有限公司匠心打造&#xff0c;专为集体公寓、学生宿舍等密集型居住空间量身定制的智能用电管理解决方案&#xff0c;其卓越性能与广泛适应性&#xff0c;如同智慧之网&#xff0c;精准覆盖并优化每一份用电需求。该系统不…

八卦GPT-5的一切

这篇超长文章——既是评论&#xff0c;也是探索——关于GPT-5 对最受期待的下一代 AI 模型的深入分析 但它不仅仅是关于GPT-5。 • 它涉及我们对下一代AI模型的期望。 • 它关于即将出现的令人兴奋的新功能&#xff08;如推理和代理&#xff09;。它不仅讨论GPT-5技术本身&…

人工智能领域科学问题

科学问题 目前中国在人工智能领域亟待解决的问题包括但不限于以下几个方面&#xff1a; 数据隐私和安全&#xff1a;随着人工智能技术的发展&#xff0c;个人数据的收集和使用越来越广泛&#xff0c;如何保护个人隐私和数据安全成为一个重要问题。 伦理和道德问题&#xff1…

初试PostgreSQL数据库

文章目录 一、PostgreSQL数据库概述1.1 PostgreSQL的历史1.2 PostgreSQL安装1.3 安装PostgreSQL二、PostgreSQL起步2.1 连接数据库2.1.1 SQL Shell2.1.2 执行SQL语句2.2 pgAdmin 42.2.1 打开pgAdmin 42.2.2 查找数据库2.2.3 打开查询工具2.2.4 执行SQL语句三、实战小结文章目录…

LLM-生成器判别器的实现

总结 首先&#xff0c;使用GPT模型获取每个词的生成概率 pLLMp_{LLM}pLLM​。然后&#xff0c;使用训练好的生成判别器&#xff0c;对每个可能的生成结果进行打分&#xff0c;得到 pθ(c∣x1:t)p_\theta(c|x_{1:t})pθ​(c∣x1:t​)。最后&#xff0c;结合两者的输出&#xff…

JAVA就业笔记6——第二阶段(3)

课程须知 A类知识&#xff1a;工作和面试常用&#xff0c;代码必须要手敲&#xff0c;需要掌握。 B类知识&#xff1a;面试会问道&#xff0c;工作不常用&#xff0c;代码不需要手敲&#xff0c;理解能正确表达即可。 C类知识&#xff1a;工作和面试不常用&#xff0c;代码不…

中科星图GVE(案例)——AI实现道路提取分析

目录 简介 函数 gve.Services.AI.roadExtraction(fromGridRes) 代码 结果 中科星图GVE&#xff08;案例&#xff09;——AI实现道路提取分析 简介 AI实现道路提取分析是指利用人工智能技术&#xff0c;通过对图像或地理数据的处理和分析&#xff0c;自动识别和提取道路信…

创新设计大师项骅:用卓越才华打造医疗科技新未来

项骅,这位在设计界声名鹊起的才俊,正准备在其璀璨的职业生涯中开启一个激动人心的新篇章。近日,他宣布即将进军医疗科技领域,这一决定在设计圈和医疗界引起了广泛关注。项骅计划以UX设计师的身份,致力于改善医疗服务的用户体验。谈到这个新挑战,他显得兴致勃勃:"我期待将我…

WPS没保存关闭了怎么恢复文档数据呢?3个方法让你轻松恢复

在日常的工作和学习中&#xff0c;我们经常会使用WPS Office这款办公软件来处理文档、表格和演示文稿等文件。然而&#xff0c;有时由于各种原因&#xff0c;我们可能会在未保存的情况下关闭了WPS&#xff0c;导致重要的数据丢失。那么&#xff0c;WPS没保存关闭了怎么恢复数据…

图像及视频的基本操作

文章目录 一、认识计算机中的图像二、图像数据的读取三、数据读取-视频四、图像的其他操作 一、认识计算机中的图像 一张彩色图片是由很多个像素点组合而成的&#xff0c;而一个像素点是由R G B三个通道组成。RGB代表红色&#xff08;Red&#xff09;、绿色&#xff08;Green&a…

我常用的两个单例模式写法 (继承Mono和不继承Mono的)

不继承Mono 不继承Mono代表不用挂载到场景物体上面&#xff0c;因此直接饿汉式 加 合并空运算符判空创建实例 >(lambda表达式)的意思是get&#xff0c;就是将instance赋给Instance属性 //单例private static JsonDataManager instance new JsonDataManager();public stati…