问小白 wenxiaobai
资讯
历史
科技
环境与自然
成长
游戏
财经
文学与艺术
美食
健康
家居
文化
情感
汽车
三农
军事
旅行
运动
教育
生活
星座命理

函数指针在嵌入式系统中的常见用法

创作时间:
作者:
@小白创作中心

函数指针在嵌入式系统中的常见用法

引用
CSDN
1.
https://blog.csdn.net/qq_48938498/article/details/140758223

函数指针在嵌入式系统中是一种非常重要的编程技术,它可以帮助开发人员编写出更加灵活、可重用和可维护的代码。本文将详细介绍函数指针在嵌入式系统中的四种常见用法:回调函数、多态实现、函数表和状态机,并通过具体的代码示例帮助读者更好地理解这些概念。

一、前言

在嵌入式系统中,函数指针的使用是比较常见的,它可以帮助我们写出更加灵活和通用的代码,并且提高代码的可维护性。这里对常见的函数指针用法进行一下总结,并结合具体代码进行分析。

二、常见用法

1. 回调函数

在嵌入式系统中,回调函数是由某个模块在特定事件发生时调用的函数,通过函数指针传递,当把函数指针作为参数传递给其他函数,后者会回调用户的函数。这个过程分为三步,首先是中断或事件处理逻辑过程,第二步是保存函数指针,当事件或中断发生时会调用函数指针,第三步是注册回调函数,也就是函数指针的初始化,这里会让函数指针指向第一步中的函数。


这是用户函数执行的内容。


保存函数指针,并且把数据通过函数指针传回去。

这里我们对函数指针进行初始化,相当于注册回调函数的过程。

2. 多态的实现

函数指针可以用来实现类似于面向对象编程中的多态行为,不同的设备驱动可以通过函数指针来实现相同的接口,这里以编写UART和I2C的驱动为例。

// 设备驱动接口定义
typedef struct {
    void (*init)(void);
    void (*send)(uint8_t *data, uint16_t length);
    void (*receive)(uint8_t *data, uint16_t length);
} DeviceDriver;  

这里定义了一个简单的驱动框架,包括初始化、发送和接收。 然后分别实现UART和I2C的初始化函数,发送函数和接收函数,可以通过选择不同的DeviceDriver结构体来切换设备驱动,从而实现灵活的驱动管理。这里以串口为例。

// 定义UART设备驱动
DeviceDriver uartDriver = {
    .init = UART_Init,
    .send = UART_Send,
    .receive = UART_Receive
};

// 定义I2C设备驱动
DeviceDriver i2cDriver = {
    .init = I2C_Init,
    .send = I2C_Send,
    .receive = I2C_Receive
};

// 选择当前使用的设备驱动
DeviceDriver *currentDriver;

// 示例:使用UART设备驱动
currentDriver = &uartDriver;
currentDriver->init();
uint8_t uartDataToSend[] = {0x11, 0x22, 0x33};
currentDriver->send(uartDataToSend, sizeof(uartDataToSend));
uint8_t uartDataToReceive[3];
currentDriver->receive(uartDataToReceive, sizeof(uartDataToReceive));

// 示例:使用I2C设备驱动
currentDriver = &i2cDriver;
currentDriver->init();
uint8_t i2cDataToSend[] = {0x44, 0x55, 0x66};
currentDriver->send(i2cDataToSend, sizeof(i2cDataToSend));
uint8_t i2cDataToReceive[3];
currentDriver->receive(i2cDataToReceive, sizeof(i2cDataToReceive));

这种方式使得代码更加模块化和易于维护,同时可以在不修改应用代码的情况下,方便地替换和升级设备驱动。

3. 函数表

函数表是一组函数指针的集合,一般用函数指针数组表示,可以用来调用不同的函数,实现多态行为或者接口抽象。

// 实现一个小型计算器的代码,用switch case结构来实现加减乘除运算的选择
switch (oper)
{
    case ADD:
        result = add(op1,op2);
        break;
    case SUB:
        result = sub(op1,op2);
        break;
    case MUL:
        result = mul(op1,op2);
        break;
    case DIV:
        result = div(op1,op2);
        break;
    default:break;
}
double add(double,double);
double sub(double,double);
double mul(double,double);
double div(double,double);

这是实现一个小型计算器的代码,用switch case结构来实现加减乘除运算的选择,这里用函数表对这个过程实现简化。

double (*oper_func[])(double,double) = {add,sub,mul,div};
result = oper_func[oper](op1,op2);  

oper从数组中选择正确的函数指针,函数调用操作符将执行这个函数。

4. 状态机

状态机用于控制系统的状态转换和行为,函数指针可以用来实现状态机的状态转换函数。

typedef void (*StateFunc)(void);
// 定义状态函数
void stateA(void);
void stateB(void);
// 定义状态机结构
typedef struct {
    StateFunc currentState;
} StateMachine;
void stateA(void) {
    printf("State A\n");   
    stateMachine.currentState = stateB;
}
void stateB(void) {
    printf("State B\n");
    stateMachine.currentState = stateA;
}
int main() {
    StateMachine stateMachine;
    stateMachine.currentState = stateA;
    // 运行状态机
    for (int i = 0; i < 10; ++i) {
        stateMachine.currentState();
        // 模拟状态切换
        stateMachine.currentState = (stateMachine.currentState == stateA) ? stateB : stateA;
    }
}

三、总结

函数指针在嵌入式系统中有广泛的应用,通过使用函数指针,可以提高代码的灵活性、可重用性和可维护性。最后,如有错误,欢迎指正!

© 2023 北京元石科技有限公司 ◎ 京公网安备 11010802042949号