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

在嵌入式系统中,结构体封装函数可以用于对于嵌入式硬件资源进行抽象和封装,从而提高软件的可维护性和可移植性。结构体封装函数通常包含数据和行为,并提供了对数据的访问和操作方法。
比如可以将硬件驱动函数封装在结构体中,方便对外提供统一的api接口,同时也便于代码的移植和扩展。另外,结构体封装函数还可以用于实现状态机、任务调度等复杂的系统功能。
在c语言中,结构体不仅可以封装数据,还可以封装函数指针。这种方式可以用于实现回调函数、状态机等,提高代码的复用性和可维护性。特别是在嵌入式当中,应用是非常多的。
结构体封装函数的作用:
将函数指针和参数打包成一个结构体,实现了代码的模块化和可复用性。在结构体中可以定义多个函数指针,实现了对函数的分类管理和调用。结构体可以作为函数的参数或返回值,传递和返回函数指针和参数。结构体封装函数的应用:
回调函数:将函数指针和参数打包成一个结构体,传递给api函数,在api函数内部执行该函数。状态机:将每个状态对应的处理函数封装成一个结构体,根据当前状态调用相应的处理函数。事件驱动:将事件处理函数封装成一个结构体,通过事件触发调用相应的处理函数。线程池:将任务处理函数封装成一个结构体,加入任务队列后由线程池调用执行结构体封装函数的好处:
更好的隐藏实现细节:结构体封装函数使得函数的实现细节被封装在结构体内部,只有结构体暴露给外部的函数指针,实现了良好的封装和信息隐藏。更加灵活的函数调用:函数指针可以被动态修改,从而实现动态的函数调用。例如,在状态机中,根据不同的状态,可以将相应的处理函数指针赋值给一个函数指针变量,从而实现状态的转换和函数的调用。更加方便的扩展性:结构体封装函数可以轻松地添加新的函数指针,从而扩展功能。在需要添加新功能时,只需要定义一个新的函数指针,并添加到结构体中,就可以实现功能的扩展,而不需要修改原有的代码。更加通用的代码:结构体封装函数可以使用于各种不同的编程范式,例如面向对象编程(oop)和函数式编程(fp),从而实现通用的代码。例如,在oop中,结构体可以被看作是一个对象,函数指针可以被看作是对象的方法,从而实现oop编程的思想。更加易于维护:结构体封装函数使得代码更加清晰、易于维护和修改。由于函数指针的定义和使用都在结构体内部,因此修改或调整代码时,只需要修改结构体中的函数指针定义或调用方式,而不需要修改其他部分的代码,从而使得代码更加健壮、易于维护和修改模块化:通过结构体封装函数,可以将多个函数和数据结构组合成一个模块,以便于模块化设计和维护。这种方法可以将代码的复杂性分解到不同的模块中,降低了代码的耦合性,提高了代码的可读性和可维护性。代码复用:结构体封装的函数可以通过传递结构体的方式重用同一个函数。这种方式可以大大减少代码量,提高代码的复用性和可维护性。可扩展性:当需要增加新的功能时,只需增加新的函数和数据结构,而不需要修改现有代码。这种方式可以大大减少代码的修改和调试时间,提高代码的可扩展性和可维护性。保护数据:通过结构体封装函数,可以将数据和函数封装在一个结构体中,防止外部代码对数据的非法访问和修改。提高安全性:将函数和数据封装在一个结构体中,可以防止其他函数对数据的非法操作,从而提高程序的安全性。举例1
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;1011// 定义结构体中的函数12void move_up(int steps) {13 // 向上移动steps个单位14 // ...15}1617void move_down(int steps) {18 // 向下移动steps个单位19 // ...20}2122void move_left(int steps) {23 // 向左移动steps个单位24 // ...25}2627void move_right(int steps) {28 // 向右移动steps个单位29 // ...30}3132int 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_right41 };4243 // 调用结构体中的函数44 point.move_up(10);45 point.move_right(5);4647 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}1011void spi_write(uint8_t data) {12 /* spi写入数据 */13}1415uint8_t spi_read(void) {16 /* spi读取数据 */17}1819int main(void) {20 spi_t spi = {spi_init, spi_write, spi_read};2122 spi.init();23 spi.write(0xaa);24 uint8_t data = spi.read();2526 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}1213// 启动pwm输出14void start_pwm(void) {15 // 启动pwm输出的代码16}1718// 停止pwm输出19void stop_pwm(void) {20 // 停止pwm输出的代码21}2223int main(void) {24 pwm_control_t pwm;2526 pwm.duty_cycle = 50; // 设置占空比为50%27 pwm.set_duty_cycle = set_duty_cycle;28 pwm.start = start_pwm;29 pwm.stop = stop_pwm;3031 pwm.set_duty_cycle(pwm.duty_cycle); // 设置占空比32 pwm.start(); // 启动pwm输出3334 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灯。

一名爬虫工程师的自白
RFID的发展史!RFID技术已大规模应用的案例
如何实现单车智能与V2X融合协同控制功能研究与验证?
HDYZ-102避雷器用监测器测试仪操作参考接线
避免EMC故障应该如何设计
嵌入式C语言之结构体封装函数说明
享受夜晚的美丽,FP7208升压恒流LED驱动IC为户外太阳能超亮LED灯带的温暖
盘点CAN节点设计时应注意的要点
MAX917 - MAX920可不带电压基准的超摆幅功率比较
潍坊打造“北方机器人小镇”;2018动力电池单笔投资最高达500亿
千元机红米Note 5支持双摄 娱乐兔跑分11万
新充电器解决方案可实现更高的电池组电压和更高的充电效率
不同激光切割的基础知识汇总
微米级拆解 揭开“齐刘海”面纱,探索人脸识别技术
安科瑞为北京冬奥会场馆供电保电提供解决方案
新型LED驱动器集成电路HV9925的主要参数及功能
BBWF2023|广和通发布Wi-Fi 7模组WN170-GL
评估PCB设计的相关因素
多功能室内环境监测系统方案_实现多参数检测
车载USB充电管理与变换电路详解 —电路图天天读(185)