一、通信的概念
通信是信息从发送端(Transmitter)到接收端(Receiver)的传输过程,其核心目标是确保数据可靠、高效地传递。在嵌入式系统中,通信是设备与外界(如传感器、上位机、其他模块)交互的基础。
通信系统的核心组成包括以下三个部分:发送端与接收端、传输介质、协议。
- 发送端与接收端:数据的源头和目的地,例如STM32微控制器作为发送端向PC发送数据,或传感器作为发送端向STM32传输采集信息。
- 传输介质:信息传递的物理载体,常见类型包括导线(如铜缆)、光纤(通过光信号传输)、无线电磁波(如Wi-Fi、蓝牙)等,其选择需考虑传输距离、速率和抗干扰能力。
- 协议:通信双方预先约定的规则集合,涵盖数据格式(如帧结构)、时序要求(如波特率同步)、错误检测机制(如校验位、CRC)等,确保数据能准确解析且完整传输。
二、通信的分类及速率
通信系统的数据传输依赖于传输介质与协议规则的协同作用。根据不同的技术特征,通信方式可划分为多种类型:按数据传送方式可分为串行通信与并行通信;按数据同步方式可分为异步通信与同步通信;按数据传输方向则分为单工、半双工与全双工通信。
1. 串行通信与并行通信
串行通信是一种基于单条数据通道逐位顺序传输数据的通信方式,其数据传输过程中每位信息均占用预定义的固定时隙。
并行通信通过多通道同步传输数据,通常以字节(8位)、字(16位)或双字(32位)为单位,利用多条独立数据线同时发送数据位,实现高速批量传输。
2. 异步通信与同步通信
异步通信是一种基于独立时钟源的通信机制,其发送端与接收端分别通过本地时钟控制数据的发送与接收时序。为确保双方数据传输的协调性,需通过预定义协议(如波特率)使两端的时钟频率保持近似一致,而非严格同步。
同步通信是一种严格依赖时钟信号对齐的通信机制,其核心要求是发送端与接收端的时钟频率及相位完全同步。
3. 单工、半双工与全双工通信
单工通信为单向传输模式,数据仅能从发送端向接收端单向流动,无法实现反向传输。其物理链路为单向传输通道,通信双方角色固定(一端恒为发送器,另一端恒为接收器)。
半双工通信支持双向数据传输,但收发操作需分时复用同一物理通道,即某一时刻仅允许单一方向的数据流动。其通过协议层控制传输方向切换,需引入握手信号或时序仲裁机制以避免冲突。
全双工通信允许数据在发送端与接收端之间同时进行双向传输,通常通过独立物理通道(如双绞线对)或频分复用技术实现收发路径隔离,彻底消除传输方向切换带来的时序瓶颈。
4.通信速率
衡量通信性能的一个非常重要的参数就是通信速率,通常以比特率(Bitrate)来表示。比特率是每秒钟传输二进制代码的位数,单位是:位/秒(bps)。如每秒钟传送 240 个字符,而每个字符格式包含 10 位(1 个起始位、1 个停止位、8个数据位),这时的比特率为:10 位×240 个/秒 = 2400 bps
三、USART简介
USART即通用同步异步收发器,是一种通用的串行、异步通信总线。该总线有两条数据线,可以实现全双工的发送和接收在嵌入式系统中常用于主机与辅助设备之间的通信。
任何USART双向通信至少需要两个脚:接收数据输入(RX)和发送数据输出(TX)。
对于串口通信来说,它的数据帧一般由以下几个部分组成:起始位,数据位,校验位,停止位。
串口通讯的一个数据包从起始信号开始,直到停止信号结束。数据包的起始信号由一个逻辑 0 的数据位表示,而数据包的停止信号可由 0.5、1、1.5 或 2 个逻辑 1 的数据位表示,只要双方约定一致即可。
在数据包的起始位之后紧接着的就是要传输的主体数据内容,也称为有效数据,有效数据的长度常被约定为 5、6、7 或 8 位长。
在有效数据之后,有一个可选的数据校验位。由于数据通信相对更容易受到外部干扰导致传输数据出现偏差,可以在传输过程加上校验位来解决这个问题。校验方法有奇校验 (odd)、偶校验(even)、0 校验 (space)、1 校验 (mark) 以及无校验 (noparity)。
四、STM32的USART使用
实验:编写一个程序实现开发板的USART1与电脑通信,如果电脑有发送数据过来,STM32芯片就会产生接收标志,我们main函数接收数据,并马上把数据返回发送给电脑。
USART1使用STM32芯片的PA9和PA10作为串口的数据发送引脚(TX)、数据接收引脚(RX)。
1.配置步骤(USART1通信)
- 使能USART1和GPIO外设时钟
- 初始化GPIO
- 初始化USART1
- 使能串口1
2.代码编写
usart_drv.c文件
#include "usart_drv.h"
/**********************************************************************
* @brief : 串口1初始化函数
*
* @param : baudrate 波特率
* @retval : 无
**********************************************************************/
void USART_Config(u32 baudrate)
{
GPIO_InitTypeDef GPIO_InitStruct;
USART_InitTypeDef USART_InitStruct;
//1、打开时钟
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA | RCC_APB2Periph_AFIO | RCC_APB2Periph_USART1, ENABLE);
//2、配置GPIO
//USART1_TX PA9的配置
GPIO_InitStruct.GPIO_Mode = GPIO_Mode_AF_PP;//复用推挽输出
GPIO_InitStruct.GPIO_Pin = GPIO_Pin_9;
GPIO_InitStruct.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(GPIOA, &GPIO_InitStruct);
//USART1_TRX PA10的配置
GPIO_InitStruct.GPIO_Mode = GPIO_Mode_IN_FLOATING;//浮空输入
GPIO_InitStruct.GPIO_Pin = GPIO_Pin_10;
GPIO_Init(GPIOA, &GPIO_InitStruct);
//3、初始化串口
USART_InitStruct.USART_BaudRate = baudrate; //波特率
USART_InitStruct.USART_HardwareFlowControl = USART_HardwareFlowControl_None; //无硬件流控制
USART_InitStruct.USART_Mode = USART_Mode_Rx | USART_Mode_Tx; //收发模式
USART_InitStruct.USART_Parity = USART_Parity_No; //无校验位
USART_InitStruct.USART_StopBits = USART_StopBits_1; //1个停止位
USART_InitStruct.USART_WordLength = USART_WordLength_8b; //字长位8位
USART_Init(USART1, &USART_InitStruct); //初始化串口1
//4、清空标志位
USART_ClearFlag(USART1, USART_FLAG_TC | USART_FLAG_RXNE); //清除标志位,防止发送数据时丢失数据
//5、使能
USART_Cmd(USART1, ENABLE);
}
usart_drv.h文件
#ifndef __USART_DRV_H
#define __USART_DRV_H
/*头文件*/
#include "stm32f10x.h"
/*宏定义*/
/*函数声明*/
void USART_Config(u32 baudrate);
#endif
main.c文件
#include "led_drv.h"
#include "systick.h"
#include "usart_drv.h"
int main(void)
{
USART_Config(115200);//串口波特率设置为115200
while (1)
{
if(USART_GetFlagStatus(USART1,USART_FLAG_RXNE)!=RESET)//判断USART接收非空标志是否置位
{
USART_ClearFlag(USART1,USART_FLAG_RXNE); //清除接收非空标志
USART_SendData(USART1,USART_ReceiveData(USART1));//将USART1接收到数据发送回去
}
}
}