freertos下printf(“hello\r\n“)和printf(“hello %d\r\n“,i)任务堆栈消耗有何区别

一 背景

原先做的项目,TCP通讯采用stm32f103+freertos+w5500方案,实现的tcp单连接通信,同事提了个需求让实现tcp多连接,于是改了一版代码。测试发现根本跑不起来,程序应该是卡死崩溃了,相关问题代码如下:

c 复制代码
void do_tcp_server(void)
{
         switch(wizGetSnSR(tcp_socket[i].sock_num))                                                /*获取socket的状态*/
         {
            case SOCK_CLOSED: 
               printf("SOCK %d CLOSED\r\n",tcp_socket[i].sock_num);                                            /*socket处于关闭状态*/
               socket(tcp_socket[i].sock_num ,Sn_MR_TCP,local_port,Sn_MR_ND);         /*打开socket*/
            break;

            case SOCK_INIT:   
               printf("SOCK %d INIT\r\n",tcp_socket[i].sock_num);                                                       /*socket已初始化状态*/
               listen(tcp_socket[i].sock_num);                                                   /*socket建立监听*/
            break;
            ...
         }
}

在上面这段代码里面,如果我将打印

c 复制代码
 printf("SOCK %d CLOSED\r\n",tcp_socket[i].sock_num);
 printf("SOCK %d INIT\r\n",tcp_socket[i].sock_num);

改为

c 复制代码
 printf("SOCK CLOSED\r\n");
 printf("SOCK INIT\r\n");

则程序运行正常。

二 定位分析过程

  1. 大方向是堆栈溢出 问了下chatgpt是说printf("hello")和printf("%d")格式化打印,消耗的堆栈是不一样的,前者纯字符串,压栈的时候只是个地址,而后者则要压入更多内容。这么说来应该是堆栈溢出问题。于是我将打印改为printf("SOCK CLOSED\r\n"")和printf("SOCK INIT\r\n")在另一个任务里面调用vTasklist打印出任务堆栈信息如下:
c 复制代码
Name          State  Prio  Stack  Num
greenLedTask   	R	3	86	3
yellowLedTask  	R	3	86	4
beepLedTask    	R	3	86	6
tcpServerTask  	R	3	0	1
redLedTask     	X	3	0	5
mail_station   	R	3	88	2
IDLE           	R	0	107	7

关联的任务函数tcpServerTask剩余堆栈大小是0,也就是说此时该任务已经没有堆栈空间了,printf改为%d打印,多一点就可能导致堆栈溢出;

2.堆栈消耗能差多少呢 我将tcpServerTask任务堆栈大小由128word改为256word,然后打印两种情况下的剩余对战情况:

c 复制代码
//printf("SOCK CLOSED\r\n"")和printf("SOCK INIT\r\n")
Name          State  Prio  Stack  Num
greenLedTask   	R	3	86	3
yellowLedTask  	R	3	86	4
beepLedTask    	R	3	86	6
tcpServerTask  	R	3	106	1
redLedTask     	X	3	0	5
mail_station   	R	3	88	2
IDLE           	R	0	107	7
c 复制代码
//printf("SOCK %d CLOSED\r\n",tcp_socket[i].sock_num);
//printf("SOCK %d INIT\r\n",tcp_socket[i].sock_num);
 Name          State  Prio  Stack  Num
redLedTask     	X	3	0	5
tcpServerTask  	R	3	57	1
IDLE           	R	0	109	7
greenLedTask   	B	3	86	3
yellowLedTask  	B	3	86	4
beepLedTask    	B	3	86	6
mail_station   	B	3	88	2

根据打印结果看printf%d格式化输出比单纯打印纯字符串,任务堆栈要多消耗50个word大小左右,所以在你任务本身剩余堆栈很少的情况下,一个printf打印就可能导致溢出,程序崩溃。

  1. 最后解决方案

由于多链接,这里打印最好能打印出socket编号,所以

  1. 增加总的堆内存大小5000-》8192
  2. 增加printf%d打印任务堆栈大小128-》256
c 复制代码
configTOTAL_HEAP_SIZE                    ((size_t)8192)
osThreadDef(tcpServerTask, StartTcpServerTask, osPriorityNormal, 0, 256);
相关推荐
FreakStudio8 天前
W55MH32L-EVB 上手测评:硬件 TCP/IP 加持的以太网单片机,MicroPython 零门槛开发
python·单片机·嵌入式·大学生·面向对象·并行计算·电子diy·电子计算机
✎ ﹏梦醒͜ღ҉繁华落℘14 天前
单片机基础知识---stm32单片机的优先级
stm32·单片机·mongodb
zd84510150014 天前
RS485 总线详解
单片机·嵌入式硬件
✎ ﹏梦醒͜ღ҉繁华落℘14 天前
编程基础 --高内聚,低耦合
c语言·单片机
科芯创展14 天前
1A,1MHz,30VIN,XZ4115,降压恒流LED驱动芯片
单片机·嵌入式硬件
集芯微电科技有限公司14 天前
四通道2A输出集成功率电感降压模块专为紧凑型方案设计
人工智能·单片机·嵌入式硬件·生成对抗网络·计算机外设
踏着七彩祥云的小丑14 天前
嵌入式测试学习第 37 天:异常场景测试:断电、拔插、干扰、非法指令
单片机·嵌入式硬件·学习
意法半导体STM3214 天前
【官方原创】如何为STM32CubeMX2配置Visual Studio Code配置方案
vscode·stm32·单片机·嵌入式硬件·策略模式·stm32cubemx·嵌入式开发
雾削木14 天前
B语言经典教程现代化重构
java·前端·stm32·单片机·嵌入式硬件
Hello-FPGA14 天前
Camera Link 与 CoaXPress 技术对比 如何选择你的相机接口
单片机·嵌入式硬件