一、通信接口背景知识
1.通信的两种方式:
①并行通信
- 传输原理:数据各个位同时传输。
- 优点:速度快
- 缺点:占用引脚资源多
②串行通信
- 传输原理:数据按位顺序传输。
- 优点:占用引脚资源少
- 缺点:速度相对较慢
2.串行通信
按照数据传送的方向,分为: - 单工:数据传输只支持数据在一个方向上传输
- 半双工:允许数据在两个方向上传输,但是,在某一时刻,只允许数据在一个方向上传输,它实际上是一种切换方向的单工通信
- 全双工:允许数据同时在两个方向上传输,因此,全双工通信是两个单工通信方式的结合,它要求发送设备和接收设备都有独立的接收和发送能力。
3.串行通信的通信方式
- 同步通信:带时钟同步信号传输
如SPI,IIC通信接口 - 异步通信:不带时钟同步信号
如UART(通用异步收发器),单总线
4.常见的串行通信接口:
通信标准 | 引脚说明 | 通信方式 | 通信方向 |
---|---|---|---|
UART(通用异步收发器) | TXD:发送端、RXD:接受端、GND:公共地 | 异步通信 | 全双工 |
单总线(1-wire) | DQ:发送/接受端 | 异步通信 | 半双工 |
SPI | SCK:同步时钟、MISO:主机输入,从机输出、MOSI:主机输出,从机输入 | 同步通信 | 全双工 |
I2C | SCL:同步时钟、SDA:数据输入/输出端 | 同步通信 | 半双工 |
二、STM32串口通信基础
1.STM32的串口通信接口
- UART:通用异步收发器
- USART:通用同步异步收发器
- 大容量STM32F10x系列芯片,包含3个USART和2个UART
2.UART异步通信方式引脚连接方法 - RXD:数据输入引脚。数据接受。
- TXD:数据发送引脚。数据发送。
串口号 | RXD | TXD |
---|---|---|
1 | PA10 | PA9 |
2 | PA3 | PA2 |
3 | PB11 | PB10 |
4 | PC11 | PC10 |
5 | PD2 | PC12 |
3.UART异步通信方式特点:
- 全双工异步通信。
- 分数波特率发生器系统,提供精确的波特率。
- -发送和接受共用的可编程波特率,最高可达4.5Mbits/s
- 可编程的数据字长度(8位或者9位);
- 可配置的停止位(支持1或者2位停止位);
- 可配置的使用DMA多缓冲器通信。
- 单独的发送器和接收器使能位。
- 检测标志:①接受缓冲器②发送缓冲器空③传输结束标志
- 多个带标志的中断源。触发中断。
- 其他:校验控制,四个错误检测标志。
4.串口通信过程
传输速度由波特率决定。
5.STM32串口异步通信需要定义的参数:
①起始位
②数据位(8位或者9位)
③奇偶校验位(第9位)
- 奇校验:如前面传输了奇数个1,则奇偶校验位设置为0;如前面传输了偶数个1,则奇偶校验位设置为1。
- 偶校验:如前面传输了奇数个1,则奇偶校验位设置为1;如前面传输了偶数个1,则奇偶校验位设置为0。
④停止位(1,15,2位)
⑤波特率设置
6.USART框图
三、 STM32串口常用寄存器和库函数
1.常用的串口相关寄存器
①USART_SR状态寄存器
②USART_DR数据寄存器
③USART_BRR波特率寄存器
④USART_CRx控制寄存器
2.波特率计算方法
T
X
/
R
x
波特率
=
f
P
C
L
K
x
(
16
∗
U
S
A
R
T
D
I
V
)
T_X/R_x波特率=\frac{f_{PCLK_x}}{(16*USARTDIV)}
TX/Rx波特率=(16∗USARTDIV)fPCLKx
- 上式中, f P C L K x f_{PCLK_x} fPCLKx是给串口的时钟(PCLK1用于USART2、3、4、5,PCLK1用于USART1);USARTDIV是一个无符号定点数,我们只要得到USARTDIV的值,就可以得到串口波特率寄存器USART->BRR的值,反过来,我们得到USART->BRR的值,也可以推导出USARTDIV的值。但我们更关心的是如何从USARTDIV的值得到USART_BRR的值,因为一般我们知道的是波特率和 P C L K x PCLK_x PCLKx的时钟,要求的就是USART_BRR的值。
- 假设我们的串口1要设置为115200的波特率,而PCLK2的时钟为72M。这样,我们根据上面的公式有:
U S A R T D I V = 72000000 / ( 115200 ∗ 16 ) = 39.0625 USARTDIV=72000000/(115200*16)=39.0625 USARTDIV=72000000/(115200∗16)=39.0625
那么得到:
DIV_Fraction=16*0.0625=1=0X01(小数部分)
DIV_Mantissa=39=0X27(整数部分)
这样,我们就得到了USART->BRR的值为0X0271。只要设置串口1的BRR寄存器值为0X0271就可以得到115200的波特率。
3.串口操作相关库函数(省略入口参数):
void USART_Init();//串口初始化:波特率、数据字长、奇偶校验、硬件流控以及收发使能
void USART_Cmd();//使能串口
void USART_ITConfig();//使能相关中断
void USART_SendData();//发送数据到串口,DR
unit16_t USART_ReceiveData();//接受数据,从DR读取接受到的数据
FlagStatus USART_GetFlagStatus();//获取状态标志位
void USART_ClearFlag();//消除状态标志位
ITStatus USART_GetITStatus();//获取中断状态标志位
void USART_ClearITPendingBit();//清除中断状态标志位
typedef struct
{
//设置波特率
uint32_t USART_BaudRate;
uint16_t USART_WordLength;
uint16_t USART_StopBits;
//奇偶校验位
uint16_t USART_Parity;
//发送/接收使能
uint16_t USART_Mode;
uint16_t USART_HardwareFlowControl
} USART_InitTypeDef;
4.串口配置的一般步骤
①串口时钟使能,GPIO时钟使能
RCC_APB2PeriphClockCmd();
②串口复位
USART_DeInit();//这一步不是必须的
③GPIO模式设置
GPIO_Init();//模式设置为GPIO_Mode_AF_PP
注意:需要查中文参考手册看设置为什么模式
(8.1.11外设的GPIO配置)
④串口参数初始化
USART_Init();
⑤开启中断并且初始化NVIC(如果需要开启中断才需要这个步骤)
NVIC_Init();
USART_ITConfig();
⑥使能串口
USART_Cmd();
⑦编写中断处理函数
USARTx_IRQHandler();
⑧串口数据收发
void USART_SendData();//发送数据到串口,DR
unit16_t USART_ReceiveData();//接受数据,从DR读取接受到的数据
⑨串口传输状态获取
FlagStatus USART_GetFlagStatus(USART_Typedef*USARTx,unit16_t USART_FLAG);
void USART_ClearITPendingBit(USART_TypeDef*USARTx,unit16_t USART_IT);
四、串口配置一般步骤
#include "stm32f10x.h"
void My_USART1_Init(void)
{
GPIO_InitTypeDef GPIO_InitStructure;
USART_InitTypeDef USART_InitStructure;
NVIC_InitTypeDef NVIC_InitStructure;
//使能GPIO和串口时钟
// RCC_APB2PeriphResetCmd(RCC_APB2Periph_GPIOA,ENABLE);
// RCC_APB2PeriphResetCmd(RCC_APB2Periph_USART1,ENABLE);
//
RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1|RCC_APB2Periph_GPIOA, ENABLE); //使能USART1,GPIOA时钟
//GPIO模式设置
GPIO_InitStructure.GPIO_Pin=GPIO_Pin_9;
GPIO_InitStructure.GPIO_Mode=GPIO_Mode_AF_PP;
GPIO_InitStructure.GPIO_Speed=GPIO_Speed_50MHz;
GPIO_Init(GPIOA,&GPIO_InitStructure);
GPIO_InitStructure.GPIO_Pin=GPIO_Pin_10;
GPIO_InitStructure.GPIO_Mode=GPIO_Mode_IN_FLOATING;
GPIO_Init(GPIOA,&GPIO_InitStructure);
//串口参数初始化
USART_InitStructure.USART_BaudRate=115200;
USART_InitStructure.USART_HardwareFlowControl=USART_HardwareFlowControl_None;//
USART_InitStructure.USART_Mode=USART_Mode_Rx|USART_Mode_Tx;//
USART_InitStructure.USART_Parity=USART_Parity_No;//无奇偶校验
USART_InitStructure.USART_StopBits=USART_StopBits_1;//设置1位停止位
USART_InitStructure.USART_WordLength=USART_WordLength_8b;//字长为8
USART_Init(USART1,&USART_InitStructure);
//使能串口
USART_Cmd(USART1,ENABLE);
//开启中断
USART_ITConfig(USART1,USART_IT_RXNE,ENABLE);
//初始化NVIC
NVIC_InitStructure.NVIC_IRQChannel=USART1_IRQn;//在stm32f10x.h中有
NVIC_InitStructure.NVIC_IRQChannelCmd=ENABLE;
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority=1;
NVIC_InitStructure.NVIC_IRQChannelSubPriority=1;
NVIC_Init(&NVIC_InitStructure);
}
//编写中断服务函数
//在startup_stm32f10x_hd.s中写了格式
void USART1_IRQHandler(void)
{
u8 res;
if (USART_GetITStatus(USART1,USART_IT_RXNE))
{
res=USART_ReceiveData(USART1);
USART_SendData(USART1,res);
}
}
int main(void)
{
//中断优先级分组
NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);
My_USART1_Init();
USART_SendData(USART1,0xaa);
while(1);
}