找回密码
 立即注册
查看: 403|回复: 10

Keil C51 在small和large模式下如何传递函数指针和参数,且参数个数超过7字节怎么处理

[复制链接]
  • 打卡等级:初来乍到
  • 打卡总天数:9
  • 最近打卡:2025-12-22 09:07:43

10

主题

28

回帖

141

积分

注册会员

积分
141
发表于 2025-12-22 09:07:43 | 显示全部楼层 |阅读模式




函数指针形式
typedef void (code*SendBy485)(uint8 xdata *dat,uint8 len);
typedef uint8 (code*pProtocolFunction)(uint8 len,uint8 xdata*input,uint8 xdata*output);

typedef void (* SendBy485)(uint8 xdata *dat,uint8 len);
typedef uint8 ( * pProtocolFunction)(uint8 len,uint8 xdata*input,uint8 xdata*output);

结构体类型
typedef struct UART{
        uint8 xdata *RecvBuf;
        uint8 xdata *SendBuf;
        uint8 RecvSize;
        uint8 SendSize;
        uint8 RecvCnt;
        uint8 TimeOut;
        uint8 RecvCplFlg;
        pProtocolFunction pAnalysis;
        SendBy485 pSendBy485;
}Uart_t,*pUart;
初始化结构体
void UartInit(pUart uart,uint8 xdata *recv,uint8 xdata *send,uint8 recvLen,uint8 sendLen,pProtocolFunction pAnalysis,SendBy485 pSend)
{
        uart->RecvBuf = recv;
        uart->SendBuf = send;
        uart->RecvSize = recvLen;
        uart->SendSize = sendLen;
        uart->RecvCnt = 0;
        uart->TimeOut = 0;
        uart->RecvCplFlg = 0;
        uart->pAnalysis = pAnalysis;
        uart->pSendBy485 = pSend;
}

uint8 MbSlaveParsing(uint8 len, uint8 xdata *input, uint8 xdata *output) {
//.....省略代码
}
void Uart1SendBy485(uint8 xdata*dat,uint8 len){
//.....省略代码
}
使用
#define U1RXLEN        80
#define U1TXLEN        80

Uart_t xdata Uart1;
uint8 xdata Uart1SendBuf[U1TXLEN];
uint8 xdata Uart1RecvBuf[U1RXLEN];

UartInit(&Uart1,Uart1RecvBuf,Uart1SendBuf,U1RXLEN,U1TXLEN,MbSlaveParsing,Uart1SendBy485);

void UartProcess(pUart uart)
{
        uint8 len = 0;
        if(uart->RecvCplFlg){
                uart->RecvCplFlg = 0;
                if(uart->pAnalysis){
                        uint8 cnt = uart->RecvCnt;
//                        code pProtocolFunction analysisFunc = uart->pAnalysis;
//                        len =  (code pProtocolFunction)(*analysisFunc)(cnt,uart->RecvBuf,uart->SendBuf);
//                        len = (code pProtocolFunction)(uart->pAnalysis)(cnt,uart->RecvBuf,uart->SendBuf);//指针方式调用,跑飞
                        len = MbSlaveParsing(cnt,uart->RecvBuf,uart->SendBuf);//直接执行时正常
                }
                Beep ^= 1;//这里OK
                uart->RecvCnt = 0;
                if(len > 0){
//                        SendBy485 Send = uart->pSendBy485;
//                        (*Send)(uart->SendBuf,len);
//                        uart->pSendBy485(uart->SendBuf,len);//跑飞
                        Uart2SendBy485(uart->SendBuf,len);//正常
                }
        }
}
Keil C51 在small和large模式下如何传递函数指针和参数,且参数个数超过7字节怎么处理?以前好像遇到过,使用reentrant解决的,这次怎么不行了?


回复

使用道具 举报 送花

  • 打卡等级:以坛为家II
  • 打卡总天数:493
  • 最近打卡:2026-04-02 08:56:15
已绑定手机

104

主题

4229

回帖

9395

积分

荣誉版主

无情的代码机器

积分
9395
发表于 2025-12-22 10:00:29 | 显示全部楼层
封装为结构体指针传递,减少参数数量。
三天不学习,赶不上刘少奇~
回复

使用道具 举报 送花

  • 打卡等级:常住居民III
  • 打卡总天数:189
  • 最近打卡:2026-04-02 19:41:58

25

主题

231

回帖

2091

积分

金牌会员

积分
2091
发表于 2025-12-22 10:59:24 | 显示全部楼层
办法一: 通用指针改为指定存储类型的指针,通用指针占4字节,指向xdata的指针占2字节,参数占用字节数下降。
办法二: 函数加 reentrant 标识,可重入函数使用堆栈传递参数,不限参数大小。需注意reentrant函数调用的所有函数也必须是reentrant,否则运行出错。
办法三: 不用函数指针,改为直接调用。函数传参使用可覆盖静态内存地址,不限参数大小。
办法四: 全局变量代替传参。
回复

使用道具 举报 送花

  • 打卡等级:初来乍到
  • 打卡总天数:9
  • 最近打卡:2025-12-22 09:07:43

10

主题

28

回帖

141

积分

注册会员

积分
141
发表于 2025-12-22 14:09:47 | 显示全部楼层
hea*** 发表于 2025-12-22 10:59
办法一: 通用指针改为指定存储类型的指针,通用指针占4字节,指向xdata的指针占2字节,参数占用字节数下降 ...

测试了xdata指针大小是2字节,code指针是3字节;pProtocolFunction是3字节;应该还是参数长度的问题。看到说什么overlay,也没整好。https://blog.csdn.net/DP29syM41zyGndVF/article/details/115878673
https://blog.csdn.net/jemofh159/article/details/6628231
https://blog.csdn.net/weixin_29437633/article/details/117184647
https://download.csdn.net/blog/column/1518615/105653470
https://news.eeworld.com.cn/mcu/article_2016121532347.html
单纯的加reentrant
uint8 MbSlaveParsing(uint8 len, uint8 xdata *input, uint8 xdata *output)  reentrant
{
        uint8 i = 0;
        for(i=0;i<8;i++){
                output[0] = input[0];
        }
        return 8;
}
回复

使用道具 举报 送花

  • 打卡等级:初来乍到
  • 打卡总天数:9
  • 最近打卡:2025-12-22 09:07:43

10

主题

28

回帖

141

积分

注册会员

积分
141
发表于 2025-12-22 17:04:59 | 显示全部楼层
//通过指针调用程序跑飞,为什么?下面直接调用就没有问题
void UartProcess(pUart uart)
{
        uint8 len = 0;
        if(uart->RecvCplFlg){
                uart->RecvCplFlg = 0;
                if(uart->pAnalysis){
                        len = (uart->pAnalysis)(uart->RecvCnt,uart->RecvBuf,uart->SendBuf);
                }
                uart->RecvCnt = 0;
                if(len > 0){
                        if(uart->pSendBy485){
                                (uart->pSendBy485)(uart->SendBuf,len);
                        }
                }
        }
}

void UartProcessLoop(void)
{
        uint8 len = 0;
#ifdef USE_UART1       
//        UartProcess(&Uart1);//通过指针调用程序跑飞,为什么?下面直接执行没有问题
        if(Uart1.RecvCplFlg){
                Uart1.RecvCplFlg = 0;
                if(Uart1.pAnalysis){
                        len = Uart1.pAnalysis(Uart1.RecvCnt,Uart1.RecvBuf,Uart1.SendBuf);
                }
                Uart1.RecvCnt = 0;
                if(len > 0){
                        if(Uart1.pSendBy485){
                                Uart1SendBy485(Uart1.SendBuf,len);
                        }
                }
        }                       
#endif
#ifdef USE_UART2       
//        UartProcess(&Uart2);
        if(Uart2.RecvCplFlg){
                Uart2.RecvCplFlg = 0;
                if(Uart2.pAnalysis){
                        len = Uart2.pAnalysis(Uart2.RecvCnt,Uart2.RecvBuf,Uart2.SendBuf);
                }
                Uart2.RecvCnt = 0;
                if(len > 0){
                        if(Uart2.pSendBy485){
                                Uart2.pSendBy485(Uart2.SendBuf,len);
                        }
                }
        }       
#endif
#ifdef USE_UART3       
//        UartProcess(&Uart3);
        if(Uart3.RecvCplFlg){
                Uart3.RecvCplFlg = 0;
                if(Uart3.pAnalysis){
                        len = Uart3.pAnalysis(Uart3.RecvCnt,Uart3.RecvBuf,Uart3.SendBuf);
                }
                Uart3.RecvCnt = 0;
                if(len > 0){
                        if(Uart3.pSendBy485){
                                Uart3SendBy485(Uart3.SendBuf,len);
                        }
                }
        }               
#endif
#ifdef USE_UART4       
//        UartProcess(&Uart4);
        if(Uart4.RecvCplFlg){
                Uart4.RecvCplFlg = 0;
                if(Uart4.pAnalysis){
                        len = Uart4.pAnalysis(Uart4.RecvCnt,Uart4.RecvBuf,Uart4.SendBuf);
                }
                Uart4.RecvCnt = 0;
                if(len > 0){
                        if(Uart4.pSendBy485){
                                Uart4SendBy485(Uart4.SendBuf,len);
                        }
                }
        }                       
#endif       
}
很奇怪,通过指针调用函数就会跑飞,直接结构体就没问题?
回复

使用道具 举报 送花

  • 打卡等级:初来乍到
  • 打卡总天数:9
  • 最近打卡:2025-12-22 09:07:43

10

主题

28

回帖

141

积分

注册会员

积分
141
发表于 2025-12-22 17:24:33 | 显示全部楼层
        {
                pUart uart = &Uart2;
                if(uart->RecvCplFlg){
                        uart->RecvCplFlg = 0;
                        if(uart->pAnalysis){
                                len = (uart->pAnalysis)(uart->RecvCnt,uart->RecvBuf,uart->SendBuf);
                        }
                        uart->RecvCnt = 0;
                        if(len > 0){
                                if(uart->pSendBy485){
                                        (uart->pSendBy485)(uart->SendBuf,len);
                                }
                        }
                }       
        }
        {
                if(Uart2.RecvCplFlg){
                        Uart2.RecvCplFlg = 0;
                        if(Uart2.pAnalysis){
                                len = Uart2.pAnalysis(Uart2.RecvCnt,Uart2.RecvBuf,Uart2.SendBuf);
                        }
                        Uart2.RecvCnt = 0;
                        if(len > 0){
                                if(Uart2.pSendBy485){
                                        Uart2.pSendBy485(Uart2.SendBuf,len);
                                }
                        }
                }
        }       
这2样都不行,51指针还是太坑了
回复

使用道具 举报 送花

  • 打卡等级:初来乍到
  • 打卡总天数:9
  • 最近打卡:2025-12-22 09:07:43

10

主题

28

回帖

141

积分

注册会员

积分
141
发表于 2025-12-22 17:41:14 | 显示全部楼层
        {
                xdata pUart  uart = &Uart2;
                if(uart->RecvCplFlg){
                        uart->RecvCplFlg = 0;
                        if(uart->pAnalysis){
                                len = (uart->pAnalysis)(uart->RecvCnt,uart->RecvBuf,uart->SendBuf);
                        }
                        uart->RecvCnt = 0;
                        if(len > 0){
                                if(uart->pSendBy485){
                                        (uart->pSendBy485)(uart->SendBuf,len);
                                }
                        }
                }       
        }
这样可以,又有什么用呢
回复

使用道具 举报 送花

  • 打卡等级:以坛为家III
  • 打卡总天数:651
  • 最近打卡:2026-04-02 13:22:49

33

主题

2927

回帖

6597

积分

论坛元老

积分
6597
发表于 2025-12-23 09:17:06 | 显示全部楼层
askhu*** 发表于 2025-12-22 14:09
测试了xdata指针大小是2字节,code指针是3字节;pProtocolFunction是3字节;应该还是参数长度的问题。看 ...

我的记忆中,不仅仅是长度。

在Keil C51的环境下,对于参数的数据类型,不同的类型,会使用R1~R7不同的寄存器进行存储。

从《Keil C51单片机高级语言应用编程与实践》一书有介绍,具体的在第四章 表4-16 参数传递的工作寄存器选择。
截图202512230916581751.jpg

点评

补充官方帮助文档: [attachimg]125953[/attachimg] [attachimg]125954[/attachimg]  详情 回复 发表于 2025-12-23 09:34
参考例程并不是对技术参 考手册的补充,而是对技术参 考手册的解释。
技术参 考手册不应该需要参考例程作为补充,而是解释成了参考例程的样子
回复

使用道具 举报 送花

  • 打卡等级:以坛为家II
  • 打卡总天数:493
  • 最近打卡:2026-04-02 08:56:15
已绑定手机

104

主题

4229

回帖

9395

积分

荣誉版主

无情的代码机器

积分
9395
发表于 2025-12-23 09:34:34 | 显示全部楼层
_奶*** 发表于 2025-12-23 09:17
我的记忆中,不仅仅是长度。

在Keil C51的环境下,对于参数的数据类型,不同的类型,会使用R1~R7不同的 ...

补充官方帮助文档:

截图202512230934037689.jpg
截图202512230934223375.jpg

点评

点赞,,,  发表于 2025-12-23 10:25
三天不学习,赶不上刘少奇~
回复

使用道具 举报 送花

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

QQ|手机版|深圳国芯人工智能有限公司 ( 粤ICP备2022108929号-2 )

GMT+8, 2026-4-2 21:06 , Processed in 0.127365 second(s), 85 queries .

Powered by Discuz! X3.5

© 2001-2026 Discuz! Team.

快速回复 返回顶部 返回列表