C语言 如何使用void(* F)(void)

t98cgbkg  于 2023-11-16  发布在  其他
关注(0)|答案(2)|浏览(149)

我有一个RTOS API,它看起来像这样:ISRInstall(int ISRnum,void(*FUNC)(void)).然而我想要的回调函数是void task(void*),因为我需要数据输入来计算。
该平台是一个SOC与Cortex-A9双核HPS与裸金属BMP支持的RTOS。
API制作人建议我用蹦床作为入口,以下是NEW BING给我的解决方案

#include <stdio.h> 

typedef struct {
    void (*func)(void*); 
    int data; 
} Callback; 

static void trampoline(void* arg) {
    Callback* cb = (Callback*)arg;
    cb->func(&(cb->data));
}

void task(void* arg) 
{
    int* data = (int*)arg;
    // using arg to do some calculations
}

// A given API
void ISRinstall(int ISRnum, void (*FUNC)(void));

int main() {
    int task_data = 42;
    Callback cb;
    cb.func = task;
    cb.data = task_data;
    ISRinstall(1, trampoline);
    trampoline(&cb);
    return 0;
}

字符串
那么,用蹦床作为void(* F)(void)的入口来传递函数是否正确呢?
如果不是,那么如何使用蹦床函数来安排带有arg的函数作为回调函数?
谢谢你

azpvetkf

azpvetkf1#

用蹦床作为void(* F)(void)的入口来传递函数与元素是否正确?
传递上下文的正确方法是使用全局变量。回调不接受任何上下文。由于ISR本身就是“全局”的,因此处理信号是必须使用全局变量的情况之一。
通常你写一个 Package 器有一个好的接口,沿着这一点,这可以简化,如果有一个接口,以获得触发ISR内的处理程序。

// ----- C HAL
void ISRinstall(int ISRnum, void (*FUNC)(void));
enum { MAX_NUMBER_OF_ISRS = 5 };

// ------ your library 
void *cookies[MAX_NUMBER_OF_ISRS] = {0};
void (*callbacks[MAX_NUMBER_OF_ISRS])(void *cookie) = {0};
static void trampoline_1(void) { callbacks[1](cookies[1]); }
static void trampoline_2(void) { callbacks[2](cookies[2]); }
static void trampoline_3(void) { callbacks[3](cookies[3]); }
/* etc */
void yourISRinstall(int isr, void (*cb)(void *cookie), void *cookie) {
    callbacks[isr] = cb;
    cookies[isr] = cookie;
    switch (isr) {
    case 1: ISRinstall(isr, trampoline_1); break;
    case 2: ISRinstall(isr, trampoline_2); break;
    case 3: ISRinstall(isr, trampoline_3); break;
    /* etc. */
    }
}

// -------------------------

#include <stdio.h>
int data;
void task(void* arg) {
    int* data = (int*)arg;
    printf("The data is %d\n", *data);
}
int main() {
   yourISRinstall(1, task, &data);
}

字符串
真实的生活例子:https://github.com/ARMmbed/mbed-os/blob/master/targets/TARGET_STM/gpio_irq_api.c#L220。

62lalag4

62lalag42#

你的回调函数是没有意义的。ISR总是一个没有参数和没有返回值的函数。如果这里的目标是注册一个由ISR调用的回调,它仍然是没有意义的,因为你绝对不应该在ISR内部调用printf
您需要重写task,使其成为可以作为ISR/从ISR调用的对象,这取决于ISRinstall应该做什么。没有办法绕过它。第1步是研究中断如何工作以及中断使用的最佳实践。

相关问题