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解决的,这次怎么不行了?
封装为结构体指针传递,减少参数数量。
办法一: 通用指针改为指定存储类型的指针,通用指针占4字节,指向xdata的指针占2字节,参数占用字节数下降。
办法二: 函数加 reentrant 标识,可重入函数使用堆栈传递参数,不限参数大小。需注意reentrant函数调用的所有函数也必须是reentrant,否则运行出错。
办法三: 不用函数指针,改为直接调用。函数传参使用可覆盖静态内存地址,不限参数大小。
办法四: 全局变量代替传参。 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;
} //通过指针调用程序跑飞,为什么?下面直接调用就没有问题
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
}
很奇怪,通过指针调用函数就会跑飞,直接结构体就没问题? {
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指针还是太坑了 {
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);
}
}
}
}
这样可以,又有什么用呢
askhua520 发表于 2025-12-22 14:09
测试了xdata指针大小是2字节,code指针是3字节;pProtocolFunction是3字节;应该还是参数长度的问题。看 ...
我的记忆中,不仅仅是长度。
在Keil C51的环境下,对于参数的数据类型,不同的类型,会使用R1~R7不同的寄存器进行存储。
从《Keil C51单片机高级语言应用编程与实践》一书有介绍,具体的在第四章 表4-16 参数传递的工作寄存器选择。
_奶咖君_ 发表于 2025-12-23 09:17
我的记忆中,不仅仅是长度。
在Keil C51的环境下,对于参数的数据类型,不同的类型,会使用R1~R7不同的 ...
补充官方帮助文档:
页:
[1]