XMC1100平台Modbus库动态缓冲区大小设置异常问题咨询
问题
在英飞凌32位ARM XMC1100芯片上用Keil开发Modbus从站库时遇到以下异常:
库中定义了MODBUS_INIT初始化结构体,用户可通过其中的TX_BUFF_SIZE字段配置发送缓冲区大小,库内函数通过该值定义局部缓冲区,但出现了缓冲区大小阈值问题:
modbus.c 核心代码
uint8_t MODBUS_SLAVE_DATA[MODBUS_HANDLER->TX_BUFF_SIZE];
modbus.h 结构体定义
typedef struct { // GENERAL INFORMATION uint8_t SLAVE_ADDRESS; uint16_t TX_BUFF_SIZE; bool BROADCAST; // HOLDING REGISTERS uint16_t *HOLDING_REGISTERS_W; size_t HOLDING_REGISTERS_W_SIZE; uint16_t *HOLDING_REGISTERS_R; size_t HOLDING_REGISTERS_R_SIZE; // COILS bool *COILS_W; size_t COILS_W_SIZE; bool *COILS_R; size_t COILS_R_SIZE; // DISCERETE INPUTS bool *DISCERETE_INPUT; size_t DISCERETE_INPUT_SIZE; // FUNCTION POINTERS TO HANDLE bool(*IO_HANDLER)(uint8_t *,uint16_t); bool(*EXCEPTION_HANDLER)(MODBUS_REP,uint8_t,uint8_t); // CALL_BACK FUNCTIONS bool(*COIL_SINGLE_WRITE_CB)(uint16_t); bool(*COIL_MULTIPLE_WRITE_CB)(uint16_t,size_t); bool(*HOLDING_REGISTER_SINGLE_WRITE_CB)(uint16_t); bool(*HOLDING_REGISTERS_MULTIPLE_WRITE_CB)(uint16_t,size_t); }MODBUS_INIT;
main.c 初始化代码
MODBUS_INIT modbusInit = { .SLAVE_ADDRESS= 20, .BROADCAST = false, .TX_BUFF_SIZE = 1000, .HOLDING_REGISTERS_W= modbusRegisters_W, .HOLDING_REGISTERS_W_SIZE =(sizeof(modbusRegisters_W)/sizeof(uint16_t)), .HOLDING_REGISTERS_R = modbusRegisters_R, .HOLDING_REGISTERS_R_SIZE = (sizeof(modbusRegisters_R)/sizeof(uint16_t)), .COILS_W = modbusCoil_W, .COILS_W_SIZE = sizeof(modbusCoil_W), .COILS_R = modbusCoil_W, .COILS_R_SIZE = sizeof(modbusCoil_W), .DISCERETE_INPUT= modbusInputDiscreat_R, .DISCERETE_INPUT_SIZE= sizeof(modbusInputDiscreat_R), // TRANSMIT POINTER .IO_HANDLER = modbusSeerialHandle, .EXCEPTION_HANDLER = modbus_error_Call_back, // CALLBACL FUNCTIONS .COIL_SINGLE_WRITE_CB= modbus_single_Coil_write_Call_back, .COIL_MULTIPLE_WRITE_CB = modbus_multiple_coils_write_Call_back, .HOLDING_REGISTER_SINGLE_WRITE_CB= modbus_single_holding_registers_write_Call_back, .HOLDING_REGISTERS_MULTIPLE_WRITE_CB= modbus_multiple_holding_registers_write_Call_back, }; modbus_slave_handle(dataRecieved,sizeof(dataRecieved),&modbusInit);
现象:当TX_BUFF_SIZE设置为484及以下时程序运行正常;设置为485及以上时出现校验和错误(数据不完整)。但如果直接在modbus.c中硬编码缓冲区大小(如uint8_t MODBUS_SLAVE_DATA[1000];),无论多大都能正常工作。
分析与解决
核心原因:栈空间溢出
你通过结构体成员定义的MODBUS_SLAVE_DATA是局部栈缓冲区,而XMC1100的默认栈空间通常较小(Keil中默认栈大小一般为1KB即1024字节)。当TX_BUFF_SIZE设为485时,这个缓冲区加上函数内其他局部变量、寄存器压栈的开销,直接超出了栈的可用空间,引发栈溢出。栈溢出会破坏相邻的栈数据(比如函数返回地址、其他变量),进而导致数据写入异常、校验和错误。
而硬编码的缓冲区属于全局/静态存储区,不在栈空间内,不受栈大小限制,因此不会出现溢出问题。
验证方式
- 查看Keil工程栈配置:打开
Options for Target->Linker选项卡,查看Stack Size的值。如果默认是0x400(1024字节),485字节的缓冲区加上其他开销刚好触碰到栈上限。 - 临时增大栈大小:将栈大小改为0x800(2048字节),测试
TX_BUFF_SIZE=1000的场景,若恢复正常则可确认是栈溢出问题。
解决方法
有两种可靠方案:
- 方案一:改用动态内存分配
从堆上分配缓冲区,避开栈空间限制,使用完成后释放内存。注意需在Keil中配置堆大小(Linker选项卡设置Heap Size),并处理分配失败的情况:uint8_t *MODBUS_SLAVE_DATA = malloc(MODBUS_HANDLER->TX_BUFF_SIZE); if(MODBUS_SLAVE_DATA == NULL){ // 处理内存分配失败,比如触发异常回调 return; } // 使用缓冲区逻辑... free(MODBUS_SLAVE_DATA); - 方案二:改用静态/全局缓冲区
将缓冲区改为静态局部变量或全局变量,使其存储在全局存储区:
注意多任务环境下需考虑线程安全,以及静态变量的初始化时机问题。static uint8_t MODBUS_SLAVE_DATA[MODBUS_HANDLER->TX_BUFF_SIZE];
内容的提问来源于stack exchange,提问作者S2G
相关产品推荐
相关产品推荐

