通信目的:的将一个设备数据传送到另一个设备,扩展硬件系统。
通信协议:制定通信规则,通信双方按照协议规则进行数据收发。
并行通信(传输原理:数据各个位同时传输;优点:速度快;缺点:占用引脚资源多;)
串行通信(传输原理:数据按位顺序传输;优点:占用引脚资源少;缺点:速度相对较慢;)
串行通信是指外设和计算机间,通过数据信号线 、地线、控制线等,按位进行传输数据的一种通讯方式,如SPI、USART、EEPROM通信等。串口通信实现了上位机(一般就是我们的电脑)与下位机(也就是我们的嵌入式设备,如51单片机,STM32)之间的信息交互。上位机可通过串口调试助手等实现数据的发送接收。
(a)单工:数据传输只支持数据在一个方向上传输,发送端->接收端。(只收不发和只发不收)
(b)半双工:允许数据在两个方向上传输,但是在某一时刻,只允许数据在一个方向上传输。实际上是一种能切换方向的单工通信。(能发能收,但不能同时进行)
(c)全双工:允许数据同时在两个方向上传输。全双工通信是两个单工通信方式的结合,它要求发送和接受设备都有独立的接收和发送能力。(能发能收,且能同时进行)
同步通信:带时钟同步信号(SCK,SCL....)。传输信息发送设备与信息接收设备需要时钟同步,两者间除数据线互连外,还需要有额外的时钟线进行互连,比如:SPI,IIC通信接口。
异步通信:不带时钟同步信号。信息发送设备与接收设备之间只需要数据线连接,无需额外的时钟线互联。虽然双方没有时钟线互联,但是通信双方是需要有约定的,比如说波特率(波特率确定了,每个位传输的时间就确定了),起始位,停止位,奇偶校验位等。接收设备根据约定利用自己的本地时钟对数据进行采样。比如:UART(通用异步收发器),单总线(1-wire)。
STM32的串行通信接口:UART:通用异步收发器 ; USART:通用同步异步收发器
STM32F4XX目前最多支持8个UART,STM32F103支持5个UART。
TXD:数据输出脚,数据发送。RXD:数据输入脚,数据接收。
TTL电平标准:输出 L:<0.8V;H:>2.4V;输入 L:<1.2V ;H:>2.0V。
RS232电平标准:逻辑1的电平为-3~-15V,逻辑0的电平为+3~+15V。
RS485电平标准:两线的压差+2~+6V表示逻辑1,-2~-6V表示逻辑0(差分信号)。
485的这种差分信号抗干扰能力比较强。485通信距离可达上千米,TTL和232也就几十米。
MCU和一些应用模块通常都是TTL电平。电脑,工业设备或者一些模块通常都是232电平。
TTL电平相同可以相互通讯;232电平相同时可以进行通讯。但是TTL和232之间是不能直接进行通讯,必须进行电平转换,通过转换芯片。
全双工异步通信。
支持小数波特率发生器系统,提供精确的波特率。
可配置8倍或者1倍过采样,为速度容差和时钟容差的灵活配置提供可能。
可编程的数据字长(8或9位),是否带奇偶校验位。
可配置的停止位(1或2位)。
可配置使用DMA多缓冲器通信(支持DMA)。
单独的发送器和接收器使能位。
可触发中断。
校验控制,四个错误检测标志。
数据发送过程:
数据接收过程:
起始位:比如下面范例,一开始电平为高,到起始位电平拉低告诉接收方要接收有用的数据了。
数据位:(8位或9位,9位是带奇偶校验位)低位先行。要发送0011,就要1100这样顺序。
奇偶校验位(第9位):奇校验:包括校验位在内的9个数据会出现奇数个1。偶校验同理。
停止位:与起始位差不多。
波特率设置:决定了每隔多长时间发送一位 / 接收一位。
例如:发送一个字节数据0x55,波特率为9600,1起始位,8数据位,1停止位,无校验。遵循低位先行。TX引脚输出的波形。
当输入电路侦测到一个数据帧的起始位后,以波特率的16倍频率进行采样:在1位的时间里可以进行16次采样。
比如:一开始一直采样结果为1,突然采样到0,说明两次采样间出现了下降沿,进入到起始位,在起始位会进行连续16次采样,没噪声干扰的话,16次采样都是低电平。实际电路会存在一些噪声。在3,5,7这三个位里至少有2个0, 8,9,10这三个位里也至少有2个0,才说明是起始位。否则重新侦测。因为8,9,10次侦测在一位信号的正中间,因此后面接收数据位时,也都在8,9,10次侦测位置进行采样。8,9,10位全为1或者全为0分别代表收到1或0。
比如设备A向设备B发送数据,若发送过快,设备B处理不过来。在无硬件流控制的情况下,设备B只能抛弃新数据或者覆盖原数据。若有硬件流控制:在硬件电路上会多出一根硬件流控制的连线,如果B没准备好接收,就置高电平,如果准备好了,就置低电平。这样的话,A接收到B的反馈信号,就只在B设备准备好的情况下才发数据。硬件流控制可以防止因为B设备处理慢而导致数据丢失的问题。
硬件流控制的两个脚:nRTS,nCTS。当A设备要给B设备发送数据时候。A设备的CTS接B设备的RTS。此时B设备反馈给A设备是否能接收。
唤醒单元:多设备时使用,被CS片选的设备就会被唤醒。
数据包作用:把单独数据打包,方便进行多字节通信。
比如:陀螺仪传感器的数据,X,Y,Z三个坐标数据。不知道接收从哪一时刻哪一位置开始接收,因此将三个数据进行一次打包,每次发送一包数据,就可以防止传输出现数据错位的问题。
打包数据的方法可自行设计,这就属于设计编码方法。如下方法:
HEX数据包:传输直接,适合一些模块发送原始的数据,比如串口通信的陀螺仪,温湿度传感器之类的。
固定包长,含包头包尾。如下:一批数据四个字节数据加上包头包尾2个字节数据打包。
可变包长,含包头包尾。如下:可变字节的一批数据加上包头包尾2个字节数据打包。
避免数据和包头包尾重复:限制数据可变范围;规定固定数据包长;增加包头包尾的长度。
文本数据包:相比HEX数据包,每个数据经过一层编码和译码,最终表现出来的就是文本格式。实际上每个文本字符背后都还是1个字节的HEX数据。
数据直观,适合一些输入指令,人机交互的场合,比如蓝牙模块的AT指令,CNC和3D打印机常用的G代码。
固定包长,含包头包尾。
可变包长,含包头包尾。
大量字符可以作为包头包尾,有效避免载荷和包头包尾重复的问题。
状态机设计:多标志位状态的方式。
三个状态:等待包头,接收数据,等待包尾。每个状态用一个变量标记。S=1,2,3。类似于标志位等待包头状态持续,直到收到包头0xFF,才在下次进入中断时候置S=1进入下个状态接受数据。在接收数据状态,再用一个变量记录接收到了多少数据,收够了在下次中断时置S=2进入等待包尾的状态。收到包尾0xFE后再转到S=1状态等待下个数据包包头。
可变包长的接收情况:在S=1的状态还要兼具等待包尾的功能,因为可变包长,包尾随时会发来。在S=1状态,收到一个数据,判断是否是\r,如果不是则正常接收,如果是则不接收,跳到S=2状态等待包尾\n。(这是两个包尾\r\n的情况,若只有一个包尾,则状态改为2给就行,在S=1状态直接跳到S=0状态即可。)
USART_SR:状态寄存器->记录一些串口发送过程中的状态
位 8 LBD: LIN 断路检测标志 (LIN break detection flag)
位 7 TXE:发送数据寄存器为空 (Transmit data register empty)
位 6 TC:发送完成 (Transmission complete)
位 5 RXNE:读取数据寄存器不为空 (Read data register not empty)
位 4 IDLE:检测到空闲线路 (IDLE line detected)
位 3 ORE:上溢错误 (Overrun error)
位 2 NF:检测到噪声标志 (Noise detected flag)
位 1 FE:帧错误 (Framing error)
位 0 PE:奇偶校验错误 (Parity error)
USART_DR:数据寄存器->CPU读写此寄存器
USART_BRR:波特率寄存器
读取状态寄存器USART_SR的值,返回一个状态值(SET or RESET):
FlagStatus USART_GetFlagStatus(USART_TypeDef* USARTx, uint16_t USART_FLAG);
读写数据寄存器USART_DR的函数:
void USART_SendData(USART_TypeDef* USARTx, uint16_t Data);
uint16_t USART_ReceiveData(USART_TypeDef* USARTx);
控制波特率寄存器USART_BRR的函数:
void USART_Init(USART_TypeDef* USARTx, USART_InitTypeDef* USART_InitStruct);
USART_InitTypeDef的成员变量:
typedef struct
{
uint32_t USART_BaudRate; //设置串口波特率
uint16_t USART_WordLength; //字长8或9位
uint16_t USART_StopBits; //停止位
uint16_t USART_Parity; //极性(奇偶校验)
uint16_t USART_Mode; //使能发送/接收,或者都使能
uint16_t USART_HardwareFlowControl; //硬件流控制
} USART_InitTypeDef;
串口时钟使能:RCC_APBxPeriphClockCmd();
GPIO 时钟使能RCC_AHB1PeriphClockCmd();
引脚复用映射:GPIO_PinAFConfig();
GPIO端口模式设置:GPIO_Init();模式设置为:GPIO_Mode_AF
串口参数初始化:USART_Init();
开启中断并且初始化NVIC(如果需要开启中断才需要这个步骤):
NVIC_Init(); USART_ITConfig();//使能相关中断
使能串口:USART_Cmd();
编写中断处理函数:USARTx_IRQHandler();
串口数据收发:void USART_SendData();//发送数据到DR
uint16_t USART_ReceiveData()//从DR读取接收到的数据
串口传输状态获取:FlagStatus USART_GetFlagStatus();
void USART_ClearITPendingBit();