欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

基于STM32串口通信USART

程序员文章站 2022-03-05 10:21:11
...

一丶在STM32的USART窗口通讯程序

开发板:野火指南者(STM32F103VE) STM32库版本:STM32F10x_StdPeriph_Lib_V3.5.0
IDE:KEIL5
代码编写工具:Source Insight 4.0(跟读代码、编写代码的最佳工具)
使用到的串口:USART1

原理图:
基于STM32串口通信USART

编写程序

新建NVIC.h、NVIC.c、User_USART.h、User_USART.c、main.c 5个文件,并从
STM32官方库的例子中将stm32f10x_it.c、stm32f10x_it.h、stm32f10x_conf.h拷贝到自己的工程目录下。

NVIC.h:
基于STM32串口通信USART
NVIC.c
基于STM32串口通信USART
User_USART.h
基于STM32串口通信USART
User_USART.c
基于STM32串口通信USART
基于STM32串口通信USART
基于STM32串口通信USART
stm32f10x_it.c
基于STM32串口通信USART
main.c
基于STM32串口通信USART最后的界面:
基于STM32串口通信USART

运行:
基于STM32串口通信USART
成功!
接下来
把程序烧录到stm32f103核心板
通过ST-link连接stm32核心板,下载官方STM32 STLink驱动
基于STM32串口通信USART
烧录成功:
基于STM32串口通信USART
运行仿真:
基于STM32串口通信USART

打开野火串口调试助手
基于STM32串口通信USART

通过串口转接线连接stm32核心板和电脑
开始发送数据:
基于STM32串口通信USART
参考资料:
链接: link.

C语言程序里全局变量、局部变量、堆、栈

基于STM32串口通信USART

全局与局部变量:

在所有函数外部定义的变量称为全局变量(Global Variable),它的作用域默认是整个程序,也就是所有的源文件,包括 .c 和 .h
文件。

定义在函数内部的变量称为局部变量(Local Variable),它的作用域仅限于函数内部, 离开该函数后就是无效的,再使用就会报错。

打开ubunt的终端,创建一个丶c文件

mkdir text0
cd text0
vim text1.c

基于STM32串口通信USART用gcc编译运行:

gcc text1.c
ls
./a.out

结果基于STM32串口通信USART
分析:

1.对于 func1(),输出结果为 20,显然使用的是函数内部的 n,而不是外部的 n;func2() 也是相同的情况。func3() 输出 10,使用的是全局变量,因为在 func3() 函数中不存在局部变量 n,所以编译器只能到函数外部,也就是全局作用域中去寻找变量 n。
2.由{ }包围的代码块也拥有独立的作用域,printf() 使用它自己内部的变量 n,输出 40。C语言规定,只能从小的作用域向大的作用域中去寻找变量,而不能反过来,使用更小的作用域中的变量。
3.对于 main() 函数,即使代码块中的 n 离输出语句更近,但它仍然会使用 main() 函数开头定义的 n,所以输出结果是 30。

堆与栈

在 C 语言中,内存分配方式不外乎有如下三种形式:
从静态存储区域分配:它是由编译器自动分配和释放的,即内存在程序编译的时候就已经分配好,这块内存在程序的整个运行期间都存在,直到整个程序运行结束时才被释放,如全局变量与
static 变量。
在栈上分配:它同样也是由编译器自动分配和释放的,即在执行函数时,函数内局部变量的存储单元都可以在栈上创建,函数执行结束时这些存储单元将被自动释放。需要注意的是,栈内存分配运算内置于处理器的指令集中,它的运行效率一般很高,但是分配的内存容量有限。
从堆上分配:也被称为动态内存分配,它是由程序员手动完成申请和释放的。即程序在运行的时候由程序员使用内存分配函数(如 malloc
函数)来申请任意多少的内存,使用完之后再由程序员自己负责使用内存释放函数(如 free
函数)来释放内存。也就是说,动态内存的整个生存期是由程序员自己决定的,使用非常灵活。需要注意的是,如果在堆上分配了内存空间,就必须及时释放它,否则将会导致运行的程序出现内存泄漏等错误。

再次创建一个.c文件

gcc text2.c
ls
./a.out

代码:

#include <stdio.h>
#include <malloc.h>
int main(void)
{
    /*在栈上分配*/
    int  i1=0;
    int  i2=0;
    int  i3=0;
    int  i4=0;
    printf("栈:向下\n");
    printf("i1=0x%08x\n",&i1);
    printf("i2=0x%08x\n",&i2);
    printf("i3=0x%08x\n",&i3);
    printf("i4=0x%08x\n\n",&i4);
     printf("--------------------\n\n");
    /*在堆上分配*/
    char  *p1 = (char *)malloc(4);
    char  *p2 = (char *)malloc(4);
    char  *p3 = (char *)malloc(4);
    char  *p4 = (char *)malloc(4);
    printf("p1=0x%08x\n",p1);
    printf("p2=0x%08x\n",p2);
    printf("p3=0x%08x\n",p3);
    printf("p4=0x%08x\n",p4);
    printf("堆:向上\n\n");
    /*释放堆内存*/
    free(p1);
    p1=NULL;
    free(p2);
    p2=NULL;
    free(p3);
    p3=NULL;
    free(p4);
    p4=NULL;
    return 0;
}

编译运行:

gcc text2.c
ls
./a.out
`

结果:
基于STM32串口通信USART
基于STM32串口通信USART
分析:

内存中的栈区主要用于分配局部变量空间,处于相对较高的地址,其栈地址是向下增长的;而堆区则主要用于分配程序员申请的内存空间,堆地址是向上增长的。

重温C语言程序里全局变量、局部变量、堆、栈等概念,在Keil中针对stm32系统进行编程,调试变量,进行验证; 通过串口输出信息到上位机,进行验证。

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

(1)栈区(stack):由编译器自动分配和释放,存放函数的参数值、局部变量的值等,其操作方式类似于数据结构中的栈。
(2)堆区(heap):一般由程序员分配和释放,若程序员不释放,程序结束时可能由操作系统回收。分配方式类似于数据结构中的链表。
(3)全局区(静态区)(static):全局变量和静态变量的存储是放在一块的,初始化的全局变量和静态变量在一块区域,未初始化的全局变量和未初始化的静态变量在相邻的另一块区域。程序结束后由系统自动释放。
(4)文字常量区:常量字符串就是存放在这里的。 (5)程序代码区:存放函数体的二进制代码。
nt a=0;

例如:

int a=0 // 始化区
char *p1;
// 局未初始化区
ain()
{
nt b;
har s[]=“abc”;
ar *p3= “1234567”;
//在文字常量区
tatic int c =0 ;
//静态初始化区

p1= (char *)malloc(10);

                                                  //堆区

trcpy(p1,“123456”);
// "123456"放在常量区
}
所以堆和栈的区别:

stack的空间由操作系统自动分配/释放,heap上的空间手动分配/释放。 tack的空间有限,heap是很大的*存储区。
序在编译期和函数分配内存都是在栈上进行,且程序运行中函数调用时参数的传递也是在栈上进行。
Cortex-m3资料可知:__initial_sp是堆栈指针,它就是FLASH的0x8000000地址前面4个字节(它根据堆栈大小,由编译器自动生成) 显然堆和栈是相邻的。

将之前的main.c函数代码修改如下,并运行

#include "led.h"
#include "delay.h"
#include "key.h"
#include "sys.h"
#include "usart.h"
#include <stdlib.h>

int k1 = 1;
int k2;
static int k3 = 2;
static int k4;
int main(void)
 { 
  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); 
  u16 t;  
 u16 len; 
 u16 times=0;
 free(p1);
  free(p2);
  delay_init();      
 NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);
 uart_init(115200); 
  LED_Init();     
 KEY_Init();
 while(1)
 { 
   for(t=0;t<len;t++)
   { 
    USART_SendData(USART1, USART_RX_BUF[t]);
     while(USART_GetFlagStatus(USART1,USART_FLAG_TC)!=SET);
   }
 
   USART_RX_STA=0;
     times++;
   if(times%500==0)
   {
    printf("\r\n嵌入式串口实验\r\n");
    printf("aaa@qq.com\r\n\r\n");
       printf("栈区-变量地址\r\n");
       printf("                i:%p\r\n", &i);
    printf("                p:%p\r\n", &p);
    printf("              str:%p\r\n", str);
        printf("\n栈区-动态申请地址\r\n");
        printf("                   %p\r\n", p1);
         printf("                   %p\r\n", p2);
        printf("\r\n.bss段\r\n");
        printf("\n全局外部无初值p\r\n", &k2);
        printf("静态外部无初值p\r\n", &k4);
        printf("静态内部无初值\r\n", &m2);
         printf("\r\n.data??\r\n");
        printf("\n全局外部有初值p\r\n", &k1);
        printf("静态外部有初值p\r\n", &k3);
        printf("静态内部有初值p\r\n", &m1);
        printf("\r\n常量区\n");
        printf("文字常量地址p\r\n",var1);
         printf("文字常量地址\r\n",var2);
        printf("\r\n代码区\n");
        printf("程序区p\n",&main);
    printf("\r\n end \r\n\r\n\r\n");
   }
   
   delay_ms(10);   
  }
 }

基于STM32串口通信USART
进行烧录
基于STM32串口通信USART
基于STM32串口通信USART