一、STM32的USART窗口通讯程序
(一)基于寄存器与基于固件库的stm32 LED流水灯例子的编程方式有什么差异?
答:固件库就是函数的集合,固件库函数的作用就是:向下负责与寄存器直接打交道,向上提供用户函数调用的接口(API)。对于STM32这种级别的MCU,数百个寄存器记起来何谈容易,于是推出了官方固件库,固件库将这些寄存器底层操作都封装起来,提供一套API供开发者使用。大多数情况下,你不需要知道操作的是哪个寄存器,你只需要知道调用哪些函数即可。
(二)STM32的USART窗口通讯程序
1、打开keil5创建一个工程,新建NVIC.h、NVIC.c、User_USART.h、User_USART.c、main.c 5个文件

2、从STM32官方库的例子中将stm32f10x_it.c、stm32f10x_it.h、stm32f10x_conf.h拷贝到自己的工程目录下

3、敲入代码
NVIC.h

NVIC.c

User_USART.h

User_USART.c

main.c

4、运行main.c函数

5、把程序烧录到stm32f103核心板
通过ST-link连接stm32核心板,下载官方STM32 STLink驱动
点击如图图标(keil5)

烧录完成

运行仿真
点击如图图标

运行仿真

6、下载官方野火串口调试助手

7、或者用烧录软件烧录.hex文件
(BOOT0接高电平,BOOT1接低电平)

8、通过串口转接线连接stm32核心板和电脑

(引脚A9 TX和A10 RX接出来,另外两根接地GND和3.3V电压)

9、打开野火调试助手
打开串口,开始发送数据

发送Stop,stm32停止发送。

二、C语言程序里全局变量、局部变量、堆、栈
1、打开ubuntu里的vscode编译器
2、下载Code Runner插件(多一个运行三角标)

可以直接运行编译好的程序。
3、敲入如下代码
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
void before()
{
}
char g_buf[16];
char g_buf2[16];
char g_buf3[16];
char g_buf4[16];
char g_i_buf[]=“123”;
char g_i_buf2[]=“123”;
char g_i_buf3[]=“123”;
void after()
{
}
int main(int argc, char **argv)
{
char l_buf[16];
char l_buf2[16];
char l_buf3[16];
static char s_buf[16];
static char s_buf2[16];
static char s_buf3[16];
char *p_buf;
char *p_buf2;
char *p_buf3;
p_buf = (char *)malloc(sizeof(char) * 16);
p_buf2 = (char *)malloc(sizeof(char) * 16);
p_buf3 = (char *)malloc(sizeof(char) * 16);
printf("g_buf: 0x%x\n", g_buf);
printf("g_buf2: 0x%x\n", g_buf2);
printf("g_buf3: 0x%x\n", g_buf3);
printf("g_buf4: 0x%x\n", g_buf4);
printf("g_i_buf: 0x%x\n", g_i_buf);
printf("g_i_buf2: 0x%x\n", g_i_buf2);
printf("g_i_buf3: 0x%x\n", g_i_buf3);
printf("l_buf: 0x%x\n", l_buf);
printf("l_buf2: 0x%x\n", l_buf2);
printf("l_buf3: 0x%x\n", l_buf3);
printf("s_buf: 0x%x\n", s_buf);
printf("s_buf2: 0x%x\n", s_buf2);
printf("s_buf3: 0x%x\n", s_buf3);
printf("p_buf: 0x%x\n", p_buf);
printf("p_buf2: 0x%x\n", p_buf2);
printf("p_buf3: 0x%x\n", p_buf3);
printf("before: 0x%x\n", before);
printf("after: 0x%x\n", after);
printf("main: 0x%x\n", main);
if (argc > 1)
{
strcpy(l_buf, argv[1]);
}
return 0;
}
3、运行代码

结果如下:
g_buf: 0x11c6f030
g_buf2: 0x11c6f040
g_buf3: 0x11c6f050
g_buf4: 0x11c6f060
g_i_buf: 0x11c6f010
g_i_buf2: 0x11c6f014
g_i_buf3: 0x11c6f018
l_buf: 0xf4a33e90
l_buf2: 0xf4a33ea0
l_buf3: 0xf4a33eb0
s_buf: 0x11c6f070
s_buf2: 0x11c6f080
s_buf3: 0x11c6f090
p_buf: 0x121d1260
p_buf2: 0x121d1280
p_buf3: 0x121d12a0
before: 0x11a6e74a
after: 0x11a6e751
main: 0x11a6e758
4、结论:
栈:地址向下递增
堆:地址向上递增
全局变量
静态变量,地址向下递增
全局变量,地址向上递增
函数,地址向上递增
三、stm32的堆、栈、全局变量的分配地址
1、继续使用一中的串口通讯代码
2、在main.c函数中stm32中定义了全局变量和局部变量

3、烧录.hex文件到stm32芯片中
4、打开调试助手,打开串口

可以看出:前3个局部变量储存到了栈中,它们地址依次减小,后三个全局变量储存到了静态区,它们地址依次增加。
5、再次修改main.c函数,定义了静态变量和指针

6、打开串口

可以看出:前三个静态变量储存到了静态区,地址依次增加。
后三个指针储存到了堆中,地址依次增加。
7、结论
在一个STM32程序代码中,从内存高地址到内存低地址,依次分布着栈区、堆区、全局区(静态区)、常量区、代码区,其中全局区中高地址分布着.bss段,低地址分布着.data段。

本文对比了STM32 USART窗口通讯中基于寄存器和固件库的编程差异,并深入剖析了C语言中全局变量、局部变量、堆和栈的内存分布。通过实例展示了STM32程序中堆栈、全局区与静态区的内存分配,揭示了嵌入式开发中关键内存区域的工作原理。
459

被折叠的 条评论
为什么被折叠?



