Ubuntu、stm32下的C程序中堆、栈、全局、局部等变量的分配地址

目录

一.相关概念

1.栈区和堆区

2.全局变量和局部变量

3.stm32数据的存储位置

二.Ubuntu系统和STM32(Keil)编程

1.代码

2.ubuntu操作

2.1vim .c文件

​​2.2进行gcc编译生成.o文件

2.3运行可执行文件

3.STM32新建工程

 4.Keil

4.1重定向printf和scanf

4.2在 stm32f1xx_hal.c 中重写fget和fput函数

4.3在main.c中添加 

4.4 在target勾选Use MicroLIB,需要调用微型库

4.5编译运行

4.6运行结果

4.7查看STM32地址分配

参考文献:


一.相关概念

1.栈区和堆区

栈区:栈又称堆栈,是用户存放程序临时创建的局部变量。由编译器自动分配释放 ,存放函数的参数值,局部变量的值等,内存的分配是连续的,它的内存分配是连续分配的,即所分配的内存是在一块连续的内存区域内。当我们声明变量时,那么编译器会自动接着当前栈区的结尾来分配内存。

堆区:堆是用于存放进程运行中被动态分配的内存段,它的大小并不固定,可动态扩张或缩减;当进程调用malloc等函数分配内存时,新分配的内存就被动态添加到堆上(堆被扩张);当利用free等函数释放内存时,被释放的内存从堆中被剔除(堆被缩减)。一般由程序员分配释放, 若程序员不释放,程序结束时可能由操作系统回收。类似于链表,在内存中的分布不是连续的,它们是不同区域的内存块通过指针链接起来的。一旦某一节点从链中断开,我们要人为的把所断开的节点从内存中释放。

正常的程序在内存中通常分为程序段、数据段、堆栈三部分。
程序段里放着程序的机器码、只读数据,这个段通常是只读,对它的写操作是非法的。
数据段放的是程序中的静态数据。
堆栈是内存中的一个连续的块。一个叫堆栈指针的寄存器(SP)指向堆栈的栈顶。堆栈的底部是一个固定地址。堆栈有一个特点就是,后进先出。也就是说,后放入的数据第一个取出。它支持两个操作,PUSH和POP。PUSH是将数据放到栈的顶端,POP是将栈顶的数据取出。动态数据存放在堆栈中。

2.全局变量和局部变量

全局变量:在所有函数外部定义的变量称为全局变量,它的作用域默认是整个程序,也就是所有的源文件。

局部变量:定义在函数内部的变量称为局部变量,它的作用域仅限于函数内部, 离开该函数的内部就是无效的,再使用就会报错。

两者的区别:

3.stm32数据的存储位置

RAM(随机存取存储器)
存储的内容可通过指令随机读写访问。RAM中的存储的数据在掉电是会丢失,因而只能在开机运行时存储数据。其中RAM又可以分为两种,一种是Dynamic RAM(DRAM动态随机存储器),另一种是Static RAM(SRAM,静态随机存储器)。栈、堆、全局区(.bss段、.data段)都是存放在RAM中。
ROM(只读存储器)
只能从里面读出数据而不能任意写入数据。ROM与RAM相比,具有读写速度慢的缺点。但由于其具有掉电后数据可保持不变的优点,因此常用也存放一次性写入的程序和数据,比如主版的BIOS程序的芯片就是ROM存储器。代码区和常量区的内容是不允许被修改的,所以存放于ROM中。

若想要了解更多的相关知识,可参考此篇博客:【IoT】STM32 内存分配详解_简一商业-优快云博客_stm32内存分配 


二.Ubuntu系统和STM32(Keil)编程

1.代码

#include <stdio.h>
#include <stdlib.h>
//定义全局变量
int init_global_a = 1;
int uninit_global_a;
static int inits_global_b = 2;
static int uninits_global_b;
void output(int a)
{
	printf("hello");
	printf("%d",a);
	printf("\n");
}
 
int main( )
{   
	//定义局部变量
	int a=2;//栈
	static int inits_local_c=2, uninits_local_c;
    int init_local_d = 1;//栈
    output(a);
    char *p;//栈
    char str[10] = "yaoyao";//栈
    //定义常量字符串
    char *var1 = "1234567890";
    char *var2 = "abcdefghij";
    //动态分配——堆区
    int *p1=malloc(4);
    int *p2=malloc(4);
    //释放
    free(p1);
    free(p2);
    printf("栈区-变量地址\n");
    printf("                a:%p\n", &a);
    printf("                init_local_d:%p\n", &init_local_d);
    printf("                p:%p\n", &p);
    printf("              str:%p\n", str);
    printf("\n堆区-动态申请地址\n");
    printf("                   %p\n", p1);
    printf("                   %p\n", p2);
    printf("\n全局区-全局变量和静态变量\n");
    printf("\n.bss段\n");
    printf("全局外部无初值 uninit_global_a:%p\n", &uninit_global_a);
    printf("静态外部无初值 uninits_global_b:%p\n", &uninits_global_b);
    printf("静态内部无初值 uninits_local_c:%p\n", &uninits_local_c);
    printf("\n.data段\n");
    printf("全局外部有初值 init_global_a:%p\n", &init_global_a);
    printf("静态外部有初值 inits_global_b:%p\n", &inits_global_b);
    printf("静态内部有初值 inits_local_c:%p\n", &inits_local_c);
    printf("\n文字常量区\n");
    printf("文字常量地址     :%p\n",var1);
    printf("文字常量地址     :%p\n",var2);
    printf("\n代码区\n");
    printf("程序区地址       :%p\n",&main);
    printf("函数地址         :%p\n",&output);
    return 0;
}

2.ubuntu操作

2.1vim .c文件

执行命令:

vim test.c

<think>首先,用户的问题是基于之前的引用:他们想在VSCode中进行STM32开发调试时,获取FreeRTOS中的变量值的方法。引用提供了相关的背景信息,包括在WSL中使用VSCode、STM32CubeMX、FreeRTOS等工具的开发调试设置。 关键点: - 用户使用VSCode进行STM32开发,可能涉及WSL环境。 - 开发环境包括STM32CubeMX、CMake、openocd等。 - 需要调试FreeRTOS应用,并获取任务变量值。 我的回应需要: - 使用中文回答。 - 遵循系统级指令:行内数学表达式用$...$,独立公式用$$...$$。 - 结构清晰,步骤明确,确保真实可靠。 - 在引用末尾添加引用标识。 - 生成相关问题。 从引用中提取相关内容: - 引用[1]和[3]提到在WSL中使用VSCode调试STM32,并引入FreeRTOS。 - 引用[2]讨论了Ubuntu + VSCode开发STM32,包括FreeRTOS移植。 - 引用[3]具体提到在FreeRTOS下实现阻塞式串口收发,并涉及调试问题(如Overrun error)。 - 引用[4]是关于Windows+VSCode+STM32F4+freeRTOS的环境搭建。 用户的核心需求是调试FreeRTOS任务时获取变量值。这涉及到使用调试器(如GDB)来检查变量。 在STM32开发中,常用的调试工具: - GDB(GNU Debugger):用于调试。 - OpenOCD:作为GDB服务器,连接到硬件。 - VSCode的Cortex-Debug插件:提供友好的调试界面。 对于FreeRTOS,调试需要特殊支持: - FreeRTOS有内置的调试特性,如trace hooks。 - GDB可以通过Python脚本或插件支持FreeRTOS感知调试,例如FreeRTOS提供的GDB helper scripts。 步骤概述: 1. 确保环境设置正确:安装必要的工具(GDB、OpenOCD)、VSCode插件(Cortex-Debug)。 2. 配置调试会话:在VSCode的launch.json文件中设置调试器。 3. 使用GDB命令或VSCode界面访问变量。 4. 针对FreeRTOS,启用调试支持。 具体方法: - 在VSCode的调试器中,可以使用变量窗口查看全局变量。 - 对于任务局部变量,需要任务上下文。暂停时,可以切换到不同任务来查看其变量。 - Cortex-Debug插件支持FreeRTOS感知,能显示任务列表和。 参考引用: - 引用[2]提到“第5章VSCode + Cortex-Debug:现代调试体验”,这应该包括调试变量。 - 引用[3]讨论调试问题,暗示调试是可行的。 结构化回答: - 介绍基本步骤。 - 详细说明如何配置和使用。 - 添加提示和注意事项。 结束时生成相关问题。 完整回答大纲: 1. **概述**:简要解释如何在VSCode调试FreeRTOS获取变量值。 2. **前提条件**:确保环境已设置(参考引用)。 3. **配置调试器**: - 安装Cortex-Debug插件。 - 配置launch.json使用GDB和OpenOCD。 - 添加FreeRTOS支持脚本。 4. **调试步骤**: - 启动调试会话。 - 暂停执行。 - 在VSCode的变量窗口中查看全局变量。 - 通过任务上下文切换来查看局部变量。 5. **高级方法**:使用GDB命令直接查询变量。 6. **注意事项**:如引用[3]提到的潜在问题。 7. **相关问题生成**。 添加引用标识: - 在结尾处自然地添加引用,如基于引用[3]的调试建议。 数学表达式:用户问题中可能没有数学内容,但如果涉及,我会添加格式。例如,如果讨论内存地址,可以用$address$。 最终回答使用中文。 </think>### VSCode中进行STM32开发调试时获取FreeRTOS变量值的方法 在VSCode环境下调试STM32应用程序时,获取FreeRTOS任务中的变量值需要结合GDB调试器和VSCode的调试插件(如Cortex-Debug)。FreeRTOS是多任务系统,变量可能位于不同任务的全局内存中,因此调试时需确保调试器能感知任务上下文。以下是逐步指南(基于您提供的引用环境:WSL/VSCode/STM32CubeMX/CMake/openocd)。 #### 前提条件 确保您的开发环境已正确设置: - **工具链安装**:GCC(ARM工具链)、openocd(用于JTAG/SWD调试),以及VSCode插件(Cortex-Debug、C/C++)。 - **FreeRTOS集成**:通过STM32CubeMX生成代码时,启用FreeRTOS支持(例如,在CubeMX中选择FreeRTOS中间件,并配置任务)。 - **编译配置**:使用CMake或Makefile编译项目,确保生成带调试符号的elf文件(例如,编译时添加`-g`选项)。 - **引用基础**:参考引用中提到的环境搭建(如WSL+VSCode调试设置)[^1][^2]。 #### 步骤1: 配置VSCode调试会话 在VSCode中,调试通过`.vscode/launch.json`文件配置。需添加FreeRTOS感知支持,让GDB识别任务结构。 1. **安装Cortex-Debug插件**:在VSCode扩展中搜索并安装"Cortex-Debug"。此插件提供FreeRTOS调试集成。 2. **修改launch.json**: - 打开项目根目录下的`.vscode/launch.json`文件。 - 添加以下配置(基于openocd和GDB): ```json { "version": "0.2.0", "configurations": [ { "name": "Cortex Debug (FreeRTOS)", "cwd": "${workspaceRoot}", "executable": "./build/your_project.elf", // 替换为您的elf文件路径 "request": "launch", "type": "cortex-debug", "servertype": "openocd", "device": "STM32F4xx", // 根据您的芯片型号修改 "configFiles": ["openocd.cfg"], // openocd配置文件 "rtos": "FreeRTOS", // 启用FreeRTOS感知 "showDevDebugOutput": true, "runToEntryPoint": "main" } ] } ``` - **关键点**:`"rtos": "FreeRTOS"` 使调试器能自动加载FreeRTOS的GDB helper脚本(如`FreeRTOS.svd`),用于解析任务变量。 - **参考**:此配置基于引用[2]中提到的VSCode + Cortex-Debug调试体验[^2]。 #### 步骤2: 启动调试并获取变量值 调试会话启动后,通过VSCode的调试界面访问变量: 1. **启动调试**:在VSCode中按下`F5`启动调试。OpenOCD会连接硬件(如ST-Link),GDB会加载elf文件。 2. **暂停执行**: - 在代码中设置断点(例如,在任务函数内部)。 - 当程序暂停时,调试器自动显示当前任务上下文。 3. **查看变量**: - **全局变量**:直接在VSCode的"变量"窗口查看(位于左侧边栏)。FreeRTOS全局变量(如`pxCurrentTCB`)会显示。 - **任务局部变量**: - 在"调用"窗口中选择特定任务(例如,点击`vTaskStartScheduler`或自定义任务函数)。 - 切换到任务上下文后,"变量"窗口会显示该任务的局部变量。 - **使用表达式计算**:在"监视"窗口中添加变量名(如`uxTaskPriorityGet(xTaskHandle)`),直接监视任务优先级等动态值。 4. **GDB命令进阶**: - 打开VSCode的调试控制台("查看" > "调试控制台"),输入GDB命令: - 列出所有任务:`info threads`(每个线程对应一个FreeRTOS任务)。 - 切换到任务:`thread n`(`n`为任务ID)。 - 打印变量:`p variable_name`(例如,`p xQueue`显示队列句柄)。 - 查看变量:`bt full`显示完整帧和局部变量。 #### 步骤3: 解决常见问题 - **调试器无法识别任务**:确保在编译时启用了FreeRTOS的调试钩子: - 在`FreeRTOSConfig.h`中设置`configUSE_TRACE_FACILITY=1`和`configUSE_STATS_FORMATTING_FUNCTIONS=1`。 - 重新编译项目(CMake中添加`-DDEBUG`)。 - **变量值不更新**:FreeRTOS任务可能在中断上下文中,需确保暂停时任务处于活跃状态。避免优化问题:编译时使用`-O0`禁用优化。 - **硬件连接问题**:参考引用[3],确保openocd配置正确(如`openocd.cfg`指定接口为`stlink-v2`)。若有串口错误(如Overrun error),可能影响调试稳定性[^3]。 - **WSL特定提示**:在WSL中运行时,确保USB设备透传(如使用`usbipd-win`)。引用[1]提到STM32CubeMX生成的FreeRTOS代码可直接用于调试[^1]。 #### 注意事项 - **性能影响**:调试时启用FreeRTOS感知会增加内存开销,避免在生产环境中使用。 - **工具兼容性**:GDB helper脚本需匹配FreeRTOS版本(通常位于FreeRTOS源码的`FreeRTOS/Source/portable/GDB`目录)。下载FreeRTOS源码并配置路径(如引用[4]中的GCC环境设置)[^4]。 - **替代方法**:如果变量值不易访问,考虑添加日志输出(如通过串口打印任务变量),参考引用[3]的串口收发实现[^3]。 ### 相关问题 1. 如何在FreeRTOS调试中查看任务使用情况? 2. VSCode调试STM32时如何设置硬件断点以减少性能开销? 3. 在FreeRTOS多任务环境下,如何避免调试时的变量访问冲突? [^2][^3]
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值