[C语言] 单片机回调函数请教:怎样获取其它文件的函数的地址

[复制链接]
 楼主| panxiaoyi 发表于 2023-3-27 22:20 | 显示全部楼层 |阅读模式
  1. //interrupt.h 文件,由甲方编写

  2. #ifndef INTERRUPT_H
  3. #define INTERRUPT_H

  4. void interrupt(void);
  5. void add(void);

  6. #endif
  1. //interrupt.c 文件,由甲方编写

  2. #include "interrupt.h"

  3. void interrupt(void)
  4. {
  5.         void (*func)();
  6.         func=add;
  7.         func();
  8.         add();
  9. }
  1. //main.c文件,由乙方编写

  2. #include <stdio.h>
  3. #include <stdlib.h>
  4. #include "interrupt.h"

  5. //==============================

  6. void add(void)
  7. {
  8.         static int test;
  9.         test++;
  10.         printf("test=%d\n",test);
  11. }

  12. //==============================

  13. int main(void)
  14. {
  15.         interrupt();
  16.         return 0;
  17. }

  18. //end
运行结果:
test=1
test=2



 楼主| panxiaoyi 发表于 2023-3-27 22:24 | 显示全部楼层
请教:如果甲方不知道乙方的函数名是 add,那么,甲方怎样才能运行乙方的add函数,就是说,甲方怎样获取乙方的add函数的地址?
 楼主| panxiaoyi 发表于 2023-3-27 22:40 | 显示全部楼层
本帖最后由 panxiaoyi 于 2023-3-27 22:45 编辑
  1. //函数 interrupt() 是模拟单片机中断运行函数 ,是由甲方编写的底层函数
  2. //甲方的目的是要在中断里面调用乙方的用户层面的函数
  3. //我现在遇到的问题是:甲方是底层开发,乙方是用户层开发,所以,甲方不知道用户函数名叫add
  4. //所以,如果甲方没有下面两条语句 那么,甲方是怎样去获取乙方的函数的地址呢
  5.   func=add;
  6.   void add(void);
  7. //我看了很多网上的回调函数的例子,这些例子要么是在同一个C文件内完成,要么非常的复杂,看不懂。
  8. //请教,谢谢

banyai 发表于 2023-3-28 08:03 | 显示全部楼层
把interrupt()函数写成需要传入函数指针参数就可以啊。
computer00 发表于 2023-3-28 09:27 | 显示全部楼层
本帖最后由 computer00 于 2023-3-28 19:57 编辑

可以让甲方给你增加一个注册中断回调函数的接口,等中断发生时,就可以回调到乙方定义的函数了。例如:
/////////////////////////////////// interrupt.c ///////////////////////////////////////
typedef int (*IsrCallbackFuncType)(int id, void *data);

#define CONFIG_MAX_INTS 8
static IsrCallbackFuncType sgIsrCbTab[CONFIG_MAX_INTS];
static void* sgIsrCbData[CONFIG_MAX_INTS];

int registerInterruptCallback(int intId, IsrCallbackFuncType callbackFunc, void *pData) {
    if (intId < 0 || intId >= CONFIG_MAX_INTS) {
        return -1;
    }

    sgIsrCbTab[intId] = callbackFunc;
    sgIsrCbData[intId] = pData;

    return 0;
}

void interrupt(void) {
    int id = 0;

    // do something, eg. id = getIntId();

    if (sgIsrCbTab[id] != 0) {
        int ret = sgIsrCbTab[id](id, sgIsrCbData[id]);
    }

    // do something, eg. clean int flag
}


//////////////////////////////////////////////// main.c ////////////////////////////////////////////
typedef int (*IsrCallbackFuncType)(int id, void *data);
int registerInterruptCallback(int intId, IsrCallbackFuncType callbackFunc, void *pData);

int timerIsrCb(int id, void *data) {
    printf("%s, %d: id = %d, data = '%s'\n", __FUNCTION__, __LINE__, id, (char *)data);
}

void main(void) {
    char buffer[128] = {"Hello LSTM"};
    int ret = registerInterruptCallback(0, timerIsrCb, (void *)buffer);
}
gyh974 发表于 2023-3-28 11:55 | 显示全部楼层
这样做有什么好处,为什么要分开两边写,还不能沟通
ayb_ice 发表于 2023-3-28 13:01 | 显示全部楼层
一般是建个数组,数组中存放函数地址,数组使用绝对定位就可以了
timerc 发表于 2023-3-28 15:25 | 显示全部楼层
正常库一般会有头文件的啊,头文件里面有函数名,库里面是函数实现,调用要看头文件里面的函数调用,不是瞎蒙吧。不同层之间,你要有头文件,不然你怎么知道哪个函数符合要求可以用。。。。乱写一通??
sanzi666 发表于 2023-3-28 17:57 | 显示全部楼层
不知道函数名字,怎么把函数指针指向函数入口地址,
除非强制定义地址,然后调用,
 楼主| panxiaoyi 发表于 2023-3-29 13:17 | 显示全部楼层
多谢大家,特别是 5楼 computer00,我会好好的学习的,就是不知道能不能看的懂,后面会继续反馈的
 楼主| panxiaoyi 发表于 2023-3-29 13:31 | 显示全部楼层
gyh974 发表于 2023-3-28 11:55
这样做有什么好处,为什么要分开两边写,还不能沟通

回复6楼,因为我现在在写小工程,渐渐的发现,工程全局变量真的越少越好,多了就容易引起逻辑混乱,查错困难。后来又发现,硬件底层很多时候需要调用应用层的函数,于是,就学习到了回调函数,现在就卡在这里了。
需要说明的是,我现在写的基本上都是8位机的代码,但是工程很多,需要经常移植,所以,上面的问题就很自然的浮出水面了
 楼主| panxiaoyi 发表于 2023-4-2 17:46 | 显示全部楼层
下面是我的理解,如果大家有空,请帮我看看是否正确,谢谢
  1. //interrupt.h 文件,由甲方编写

  2. #ifndef INTERRUPT_H
  3. #define INTERRUPT_H

  4. void interrupt(void);
  5. void CallBackRegister(void(*func2)());

  6. #endif

  1. //interrupt.c                            //模拟单片机中断文件,由甲方编写

  2. #include "interrupt.h"

  3. static void (*func3)();                  //定义函数指针变量(产生代码,非声明)
  4.               
  5. //==============================

  6. void CallBackRegister(void(*func2)()) {  //定义注册函数,给乙方使用
  7.         func3 = func2;                       //记忆乙方的函数地址,这就是回调函数注册
  8. }

  9. //==============================

  10. void interrupt(void) {
  11.         void (*func)();                      //定义局部函数指针变量
  12.         func = func3;                        //将上面注册进来的地址赋值测试
  13.         func();                              //通过指针,运行被调用的函数
  14.         add();                               //普通方式,直接调用函数
  15. }

  16. //==============================

  17. /*
  18. 请教:

  19. 1:
  20. 请问,这里的甲方是不是(必须)要定义一个本文件的全局函数指针变量 func3
  21. 然后,注册函数 CallBackRegister 和 中断函数 interrupt 共用这个变量,
  22. 这样甲方才能"知道"和"运行"乙方传进来的函数

  23. 2:
  24. 我在代码上的注释是否正确,因为它代表了我的理解。谢谢
  25. */

  1. //main.c                           //main.c 文件,由乙方编写

  2. #include <stdio.h>
  3. #include "interrupt.h"

  4. //==============================

  5. void add(void) {                   //定义被调用的函数,这个函数叫“回调函数”
  6.         static int test;               //测试变量
  7.         test++;                        //变量++
  8.         printf("test=%d\n", test);     //输出显示
  9. }

  10. //==============================

  11. int main(void) {                   //用户(乙方)的主函数
  12.         CallBackRegister(add);         //注册回调函数,就是把add函数的地址告诉甲方
  13.         interrupt();                   //模拟单片机进入中断服务函数
  14.         return 0;
  15. }

  16. //end


 楼主| panxiaoyi 发表于 2023-4-2 17:49 | 显示全部楼层
代码截图

本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有账号?注册

×
zwsam 发表于 2023-12-30 00:08 | 显示全部楼层
zwsam 发表于 2023-12-30 00:08 | 显示全部楼层
zwsam 发表于 2023-12-30 00:08 | 显示全部楼层
您需要登录后才可以回帖 登录 | 注册

本版积分规则

53

主题

414

帖子

2

粉丝
快速回复 在线客服 返回列表 返回顶部

53

主题

414

帖子

2

粉丝
快速回复 在线客服 返回列表 返回顶部