菜鸟入门6,STM32串口通信


前言

此次本菜鸟有四个小任务

  1. 说明基于寄存器与基于固件库编程方式差异。

2.在STM32完成USART窗口通讯程序。

  1. 重温C语言程序里全局变量、局部变量、堆、栈等概念,并在ubuntu系统中编程,输出信息进行验证;

  2. 在Keil中针对stm32系统进行编程,调试变量,进行验证; 通过串口输出信息到上位机,进行验证。


1. 基于寄存器与基于固件库编程方式差异。

固件库就是函数的集合,作用就是:向下负责与寄存器直接打交道,向上提供用户函数调用的接口(API)。固件库将寄存器底层操作都封装起来,提供一套API供开发者使用,需要知道操作的是哪个寄存器,你只需要知道调用哪些函数即可。
寄存器是中央处理器内的组成部分。寄存器是有限存贮容量的高速存贮部件,它们可用来暂存指令、数据和地址。寄存器更贴近底层,对外设的工作原理和运行机理会有更深的理解。

2.STM32的USART窗口通讯程序

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

首先,如果你的板子新到没拆开,那你就要进行一系列操作
连接硬件,下载驱动,下载串口调试助手,在里面设置参数

(由于上篇文章提到了,这篇不再赘述,需要的小伙伴可以点击链接),但是我已经完成了这部分操作,接下来,直接对野火资料里提供的文件进行操作
首先打开野火提供的文件

在这里插入图片描述
观察它的主程序
在这里插入图片描述
修改user的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("shoudao");
        while(1);
			}
	}
	i++;
}

修改主程序,代码如下:

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

在这里插入图片描述
编译运行,生成hex文件
在这里插入图片描述
烧录程序
打开mcuisp,设置如下
在这里插入图片描述
在这里插入图片描述

烧录成功
在这里插入图片描述

打开串口调试助手,设置如下
在这里插入图片描述
点击打开串口,效果如下,当发送stop stm32!程序停止并返回shoudao
在这里插入图片描述

3. 重温C语言程序里全局变量、局部变量、堆、栈等概念,并在ubuntu系统中编程,输出信息进行验证;

全局变量、局部变量

从作用域看:

全局变量具有全局作用域。全局变量只需在一个源文件中定义,就可以作用于所有的源文件。当然,其他不包含全局变量定义的源文件需要用extern 关键字再次声明这个全局变量。

静态局部变量具有局部作用域,它只被初始化一次,自从第一次被初始化直到程序运行结束都一直存在,它和全局变量的区别在于全局变量对所有的函数都是可见的,而静态局部变量只对定义自己的函数体始终可见。

从分配内存空间看:
全局变量,静态局部变量,静态全局变量都在静态存储区分配空间,而局部变量在栈里分配空间

堆、栈

栈区是普通的栈数据结构,遵循LIFO后进先出的规则,局部变量安排在那里是ASM时就规定的,这样可以在一个函数结束后平衡堆栈,操作简单,效率高

堆(动态区)在这里应当叫堆栈(不要和数据结构中的堆搞混)是程序在编译时产生的一块用于产生动态内存分配使用的块,操作比较栈要麻烦许多,在分配时要判 断最优的地址(防止产生无用的内存碎片(由于屡次的NEW和DELETE产生的夹在两块使用中内存中的空余小内存(不容易被分配))),分配和回收时的效 率比栈低多了

在ubuntu系统中编程

在Ubuntu下创建c1.c文件,代码如下:

#include <stdio.h>
#include <stdlib.h>
int k1 = 1;
int k2;
static int k3 = 2;
static int k4;
int main( )
{   static int m1=2, m2;
    int i = 1;
    char *p;
    char str[10] = "hello";
    char *var1 = "123456";
    char *var2 = "abcdef";
    int *p1=malloc(4);
    int *p2=malloc(4);
    free(p1);
    free(p2);
    printf("栈区-变量地址\n");
    printf("                i:%p\n", &i);
    printf("                p:%p\n", &p);
    printf("              str:%p\n", str);
    printf("\n堆区-动态申请地址\n");
    printf("                   %p\n", p1);
    printf("                   %p\n", p2);
    printf("\n.bss段\n");
    printf("全局外部无初值 k2:%p\n", &k2);
    printf("静态外部无初值 k4:%p\n", &k4);
    printf("静态内部无初值 m2:%p\n", &m2);
    printf("\n.data段\n");
    printf("全局外部有初值 k1:%p\n", &k1);
    printf("静态外部有初值 k3:%p\n", &k3);
    printf("静态内部有初值 m1:%p\n", &m1);
    printf("\n常量区\n");
    printf("文字常量地址     :%p\n",var1);
    printf("文字常量地址     :%p\n",var2);
    printf("\n代码区\n");
    printf("程序区地址       :%p\n",&main);
    return 0;
}

编译运行
在这里插入图片描述
我们可以发现六个区域的地址都是逐步递增的。

**解释**

参考
C/C++程序内存的各种变量存储区域和各个区域详解.

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

C语言中关键字volatile追根问底.

4. 在Keil中针对stm32系统进行编程,调试变量,进行验证; 通过串口输出信息到上位机,进行验证。

在keil中保留之前串行口通讯的模板,修改其主程序,在里面定义全局变量和局部变量,并返回它们的地址给上位机:

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

编译运行
在这里插入图片描述
烧录程序并打开串口调试助手
在这里插入图片描述
在这里插入图片描述

前三个是局部变量,被储存在栈中,地址由高向低减少。
后三个是全局变量,被储存在静态区,地址由低向高增加

再次修改主程序,在里面定义静态变量和指针,并返回它们的地址

#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程序代码中,从内存高地址到内存低地址,依次分布着栈区、堆区、全局区(静态区)、常量区、代码区,其中全局区中高地址分布着.bss段,低地址分布着.data段。
参考:
STM32 内存分配详解.

基于STM32分析栈、堆、全局区、常量区、代码区、RAM、ROM

STM32 KEIL下的堆栈设置

总结

以上就是stm32串口通信部分的全部内容

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值