STM32串口通信及stm32中的堆、栈、全局变量的分配地址分析

一. 基于寄存器与基于固件库的stm32 LED流水灯的编程方式的差异

寄存器:相对来说是属于更底层的,类似于驱动层,在寄存器在使用时必须要清楚自己要操作那个一个寄存器,就很复杂,需要了解清楚寄存器的底层配置。
固件库:则类似通过将寄存器封装之后的应用层。固件库更像是包装好给用户的产品一样,只需要我们使用就行了,让封装自己和寄存器打交道,而且固件库不需要了解那么多甚至不了解就可以直接开发,并不需要太多专业知识。

二. STM32串口通信实施

1. 准备工作

注:本文使用野火的指南者开发板

STM32的USART窗口通讯程序,要求:
1)设置波特率为115200,1位停止位,无校验位。
2)STM32系统给上位机(win10)连续发送“hello windows!”,上位机接收程序可以使用“串口调试助手“,也可自己编程。
3)当上位机给stm32发送“Stop,stm32”后,stm32停止发送。

  • 下载野火所提供指南者配套资料
  • 安装配套的串口驱动器

2. 代码部分

打开资料里的工程,文件位置如下:
在这里插入图片描述
打开工程
在这里插入图片描述
在工程中找到stm32f10x_it.c文件,把里面的中断函数改为:

int i=0;int ch;
uint8_t ucTemp[20];
void DEBUG_USART_IRQHandler(void)
{
	if(USART_GetITStatus(DEBUG_USARTx,USART_IT_RXNE)!=RESET)   //接收触发
	{
		ucTemp[i] = USART_ReceiveData(USART1);	      //接收缓存
	}	
	//接收完毕后,判断是否为停止标志	
	if(ucTemp[i] == '!'&&ucTemp[i-1] == '2'&&ucTemp[i-2] == '3'&&ucTemp[i-3] == 'm'&&ucTemp[i-4] == 't'&&ucTemp[i-5] == 's'
		&&ucTemp[i-6] == ' '&&ucTemp[i-7] == 'p'&&ucTemp[i-8] == 'o'&&ucTemp[i-9] == 't'&&ucTemp[i-10] == 's')
	  {
				printf("收到\n");
				for(i=0;i<20;i++)
				{
					ucTemp[i]=0;      //清空接收缓存
				}
				while(1)            //停止发送后一直循环,等待继续发送标志
			    {
					if(USART_GetITStatus(DEBUG_USARTx,USART_IT_RXNE)!=RESET)   //接收到发送标志
					{
						ch = USART_ReceiveData(USART1);   //将接收到的值赋给ch
					}
					if(ch == '1')            //如果接受到`1`,继续发送
					{
						ch=0;
						printf("继续\n");
						break;
					}
			    }	
	  }
  i++;
}

修改main.c,

#include "stm32f10x.h"
#include "bsp_usart.h"


void delay(uint32_t count)
{
	while(count--);
}
int main(void)
{	
  USART_Config();
  while(1)
	{	
		printf("hello windows 10!\n");
		delay(5000000);
	}	
}

进行编译,下载

3. 结果展示

在这里插入图片描述

三. C语言程序里全局变量、局部变量、堆、栈等概念

C语言在内存中一共分为如下几个区域,分别是:

  1. 内存栈区: 存放局部变量名;
  2. 内存堆区: 存放new或者malloc出来的对象;
  3. 常数区: 存放局部变量或者全局变量的值;
  4. 静态区: 用于存放全局变量或者静态变量;
  5. 代码区:二进制代码。

1. 在ubuntu中进行编程,分析

创建stma.c文件,并编辑代码

gedit stm32.c

代码如下:

#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;
}

对其进行gcc编译

gcc stma.c -o stma

2. 结果

执行

./stma

在这里插入图片描述
分析
栈存放区域是由高地址到低地址向下增长
堆存放区是由低地址到高地址像上增长
静态变量地址从高地址到低地址向下增长
函数地址是从低地址到高地址向上增长

四. Keil中针对stm32系统进行编程,调试变量,进行验证

通过串口输出信息到上位机,进行验证。并归纳出stm32的堆、
栈、全局变量的分配地址,与ARM教材中的地址分配进行对比。

使用第二部分使用的工程,更改main.c代码

#include "stm32f10x.h"
#include "bsp_usart.h"

char global1[16];
char global2[16];
char global3[16];
	
int main(void)
{	
	char part1[16];
  char part2[16];
  char part3[16];

  USART_Config();

  printf("part1: 0x%p\n", part1);
  printf("part2: 0x%p\n", part2);
  printf("part3: 0x%p\n", part3);
	 
  printf("global1: 0x%p\n", global1);
  printf("global2: 0x%p\n", global2);
  printf("global3: 0x%p\n", global3);
  while(1)
	{	
		
	}	
}

编译下载,连接板子,打开串口可得
在这里插入图片描述
可以得到如下结果:
前3行为局部变量,储存在栈中,地址依次减小;
后3行全局变量,储存在静态区,地址依次增加。
再把main.c改为如下代码

#include "stm32f10x.h"
#include "bsp_usart.h"
#include <stdlib.h>

int main(void)
{	
  static char st1[16];
  static char st2[16];
  static char st3[16];
  char *p1;
  char *p2;
  char *p3;

 
  USART_Config();

  printf("st1: 0x%p\n", st1);
  printf("st2: 0x%p\n", st2);
  printf("st3: 0x%p\n", st3);
	 
  p1 = (char *)malloc(sizeof(char) * 16);
  p2 = (char *)malloc(sizeof(char) * 16);
  p3 = (char *)malloc(sizeof(char) * 16);
	
  printf("p1: 0x%p\n", p1);
  printf("p2: 0x%p\n", p2);
  printf("p3: 0x%p\n", p3);
  while(1)
	{	
		
	}	
}

编译下载后,连接stm32
在这里插入图片描述
可以发现:
前3个是静态变量,储存到了静态区,地址依次增加;
后3个是指针,储存到了堆中,地址依次增加。

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值