STM32串口通讯初步学习
本文目录
- 一.说明基于寄存器与基于固件库的stm32 LED流水灯例子的编程方式有什么差异?
- 二.完成STM32的USART窗口通讯程序,要求如下:
- 1.如何进行烧录
- 2.代码执行及其运行结果
- 三.学习C语言程序里全局变量、局部变量、堆、栈等概念,并在ubuntu系统中编程,输出信息进行验证;
- 1.C语言在内存中有哪几个区域?
- 2.一个由c/C++编译的程序占用的内存有哪几个部分?
- 3.例子程序如下:
- 4.关于C语言中关键字volatile的相关问题
- 四.在Keil中针对stm32系统进行编程,调试变量,进行验证; 通过串口输出信息到上位机,进行验证。
一.说明基于寄存器与基于固件库的stm32 LED流水灯例子的编程方式有什么差异?
1.寄存器是中央处理器内的组成部分。寄存器是有限存贮容量的高速存贮部件,它们可用来暂存指令、数据和地址。基于寄存器来进行流水灯的编程,它更贴近底层,对外设的工作原理和运行机理会有更深的理解。
2.STM32标准外设库之前的版本也称固件函数库或简称固件库,是一个固件函数包,它由程序、数据结构和宏组成,包括了微控制器所有外设的性能特征。基于这种方式进行流水灯的编程,会比较简单,易于编程,因为目前比较多的例程是使用固件库编写的。
二.完成STM32的USART窗口通讯程序,要求如下:
1)设置波特率为115200,1位停止位,无校验位。
2)STM32系统给上位机(win10)连续发送“hello windows!”,上位机接收程序可以使用“串口调试助手“,也可自己编程。
3)当上位机给stm32发送“Stop,stm32”后,stm32停止发送。
1.如何进行烧录
(1)我们使用的是野火指南针开发板,配套有相应的教程,其板子连接电脑如下所示:
(2)打开mcuisp助手
(3)进行如下操作即可将文件烧录进去
1.搜索串口
2.选择要下载的HEX文件
3.校验、编程后执行
4.DTR 低电平复位,RTS 高电平进入 bootloader
5.开始进行串口执行
2.代码执行及其运行结果
(1)打开开发板附赠教程中的相应工程
(2)将其中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++;
}
(3)将主函数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);}
}
(4)编译生成hex文件
(5)将上述HEX文件烧录到助手当中,进行编程后,打开串口调试助手,点击打开串口,即可以看到stm32发给电脑的信息了
烧录成功:
串口助手调试:
停止发送:
三.学习C语言程序里全局变量、局部变量、堆、栈等概念,并在ubuntu系统中编程,输出信息进行验证;
1.C语言在内存中有哪几个区域?
- 内存栈区: 存放局部变量名;
- 内存堆区: 存放new或者malloc出来的对象;
- 常数区: 存放局部变量或者全局变量的值;
- 静态区: 用于存放全局变量或者静态变量;
- 代码区:二进制代码。
2.一个由c/C++编译的程序占用的内存有哪几个部分?
1、栈区(stack)— 由编译器自动分配释放 ,存放函数的参数值,局部变量的值等。其操作方式类似于数据结构中的栈。
2、堆区(heap) — 一般由程序员分配释放, 若程序员不释放,程序结束时可能由OS回收 。注意它与数据结构中的堆是两回事,分配方式倒是类似于链表,呵呵。
3、全局区(静态区)(static)—,全局变量和静态变量的存储是放在一块的,初始化的全局变量和静态变量在一块区域(RW), 未初始化的全局变量和未初始化的静态变量在相邻的另一块区域(ZI)。 - 程序结束后有系统释放
4、文字常量区 —常量字符串就是放在这里的。 程序结束后由系统释放 (RO)
5、程序代码区—存放函数体的二进制代码。 (RO)
3.例子程序如下:
例子程序如下:
#include <stdio.h>
#include <string.h>
#include <stdlib.h>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;
}
源代码如上,其在ubantu中运行结果如下所示:
我们可以看到从低地址到高地址,如图:
4.关于C语言中关键字volatile的相关问题
Volatile这个关键字的必要性(真正意义之所在)
但其他程序(例如内核程序或一个中断)修改了内存中该变量的值,此时寄存器R中的值并不会随之改变而更新,由于优化器的作用编译器仍然去利用之前存放在寄存器R中的值,而不去寻址内存中的值(但我们必须改变这个变量的值)。为了解决这种情况C语言就引入了volatile限定词,让代码在引用该变量时多费一点劲儿,再去内存中取出该变量的值。
Volatile和register的对比
volatile 跟以前的 register 相反。 register 告诉编译器尽量将变量放到寄存器中使用, 而volatile 强制将更改后的值写回内存。如果不写回内存,对于一些全局共享的变量,可能导致不一致问题。
Volatile关键字应用的三个地方
1、 修改硬件寄存器,尤其是状态寄存器
大家都知道,在硬件级别,如果寄存器值自动改变了,编译器是不会主动发现的。经过编译器的自动优化,我们读到的都是寄存器中存储的旧的状态寄存器的值, 而非最新的状态寄存器值。
2、 多线程中被几个线程共享的变量
线程修改共享变量var是不会通知编译器的。所以线程A坚持不懈地读着var在寄存器或者cache中的副本,读出来的内容是0, 但很可惜,线程B早就把var变量给修改为1了。鉴于此,我们必须加上volatile这个关键字来解决这个问题。
3、 中断服务程序ISR当中用
ISR:中断服务程序 (interrupt service routine)
四.在Keil中针对stm32系统进行编程,调试变量,进行验证; 通过串口输出信息到上位机,进行验证。
用第二大点的串口通信模板,我们将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){ }
}
其运行结果如下所示:
我们可以看到:
前3个part变量为局部变量,它们储存到了栈中,地址依次减小。
后三个global为全局变量,它们储存到了静态区,地址依次增加。
我们用下面的主函数来定义了静态变量和指针
#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){ }
}
运行结果如下所示:
前三个静态变量储存到了静态区,地址依次增加。
后三个指针储存到了堆中,地址依次增加。
结合两次结果看(针对于测试的3个区域),可以大概看出栈在顶层(地址最大),然后依次是堆,静态区。
总结:
在一个STM32程序代码中,从内存高地址到内存低地址,依次分布着栈区、堆区、全局区(静态区)、常量区、代码区,其中全局区中高地址分布着.bss段,低地址分布着.data段。
总的分布如下所示:
一、栈区(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、代码区
程序执行代码存放在代码区。
字符串常量也有可能存放在代码区。
STM32串口通讯初步学习相关推荐
- K210学习笔记(五)——MAIX BIT(K210)与STM32串口通讯
前言 uart 模块主要用于驱动开发板上的异步串口,可以自由对 uart 进行配置.k210 一共有3个 uart,每个 uart 可以进行自由的引脚映射. 一.MAIX BIT串口使用步骤 1.引脚 ...
- 作业—STM32串口通讯
STM32串口通信 一.基于寄存器与基于固件库的stm32 LED流水灯例子的编程方式有什么差异 二.STM32的USART窗口通讯程序 1.烧录代码 2.代码 3.效果图 三.c语言程序里全局变量. ...
- stm32串口通讯问题
stm32串口通讯问题 在串口试验中,串口通讯不正常,则可能会出现以下问题: 1. 配置完成后,串口没有任何消息打印. 原因:1,端口配置有问题,需要重新检查I/O口的配置 2,接线有问题,检查接线是 ...
- 串口通讯助手学习交流
串口通讯助手学习交流 最近花了一些时间用C#写了一个串口通讯助手,因为工作中用到了串口通信,最开始是用C++中的MFC写的,后面觉得C#更方便一些,使用的都是SerialPort类:而且我的C#也是自 ...
- STM32 —— 串口通讯
STM32 -- 串口通讯 什么是串口通讯 串口通讯(Serial Communication)是一种设备间非常常用的串行通讯方式,因为它简单便捷,因此大部分电子设备都支持该通讯方式,其通讯协议可分层 ...
- STM32—串口通讯详解
串口通讯目录 物理层 协议层 USART简介 开发板与上位机的连接 代码讲解: 一.初始化结构体 二.NVIC配置中断优先级 三.USART配置函数讲解 四.传输数据的函数: 1.发送一个字节 2.发 ...
- STM32串口通讯实现——USB转串口
一.RS232,TTL简介 RS232是个人计算机的通讯接口之一,一般会有两组RS323接口,分别为COM1和COM2,电平标准为+12V为逻辑负,-12为逻辑正. TTL电平为5V为逻辑正,0为逻辑 ...
- STM32串口通讯数据丢失原因分析及解决办法
在进行串口通讯实验时,一时不仔细可能会发现通讯不正常,数据丢失的现象,包括丢失第一个字符,或只收到最后一个字符等等,本文接下来将就这类问题展开讨论. 首先是通过MCU向上位机发送数据: 若程序如下图所 ...
- 嵌入式作业(六):STM32串口通讯
目录 一.基于寄存器与基于固件库的编程方式有什么差异. 二.STM32的USART窗口通讯程序 1.烧录代码的方式 2.代码及效果图 三.C语言程序里全局变量.局部变量.堆.栈等概念 四.stm32的 ...
- Stm32串口通讯的几种方式及其优缺点
1.延时等待 原理:串口发送指令/数据之后,通过延时函数延时一定时间,等待从机的响应. 优点:实现简单,对于快速相应和长度不长的通讯可以使用此方法 缺点:(1)在非实时环境中,由于延时的存在会影响系统 ...
最新文章
- tensorflow 代码调试工具tfdbg的用法
- 儿童吹泡泡水简单配方_儿童吹泡泡水简单配方[组图]
- mysql里添加不了中文_为什么MySQL不能添加中文
- alias怎么每次登陆都保存_alias命令使用说明
- cf1553E. Permutation Shift
- 小米海外召回有潜在风险的电动滑板车 中国区无此风险
- 商业有规律,赚钱有方法,不要在盲目努力了
- Git教程——回到从前 (checkout 针对单个文件)
- 线代总结1 线性代数中的线性方程组
- DevExpress GridView 排序状态下新增行不参与排序
- 英伟达显卡老版本驱动下载网址
- 想定制Android系统实现改机?看完我也会了
- opencv手动实现运动目标检测
- VR系列——Oculus最佳实践:七、虚拟幻境头晕(下)
- 朋友圈点赞、发红包 测试用例的设计点
- 基于layui 2.*省市级三级联动
- 【职业规划】第一篇:程序员分级之初级程序员
- 微信小程序:2022强大的修复版趣味心理测试小程序源码,趣味测试引流裂变神器,流量主激励广告实现管道收益
- NVT 异常开机log
- online operating system 网页操作系统(web操作系统简称Webos) 小调查
热门文章
- 蚂蚁课堂学习笔记之springAop和Ioc
- android刷成苹果手机版下载地址,安卓怎么刷苹果系统 安卓变苹果系统方法教程...
- 北师计算机应用基础开放作业,北师大计算机应用基础开放作业答案
- php中没有 simhei.ttf,linux虚拟主机jpgraph找不到simhei.ttf字体
- Fortran入门教程(十)——结构体
- 21年,周杰伦越发孤独
- 计算机界面视频录制软件,怎么进行电脑界面上的画面录制,推荐下好用的电脑录屏软件呗...
- 情人节送对象什么礼物好?适合送男友的礼物
- 火狐firebug,firepath以及Selenium IDE插件安装方法
- 如何在整个数据库中查寻一条数据?