STM32
登录
直播中
南风一号
8年用户
985经验值
擅长:EMC/EMI设计
私信
关注
[问答]
如何去实现在STM32的USART窗口通讯程序呢
开启该帖子的消息推送
STM32
USART
通讯程序
基于寄存器与基于固件库的
STM32
LED流水灯例子的编程方式有什么差异呢?
如何去实现在STM32的USART窗口通讯程序呢?
回帖
(1)
石飞鹏
2021-12-1 15:29:54
一、基于寄存器与基于固件库的stm32 LED流水灯例子的编程方式有什么差异
使用固件库,目前比较多的例程是使用固件库编写的。官方的例子也都采用固件库方式。特点就是简单,易于理解,资料多。如果你没有CortexM系列内核的开发基础,建议从固件库开始玩起。等有一定基础,或是特别需要时再用寄存器。
使用寄存器,想要深入理解CortexM3内核或是需要为了获得更好的可移植性,学习寄存器编程会比较有帮助。但是从专业的角度上看,寄存器更贴近底层,对外设的工作原理和运行机理会有更深的理解。
二、STM32的USART窗口通讯程序
完成这次任务用到的是stm32核心板,根据原理图连好线后应该如下图所示:
要求完成以下任务:
1)设置波特率为115200,1位停止位,无校验位。
2)STM32系统给上位机(win10)连续发送“hello windows!”,上位机接收程序可以使用“串口调试助手“,也可自己编程。
3)当上位机给stm32发送“Stop,stm32”后,stm32停止发送。
续经过以下操作完成:
步骤1
:
准备工作
1、keil5软件,版本最好在5.20以上,野火串口调试助手。
2、stm32核心板、u***转TTL线、TL-link下载线。
3、现成的keil工程(用于完成任务的工程代码,可在野火官网下载)
步骤2
:
烧录
打开现成的keil工程
打开后如下:
将已经连接好的stm32核心板连接到电脑上
打开设备管理器应该如下:
keil中进行编译,生成.axf文件
点击魔术棒–>Debug–>ST-link Debugger
点击settings–>SW
点击Flash Download–>Erase Full Chip–>add
添加完成后依次点确定,ok完成设置。
进行烧录
点击Download进行下载
下载完成后如图:
至此,完成扫烧录。
步骤3
:
打开野火调试助手,进行验证
具体过程如下图:
可以看到要求已经实现,会连续发送woshiweishien,输入Stop,stm32时,会停止发送。
相关代码:(因为在野火官网可以下载现成的,故只给出main函数部分)
#include "led.h"
#include "delay.h"
#include "key.h"
#include "sys.h"
#include "usart.h"
#include
int hcr=1;
int main(void)
{
char stop[]={'S','t','o','p',',','s','t','m','3','2'};
u16 t;
u16 len;
u16 times=0;
delay_init();
NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);
uart_init(115200);
LED_Init();
KEY_Init();
while(hcr)
{
if(USART_RX_STA&0x8000)
{
len=USART_RX_STA&0x3fff;
printf("rnhello windows!:rnrn");
for(t=0;t
{if (hcr>=10) {hcr=0;break;}}
for(t=0;t
{
USART_SendData(USART1, USART_RX_BUF[t]);
while(USART_GetFlagStatus(USART1,USART_FLAG_TC)!=SET);
}
printf("rnrn");//²åÈë»»ÐÐ
USART_RX_STA=0;
}
else
{
times++;
if(times%100==0)
{
printf("rnwoshiiweishenrn");
}
delay_ms(10);
}
}
}
三、重温C语言程序里全局变量、局部变量、堆、栈等概念,并在ubuntu系统中编程,输出信息进行验证
1、全局变量与局部变量
在所有函数外部定义的变量称为
全局变量(Global Variable)
,它的作用域默认是整个程序,也就是所有的源文件,包括 .c 和 .h 文件。
定义在函数内部的变量称为
局部变量(Local Variable)
,它的作用域仅限于函数内部, 离开该函数后就是无效的,再使用就会报错。
局部变量和全局变量的zhongh综合示例演示:
代码:
#include
int n = 10; //全局变量
void func1(){
int n = 20; //局部变量
printf("func1 n: %dn", n);
}
void func2(int n){
printf("func2 n: %dn", n);
}
void func3(){
printf("func3 n: %dn", n);
}
int main(){
int n = 30; //局部变量
func1();
func2(n);
func3();
//代码块由{}包围
{
int n = 40; //局部变量
printf("block n: %dn", n);
}
printf("main n: %dn", n);
return 0;
}
在Ubuntu下编译运行
分析:
对于 func1(),输出结果为 20,显然使用的是函数内部的 n,而不是外部的 n;func2() 也是相同的情况。
func3() 输出 10,使用的是全局变量,因为在 func3() 函数中不存在局部变量 n,所以编译器只能到函数外部,也就是全局作用域中去寻找变量 n。
由{ }包围的代码块也拥有独立的作用域,printf() 使用它自己内部的变量 n,输出 40。
C语言规定,只能从小的作用域向大的作用域中去寻找变量,而不能反过来,使用更小的作用域中的变量。对于 main() 函数,即使代码块中的 n 离输出语句更近,但它仍然会使用 main() 函数开头定义的 n,所以输出结果是 30。
2、堆与栈
在 C 语言中,内存分配方式不外乎有如下三种形式:
从静态存储区域分配:它是由编译器自动分配和释放的,即内存在程序编译的时候就已经分配好,这块内存在程序的整个运行期间都存在,直到整个程序运行结束时才被释放,如全局变量与 static 变量。
在栈上分配:它同样也是由编译器自动分配和释放的,即在执行函数时,函数内局部变量的存储单元都可以在栈上创建,函数执行结束时这些存储单元将被自动释放。需要注意的是,栈内存分配运算内置于处理器的指令集中,它的运行效率一般很高,但是分配的内存容量有限。
从堆上分配:也被称为动态内存分配,它是由程序员手动完成申请和释放的。即程序在运行的时候由程序员使用内存分配函数(如 malloc 函数)来申请任意多少的内存,使用完之后再由程序员自己负责使用内存释放函数(如 free 函数)来释放内存。也就是说,动态内存的整个生存期是由程序员自己决定的,使用非常灵活。需要注意的是,如果在堆上分配了内存空间,就必须及时释放它,否则将会导致运行的程序出现内存泄漏等错误。
堆与栈的综合示例演示:
代码:
#include
#include
int main(void)
{
/*在栈上分配*/
int i1=0;
int i2=0;
int i3=0;
int i4=0;
printf("栈:向下n");
printf("i1=0x%08xn",&i1);
printf("i2=0x%08xn",&i2);
printf("i3=0x%08xn",&i3);
printf("i4=0x%08xnn",&i4);
printf("--------------------nn");
/*在堆上分配*/
char *p1 = (char *)malloc(4);
char *p2 = (char *)malloc(4);
char *p3 = (char *)malloc(4);
char *p4 = (char *)malloc(4);
printf("p1=0x%08xn",p1);
printf("p2=0x%08xn",p2);
printf("p3=0x%08xn",p3);
printf("p4=0x%08xn",p4);
printf("堆:向上nn");
/*释放堆内存*/
free(p1);
p1=NULL;
free(p2);
p2=NULL;
free(p3);
p3=NULL;
free(p4);
p4=NULL;
return 0;
}
在Ubuntu下编译运行
分析:
从运行结果中不难发现,内存中的栈区主要用于分配局部变量空间,处于相对较高的地址,其栈地址是向下增长的;而堆区则主要用于分配程序员申请的内存空间,堆地址是向上增长的。
四、重温C语言程序里全局变量、局部变量、堆、栈等概念,在Keil中针对stm32系统进行编程,调试变量,进行验证; 通过串口输出信息到上位机,进行验证。
1、栈区(stack)
临时创建的局部变量存放在栈区。
函数调用时,其入口参数存放在栈区。
函数返回时,其返回值存放在栈区。
const定义的局部变量存放在栈区。
2、堆区(heap)
堆区用于存放程序运行中被动态分布的内存段,可增可减。
可以有malloc等函数实现动态分布内存。
有malloc函数分布的内存,必须用free进行内存释放,否则会造成内存泄漏。
3、.bss段
未初始化的全局变量存放在.bss段。
初始化为0的全局变量和初始化为0的静态变量存放在.bss段。
.bss段不占用可执行文件空间,其内容有操作系统初始化。
4、.data段
已经初始化的全局变量存放在.data段。
静态变量存放在.data段。
.data段占用可执行文件空间,其内容有程序初始化。
const定义的全局变量存放在.rodata段。
在串口通信工程中将main函数代码改成如下:
#include "led.h"
#include "delay.h"
#include "key.h"
#include "sys.h"
#include "usart.h"
#include
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); //ÉèÖÃNVICÖжϷÖ×é2:2λÇÀÕ¼ÓÅÏȼ¶£¬2λÏìÓ¦ÓÅÏȼ¶
uart_init(115200); //´®¿Ú³õʼ»¯Îª115200
LED_Init(); //LED¶Ë¿Ú³õʼ»¯
KEY_Init(); //³õʼ»¯Óë°´¼üÁ¬½ÓµÄÓ²¼þ½Ó¿Ú
while(1)
{
for(t=0;t
{
USART_SendData(USART1, USART_RX_BUF[t]);//Ïò´®¿Ú1·¢ËÍÊý¾Ý
while(USART_GetFlagStatus(USART1,USART_FLAG_TC)!=SET);//µÈ´ý·¢ËͽáÊø
}
USART_RX_STA=0;
times++;
if(times%500==0)
{
printf("rnǶÈëʽ´®¿ÚʵÑérn");
printf("hcr@2219491180qqcomrnrn");
printf("Õ»Çø-±äÁ¿µØÖ·rn");
printf(" i:%prn", &i);
printf(" p:%prn", &p);
printf(" str:%prn", str);
printf("n¶ÑÇø-¶¯Ì¬ÉêÇëµØÖ·rn");
printf(" %prn", p1);
printf(" %prn", p2);
printf("rn.bss¶Îrn");
printf("nÈ«¾ÖÍⲿÎÞ³õÖµ k2£º%prn", &k2);
printf("¾²Ì¬ÍⲿÎÞ³õÖµ k4£º%prn", &k4);
printf("¾²Ì¬ÄÚ²¿ÎÞ³õÖµ m2£º%prn", &m2);
printf("rn.data¶Îrn");
printf("nÈ«¾ÖÍⲿÓгõÖµ k1£º%prn", &k1);
printf("¾²Ì¬ÍⲿÓгõÖµ k3£º%prn", &k3);
printf("¾²Ì¬ÄÚ²¿ÓгõÖµ m1£º%prn", &m1);
printf("rn³£Á¿Çøn");
printf("ÎÄ×Ö³£Á¿µØÖ· £º%prn",var1);
printf("ÎÄ×Ö³£Á¿µØÖ· £º%prn",var2);
printf("rn´úÂëÇøn");
printf("³ÌÐòÇøµØÖ· £º%pn",&main);
printf("rn end rnrnrn");
}
delay_ms(10);
}
}
在keil中如下图:
在进行烧录,烧录过程在STM32的USART窗口通讯程序中已经给出。
一、基于寄存器与基于固件库的stm32 LED流水灯例子的编程方式有什么差异
使用固件库,目前比较多的例程是使用固件库编写的。官方的例子也都采用固件库方式。特点就是简单,易于理解,资料多。如果你没有CortexM系列内核的开发基础,建议从固件库开始玩起。等有一定基础,或是特别需要时再用寄存器。
使用寄存器,想要深入理解CortexM3内核或是需要为了获得更好的可移植性,学习寄存器编程会比较有帮助。但是从专业的角度上看,寄存器更贴近底层,对外设的工作原理和运行机理会有更深的理解。
二、STM32的USART窗口通讯程序
完成这次任务用到的是stm32核心板,根据原理图连好线后应该如下图所示:
要求完成以下任务:
1)设置波特率为115200,1位停止位,无校验位。
2)STM32系统给上位机(win10)连续发送“hello windows!”,上位机接收程序可以使用“串口调试助手“,也可自己编程。
3)当上位机给stm32发送“Stop,stm32”后,stm32停止发送。
续经过以下操作完成:
步骤1
:
准备工作
1、keil5软件,版本最好在5.20以上,野火串口调试助手。
2、stm32核心板、u***转TTL线、TL-link下载线。
3、现成的keil工程(用于完成任务的工程代码,可在野火官网下载)
步骤2
:
烧录
打开现成的keil工程
打开后如下:
将已经连接好的stm32核心板连接到电脑上
打开设备管理器应该如下:
keil中进行编译,生成.axf文件
点击魔术棒–>Debug–>ST-link Debugger
点击settings–>SW
点击Flash Download–>Erase Full Chip–>add
添加完成后依次点确定,ok完成设置。
进行烧录
点击Download进行下载
下载完成后如图:
至此,完成扫烧录。
步骤3
:
打开野火调试助手,进行验证
具体过程如下图:
可以看到要求已经实现,会连续发送woshiweishien,输入Stop,stm32时,会停止发送。
相关代码:(因为在野火官网可以下载现成的,故只给出main函数部分)
#include "led.h"
#include "delay.h"
#include "key.h"
#include "sys.h"
#include "usart.h"
#include
int hcr=1;
int main(void)
{
char stop[]={'S','t','o','p',',','s','t','m','3','2'};
u16 t;
u16 len;
u16 times=0;
delay_init();
NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);
uart_init(115200);
LED_Init();
KEY_Init();
while(hcr)
{
if(USART_RX_STA&0x8000)
{
len=USART_RX_STA&0x3fff;
printf("rnhello windows!:rnrn");
for(t=0;t
{if (hcr>=10) {hcr=0;break;}}
for(t=0;t
{
USART_SendData(USART1, USART_RX_BUF[t]);
while(USART_GetFlagStatus(USART1,USART_FLAG_TC)!=SET);
}
printf("rnrn");//²åÈë»»ÐÐ
USART_RX_STA=0;
}
else
{
times++;
if(times%100==0)
{
printf("rnwoshiiweishenrn");
}
delay_ms(10);
}
}
}
三、重温C语言程序里全局变量、局部变量、堆、栈等概念,并在ubuntu系统中编程,输出信息进行验证
1、全局变量与局部变量
在所有函数外部定义的变量称为
全局变量(Global Variable)
,它的作用域默认是整个程序,也就是所有的源文件,包括 .c 和 .h 文件。
定义在函数内部的变量称为
局部变量(Local Variable)
,它的作用域仅限于函数内部, 离开该函数后就是无效的,再使用就会报错。
局部变量和全局变量的zhongh综合示例演示:
代码:
#include
int n = 10; //全局变量
void func1(){
int n = 20; //局部变量
printf("func1 n: %dn", n);
}
void func2(int n){
printf("func2 n: %dn", n);
}
void func3(){
printf("func3 n: %dn", n);
}
int main(){
int n = 30; //局部变量
func1();
func2(n);
func3();
//代码块由{}包围
{
int n = 40; //局部变量
printf("block n: %dn", n);
}
printf("main n: %dn", n);
return 0;
}
在Ubuntu下编译运行
分析:
对于 func1(),输出结果为 20,显然使用的是函数内部的 n,而不是外部的 n;func2() 也是相同的情况。
func3() 输出 10,使用的是全局变量,因为在 func3() 函数中不存在局部变量 n,所以编译器只能到函数外部,也就是全局作用域中去寻找变量 n。
由{ }包围的代码块也拥有独立的作用域,printf() 使用它自己内部的变量 n,输出 40。
C语言规定,只能从小的作用域向大的作用域中去寻找变量,而不能反过来,使用更小的作用域中的变量。对于 main() 函数,即使代码块中的 n 离输出语句更近,但它仍然会使用 main() 函数开头定义的 n,所以输出结果是 30。
2、堆与栈
在 C 语言中,内存分配方式不外乎有如下三种形式:
从静态存储区域分配:它是由编译器自动分配和释放的,即内存在程序编译的时候就已经分配好,这块内存在程序的整个运行期间都存在,直到整个程序运行结束时才被释放,如全局变量与 static 变量。
在栈上分配:它同样也是由编译器自动分配和释放的,即在执行函数时,函数内局部变量的存储单元都可以在栈上创建,函数执行结束时这些存储单元将被自动释放。需要注意的是,栈内存分配运算内置于处理器的指令集中,它的运行效率一般很高,但是分配的内存容量有限。
从堆上分配:也被称为动态内存分配,它是由程序员手动完成申请和释放的。即程序在运行的时候由程序员使用内存分配函数(如 malloc 函数)来申请任意多少的内存,使用完之后再由程序员自己负责使用内存释放函数(如 free 函数)来释放内存。也就是说,动态内存的整个生存期是由程序员自己决定的,使用非常灵活。需要注意的是,如果在堆上分配了内存空间,就必须及时释放它,否则将会导致运行的程序出现内存泄漏等错误。
堆与栈的综合示例演示:
代码:
#include
#include
int main(void)
{
/*在栈上分配*/
int i1=0;
int i2=0;
int i3=0;
int i4=0;
printf("栈:向下n");
printf("i1=0x%08xn",&i1);
printf("i2=0x%08xn",&i2);
printf("i3=0x%08xn",&i3);
printf("i4=0x%08xnn",&i4);
printf("--------------------nn");
/*在堆上分配*/
char *p1 = (char *)malloc(4);
char *p2 = (char *)malloc(4);
char *p3 = (char *)malloc(4);
char *p4 = (char *)malloc(4);
printf("p1=0x%08xn",p1);
printf("p2=0x%08xn",p2);
printf("p3=0x%08xn",p3);
printf("p4=0x%08xn",p4);
printf("堆:向上nn");
/*释放堆内存*/
free(p1);
p1=NULL;
free(p2);
p2=NULL;
free(p3);
p3=NULL;
free(p4);
p4=NULL;
return 0;
}
在Ubuntu下编译运行
分析:
从运行结果中不难发现,内存中的栈区主要用于分配局部变量空间,处于相对较高的地址,其栈地址是向下增长的;而堆区则主要用于分配程序员申请的内存空间,堆地址是向上增长的。
四、重温C语言程序里全局变量、局部变量、堆、栈等概念,在Keil中针对stm32系统进行编程,调试变量,进行验证; 通过串口输出信息到上位机,进行验证。
1、栈区(stack)
临时创建的局部变量存放在栈区。
函数调用时,其入口参数存放在栈区。
函数返回时,其返回值存放在栈区。
const定义的局部变量存放在栈区。
2、堆区(heap)
堆区用于存放程序运行中被动态分布的内存段,可增可减。
可以有malloc等函数实现动态分布内存。
有malloc函数分布的内存,必须用free进行内存释放,否则会造成内存泄漏。
3、.bss段
未初始化的全局变量存放在.bss段。
初始化为0的全局变量和初始化为0的静态变量存放在.bss段。
.bss段不占用可执行文件空间,其内容有操作系统初始化。
4、.data段
已经初始化的全局变量存放在.data段。
静态变量存放在.data段。
.data段占用可执行文件空间,其内容有程序初始化。
const定义的全局变量存放在.rodata段。
在串口通信工程中将main函数代码改成如下:
#include "led.h"
#include "delay.h"
#include "key.h"
#include "sys.h"
#include "usart.h"
#include
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); //ÉèÖÃNVICÖжϷÖ×é2:2λÇÀÕ¼ÓÅÏȼ¶£¬2λÏìÓ¦ÓÅÏȼ¶
uart_init(115200); //´®¿Ú³õʼ»¯Îª115200
LED_Init(); //LED¶Ë¿Ú³õʼ»¯
KEY_Init(); //³õʼ»¯Óë°´¼üÁ¬½ÓµÄÓ²¼þ½Ó¿Ú
while(1)
{
for(t=0;t
{
USART_SendData(USART1, USART_RX_BUF[t]);//Ïò´®¿Ú1·¢ËÍÊý¾Ý
while(USART_GetFlagStatus(USART1,USART_FLAG_TC)!=SET);//µÈ´ý·¢ËͽáÊø
}
USART_RX_STA=0;
times++;
if(times%500==0)
{
printf("rnǶÈëʽ´®¿ÚʵÑérn");
printf("hcr@2219491180qqcomrnrn");
printf("Õ»Çø-±äÁ¿µØÖ·rn");
printf(" i:%prn", &i);
printf(" p:%prn", &p);
printf(" str:%prn", str);
printf("n¶ÑÇø-¶¯Ì¬ÉêÇëµØÖ·rn");
printf(" %prn", p1);
printf(" %prn", p2);
printf("rn.bss¶Îrn");
printf("nÈ«¾ÖÍⲿÎÞ³õÖµ k2£º%prn", &k2);
printf("¾²Ì¬ÍⲿÎÞ³õÖµ k4£º%prn", &k4);
printf("¾²Ì¬ÄÚ²¿ÎÞ³õÖµ m2£º%prn", &m2);
printf("rn.data¶Îrn");
printf("nÈ«¾ÖÍⲿÓгõÖµ k1£º%prn", &k1);
printf("¾²Ì¬ÍⲿÓгõÖµ k3£º%prn", &k3);
printf("¾²Ì¬ÄÚ²¿ÓгõÖµ m1£º%prn", &m1);
printf("rn³£Á¿Çøn");
printf("ÎÄ×Ö³£Á¿µØÖ· £º%prn",var1);
printf("ÎÄ×Ö³£Á¿µØÖ· £º%prn",var2);
printf("rn´úÂëÇøn");
printf("³ÌÐòÇøµØÖ· £º%pn",&main);
printf("rn end rnrnrn");
}
delay_ms(10);
}
}
在keil中如下图:
在进行烧录,烧录过程在STM32的USART窗口通讯程序中已经给出。
举报
更多回帖
rotate(-90deg);
回复
相关问答
STM32
USART
通讯程序
STM32
的
USART
窗口
通讯
程序
该如何
去
实现
呢
2021-12-07
853
求大佬分享
STM32
的
USART
窗口
通讯
程序
2022-02-10
498
怎样
去
完成
STM32
的
USART
串口
通讯
程序
2021-09-28
1011
如何完成
STM32
的
USART
窗口
通讯
实验
2022-02-24
745
求大佬分享在
STM32
的
USART
窗口
通讯
程序
2021-12-02
339
怎样
去
实现
一种
USART
串口通信
程序
呢
2022-02-18
686
怎样在ubuntu中对
stm32
系统进行编程
呢
2021-12-02
1231
怎样
去
完成一个
STM32
的
USART
串口
通讯
程序
呢
2022-02-18
537
如何
去
实现
stm32
USART
串口的
程序
代码
呢
2021-12-10
789
如何
去
实现
STM32
的
USART
串口接收数据处理
呢
2021-12-09
749
发帖
登录/注册
20万+
工程师都在用,
免费
PCB检查工具
无需安装、支持浏览器和手机在线查看、实时共享
查看
点击登录
登录更多精彩功能!
首页
论坛版块
小组
免费开发板试用
ebook
直播
搜索
登录
×
20
完善资料,
赚取积分