【stm32_6.1】串行异步接口USART,串口的原理和应用

目录

[1. 通信的方式](#1. 通信的方式)

(1)串行通信

(2)并行通信

[2. 串行通信的数据的传送方向](#2. 串行通信的数据的传送方向)

[3. 串行通信按照数据的通信方式](#3. 串行通信按照数据的通信方式)

[4. 串行接口意义](#4. 串行接口意义)

九针串口

[5. 硬件接线说明](#5. 硬件接线说明)

6.串口通信参数

(1)字符格式

(2)通信速率

[7. USART的使用流程](#7. USART的使用流程)

[8. USART中断请求](#8. USART中断请求)

[案例1 :检测RXNE中断事件标志](#案例1 :检测RXNE中断事件标志)

[案例2 :检测状态标志](#案例2 :检测状态标志)

9.程序设计


1. 通信的方式

" 处理器与外部设备之间 " 或者 " 处理器与处理器之间 " 通信的方式 分两种:串行通信和并行通信。

(1)串行通信

|----------|---------------------------------------------------|
| 串行通信 | 传输原理:数据按位依次顺序传输 (每一位占据固定的时间长度 MSB or LSB) |
| 串行通信 | 优点:占用引脚资源少、成本低、传输距离远 |
| 串行通信 | 缺点:速度慢 |
| 串行通信 | 应用场合:常用于工控、测量设备,以及部分通信设备 如 USB、COM口 |

(2)并行通信

|----------|---------------------------------------|
| 并行通信 | 传输原理:数据按位同时传输(按照字节或者字节的倍数去传输) |
| 并行通信 | 优点:速度快 |
| 并行通信 | 缺点:占用引脚多,成本高、传输距离近、抗干扰能力弱(串扰) |
| 并行通信 | 应用场合:一般适用数据量大、传输距离较近的场合 如计算机总线 |

2. 串行通信的数据的传送方向

单工 :数据只能从一方传向另一方,而不能往反方向传输。这是根据应用的特点,对通信双方的软、硬件进行了简化。单向传输设备,如并行接口打印机就是通过单工的方式进行数据传输的。

例如:打印机

半双工:允许数据往两方传向传输,但只能交替进行,而不能同时进行的传输方式。

例如:对讲机。

全双工 :数据支持同时在两个方向上传输,就相当于两个单工通信的结合。

例如:移动电话。

3. 串行通信按照数据的通信方式

++同步通信 : 带时钟同步信号++,如IIC接口和SPI接口都属于同步通信。

同步通信要求通信双方的时钟必须一致(发送数据的同时进行接收数据)。

同步通信是一种连续串行传输数据的通信方式,一次只传输一帧数据

|----|----------------------|
| 优点 | 相对于异步通信而言,同步通信传输速率更高 |
| 缺点 | 通信双方必须使用同一个时钟 |

++++异步通信++++ ++++:++++ ++++不带时钟同步信号++++ ,如++++UART++++接口就属于异步通信。

UART(Universal Asynchronous Receiver/Transmitter)

  • 异步通信要求++++通信双方必须具有接收器和发送器++++ ,++++但是接收器和发送器可以使用各自的时钟++++。
  • 异步通信是以字符为单位** 去**传输
  • 由于异步通信工作是非同步的,所以接收器必须时刻做好接收数据的准备所以每个字符都会使用 起始位 停止位 代表字符的开始和结束,相比于同步通信而言设备成本低,但是缺点是信道利用率低。

注意:使用异步通信, 通信双方要约定好的字符格式和通信速率 ,否则会导致数据丢失等问题出现。

4. 串行接口意义

串行通信把数据按位进行顺序传输 (一个字节以比特的形式发出 去),++在计算机传输的过程中是使用并行通信的 ,单片机用的是串行通信++ ,所以++++涉及到串转并和并转串++++ 。可以利用软件实现,也可以用硬件实现。如果使用软件(程序/设计算法的方式)实现,会增大CPU的负担(本来CPU传数据就行,现还得转数据),通常使用硬件(串口)实现。

++++串口是计算机进行串行通信的物理接口++++ ,线路简单,++++串口是按位进行数据的收发++++ ,可以++++用一根线(TXD)发送数据的同时用另一根线接收(RXD)。++++

九针串口

常用的串口接口有两种:9针串口(DB-9) 25针串口(DB-25) 每种都分为公头和母头。

一般DB9串口有9个引脚,但是一般作为串口通信时只需要用到三个引脚,分别是RXD、TXD、GND,其他的线一般用于握手。

++单片机和计算机进行串口通信,则需要注意串口的电平协议,单片机采用的是TTL电平,而计算机采用的RS232电平,所以单片机需要和计算机通信,则需要增加如MAX232电平转换芯片进行电气转换。++

TTL电平协议 :采用正逻辑电平 +5V等价于逻辑1 0V等价于逻辑0

RS232电平协议 :采用负逻辑电平 -15V~-3V等价于逻辑1 +3V~+15V等价于逻辑0

5. 硬件接线说明

对于目前,很多设备++++直接采用4针的串口(TXD、RXD、GND、VCC),然后通过CH340芯片进行转换++++,就可以直接通过USB口转串口的方式达到和计算机通信的目的。

串口的输出输入Tx,Rx

USB的输出输入D+,D-

  • 采用有线方式与PC机进行通信 ,则需要用到CH340转换芯片,数据会通过USART1串口传输。
  • 采用无线方式与手机进行通信 ,则不需要用到CH340转换芯片,但是需要通过蓝牙模块进行数据的转发,蓝牙模块如果接在USART1串口的接口,则数据也是通过USART1进行传输。

注意:如果打算实现有线通信和无线通信的结合,则需要把无线通信模块链接在其他的串口上即可, ++++想要和计算机通信,只能使用USART1串口,因为引脚是固定的。++++

单片机传输用的串行通信,计算机传输用的并行通信,==> 涉及串行、并行中间的转换

串口的存在,是为了增加硬件,降低CPU的负担。

CH340是实现USB转串口的转接芯片。

6.串口通信参数

++++串口通信属于全双工异步通信++++ ,所以++通信双方必须具有发送端(TXD)与接收端(RXD)++。

++++由于异步通信不需要时钟来进行数据同步,但是++++ ++++通信双方必须提前约定好字符格式++++ ++++与通信速率。++++

(1)字符格式

在进行串口通信的时候,需要通信双方在协议层规定好传输的数据包(字符帧)的格式 ,字符帧由起始位、数据位、校验位、停止位组成。这样通信双方就可以利用起始位和停止位实现同步。 关于字符格式的相关参数的说明可以参考STM32中文参考手册第26.3.1章节。

(2)通信速率

在串口通信中,如果设置好了通信的字符格式,还需要通信双方约定好通信速率,也就是单位时间内传输的有效二进制数的个数,所以也被称为波特率(bps baud pre second)。

一般串口通信常用的波特率为9600bps 、38400bps、57600bps、115200bps,当然也有其他的选择,波特率有对应的计算公式,可以参考STM32中文参考手册的第26.3.4章节。

举个例子 :大多数使用串口通信的传感器的字符格式都是8bit数据位、1bit停止位、无奇偶校验位,当然还必须有1bit起始位,所以++++一帧数据是10bit,如果通信速率设置为9600bps,则单位时间内能传输的数据帧为9600/10 = 960帧++++。这是使用频率最高的一种通信速率!!!!

7. USART的使用流程

USART指的是++++通用同步异步收发器++++ ,是STM32中的串行通信设备,STM32F407ZET6一共提供了6个串行接口供用户使用,其中4个为USART,2个为UART。++++UART指的是通用异步收发器,其实就是在USART的基础上裁掉了同步通信的功能,只保留了异步通信。++++

平时大家一般都是使用串口的异步通信功能,区分同步还是异步其实很简单,就是看是否在通信是对外提供时钟输出

8. USART中断请求

如果打算串口发送字符串,由于字符串属于字符序列,所以按照顺序发送字符,由于++串口外设的发送数据寄存器是8bit的,每次只能发送1个字符++ ,并且只有等上一次字符发送完成,才可以发送下一个字符。

可以通过检测 "串口外设的发送数据寄存器" 是否为空,来判断待发送的字节是否发送完成 ,所以需要检测状态标志。

案例1 :检测RXNE中断事件标志

cpp 复制代码
void USART1_IRQHandler(void)
{
	/* USART in Receiver mode */	//收到数据的时候发生触发
	if (USART_GetITStatus(USART1, USART_IT_RXNE) == SET)//串口的RX检测到数据
	{
			uint8_t data = 0;
			/* Receive Transaction data */
			data = USART_ReceiveData(USART1);//单片机接收数据
		
		//由于当前单片机没有屏幕显示接收到的数据,只能把接收到的数据返回给计算机
		USART_SendData(USART1, data);
	}
}

USART_SendData() 函数本身是"非阻塞"的。 它只负责将数据写入寄存器,然后立即返回,并不会等待数据真正从硬件上发送完毕。

++++如果在发送完一个字节后,没有确认上一个字节是否发送完成就立即尝试发送下一个字节,可能会导致数据覆盖或丢失。++++

Q :如何确保数据可靠发送?

**调用 USART_SendData() 后,必须配合使用状态标志检查函数 USART_GetFlagStatus() 来确保数据真正发送完毕。**通常有两种等待方式:

  • 等待发送数据寄存器空(TXE, Transmit Data Register Empty)标志: 表示TDR中的数据已经转移到移位寄存器,可以写入下一个数据。这是最常用的方式。
  • 等待发送完成(TC, Transmission Complete)标志: 表示不仅TDR空了,整个数据帧(包括停止位)都已经从移位寄存器发送出去了。在关闭串口或进入低功耗模式前,等待此标志尤为重要。

案例2 :检测状态标志

cpp 复制代码
void SendComputerString(char *string)
{
	while(*string != '\0')
	{
		USART_SendData(USART1, *string++ );
		while(USART_GetFlagStatus(USART1, USART_FLAG_TXE)==RESET);	//检测"发送数据寄存器数据位为空"	
	}
	
}

USART_SendData() : 是单片机/MCU主动给**发数据。 单片机-->**

触发中断 : 触发"计算机上在上位机向MCU发送数据"的中断。 计算机-->单片机

9.程序设计

需求:实现可以向计算机的串口调试助手发送一个字符串,要求把程序封装为一个接口,该接口专门用于发送字符串。

cpp 复制代码
/**
   ******************************************************************************
   * @file    GPIO/GPIO_IOToggle/main.c 
   * @author  
   * @version 
   * @date    03-August-2026
   * @brief   利用USART1和计算机通信	
							USART1_TX -- PA9
							USART1_RX -- PA10
   ******************************************************************************
**/

#include "stm32f4xx.h"  //必须要包含的头文件
#include <string.h>

void delay_us(uint32_t nus);

void delay_ms(uint32_t nms);

void delay_s(uint32_t ns);

void USART1_Config(unsigned int baud)
{
		USART_InitTypeDef USART_InitStructure;
	NVIC_InitTypeDef NVIC_InitStructure;
	GPIO_InitTypeDef GPIO_InitStructure;
	
	//Enable peripheral clock using the following functions
	/* Enable USART clock */
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1, ENABLE);
	
	//According to the USART mode, enable the GPIO clocks
	/* Enable GPIO clock */
	RCC_AHB1PeriphClockCmd( RCC_AHB1Periph_GPIOA , ENABLE);
	
	//Peripheral's alternate function:
	/* Connect USART pins to AF7 */
	GPIO_PinAFConfig(GPIOA, GPIO_PinSource9, GPIO_AF_USART1);
	GPIO_PinAFConfig(GPIOA, GPIO_PinSource10, GPIO_AF_USART1);

	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF;
	GPIO_InitStructure.GPIO_Speed = GPIO_Speed_100MHz;
	GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;
	GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_UP;
	GPIO_InitStructure.GPIO_Pin = GPIO_Pin_9 | GPIO_Pin_10;
	GPIO_Init(GPIOA, &GPIO_InitStructure);
	
	/* Program the Baud Rate, Word Length , Stop Bit, Parity, Hardware 
     flow control and Mode(Receiver/Transmitter) using the USART_Init()
     function. */
	USART_InitStructure.USART_BaudRate = baud;									//波特率
	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(USART1, &USART_InitStructure);
	
	//Enable the NVIC and the corresponding interrupt
	/* NVIC configuration */
	/* Configure the Priority Group to 2 bits */
	NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);

	/* Enable the USARTx Interrupt */
	NVIC_InitStructure.NVIC_IRQChannel = USART1_IRQn;
	NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0;
	NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;
	NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
	NVIC_Init(&NVIC_InitStructure);
	
	USART_ITConfig(USART1, USART_IT_RXNE, ENABLE);//接收缓冲区为空的时候使用中断
	
	// Enable the USART using the USART_Cmd() function.
	USART_Cmd(USART1, ENABLE);
}

//向计算机的串口调试助手发送一个字符串,要求把程序封装为一个接口,该接口专门用于发送字符串。
void SendComputerString(char *string)	//参数里传入一个字符串
{
	while(*string != '\0')
	{
		USART_SendData(USART1, *string++ );
		while(USART_GetFlagStatus(USART1, USART_FLAG_TXE)==RESET);
	}
	
}

int main()
{
	USART1_Config(9600);
	
	while(1)
	{
		SendComputerString("12345\r\n");
		//USART_SendData(USART1, 'f');//单片机给计算机发,不需要中断
		delay_ms(500);
	}
}

void USART1_IRQHandler(void)
{
	/* USART in Receiver mode */	//收到数据的时候发生触发
	if (USART_GetITStatus(USART1, USART_IT_RXNE) == SET)//串口的RX检测到数据
	{
			uint8_t data = 0;
			/* Receive Transaction data */
			data = USART_ReceiveData(USART1);//单片机接收数据
		
		//由于当前单片机没有屏幕显示接收到的数据,只能把接收到的数据返回给计算机
		USART_SendData(USART1, data);
	}
}

void delay_us(uint32_t nus)
{
	SysTick->CTRL = 0; 									// 关闭systick的控制状态寄存器――该寄存器的bit0置0
	SysTick->LOAD = ( 21 * nus - 1); 		// systick的重载寄存器――计数时长 = 计数周期 * 计数次数
	SysTick->VAL = 0; 									// 清空systick的当前数值寄存器
	SysTick->CTRL = 1; 									// 使能systick的控制状态寄存器――该寄存器的bit0置1
	while ((SysTick->CTRL & 0x00010000)==0);// 递减计数到了则控制状态寄存器的bit16为1,计数次数没到则bit16为0.
	SysTick->CTRL = 0; 									//关闭systick的控制状态寄存器
}

void delay_ms(uint32_t nms)
{
	SysTick->CTRL = 0; 									// 关闭systick的控制状态寄存器――该寄存器的bit0置0
	SysTick->LOAD = ( 21*1000*nms - 1); // systick的重载寄存器――计数时长 = 计数周期 * 计数次数
	SysTick->VAL = 0; 									// 清空systick的当前数值寄存器
	SysTick->CTRL = 1; 									// 使能systick的控制状态寄存器――该寄存器的bit0置1
	while ((SysTick->CTRL & 0x00010000)==0);// 递减计数到了则控制状态寄存器的bit16为1,计数次数没到则bit16为0.
	SysTick->CTRL = 0; 									//关闭systick的控制状态寄存器
}

void delay_s(uint32_t ns)
{
	while(ns--)
	{
		delay_ms(500);
		delay_ms(500);
	}
}

同步通信:发送的时候会接收。

Q:如何区分是同步通信or异步通信

A:看算法需要脉冲信号/时钟。

如果需要脉冲信号/时钟,就是同步;

如果不需要脉冲信号/时钟,就是异步。

相关推荐
啧不应该啊4 小时前
Day1 C与python输入输出语句区别
c语言·开发语言
雅斯驰4 小时前
4Gbit密度+16位总线宽度:H5AN4G6NBJR-UHC在DDR4成熟期的产品定位
运维·单片机·嵌入式硬件·物联网·自动化
weixin_456808384 小时前
【沁恒蓝牙开发】电压监控
单片机·嵌入式硬件
LCG元4 小时前
STM32实战:基于RT-Thread的STM32开发环境搭建与LED任务
stm32·单片机·嵌入式硬件
ye150127774554 小时前
220V转12V1000mA恒流驱动WT5112
单片机·嵌入式硬件·其他·硬件工程
wuminyu5 小时前
专家视角看Java多态性的底层基石vtable(虚函数表)构建过程解析
java·linux·c语言·jvm·c++
青山_FPGA5 小时前
以太网 MAC-PHY 接口总结
嵌入式硬件·macos
振南的单片机世界5 小时前
函数调用时,返回地址和局部变量都存“栈”里
stm32·单片机·嵌入式硬件
ye150127774555 小时前
220V降12V降24V风扇驱动WT5112
单片机·嵌入式硬件·其他·硬件工程