Stm32串口通信基础实验

目录

  • 一、基于寄存器与基于固件库的stm32 LED流水灯的编程方式的差异
  • 二、STM32串口通信
      • STM32的USART窗口通讯程序设计步骤(方法)
  • 三、C语言中,局部变量、全局变量、静态变量、堆、栈的内存地址
      • 全局变量、局部变量、堆、栈等概念
      • 在ubuntu系统中编程,输出信息进行验证
  • 四、在Keil中针对stm32系统进行编程,调试变量,进行验证
  • 五、总结

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

两者之间的差异主要体现在如下方面:
1.使用固件库:目前比较多的例程是使用固件库编写的。官方的例子也都采用固件库方式。特点就是简单,易于理解,资料多。如果你没有CortexM系列内核的开发基础,建议从固件库开始玩起。等有一定基础,或是特别需要时再用寄存器。

2.使用寄存器:想要深入理解CortexM3内核或是需要为了获得更好的可移植性,学习寄存器编程会比较有帮助。但是从专业的角度上看,寄存器更贴近底层,对外设的工作原理和运行机理会有更深的理解。

二、STM32串口通信

STM32的USART窗口通讯程序设计步骤(方法)

1.本次实验使用的是stm32f103指南者,从电脑中下载程序到stm32我采用的是使用串口下载程序
2.先下载以下几个压缩包:
Stm32串口通信基础实验_第1张图片
Stm32串口通信基础实验_第2张图片

下载链接
提取码:yong
3.用usb线把stm32开发板和电脑相连接,stm32端连接 ‘usb转串口’,打开stm32开关,小红灯亮起即可, 其中要求开发版上BOOT0和BOOT1接地,RXD接A9,TXD接A10,开发板买来默认就是这样,不需要改动:
Stm32串口通信基础实验_第3张图片
4.打开我们下载的安装包,点击CH341SER.EXE安装,显示安装成功:Stm32串口通信基础实验_第4张图片
Stm32串口通信基础实验_第5张图片
5.然后打开串口下载助手mcuisp:Stm32串口通信基础实验_第6张图片
6.在该页面进行如下设置(在后续的步骤中要进行更换其中的.hex文件,现在暂时不管):Stm32串口通信基础实验_第7张图片

7.该处串口通信实现以下功能:
*设置波特率为115200,1位停止位,无校验位。

*STM32系统给上位机(win10)连续发送“hello windows!”,

*当上位机给stm32发送“Stop stm32!”后,stm32停止发送,并返回信息“收到”。

然后我们打开如下图中所示的之前下载好的的文件:Stm32串口通信基础实验_第8张图片
8.打开之后进入如下界面,之后我们对部分程序进行一些改动:Stm32串口通信基础实验_第9张图片
9.我们开始修改其中的部分函数,如下:
*将stm32f10x_it.c文件的串口中断服务函数部分改为:

int i=0;
uint8_t ucTemp[50];
void DEBUG_USART_IRQHandler(void)
{
	if(USART_GetITStatus(DEBUG_USARTx,USART_IT_RXNE)!=RESET)
	{
		ucTemp[i] = USART_ReceiveData(USART1);	
	}
  if(ucTemp[i] == '!')
	{
		if(ucTemp[i-1] == '2'&&ucTemp[i-2] == '3'&&ucTemp[i-3] == 'm'&&ucTemp[i-4] == 't'&&ucTemp[i-5] == 's'&&ucTemp[i-6] == ' ')
			if(ucTemp[i-7] == 'p'&&ucTemp[i-8] == 'o'&&ucTemp[i-9] == 't'&&ucTemp[i-10] == 's')
			{
				printf("收到!");
        while(1);
			}
	}
	i++;
}

如图:Stm32串口通信基础实验_第10张图片
再将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);
	}	
}

如图:Stm32串口通信基础实验_第11张图片
10.编译生成hex文件了,按照上面的方式(第6步)把hex文件烧录到stm32中,然后打开最开始下载的串口调试助手,点击打开串口,便可看到stm32发给电脑的信息,我们输入stop stem32!即可停止:Stm32串口通信基础实验_第12张图片
Stm32串口通信基础实验_第13张图片
最终我们打开串口之后运行结果如下:Stm32串口通信基础实验_第14张图片

三、C语言中,局部变量、全局变量、静态变量、堆、栈的内存地址

全局变量、局部变量、堆、栈等概念

一个由C/C++编译的程序占用的内存分为以下几个部分

1、栈区(stack)— 程序运行时由编译器自动分配,存放函数的参数值,局部变量的值等:

其操作方式类似于数据结构中的栈。

2、堆区(heap) — 在内存开辟另一块存储区域:

一般由程序员分配释放, 若程序员不释放,程序结束时可能由OS回收 。
注意它与数据结构中的堆是两回事,分配方式倒是类似于链表。

3、全局区(静态区)(static)—编译器编译时即分配内存:

全局变量和静态变量的存储是放在一块的,
初始化的全局变量和静态变量在一块区域,
未初始化的全局变量和未初始化的静态变量在相邻的另一块区域。
程序结束后由系统释放

4、文字常量区 —常量字符串就是放在这里的。 程序结束后由系统释放。

5、程序代码区—存放函数体的二进制代码。

在ubuntu系统中编程,输出信息进行验证

1、首先我们先用gedit命令创建一个ll.c的文件并进入编写如下程序:

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

Stm32串口通信基础实验_第15张图片
其中:

l_buf/l_buf2/l_buf3 ,直接定义,是由编译器自动分配的,存储在栈中
s_buf/s_buf2/s_buf3,定义static,编译器编译时分配内存。为全局变量,在全局初始化区
p_buf/p_buf2/p_buf3,他们指向的空间,通过malloc申请空间,存放在堆中
g_buf/g_buf2/g_buf3/g_buf4/,定义的为全局变量,在全局初始化区

2、然后我们用gcc命令运行编译程序生成可执行文件ll:
在这里插入图片描述
Stm32串口通信基础实验_第16张图片
3、输入命令./ll执行该可执行程序得到以下结果:
Stm32串口通信基础实验_第17张图片
4、通过对结果进行分析,我们可以知道:

栈存放区域是由高地址到低地址向下增长
堆存放区是由低地址到高地址像上增长
静态变量地址从高地址到低地址向下增长
函数地址是从低地址到高地址向上增长

如图所示:
Stm32串口通信基础实验_第18张图片

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

在一个STM32程序代码中,从内存高地址到内存低地址,依次分布着栈区、堆区、全局区(静态区)、常量区、代码区,其中全局区中高地址分布着.bss段,低地址分布着.data段。

总的分布如下图:
Stm32串口通信基础实验_第19张图片
1、栈区(stack)

临时创建的局部变量存放在栈区。

函数调用时,其入口参数存放在栈区。

函数返回时,其返回值存放在栈区。

const定义的局部变量存放在栈区。

2、堆区(heap)

堆区用于存放程序运行中被动态分布的内存段,可增可减。

可以有malloc等函数实现动态分布内存。

有malloc函数分布的内存,必须用free进行内存释放,否则会造成内存泄漏。

3、全局区(静态区)

全局区有.bss段和.data段组成,可读可写。

4、.bss段

未初始化的全局变量存放在.bss段。

初始化为0的全局变量和初始化为0的静态变量存放在.bss段。

.bss段不占用可执行文件空间,其内容有操作系统初始化。

5、.data段

已经初始化的全局变量存放在.data段。

静态变量存放在.data段。

.data段占用可执行文件空间,其内容有程序初始化。

const定义的全局变量存放在.rodata段。

6、常量区

字符串存放在常量区。

常量区的内容不可以被修改。

7、代码区

程序执行代码存放在代码区。

字符串常量也有可能存放在代码区。

使用之前野火的串口通信模板,把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)
	{	
		
	}	
}

8、我们在keil软件工程之中修改main.c之后运行如图:
Stm32串口通信基础实验_第20张图片
其中图中箭头所示表示:

Code:表示程序所占用 FLASH 的大小(FLASH)。
RO-data:即 Read Only-data,表示程序定义的常量,如 const 类型(FLASH)。
RW-data:即 Read Write-data,表示已被初始化的全局变量(SRAM)
ZI-data:即 Zero Init-data,表示未被初始化的全局变量(SRAM)
*FLASH占用大小计算公式:Code+RO-data
*SRAM占用大小计算公式:RW-data+ZI-data
/

9、然后将生成hex文件,按之前的步骤烧制到stm32中,再打开串口调试助手,点击打开串口,然后点击stm32上的reset按钮就可以得到以下结果:
Stm32串口通信基础实验_第21张图片
可以发现:
前3行为局部变量,它们储存到了栈中,地址依次减小;
后三行全局变量,它们储存到了静态区,地址依次增加。

10、再将main.c改为以下函数(定义了静态变量和指针):

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

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)
	{	
		
	}	
}

将生成的hex文件烧制到stm32中,打开串口调试助手,点击打开串口,然后点击stm32上的reset按钮就可以得到如下:
Stm32串口通信基础实验_第22张图片
可以发现:
前三个静态变量储存到了静态区,地址依次增加;
后三个指针储存到了堆中,地址依次增加。

11、综合以上两次修改后的实验结果可以得出:

栈存放区域是由高地址到低地址向下增长;
堆存放区是由低地址到高地址像上增长;
静态变量地址从高地址到低地址向下增长;
函数地址是从低地址到高地址向上增长。
(验证了之前在Ubuntu下得出的结论)

五、总结

通过本次STM32串口通信试验,让我了解了全局变量、局部变量、堆、栈等概念,以及如何烧制程序等等,学到了很多新的东西!

你可能感兴趣的:(keil,mdk,stm32,ubuntu)