askhua520 发表于 2025-12-22 09:07:43

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





函数指针形式
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;
uint8 xdata Uart1RecvBuf;

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解决的,这次怎么不行了?


ercircle 发表于 2025-12-22 10:00:29

封装为结构体指针传递,减少参数数量。

health 发表于 2025-12-22 10:59:24

办法一: 通用指针改为指定存储类型的指针,通用指针占4字节,指向xdata的指针占2字节,参数占用字节数下降。
办法二: 函数加 reentrant 标识,可重入函数使用堆栈传递参数,不限参数大小。需注意reentrant函数调用的所有函数也必须是reentrant,否则运行出错。
办法三: 不用函数指针,改为直接调用。函数传参使用可覆盖静态内存地址,不限参数大小。
办法四: 全局变量代替传参。

askhua520 发表于 2025-12-22 14:09:47

health 发表于 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 = input;
        }
        return 8;
}

askhua520 发表于 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       
}
很奇怪,通过指针调用函数就会跑飞,直接结构体就没问题?

askhua520 发表于 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指针还是太坑了

askhua520 发表于 2025-12-22 17:41:14

        {
                xdata pUartuart = &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);
                                }
                        }
                }       
        }
这样可以,又有什么用呢

_奶咖君_ 发表于 2025-12-23 09:17:06

askhua520 发表于 2025-12-22 14:09
测试了xdata指针大小是2字节,code指针是3字节;pProtocolFunction是3字节;应该还是参数长度的问题。看 ...

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

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

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

ercircle 发表于 2025-12-23 09:34:34

_奶咖君_ 发表于 2025-12-23 09:17
我的记忆中,不仅仅是长度。

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

补充官方帮助文档:



页: [1]
查看完整版本: Keil C51 在small和large模式下如何传递函数指针和参数,且参数个数超过7字节怎么处理