STM32 USART—串口通信

2023-11-10

目录

一、串口通信协议物理层电平标准:

1.RS232标准:

2.USB转串口通讯(常用)

3.原生的串口到串口

二、串口通信协议软件层:

三、串口功能框图

1.引脚

2.数据寄存器USART_DR

3.字符帧组成介绍

4.发送与接收数据

5.串口的通信速率

四、代码讲解

1.USART初始化结构体:

2.同步时钟初始化结构体:

3.编程时常用到的固件库函数:

五、程序实验

一、串口通信协议物理层电平标准:

1.RS232标准:

RS-232 标准主要规定了信号的用途、通讯接口以及信号的电平标准。

设备A、B两者的电平不同,要把两者的TTL电平都转换为RS-232标准的电平。

1、RS232标准串口主要用于工业设备直接通信

2、电平转换芯片一般有MAX3232, SP3232

2.USB转串口通讯(常用)

结构图:

1、USB转串口主要用于设备跟电脑通信

2、电平转换芯片一般有CH340、PL2303,CP2102,FT232

3、使用的时候电脑端需要安装电平转换芯片的驱动

3.原生的串口到串口

1、原生的串口通信主要是控制器跟串口的设备或者传感器通信,不需要经过电平转换芯片来转换电平,直接就用TTL电平通信。

2、GPS模块、GSM模块、串口转WIFI模块、HC04蓝牙模块。

二、串口通信协议软件层:

 

起始位:由1个逻辑0的数据位表示。

结束位:由0.5、1、1.5或2个逻辑1的数据位表示。

有效数据:在起始位后紧接着的就是有效数据,有效数据的长度常被约定为5、6、7或8位长。

 校验位:可选,为的是数据的抗干扰性。

校验方法分为:奇校验(odd)、偶校验(even)、0校验(space)、1校验(mark)、无校验(noparity)。

奇校验要求有效数据和校验位中“1”的个数为奇数,比如一个8位长的有效数据为:01101001,此时总共有4个“1”,为达到奇校验效果,校验位为“1”,最后传输的数据将是8位的有效数据加上1位的校验位总共9位。偶校验与奇校验要求刚好相反,要求帧数据和校验位中“1”的个数为偶数,比如数据帧:11001010,此时数据帧“1”的个数为4个,所以偶校验位为“0”。0校验是不管有效数据中的内容是什么,校验位总为“0”,1校验是校验位总为“1”。

通常配置无校验位,数据位8,停止位1.

三、串口功能框图

1:引脚 2:数据寄存器 3:控制器 4:波特率

1.引脚

功能引脚 TX:发送数据输出引脚。 RX:接收数据输入引脚。

nRTS:请求以发送 (Request To Send),n 表示低电平有效。如果使能 RTS 流控制,当 USART 接 收器准备好接收新数据时就会将 nRTS 变成低电平;当接收寄存器已满时,nRTS 将被设置为高 电平。该引脚只适用于硬件流控制。

nCTS:清除以发送 (Clear To Send),n 表示低电平有效。如果使能 CTS 流控制,发送器在发送下 一帧数据之前会检测 nCTS 引脚,如果为低电平,表示可以发送数据,如果为高电平则在发送完 当前数据帧之后停止发送。该引脚只适用于硬件流控制。

SCLK:发送器时钟输出引脚。这个引脚仅适用于同步模式。

后面3个都不常用

  

2.数据寄存器USART_DR

9-31位:保留为0,0-8位:包含了发送或接收的数据。由于它是由两个寄存器组成的,一个给发送用(TDR),一个给接收用(RDR),该寄存器兼具读和写的功能

当使能校验位(USART_CR1中PCE位被置位)进行发送时,写到MSB(最高有效位)的值(根据数据的长度不同,MSB是第7位或者第8位)会被后来的校验位取代。当使能校验位进行接收时,读到的MSB位是接收到的校验位。

3.字符帧组成介绍

 

一个字符帧发送需要三个部分:起始位+数据帧+停止位。起始位是一个位周期的低电平,位周期就是每一位占用的时间;数据帧就是我们要发送的8位或9位数据,数据是从最低位开始传输的;停止位是一定时间周期的高电平。

第9位数据是否有效要取决于USART控制寄存器1(USART_CR1) 的M位设置,当M位为0时表示8位数据字长,当M位为1表示9位数据字长,我们一般使用8数据字长。

停止位时间长短是可以通过USART控制寄存器2(USART_CR2)的 STOP[1:0]位控制,可选0.5个、1个、1.5个和2个停止位。默认使用 1停止位。2个停止位适用于正常USART模式、单线模式和调制解调器模式。0.5个和1.5个停止位用于智能卡模式。

将USART_CR1寄存器的PCE位置1就可以启动奇偶校验控制,PS位进行校验选择。接收数据时如果出现奇偶校验位验证失败,会见 USART_SR寄存器的PE位置1,并可以产生奇偶校验中断。

4.发送与接收数据

发送:将USART_CR1寄存器的UE、TE、RE位都要置1(3个使能)。

USART_SR : TXE置1,表示要发送的数据已经全部从发送数据寄存器(TDR)转移到了发送移位寄存器。

USART_CR1 : USART_SR的TXE位置1后,CR1的TXEIE位置1,产生USART中断。

USART_SR : TC置1,表示数据已经通过TX引脚成功发送。

USART_CR1: 当USART_SR中的TC为’1’时,CR1的TCIE位置1,产生USART中断。

接受:USART_SR RXNE置1,数据已接受完成

USART CR1:RXNEIE

5.串口的通信速率

串口通信里面,波特率是等于比特率的。USART_BRR:波特率寄存器

Tx / Rx 波特率 = Fck/16* ( USARTDIV )

这里的Fck是给外设的时钟(PCLK1用于USART2、3、4、5 36M,PCLK2用于USART1 72M)

USARTDIV是一个无符号的定点数。这12位的值设置在USART_BRR寄存器。

四、代码讲解

1.USART初始化结构体:

波特率:115200/9600

字长:0(8位)

模式选择:接收还是发送

2.同步时钟初始化结构体:

同步模式,我们经常用不到。

3.编程时常用到的固件库函数:

1-串口初始化函数

Void USART_Init (USART_TypeDef* USARTx, USART_InitTypeDef* USART_InitStruct)

2-中断配置函数

Void USART_ITConfig(USART_TypeDef* USARTx, uint16_t USART_IT,FunctionalState NewState)

3-串口使能函数

void USART_Cmd(USART_TypeDef* USARTx, FunctionalState NewState)

4-数据发送函数

void USART_SendData (USART_TypeDef*USARTx,uint16_t Data)

5-数据接收函数

uint16_t USART_ReceiveData(USART_TypeDef*USARTx)

6-中断状态位获取函数     

ITStatus USART GetITStatus (USART_TypeDef*USARTx,uint16_t USART_IT)

五、程序实验

【1】单片机给电脑发送数据,电脑上位机把数据打印出来;电脑上位机给单片机发数据,单片机接收到数据之后立马发回给电脑,并打印出来(注意这是两个要求)。

 编程要点:

  单片机接收数据选择中断接收

1-初始化串口需要用到的GPIO(跟之前讲的一样)

2-初始化串口,配置串口的初始化结构体USART_InitTypeDef

3-中断配置(接收中断,中断优先级)

  接收数据我们采用中断的形式,首先配置串口中断优先级,注意这个函数也要复制到该c文件下;然后使能串口接收中断;

	//串口中断优先级配置
	NVIC_Configuration();
	//使能串口接收中断
	USART_ITConfig(DEBUG_USARTx, USART_IT_RXNE, ENABLE);	

最后别忘了写中断服务函数:接收数据

// 串口中断服务函数
void DEBUG_USART_IRQHandler(void)
{
  uint8_t ucTemp;
	if(USART_GetITStatus(DEBUG_USARTx,USART_IT_RXNE)!=RESET)
	{		
		ucTemp = USART_ReceiveData(DEBUG_USARTx);
    USART_SendData(DEBUG_USARTx,ucTemp);    
	}	 
}

这样就可以向单片机发送数据并返回到接收区。但是,如果我们发送的数据较多(比如发送“好好学习天天向上”,8个字符就要产生8次中断,这对于单片机CPU负荷很大,所以我们可以先把发送的数据放在一个缓冲区,等电脑端不发送了,全部缓存好了一起给单片机发送过去。这就是“队列机制”,这个应用十分广泛)。

4-使能串口 USART_Cmd()函数

5-编写发送和接收函数(应用官网写好的发送字符、字符串函数,除此之外,还可以用printf函数来发送数据)

对 printf函数发送数据的解释(较为重要):

我们不能直接调用printf函数来对串口进行发送数据,printf 函数里面会调用 fputc 这个函数(这个函数是真正发送数据的函数);而通过串口把数据发送到电脑的上位机是用 USART_SendData这个函数,所以需要在fputc这个函数里面调用USART_SendData这个函数。因此,我们都写了两个函数放在 bsp_uart.c 文件下:重定向c库函数printf到串口,重定向后可使用printf函数(发送数据);重定向c库函数scanf到串口,重写向后可使用scanf、getchar等函数(接收数据)

///重定向c库函数printf到串口,重定向后可使用printf函数
int fputc(int ch, FILE *f)//发送数据
{
		/* 发送一个字节数据到串口 */
		USART_SendData(DEBUG_USARTx, (uint8_t) ch);
		
		/* 等待发送完毕 */
		while (USART_GetFlagStatus(DEBUG_USARTx, USART_FLAG_TXE) == RESET);		
	
		return (ch);
}

///重定向c库函数scanf到串口,重写向后可使用scanf、getchar等函数
int fgetc(FILE *f)//接收数据
{
		/* 等待串口输入数据 */
		while (USART_GetFlagStatus(DEBUG_USARTx, USART_FLAG_RXNE) == RESET);

		return (int)USART_ReceiveData(DEBUG_USARTx);
}

6-编写中断服务函数

拓展:如果换成串口2的话,软件部分只更改.h文件里的宏定义即可;硬件注意接线连接正确。

【2】电脑给单片机发命令,用于控制开发板上的灯。

int main(void)
{
	/*在程序来到main函数这里的时候,系统时钟已经配置成72M*/
	uint8_t temp;
	
	DEBUG_UART_Config();
	LED_GPIO_Config();//初始化相关的GPIO
	//USART_SendData(DEBUG_USARTx,'a');
	//Usart_SendString(DEBUG_USARTx,"你好");
	printf("你好\n");
	
/*对 printf函数发送数据的解释
	我们不能直接调用printf函数来对串口进行发送数据,
    printf 函数里面会调用 fputc 这个函数(这个函数是真正发送数据的函数),
	而通过串口把数据发送到电脑的上位机是用 USART_SendData这个函数,
	所以需要在 fputc 这个函数里面调用 USART_SendData 这个函数。
	因此,我们都写了两个函数放在 bsp_uart.c 文件下:
	重定向c库函数printf到串口,重定向后可使用printf函数(发送数据)
	重定向c库函数scanf到串口,重写向后可使用scanf、getchar等函数(接收数据)
*/
	while(1)
	{
		temp = getchar();//gatchar()函数只能接收一个字符
/*      getchar 会调用int fgetc(FILE *f)函数,那个函数里面在一直循环判断时候接收完毕
	    这与中断产生冲突,所以我们取消用中断来接收数据,在while循环里面接收数据
*/
		printf("接收到的字符为:%c",temp);
		
		switch(temp)
		{
			case '1': LED1_ON;LED2_OFF; break;
			case '2': LED2_ON;LED1_OFF; break;
			default : LED1_OFF;LED2_OFF;break;
		}
	}
}

getchar 会调用int fgetc(FILE *f)函数,那个函数里面在一直循环判断时候接收完毕,这与中断产生冲突,所以我们取消用中断来接收数据,在while循环里面接收数据。用switch语句来判断接收到的数据,来执行对灯的指令。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

STM32 USART—串口通信 的相关文章

  • 使用 gnueabihf 为 ARMv6 构建

    我尝试为 ARMv6 构建应用程序 但失败了 我猜问题是工具链支持硬浮点 但 ARMv6 不支持 好吧 首先我设置 march armv6 编译失败 opt gcc linaro arm linux gnueabihf 4 8 2014 0
  • 在嵌入式设备上使用new或malloc引起的段错误[关闭]

    这个问题不太可能对任何未来的访客有帮助 它只与一个较小的地理区域 一个特定的时间点或一个非常狭窄的情况相关 通常不适用于全世界的互联网受众 为了帮助使这个问题更广泛地适用 访问帮助中心 help reopen questions 我正在尝试
  • 如何在 Android 设备上运行 VS Code [重复]

    这个问题在这里已经有答案了 我有 Galaxy Tab S6 它具有替代笔记本电脑的很酷的功能 例如连接鼠标和键盘 但不幸的是它运行 Android 操作系统 并且没有很多开发应用程序可用于 Android 所以我想是否有一个选项可以在至少
  • 尝试使用 qemu-arm 运行arm二进制文件时如何解决“加载共享库时出错”?

    我正在运行 Linux Mint 14 并安装了 qemu qemu user 和 gnueabi 工具链 我编译了 test carm linux gnueabi gcc test c o test 当我尝试跑步时qemu arm usr
  • M1 MacBook Pro 上的 Android Studio 无法使用 ABI armeabi-v7a 模拟系统映像

    我的 M1 Macbook Pro 上的 Android Studio 可以很好地模拟 ABI arm64 v8a 的所有系统映像 API 24 29 30 31 但是 它无法使用 ABI armeabi v7a 运行所有映像 例如 API
  • 移动数组中的元素

    我需要一点帮助 我想将数组中的元素向上移动一个元素 以便新位置 1 包含位置 1 中的旧值 new 2 包含 old 1 依此类推 旧的最后一个值被丢弃 第一个位置的新值是我每秒给出的新值 我使用大小为 10 的数组 uint32 t TE
  • 为什么 i2c_smbus 函数不可用? (I2C——嵌入式Linux)

    有很多参考使用i2c smbus 开发嵌入式 Linux 软件时在 I2C 总线上进行通信的函数 什么时候i2c smbus函数如i2c smbus read word data在软件项目中引用了 ARM8 处理器错误 例如 i2c smb
  • 了解 ctags 文件格式

    我使用 Exhuberant ctags 来索引我的 c 项目中的所有标签 c project 是 Cortex M7 微控制器的嵌入式软件 结果是一个标签文件 我正在尝试阅读该文件并理解所写的内容 根据我找到的 ctags 和 Exhub
  • 在linux x86平台上学习ARM所需的工具[关闭]

    Closed 此问题正在寻求书籍 工具 软件库等的推荐 不满足堆栈溢出指南 help closed questions 目前不接受答案 我有一个 x86 linux 机器 在阅读一些关于 ARM 的各种信息时 我很好奇 现在我想花一些时间学
  • 基于 Windows 8 ARM 的平板电脑上的 VB6

    随着 Windows 8 将支持 VB6 我的问题是 Microsoft 是否在任何地方表示 是或否 VB6 应用程序将在基于 ARM 的平板电脑上运行 如果没有 是否有任何 ARM 模拟器 以便我们可以在 Windows 8 ARM 平板
  • saber sd 如何在没有 SPL 的情况下直接从 uboot 启动

    sabre sd 基于 imx 6 最大内部 RAM 约为 150Kb 然而 uboot 足够大 可以容纳在这个空间中 在这个场景中事情是如何进行的 https community freescale com docs DOC 95015
  • 为什么 GCC 交叉编译不构建“crti.o”?

    在尝试为arm构建gcc 4 x x交叉编译器时 我陷入了缺失的困境crti o文件在 BUILD DIR gcc子目录 An strace在顶层Makefile表明编译后的xgcc正在调用交联器ld with crti o 作为一个论点
  • Qemu flash 启动不起作用

    我有一本相当旧的 2009 年出版 嵌入式 ARM Linux 书 其中使用u boot and qemu 的用法qemu与u boot书中对二进制的解释如下 qemu system arm M connex pflash u boot b
  • arm-linux-gnueabi 编译器选项

    我在用 ARM Linux gnueabi gcc在 Linux 中为 ARM 处理器编译 C 程序 但是 我不确定它编译的默认 ARM 模式是什么 例如 对于 C 代码 test c unsigned int main return 0x
  • 什么是遗留中断?

    我正在开发一个项目 试图弄清楚 ARM 架构的全局中断控制器中如何处理中断 我正在使用 pl390 中断控制器 我看到有一条线被称为传统中断 它绕过了分配器逻辑 假设有 2 个中断可以被编程为传统中断 任何人都可以帮助解释一下什么是遗留中断
  • arm64和armhf有什么区别?

    Raspberry Pi Type 3 具有 64 位 CPU 但其架构不是arm64 but armhf 有什么区别arm64 and armhf armhf代表 arm hard float 是给定的名称Debian 端口 https
  • 如何获取结构体中任意成员的位位置

    如何获取结构体中任意成员的位位置 在示例中 gt typedef struct BitExamStruct unsigned int v1 3 unsigned int v2 4 unsigned int v3 5 unsigned int
  • 设备树不匹配:.probe 从未被调用

    我无法理解设备树的工作原理 或者具体来说为什么该驱动程序无法初始化 这是在 android 版本 3 10 的 rockchip 供应商内核中 驱动程序 看门狗 rk29 wdt c 为了可读性而减少 static const struct
  • 为arm构建WebRTC

    我想为我的带有arm926ej s处理器的小机器构建webrtc 安装 depot tools 后 我执行了以下步骤 gclient config http webrtc googlecode com svn trunk gclient s
  • 需要一些建议来开始在 ARM(使用 Linux)平台上编程

    我 也许 很快就会在托管 Linux 发行版的 ARM 平台上工作 我不知道哪个发行版 我知道该项目涉及视频流 但我无法告诉你更多信息 其实我只收到通知 还没见到任何人 我从来没有在这样的平台上工作过 所以我的想法是在项目开始之前进行测试

随机推荐

  • 小程序可以通过以下几种方式下发消息

    1 模板消息 小程序可以通过模板消息向用户发送通知 例如订单状态更新 活动提醒等 开发者需要先在小程序后台设置好模板消息 并获取到模板消息的模板ID 然后在代码中调用相应的API 将模板消息的内容填充并发送给用户 以下是一个示例代码 用于发
  • CSS开发技巧(四):解决flex多行布局的行间距异常、子元素高度拉伸问题

    在使用flex布局时 若出现换行 有两种较为特殊的现象是值得我们研究的 子元素高度被拉伸 其实际高度大于它的内容高度 各行子元素之间的行间距过大 甚至我们根本没有给子元素设置margin 现在我们将要探究引发这两种现象的原因及解决方案 一
  • for循环三种跳出循环的方法(retrun、continue、break)Mark

    1 continue 指的是跳出当前循环 即不执行continue后的语句 直接进入下次循环 continue语句和break语句差不多 不同的是 它不是退出一个循环 而是跳出当前循环 进行下一轮循环 public static void
  • mac 下的 bash gradle command not found

    最近在用android studio 使用命令行打包的时候出现 bash gradle command not found这个问题 其实也就是因为自己唑gradle的环境变量给弄丢了 但是由于来自大山的孩子对于mac不是很熟 所以不知道咋去
  • Redis3.0.7 cluster/集群 安装配置教程

    原文地址 http blog csdn net ouchuquan article details 50884479 参考地址 http doc redisfans com topic cluster tutorial html http
  • ios 轻 App

    整体建议 使用在一些展示项目中 少量数据产生的 需要借助apple平台让用户了解到的 另外 该功能也可以作为品牌宣传 特别是一些景点之类 简单 页面的 轻 App 是 app 的一小部分 因此您可以使用 iOS SDK 在与完整 app 相
  • Rational rose 2007 下载和安装教程

    文章目录 Rational rose 简介 一 下载Rational rose 2007 二 安装Rational rose 2007 三 激活Rational Rose 2007 四 启动Rational Rose 2007 Ration
  • C++多态性

    本文参考浅谈C 多态性 多态性可以简单地概括为 一个接口 多种方法 程序在运行时才决定调用的函数 它是面向对象编程领域的核心概念 多态 polymorphism 字面意思多种形状 C 多态性是通过虚函数来实现的 虚函数允许子类重新定义成员函
  • 11.16---遍历数组赋值给对象失败,const定义常量不能重新再赋值,render的参数

    1 遍历数组赋值给对象失败 取到的都是最后一项的值 let result item list forEach function value item a value a item b value b result pust item 结果得
  • 字符串合并并处理(C++实现)

    按照指定规则对输入的字符串进行处理 详细描述 将输入的两个字符串合并 对合并后的字符串进行排序 要求为 下标为奇数的字符和下标为偶数的字符分别从小到大排序 这里的下标意思是字符在字符串中的位置 对排序后的字符串进行操作 如果字符为 0 9
  • 关于结构体中最后的 char [0]

    问题 结构体中最后定义一个类似 char p 0 这样的成员 有何意义 回复1 这是个广泛使用的常见技巧 常用来构成缓冲区 比起指针 用空数组有这样的优势 1 不需要初始化 数组名直接就是所在的偏移 2 不占任何空间 指针需要占用int长度
  • vue中实现div可编辑,并插入指定元素,样式

    前言 vue中实现一个既可以编辑内容 有可以动态编辑内容插入一个带有样式的内容 改变默认内容后 这个样式消失的效果 这里来整理下调研与解决实现问题之路 实现最终效果 图2为默认内容 1 可以光标点击任意地方 然后点击按钮 插入带有span的
  • 删除流氓软件的方法

    电脑在网上下载一些东西时经常被捆绑下载很多流氓软件 导致电脑是不是跳出一些弹窗广告 烦不胜烦 经过努力奋斗终于把流氓软件都删除了 下面介绍几个删除流氓软件的经验 1 如果软件不是安装在C盘 可以使用bitloacker给D盘加密 这样开机就
  • CAS单点登录-自定义认证登录策略(五)

    在上一节中我们使用了CAS的提供的JDBC 方式的登录认证 基本上能够满足我们多种需求的认证 但是如果CAS框架提供的方案还是不能满足我们的需要 比如我们不仅需要用户名和密码 还要验证其他信息 比如邮箱 手机号 但是邮箱 手机信息在另一个数
  • 毕业设计 - 基于stm32的WiFi监控小车

    文章目录 1 背景 2 系统设计方案 2 1 实现功能 2 1 1 硬件部分 2 1 2 软件部分 2 1 3 WIFI通信功能 2 2 系统架构 2 2 1 WiFi 通信 2 2 2 电机驱动 2 2 3 摄像头 2 2 4 舵机 2
  • 淘宝商品详情

    contact link 待签名参数 uid ttid 231200 taobao android 9 16 0 data 7B 22itemNumId 22 3A 22638728868726 22 7D lng 23 366706 ut
  • 【报错记录】解决CentOS免密失败的问题,以及解决免密问题的排查流程

    前言 本文相当于对之前的文章进行的补充 原创 三台CentOS7非root用户间实现相互间的免密登录 DCTANT的博客 CSDN博客 现场遇到一台旧服务器与其他服务器免密失败的问题 明明 ssh目录中authorized keys中的公钥
  • 图片等比例缩放,javademo

    图片等比缩小 放大需要将图片适配到现有的目标中 思想就是 下面代码 int w Integer parseInt width 原始宽 int h Integer parseInt height 原始高 int w1 450 固定宽 int
  • Ubuntu下如何创建文本文件

    找到要创建文件的位置 右键单机打开终端 输入sudo gedit 文件名字 就可以创建成功啦
  • STM32 USART—串口通信

    目录 一 串口通信协议物理层电平标准 1 RS232标准 2 USB转串口通讯 常用 3 原生的串口到串口 二 串口通信协议软件层 三 串口功能框图 1 引脚 2 数据寄存器USART DR 3 字符帧组成介绍 4 发送与接收数据 5 串口