STM32—串口通讯详解

发布者:星空行者最新更新时间:2021-09-02 来源: eefocus关键字:STM32  串口通讯  物理层  协议层 手机看文章 扫描二维码
随时随地手机看文章

串口通讯(Serial Communication)是一种设备间非常常用的串行通讯方式,因为它简单便捷,因此大部分电子设备都支持该通讯方式,其通讯协议可分层为协议层和物理层。物理层规定通信协议中具有机械、电子功能的特性,从而确保原始数据在物理媒体的传播;协议层主要规定通讯逻辑,统一双方的数据打包、解包标准。通俗的讲物理层规定我们用嘴巴还是肢体交流,协议层规定我们用中文还是英文交流。下面分析一下串口通讯协议的物理层和协议层。


物理层

1.通讯结构

串口通讯的物理层的主要标准是RS-232标准,其规定了信号的用途、通讯接口及信号的电平标准,其通讯结构如下:

在这里插入图片描述

在设备内部信号是以TTL电平标准传输的,设备之间是通过RS-232电平标准传输的,而且TTL电平需要经过电平转换芯片才能转化为RS-232电平,RS-232电平转TTL电平也是如此。


2.电平标准

根据使用的电平标准不同,串口通讯可分为 RS-232标准 及TTL标准,具体标准如下:

在这里插入图片描述

在电子电路中常使用TTL的电平标准,但其抗干扰能力较弱,为了增加串口的通讯距离及抗干扰能力,使用RS-232电平标准在设备之间传输信息,经常使用MA3232芯片对TTL电平及RS-232电平进行相互转换。


协议层

1.数据包

串口通讯的数据包由发送设备通过自身的TXD接口传输到接收设备得RXD接口,在协议层中规定了数据包的内容,具体包括起始位、主体数据(8位或9位)、校验位以及停止位,通讯的双方必须将数据包的格式约定一致才能正常收发数据。

在这里插入图片描述

2.波特率

由于异步通信中没有时钟信号,所以接收双方要约定好波特率,即每秒传输的码元个数,以便对信号进行解码,常见的波特率有4800、9600、115200等。STM32中波特率的设置通过串口初始化结构体来实现。

3.起始和停止信号

数据包的首尾分别是起始位和停止位,数据包的起始信号由一个逻辑0的数据位表示,停止位信号可由0.5、1、1.5、2个逻辑1的数据位表示,双方需约定一致。STM32中起始和停止信号的设置也是通过串口初始化结构体来实现。

4.有效数据

有效数据规定了主题数据的长度,一般为8或9位,其在STM32中也是通过串口初始化结构体来实现的。

5.数据校验

在有效数据之后,有一个可选的数据校验位。由于数据通信相对更容易受到外部干扰导致传输数据出现偏差,可以在传输过程加上校验位来解决这个问题。校验方法有奇校验(odd)、偶校验(even)、 0 校验(space)、 1 校验(mark)以及无(noparity)。这些也都可以在串口初始化结构体中实现的。


USART简介

USART(通用同步异步收发器)是一个串行通信设备,可以灵活地与外部设备进行全双工数据交换。有别于 USART 还有一个UART,它是在 USART 基础上裁剪掉了同步通信功能,只有异步通信。简单区分同步和异步就是看通信时需不需要对外提供时钟输出,我们平时用的串口通信基本都是 UART。USART 在 STM32 应用最多莫过于“打印”程序信息,一般在硬件设计时都会预留一USART 通信接口连接电脑,用于在调试程序是可以把一些调试信息“打印”在电脑端的串口调试助手工具上,从而了解程序运行是否正确、如果出错哪具体哪里出错等等。

STM32中一共有5个USART,如示:

在这里插入图片描述

USART的USB转串口原理图如下:

在这里插入图片描述

USART1的发送和接收端口是事先连接好的,如果要使用其他USART只需要将相应的发送接收端口按图连接好即可。


USART有多个中断请求事件:

在这里插入图片描述

开发板与上位机的连接

开发板与上位机之间通过USB线连接,所以在上位机上要配置一个USB转串口 的驱动,以便把USB传输过来的电平转换为TTL电平,TTL电平才能与串口调试助手建立联系。一般使用CH341驱动作为win10下的USB转串口,驱动安装成功的情况下接入USB会在计算机的设备管理器的端口中发现串口:

在这里插入图片描述

(win7系统一般选择CH340作为USB转串口驱动。)


代码讲解:

固件库编程的一大好处就是我们可以根据固件库函数来学习外设的相关知识,而且固件库函数的编写都是建立在对底层寄存器操作上的,所以通过讲解代码可以更好理解串口通讯相关知识。


一.初始化结构体

typedef struct {

 uint32_t USART_BaudRate; // 波特率

 uint16_t USART_WordLength; // 字长

 uint16_t USART_StopBits; // 停止位

 uint16_t USART_Parity; // 校验位

 uint16_t USART_Mode; // USART 模式

 uint16_t USART_HardwareFlowControl; // 硬件流控制

 } USART_InitTypeDef;


USART初始化结构体中的相应变量都对应着数据包中的相对内容。


二.NVIC配置中断优先级

我们在串口接收信息时采用了触发中断事件,所以要配置一下串口中断的优先级:


NVIC_Configuration(void)

{

  NVIC_InitTypeDef NVIC_InitStructure;

  

  /* 嵌套向量中断控制器组选择 */

  NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);

  

  /* 配置USART为中断源 */

  NVIC_InitStructure.NVIC_IRQChannel = DEBUG_USART_IRQ;

  /* 抢断优先级*/

  NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 1;

  /* 子优先级 */

  NVIC_InitStructure.NVIC_IRQChannelSubPriority = 1;

  /* 使能中断 */

  NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;

  /* 初始化配置NVIC */

  NVIC_Init(&NVIC_InitStructure);

}


中断相关的知识之前详细讲过,此处就不再累赘讲述。

中断知识链接


三.USART配置函数讲解

USART配置函数的主要作用是打开串口与相应的GPIO引脚,配置好相应串口信息与GPIO引脚的工作模式,以便信息的传输与接收。


void DEBUG_USART_Config(void)

{

GPIO_InitTypeDef GPIO_InitStructure;

USART_InitTypeDef USART_InitStructure;

/* 第一步:初始化GPIO */

// 打开串口GPIO的时钟

DEBUG_USART_GPIO_APBxClkCmd(DEBUG_USART_GPIO_CLK, ENABLE);

// 将USART Tx的GPIO配置为推挽复用模式

GPIO_InitStructure.GPIO_Pin = DEBUG_USART_TX_GPIO_PIN;

GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;

GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;

GPIO_Init(DEBUG_USART_TX_GPIO_PORT, &GPIO_InitStructure);


  // 将USART Rx的GPIO配置为浮空输入模式

GPIO_InitStructure.GPIO_Pin = DEBUG_USART_RX_GPIO_PIN;

GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;

GPIO_Init(DEBUG_USART_RX_GPIO_PORT, &GPIO_InitStructure);

/* 第二步:配置串口的初始化结构体 */

// 打开串口外设的时钟

DEBUG_USART_APBxClkCmd(DEBUG_USART_CLK, ENABLE);

// 配置串口的工作参数

// 配置波特率

USART_InitStructure.USART_BaudRate = DEBUG_USART_BAUDRATE;

// 配置 针数据字长

USART_InitStructure.USART_WordLength = USART_WordLength_8b;

// 配置停止位

USART_InitStructure.USART_StopBits = USART_StopBits_1;

// 配置校验位

USART_InitStructure.USART_Parity = USART_Parity_No ;

// 配置硬件流控制

USART_InitStructure.USART_HardwareFlowControl = USART_HardwareFlowControl_None;

// 配置工作模式,收发一起

USART_InitStructure.USART_Mode = USART_Mode_Rx | USART_Mode_Tx;

// 完成串口的初始化配置

USART_Init(DEBUG_USARTx, &USART_InitStructure);


/*--------------------------------------------------------*/

// 串口中断优先级配置

NVIC_Configuration();

// 使能串口接收中断

USART_ITConfig(DEBUG_USARTx, USART_IT_RXNE, ENABLE);

/*--------------------------------------------------------*/

/* 第三步:使能串口 */

// 使能串口

USART_Cmd(DEBUG_USARTx, ENABLE);

}


第一步:打开了GPIO的时钟,设置发送和接收引脚的信息,将Tx(发送引脚)配置为推挽复用模式用来发送数据,Rx(接收引脚)配置为浮空输入模式用来接收数据。


第二步:首先打开USART1 的时钟,根据USART初始化结构体成员配置相关的信息,之后利用初始化函数将初始化结构体中的信息写入相应寄存器中,然后的话就是引用NVIC_Configuration()函数配置串口中断优先级,打开相应的串口接收中断,中断接收函数的参数如下:

在这里插入图片描述

第三步 :最后相当于打开总电源——使能串口


USART配置函数完成后代表,USART1 的接收和发送准备工作已经准备就绪,接下来就是,串口与上位机之间的信息传递了,信息的发送和接收都有相对于的函数。


四.传输数据的函数:

开发板与上位机之间的数据传输可以有多种方法,下面一一介绍:


1.发送一个字节

以USART_SendData(pUSARTx,ch); 函数为基础建立的函数可以向上位机发送一个字节的数据,利用FlagStatus USART_GetFlagStatus(USART_TypeDef* USARTx, uint16_t USART_FLAG) 读取发送数据寄存器的状态来 等待发送寄存器将数据成功发送。


void Usart_SendByte( USART_TypeDef * pUSARTx, uint8_t ch)

{

/* 发送一个字节数据到USART */

USART_SendData(pUSARTx,ch);

/* 等待发送数据寄存器为空 */

while (USART_GetFlagStatus(pUSARTx, USART_FLAG_TXE) == RESET);

}


2.发送字符串

本质是利用上面的字节发送函数逐位发送字符串中的内容


void USART_SendString(USART_TypeDef * pUSARTx, char *str)

{

unsigned int   k=0;

while(*(str+k)!='')

{

USART_SendData(pUSARTx, *(str+k));

/* 等待发送数据寄存器为空 */

while (USART_GetFlagStatus(pUSARTx, USART_FLAG_TXE) == RESET);

k++;

}

while(USART_GetFlagStatus(pUSARTx,USART_FLAG_TC)==RESET);   /* TC:传输完成标志 */

}


3.重定向printf函数发送字符串

关于重定向的知识之前总结过,链接:重定向知识。重定向后的printf()函数功能强大,具有向串口调试助手打印数据的功能,使用方法和c语言时一样,比如printf("欢迎来到小全全的串口实验n");就可以将“欢迎来到小全全的串口实验”这句话发送到上位机中,而且换行符“n”还具有换行作用。


/* 重定向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;

}


4.重定向getchar函数接收字符

具体操作与重定向后的printf函数类似,比如可以通过如下代码向上位机发送已经接收到的数据:


x=getchar();

printf("接收到的字符是:%cn",x);


重定义如下:


///重定向c库函数scanf到串口,重写向后可使用scanf、getchar等函数

int fgetc(FILE *f)

{

/* 等待串口输入数据 */

while (USART_GetFlagStatus(DEBUG_USARTx, USART_FLAG_RXNE) == RESET);


return (int)USART_ReceiveData(DEBUG_USARTx);

}


在使用此函数作为接收数据时记得关闭串口得接收中断!!!


5.通过中断接收

在stm32f10x_it.c中编写USART1中断源相对应得中断函数,利用了固件库函数中的

USART_ReceiveData(DEBUG_USARTx);接收函数

USART_SendData(DEBUG_USARTx, x);发送函数

USART_GetITStatus(DEBUG_USARTx, USART_IT_RXNE);判断标志位函数


/* #define  DEBUG_USART_IRQn         USART1_IRQn 

   #define  DEBUG_USART_IRQHandler   USART1_IRQHandler */

void DEBUG_USART_IRQHandler(void)

{

uint16_t  x;

/* 判断是否收到中断信号 */

if(USART_GetITStatus(DEBUG_USARTx, USART_IT_RXNE) == SET)

{

x = USART_ReceiveData(DEBUG_USARTx);

USART_SendData(DEBUG_USARTx, x);

}


}


结语

以固件库函数编程的思路讲解,未能顾及到众多寄存器的讲解,我认为进行固件库编程本身就是学习操作寄存器的过程,很多时候我们不需要知道如何操作寄存器,只要了解如何操作固件库函数即可。(吹爆固件库编程)

关键字:STM32  串口通讯  物理层  协议层 引用地址:STM32—串口通讯详解

上一篇:STM32—中断详解(配合按键中断代码,代码亲测)
下一篇:STM32—IIC通信(软件实现底层函数)

推荐阅读最新更新时间:2024-11-05 10:45

STM32 USB IAP 步骤
1.下载STM32_USB-FS-Device_Lib_V3.2.1.rar 2.安装DfuSe_Demo_V3.0_Setup.exe。 3.打开...\STM32_USB-FS-Device_Lib_V3.2.1\Project\Device_Firmware_Upgrade\MDK-ARM\DFU.uvproj 修改://#define ApplicationAddress 0x08003000为#define ApplicationAddress 0x08004000(因为要修改程序增加空间) 编译程序,用stlink/Jlink将程序下载到STM32中。 4.用usb线连接STM32板,PC端出现发现新硬件。 5.安装
[单片机]
stm32初始化三个串口
serial.c #include serial.h int fputc(int ch,FILE *p) //在使用printf时系统自动条用此函数 { USART_SendData(USART2,(u8)ch); while(USART_GetFlagStatus(USART2,USART_FLAG_TXE)==RESET); return ch; } /******************************************************************************* * 函 数 名 : serial_in
[单片机]
STM32学习笔记一一内存管理
1.简介 内存管理:指软件运行时对计算机内存资源的分配和使用的技术。其最主要的目的是如何高效,快速的分配,并且在适当的时候释放和回收内存资源。 内存管理的实现方法有很多种,最终都是要实现两个函数: malloc 和 free。 malloc :函数用于内存申请; free: 函数用于内存释放。 1.1 分块式内存管理原理 由上图可知,分块式内存管理由内存池和内存管理表两部分组成。内存池被等分为 n块,对应的内存管理表,大小也为 n,内存管理表的每一个项对应内存池的一块内存。 内存管理表的项值代表的意义:当该项值为 0 的时候,代表对应的内存块未被占用;当该项值非零的时候,代表该项对应的内存块已经被占用,其数
[单片机]
<font color='red'>STM32</font>学习笔记一一内存管理
STM32时钟系统
在STM32上如果不使用外部晶振,OSC_IN和OSC_OUT的接法 如果使用内部RC振荡器而不使用外部晶振,请按照下面方法处理: 1)对于100脚或144脚的产品,OSC_IN应接地,OSC_OUT应悬空。 2)对于少于100脚的产品,有2种接法: 2.1)OSC_IN和OSC_OUT分别通过10K电阻接地。此方法可提高EMC性能。 2.2)分别重映射OSC_IN和OSC_OUT至PD0和PD1,再配置PD0和PD1为推挽输出并输出'0'。此方法可以减小功耗并(相对上面2.1)节省2个外部电阻。 使用HSE时钟,程序设置时钟参数流程: 1、将RCC寄存器重新设置为默认值 RCC_DeInit; 2、
[单片机]
<font color='red'>STM32</font>时钟系统
STM32 Cubemax(十四) ——基于Cubemax的FreeRTOS移植与LED点灯测试
前言 之前的代码其实一直都是裸机在跑,即本质上就是在一个while(1)中在跑,这对于任务量较小的程序来说,没有什么问题。但最近遇到一些工程性的代码,其参考代码均采用了FreeRTOS操作系统,以此来记录一下自己的学习过程。 一、CubeMax移植FreeRTOS 废话不多说,想把FreeRTOS配置起来,再说一些其他东西。 时钟配置 时钟树配置 这个地方主要根据自己的开发板配置下面两个部分 嘀嗒时钟配置 如果使用FreeRTOS,嘀嗒时钟源要使用定时器产生的,这里不说原因,先配置就好。 FreeRTOS配置 这里下面的配置功能,等有特殊功能需要,再介绍,这里不需要动(其实也就是打开或者关闭一些功能) Fr
[单片机]
<font color='red'>STM32</font> Cubemax(十四) ——基于Cubemax的FreeRTOS移植与LED点灯测试
基于STM32的LED点阵屏的设计与实现
近年来,随着信息产业的高速发展,点阵LED 显示屏已广泛应用于金融行业、邮电行业、体育馆、广告业等各种广告发布和信息显示系统,成为信息传送的重要手段。本文介绍的LED 书写点阵屏,不但可以像普通显示屏一样作为信息输出设备,而且可以通过光笔直接在LED 显示屏上进行信息输入,普通的显示屏也具有 手写 的功能了。 1 硬件系统设计 本系统总体框图如图1 所示,由键盘与显示模块、光笔模块、LED 点阵屏模块、STM32 控制模块、电源模块五部分组成。 图1 总体方案方框图 1. 1 核心控制模块 本系统以STM32F103VCT6 为控制核心。 STM32 是32 位微处理器,具有低功耗,中断延迟小,高性能等特点。STM3
[单片机]
基于<font color='red'>STM32</font>的LED点阵屏的设计与实现
stm32中i2c之学习浅谈
首先介绍下自己的学习背景,博主本人是在上周刚入门stm32并且学习gpio口基本用法和中断的介绍。在这样的知识储备下我开始学习I2c通信协议,并尝试编写了师兄布置的一个小任务。 1.1. I2C总线物理结构 首先介绍下i2c通信协议,从物理层上来看这是一种非常简洁明了的通信协议。本身一共就两条总线,一条SCL(时钟总线),一条SDA(数据总线)。通信原理是通过对SCL和SDA线高低电平时序的控制,来 产生I2C总线协议所需要的信号进行数据的传递。在总线空闲状态时,这两根线一般被上面所接的上拉电阻拉高,保持着高电平。硬件图如下: 1.2 I2C总线特征 I2C总线上的每一个设备都可以作为主设备或
[单片机]
<font color='red'>stm32</font>中i2c之学习浅谈
STM32让printf通过串口打印及自定义printf函数
在嵌入式系统中,通过串口打印log是非常重要的调试手段,但是直接调用底层驱动打印信息非常不方便,在c语言中一般使用printf打印基本的显示信息,而默认printf的结果不会通过串口发送,所以需要对printf的输出进行重定向。 有时候需要同时从多个串口输出信息,如果仍然想通过printf函数输出信息,就需要自己写printf的实现。 一. 初始化端口和配置 对串口用到的GPIO进行配置,并对串口的参数进行初始化。 二. 宏定义并实现具体的发送函数 代码在编译时首先判断__GNUC__有无定义,之后将PUTCHAR_PROTOTYPE替换成具体的定义。在keil5中,使用fputc函数,所以其实
[单片机]
<font color='red'>STM32</font>让printf通过串口打印及自定义printf函数
小广播
设计资源 培训 开发板 精华推荐

最新单片机文章
何立民专栏 单片机及嵌入式宝典

北京航空航天大学教授,20余年来致力于单片机与嵌入式系统推广工作。

换一换 更多 相关热搜器件
更多往期活动
随便看看

 
EEWorld订阅号

 
EEWorld服务号

 
汽车开发圈

电子工程世界版权所有 京B2-20211791 京ICP备10001474号-1 电信业务审批[2006]字第258号函 京公网安备 11010802033920号 Copyright © 2005-2024 EEWORLD.com.cn, Inc. All rights reserved