IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> 开发工具 -> 变量存储重温与Clion编辑器的学习与实践 -> 正文阅读

[开发工具]变量存储重温与Clion编辑器的学习与实践

一、实验要求

1、 编写一个C程序,重温全局变量、局部变量、堆、栈等概念,在Ubuntu(x86)系统和STM32(Keil)中分别进行编程、验证(STM32 通过串口printf 信息到上位机串口助手) 。归纳出Ubuntu、stm32下的C程序中堆、栈、全局、局部等变量的分配地址,进行对比分析。
2、安装Clion2021,采用一套新的嵌入式软件开发工具包(替代Keil),完成stm32F103 点亮LED的程序。

二、变量存储重温

1、内存分配

(1)内存属性简述

静态分配内存:在程序编译和链接时就确定好的内存
动态分配内存:在程序加载、调入、执行的时候分配/回收的内存

(2)内存分区简述

栈区(stack):由编译器自动分配释放,存放函数形参和局部变量(auto类型)。其操作方式类似于数据结构中的栈。
堆区(heap):程序动态申请分配和释放空间。一般由程序员分配释放,若程序员不释放,程序结束时可能由OS回收 。(与数据结构中的堆不同,分配方式类似于链表)
全局/静态区(static):全局变量和静态变量的存储是放在一块的,初始化的全局变量和静态变量在一块区域, 未初始化的全局变量、未初始化的静态变量在相邻的另一块区域。(当程序结束后,变量由系统释放)
文字常量区:存放常量字符串(当程序结束后,常量字符串由系统释放)
程序代码区:存放函数体的二进制代码
注意:
一个正常的程序在内存中通常分为程序段、数据段、堆栈三部分。
程序段:程序的机器码、只读数据,通常是只读,对它的写操作是非法的。
数据段:程序中的静态数据。
堆栈:内存中的一个连续的块。动态数据则通过堆栈来存放。堆栈指针寄存器(SP)指向堆栈的栈顶。堆栈的底部是一个固定地址,其特点是后进先出,即后放入的数据第一个取出。它支持PUSH、POP操作。PUSH是将数据放到栈的顶端,POP是将栈顶的数据取出。
在这里插入图片描述
在这里插入图片描述

(3)分区进行对比

注意:
① 随着函数调用层数的增加,函数栈帧是一块块地向内存低地址方向延伸的。
② 随着进程中函数调用层数的减少(即各函数调用的返回),栈帧会一块块地被遗弃而向内存的高址方向回缩。
③ 各函数的栈帧大小随着函数的性质的不同而不等,由函数的局部变量的数目决定。
④ 进程对内存的动态申请是发生在Heap(堆)里的,随着系统动态分配给进程的内存数量的增加,Heap(堆)有可能向高址或低址延伸,这依赖于不同CPU的实现,但一般来说是向内存的高地址方向增长的。
⑤ 在未初始化数据区(BSS)或者Stack(栈区)的增长耗尽了系统分配给进程的自由内存的情况下,进程将会被阻塞,重新被操作系统用更大的内存模块来调度运行。

在这里插入图片描述

(4)STM32数据存储位置

代码区和常量区的内容编译后存储在ROM中;栈、堆、全局区(.bss段、.data段)存放在RAM中。
在这里插入图片描述

2、编程进行验证

(1)Ubuntu验证

【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] = "lyy";
    //定义常量字符串
    char *var1 = "123456";
    char *var2 = "yushu";
    //动态分配
    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】终端创建、查看

在这里插入图片描述
在这里插入图片描述

(2)STM32验证

【1】代码生成

由于做过很多次自动生成代码的过程,这里不再重复,给出生成后的代码压缩包如下:
链接:https://pan.baidu.com/s/1jJHzOzG4AjrXWWC4wJ8xBA
提取码:1521

【2】代码编写

bsp_usart.h文件
添加头文件:

#include <stdio.h>
#include <stdlib.h>

在这里插入图片描述

在这里插入图片描述
main.c 文件

#include "stm32f10x.h"
#include "bsp_usart.h"  //添加 bsp_usart.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(void)
{	
	//定义局部变量
	int a=2;
	static int inits_local_c=2, uninits_local_c;
	int init_local_d = 1;
	char *p;
	char str[10] = "lyy";
	//定义常量字符串
	char *var1 = "123456";
	char *var2 = "yushu";
	//动态分配
	int *p1=malloc(4);
	int *p2=malloc(4);
	USART_Config();//串口初始化
	output(a);
	//释放
	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;
}

bsp_usart.c 文件
重写 fputc 函数:

int fputc(int ch, FILE *f)
{
	USART_SendData(DEBUG_USARTx, (uint8_t)ch);
	
	while(USART_GetFlagStatus(DEBUG_USARTx, USART_FLAG_TXE) == RESET);
	
	return (ch);
}

在这里插入图片描述
编译main.c
在这里插入图片描述
编译后可看到Code、RO-data、RW-data、ZI-data段的大小。
注释
Code:存储程序代码 ?
RO-data:存储const常量和指令
?RW-data:存储初始化值不为0的全局变量
?ZI-data:存储未初始化/初始化值为0的全局变量
ROW(Flash)=Code + RO-Data + RW-Data
RAM=RW-data+ZI-data

【3】烧录输出

用mcuisp 软件开始烧录
在这里插入图片描述
用SSCOM打开串口后,按一下芯片上的RESET,显示输出结果:
在这里插入图片描述
当用XCOM串口调试助手时会横向输出,这里不建议使用
在这里插入图片描述

(3)分析比较

Ubuntu在栈区和堆区的地址值都是从上到下增长的,STM32在栈区的地址值是从上到下减小的,在堆区的地址值是从上到下增长的。从每个区来看,栈区的地址是处于高地址,代码区的地址是处于低地址。

三、Clion介绍、安装及配置

1、Clion介绍

Clion 是一款专为开发C及C++所设计的跨平台IDE。 它是以IntelliJ为基础设计的,包含了许多智能功能来提高开发人员的生产力。 CLion帮助开发人员使用智能编辑器来提高代码质量、自动代码重构并且深度整合CMake编译系统,从而提高开发人员的工作效率。

2、安装 CLion2021

(1)下载

clion官网:
CLion: A Cross-Platform IDE for C and C++ by JetBrains
可通过百度网盘下载(这里我借用的别人的网址)
网盘:https://pan.baidu.com/s/1-uhNBBdWsPfgxBqaDqigqA
提取码:qwer

(2)安装教程

双击exe文件点击Next
在这里插入图片描述
可修改安装位置
在这里插入图片描述
可勾选,add “bin” folder to the PATH,则等会儿不用加入环境变量
在这里插入图片描述
接下来一路next
在这里插入图片描述
finish
在这里插入图片描述
打开clion,短期试用即可
在这里插入图片描述
点击log in to …创建账户
在这里插入图片描述
在这里插入图片描述
这里我用QQ邮箱注册
在这里插入图片描述
在这里插入图片描述
点击submit即可,注册成功后退出,再登陆
在这里插入图片描述
在这里插入图片描述
点击start trial
在这里插入图片描述

3、安装arm-none-eabi-gcc

(1)下载

官网地址:GNU Toolchain | GNU Arm Embedded Toolchain Downloads – Arm Developer

选择gcc-arm-none-eabi-10.3-2021.10-win32.exe

在这里插入图片描述

(2)安装教程

选择中文简体
在这里插入图片描述
接下来跟着安装向导继续就行了
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
自动弹出记事本和cmd
在这里插入图片描述

4、安装openocd

(1) 下载解压

官网:Download OpenOCD for Windows
下载的是最新的11.18的,这是一个压缩包,解压即可
在这里插入图片描述
在这里插入图片描述

5、安装MinGW

(1)下载解压

网盘下载:https://pan.baidu.com/s/1Q9lzsIWJJ4_MPThVYDnENg
提取码:qwer
下载后与openocd一样只需解压文件即可
在这里插入图片描述

6、添加到系统环境变量

arm-none-eabi-gcc 路径下bin文件夹
Openocd路径下bin文件夹
mingw64路径下bin文件夹

系统环境变量添加打开方法:
设置–>系统–>关于–>高级系统设置–>环境变量
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
然后检查一下安装成功没有
在命令行输入arm-none-eabi-gcc -v,有输出则表示成功。
在这里插入图片描述

7、Clion配置

(1)创建工程

在这里插入图片描述
点击create
在这里插入图片描述

(2)配置toolchains

选择 File-Settings-Build-Toolchains,添加 MinGW,右边会自动匹配好路径信息,将debugger选择arm-none-eabi-gcc 路径下bin文件夹中的arm-none-eabi-gdb.exe
在这里插入图片描述

(3)配置Embedded Development

选择 File-Settings-Build-Embedded Development,将右侧的 OpenOCD 文件目录转换到自己下载的位置,最后点击 Test 发现提示颜色为墨绿色,即代表配置成功 (顺便把 CubeMX 也配置了)
在这里插入图片描述
OK

四、实验

1、工程创建

用 CLion 创建新工程
选择 STM32CubeMX ,填写好项目要保存的路径,点击 Create 即可
在这里插入图片描述

2、生成工程

进入cubemx后,系统默认为f030F4Px,而我们需要用到f103c8t6,点击回到选择芯片位置。然后选择芯片
配置RCC
在这里插入图片描述
配置 SYS
在这里插入图片描述
配置引脚
设置 PC13 引脚为 GPIO_Output 来点亮 LED 灯。
在这里插入图片描述
配置串口 USART1
在这里插入图片描述
命名工程文件并设置
Project Name 要重新填写一下(因为换芯片的过程,其实是 Cube 新建了一个 ioc 文件),建议填写之前的工程名和文件目录,这样就可以把之前不想要的那个 .ioc 文件覆盖掉。
然后Toolchain/IDE那里,选择 SW4STM32
在这里插入图片描述

最后点击右上角,选择 Yes,生成工程,点击open projects
在这里插入图片描述

3、配置clion工程

回到 CLion,可以看到出现了如下界面,选择 stm32f103c8_biue_pill.cfg 文件,并使用
在这里插入图片描述

4、代码改变及烧录运行

添加代码
打开 main.c 文件,在 while 循环里添加使 PC13 引脚 LED 闪烁的代码

while (1)
  {
    /* USER CODE END WHILE */
    HAL_GPIO_WritePin(GPIOC, GPIO_PIN_13, GPIO_PIN_SET);
    HAL_Delay(500);
    HAL_GPIO_WritePin(GPIOC, GPIO_PIN_13, GPIO_PIN_RESET);
    HAL_Delay(500);
    /* USER CODE BEGIN 3 */
  }


编译
在这里插入图片描述
烧录
在这里插入图片描述

5、结果

在这里插入图片描述

五、总结

此次实验只要求看懂代码就可以了,不需要自己编写,有代码可以使用,可能在clion软件安装配置上比较麻烦,需要注册账户,其他注意操作认真仔细就可以了,总之,参考大佬的代码及博客,完成了此次实验。

六、参考文献

https://blog.csdn.net/qq_43279579/article/details/110308101
https://blog.csdn.net/liwei16611/article/details/88545248
https://my.oschina.net/mizhinian/blog/4472814
https://blog.csdn.net/u011784994/article/details/53157614
https://blog.csdn.net/m0_58892312/article/details/121866325
https://blog.csdn.net/qq_60678931/article/details/121866156

  开发工具 最新文章
Postman接口测试之Mock快速入门
ASCII码空格替换查表_最全ASCII码对照表0-2
如何使用 ssh 建立 socks 代理
Typora配合PicGo阿里云图床配置
SoapUI、Jmeter、Postman三种接口测试工具的
github用相对路径显示图片_GitHub 中 readm
Windows编译g2o及其g2o viewer
解决jupyter notebook无法连接/ jupyter连接
Git恢复到之前版本
VScode常用快捷键
上一篇文章      下一篇文章      查看所有文章
加:2021-12-18 16:11:43  更:2021-12-18 16:11:48 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年12日历 -2024/12/25 1:25:07-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码
数据统计