基于STM32串口通信USART
这里写目录标题
一丶在STM32的USART窗口通讯程序
开发板:野火指南者(STM32F103VE) STM32库版本:STM32F10x_StdPeriph_Lib_V3.5.0
IDE:KEIL5
代码编写工具:Source Insight 4.0(跟读代码、编写代码的最佳工具)
使用到的串口:USART1
原理图:
编写程序
新建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:
NVIC.c
User_USART.h
User_USART.c
stm32f10x_it.c
main.c
最后的界面:
运行:
成功!
接下来
把程序烧录到stm32f103核心板
通过ST-link连接stm32核心板,下载官方STM32 STLink驱动
烧录成功:
运行仿真:
打开野火串口调试助手
通过串口转接线连接stm32核心板和电脑
开始发送数据:
参考资料:
链接: link.
C语言程序里全局变量、局部变量、堆、栈
全局与局部变量:
在所有函数外部定义的变量称为全局变量(Global Variable),它的作用域默认是整个程序,也就是所有的源文件,包括 .c 和 .h
文件。定义在函数内部的变量称为局部变量(Local Variable),它的作用域仅限于函数内部, 离开该函数后就是无效的,再使用就会报错。
打开ubunt的终端,创建一个丶c文件
mkdir text0
cd text0
vim text1.c
用gcc编译运行:
gcc text1.c
ls
./a.out
结果
分析:
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
`
结果:
分析:
内存中的栈区主要用于分配局部变量空间,处于相对较高的地址,其栈地址是向下增长的;而堆区则主要用于分配程序员申请的内存空间,堆地址是向上增长的。
重温C语言程序里全局变量、局部变量、堆、栈等概念,在Keil中针对stm32系统进行编程,调试变量,进行验证; 通过串口输出信息到上位机,进行验证。
在一个STM32程序代码中,从内存高地址到内存低地址,依次分布着栈区、堆区、全局区(静态区)、常量区、代码区,其中全局区中高地址分布着.bss段,低地址分布着.data段。
(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);
}
}
进行烧录
上一篇: Windows应用程序(C/C++)(1)消息机制
下一篇: vue基本语法------持续更新