目录
一、通信特点
异步、串行、全双工
一般描述某种通信的特点为: 同步/异步 , 串行/并行 , 半双工/全双工
同步:要求一个芯片控制另一芯片的时序,一般,两者之间至少采用一个总线连接以控制时钟(“时钟线”),
其中主机主动控制时钟线(通过时钟线输出),从机被动接受时钟线(通过时钟线输入)。
异步:双方不会通过总线连接时钟,异步通信要求双方使用独立的时钟生成装置(波特率发生器),生成相 同的通信速度。
串行:在每个数据方向上仅有一根数据线。每次仅传输一位数据。 并行:在每个数据方向上有多根数据线。每次可以传输数据的多个位(一般是8/16位)
半双工:数据线仅有一组,同一时刻,只有一方控制数据线的发送,另一方接收数据(即双方不能同时发送 数据)
全双工:数据线有两组或以上,同一时刻,通信双方都可以给对方发送数据。
一种通信的特点与它的总线构成是相关的。
二、通信应用
- 部分无线通信模块具有UART通信接口,比如蓝牙模块、NBIOT模块、WIFI模块、GSM模块、GPS模块
- 是一种容易实现的MCU和电脑间的通信方式,用于辅助调试代码 (MCU传送变量、寄存器的值给电脑)
- 用于电脑控制MCU(电脑传送 指令数据 给MCU),通过上位机控制下位机
三、接线示意图
TX:发送引脚
RX:接收引脚
三、UART通信协议
一帧数据的构成:起始位+ 数据位 + 校验位 + 停止位
起始位:1位,逻辑’0’
数据位:5~8位,可以在MCU中设置
校验位:0~1位, 无校验/奇校验/偶校验
奇校验:在数据位中有奇数个逻辑‘1’时,该位为0;否则为1
偶校验:在数据位中有偶数个逻辑‘1’时,该位为0;否则为1
停止位:0.5~2位,(传输每个都会占用固定时长),逻辑‘1’
数据传输顺序:先传送数据的低位
通信速度(波特率baud):在单片机应用,常用通信速度有2400、4800、9600、19200、115200 bit/s
四、STM32F4 串口使用
1、资源分布
查看芯片的数据手册
一共有6个,分别是USART1和USART6挂载在APB2总线(84MHz)
USART2、USART3、UART4、UART5挂载在APB1总线(42MHz)
USART:表示通用同步异步收发器(由于其同步功能应用较少,一般不使用其同步功能)
UART :表示通用异步收发器
2、特性
查看芯片的参考手册 第26章 USART
主要特性:
同步\异步、串行、全双工
过采样倍数可以设置(16倍/8倍)
可以编程设置该接口的通信速度
数据字长度可编程(8 位或 9 位) (这里的数据字包含 数据位 + 校验位)
发送器和接收器具有单独使能位
传输检测标志:(通过查看这些标志,可以确定发生过的事件;若发生了这些事件,则该外设的状态寄存器SR的特定位会被置位)
— 接收缓冲区已满
— 发送缓冲区为空
— 传输结束标志
四个错误检测标志:(SR上有相应的位)
— 溢出错误
— 噪声检测
— 帧错误
— 奇偶校验错误
十个具有标志位的中断源(指该外设有最多10种可以触发中断的事件)
3、UART框图
结合框图和USARTx->CR1寄存器可以确定,对USARTx外设常见配置有:
- 数据帧格式设置(起始位、数据位、校验位、停止位)
- 通信速度设置
- 发送器和接收器使能
- 使能USARTx
框图中可以看出发送寄存器和接收寄存器共同构成DR(数据寄存器),CPU通过对USARTx->DR进行写/读操作可以分别实现发送/接收 数据。
由于串行通信传输一个字节数据需要一定的时间,在上一帧数据传输完成前,不可以立刻传送下一帧数据(强行传输会导致数据丢失)。所以在传输数据时,需要查询发送器/接收器状态,确认是否发生了 一帧数据传送完成 或 准备好接收一帧数据 的事件。
4、使用方法
当相应的GPIO引脚被复用为USRATx的Tx和Rx后,将由此USARTx外设控制这两个GPIO引脚,实现串口通信中的发送和接收(即这两个GPIO引脚将不再受到GPIOx->ODR等寄存器的影响了),开发板相关原理图如下。
5、相关库函数
附:引脚复用库函数
void GPIO_PinAFConfig (GPIO_TypeDef *GPIOx, uint16_t GPIO_PinSource, uint8_t GPIO_AF)
改变指定引脚的映射功能(复用功能)【该操作需要在将GPIO引脚配置为复用模式后使用】
比如,将PA9复用为USART1_Tx
(所有引脚的详细复用功能参考芯片数据手册 第3.7表格—复用功能映射)
GPIO_PinAFConfig (GPIOA, GPIO_PinSource9, GPIO_AF_USART1);
UART库函数
1、void USART_Init (USART_TypeDef *USARTx, USART_InitTypeDef *USART_InitStruct)
基于参数USART_InitStruct 初始化USARTx外设
2、void USART_Cmd (USART_TypeDef *USARTx, FunctionalState NewState)
USARTx外设使能
3、void USART_SendData (USART_TypeDef *USARTx, uint16_t Data)
通过串口发送数据(一个字节)
4、uint16_t USART_ReceiveData (USART_TypeDef *USARTx)
通过串口接收数据(一个字节)
5、void USART_ClearFlag (USART_TypeDef *USARTx, uint16_t USART_FLAG)
清除USARTx的挂起标志
6、FlagStatus USART_GetFlagStatus (USART_TypeDef *USARTx, uint16_t USART_FLAG)
查询USARTx的指定事件是否发生
6、函数实例
(1)初始化
USART1_init();
- 激活GPIOx时钟
- 将使用到引脚配置复用模式
- 将这些引脚映射到USARTx(此后,PA9和PA10作为USART1的发送和接收引脚)
- 激活USARTx时钟
- USARTx库函数初始化
USART_Init () - 使能USARTx
USART_Cmd ()
/***********************************
函数名:uart1_init
参数:u32 baud 波特率
返回值:无
功能:uart1初始化
备注:pa9 (usart1_tx)
pa10(usart1_rx)
***********************************/
void uart1_init(u32 baud)
{
//创建一个清单
GPIO_InitTypeDef gpio_InitStruct;
USART_InitTypeDef usart_InitStruct;
/*将PA9,PA10作为USART1的Tx和Rx*/
//1.激活GPIOA时钟
RCC_AHB1PeriphClockCmd (RCC_AHB1Periph_GPIOA, ENABLE);
//2.配置PA9和PA10为复用模式
//填写清单
gpio_InitStruct.GPIO_Mode = GPIO_Mode_AF ;
gpio_InitStruct.GPIO_OType = GPIO_OType_PP ;
gpio_InitStruct.GPIO_Pin = GPIO_Pin_9 | GPIO_Pin_10 ;
gpio_InitStruct.GPIO_PuPd = GPIO_PuPd_NOPULL ;
gpio_InitStruct.GPIO_Speed = GPIO_Low_Speed ;
//导入清单,完成配置
GPIO_Init (GPIOA, &gpio_InitStruct);
//3.将PA9和PA10映射到USART1
GPIO_PinAFConfig (GPIOA, GPIO_PinSource9, GPIO_AF_USART1);
GPIO_PinAFConfig (GPIOA, GPIO_PinSource10, GPIO_AF_USART1);
/*激活,初始化,使能USART1*/
//4.激活USART1
RCC_APB2PeriphClockCmd (RCC_APB2Periph_USART1, ENABLE);
//5.配置USART1
//填写清单
usart_InitStruct.USART_BaudRate = baud ;
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 ;
usart_InitStruct.USART_WordLength = USART_WordLength_8b ;
//导入清单,完成配置
USART_Init (USART1, &usart_InitStruct);
//6.使能USART1
USART_Cmd (USART1, ENABLE);
}
(2)发送一个字节
/***********************************
函数名:uart1_sendByte
参数:u8 data 待发送内容
返回值:无
功能:通过串口1发送单字节
备注:等待发送完成
***********************************/
void uart1_sendByte(u8 data)
{
//1.往DR写入数据
USART_SendData (USART1, data);
//2.等待本帧的数据位发送完成,清除标志位
while(SET != USART_GetFlagStatus (USART1, USART_FLAG_TXE));
//之后对DR进行写操作,TXE标志位自动清除
}
(3)发送一个字符串
/***********************************
函数名:uart1_sendString
参数:const char *str 指向待发送的字符串
返回值:无
功能:通过串口1发送字符串
备注:字符串(多次调用发送单字节函数)
调用次数 和 字符串长度有关
***********************************/
//(const) char *p / char str[] / (const) u8 *p / u8 str[]
void uart1_sendString(const char *str)
{
//多次调用发送单字节函数
while(*str != '\0')
{
uart1_sendByte(*str);
str++;
}
//由于上方结构未发送'\0',补发'\0'
uart1_sendByte('\0');
}
(4)接收一个字节
/***********************************
函数名:uart1_recvByte
参数:无
返回值:u8 接收到数据
功能:通过串口1接收单字节
备注:等待可以接收
该函数具有阻塞特性
***********************************/
u8 uart1_recvByte(void)
{
//1.等待可以接收一帧数据,考虑清除标志位
while(SET != USART_GetFlagStatus (USART1, USART_FLAG_RXNE));
//2.USARTx库函数接收数据,清除RXNE标志位
return USART_ReceiveData (USART1);
}
(5)接收一个字符串
/***********************************
函数名:uart1_recvString
参数:char *p 指向接收字符串的空间
返回值:无
功能:通过串口1接收字符串
备注:等待可以接收
该函数具有阻塞特性
若接收电脑端XCOM发送字符串,由于该软件
无法发送字符串,但可以勾选发送新行
***********************************/
void uart1_recvString(char *p)
{
u8 data;
do
{
//调用接收单字节函数
data = uart1_recvByte();
*p = data;
p++;
}
while( (data != '\0') && (data != '\n') );//&& (data != '\n') 若不是电脑端发送可以不要
//!((data == '\0') || (data == '\n'))
*p = '\0'; //补充接收'\0'是考虑到会接收到'\n'的情况
}
五、实战《上位机控制开发板小灯》
思路:电脑通过串口与开发板相连,电脑通过串口发送指令(eg:LED_ON),开发板接收指令识别并进行LED灯的操作。
工程代码:
百度云链接:https://pan.baidu.com/s/1f3mj-WE-XMzHI-AMdW_oRg
提取码:aaaa