(1)全双工异步通信
(2)小数波特率发生器系统— 通用可编程收发波特率
(3)数据字长度可编程( 8 位或 9 位)
(4)停止位可配置 - 支持 1 或 2 个停止位
(5)用于同步发送的发送器时钟输出
(6)单线半双工通信
(7)使用 DMA(直接存储器访问)实现可配置的多缓冲区通信— 使用 DMA 在预留的 SRAM 缓冲区中收/发字节
(8)发送器和接收器具有单独使能位
(9)传输检测标志:
— 接收缓冲区已满
— 发送缓冲区为空
— 传输结束标志
(10)奇偶校验控制:
— 发送奇偶校验位
— 检查接收的数据字节的奇偶性
(11)四个错误检测标志:
— 溢出错误
— 噪声检测
— 帧错误
— 奇偶校验错误
(12) 十个具有标志位的中断源:
— CTS 变化
— LIN 停止符号检测
— 发送数据寄存器为空
— 发送完成
— 接收数据寄存器已满
— 接收到线路空闲
— 溢出错误
— 帧错误
— 噪声错误
— 奇偶校验错误
--------------具体见《STMF4XX中文参考手册》
正常工作至少要的两根线
RX: 接收数据输入引脚就是串行数据输入引脚。过采样技术可区分有效输入数据和噪声,从而用于恢复数据。
TX: 发送数据输出引脚。如果关闭发送器,该输出引脚模式由其 I/O 端口配置决定。如果使能了发送器但没有待发送的数据,则 TX 引脚处于高电平。在单线和智能卡模式下,该 I/O用于发送和接收数据( USART 电平下,随后在 SW_RX 上接收数据)。
正常 USART 模式下,通过这些引脚以帧的形式发送和接收串行数据:
● 发送或接收前保持空闲线路
● 起始位
● 数据(字长 8 位或 9 位),最低有效位在前
● 用于指示帧传输已完成的 0.5 个、 1 个、 1.5 个、 2 个停止位
● 该接口使用小数波特率发生器 - 带 12 位尾数和 4 位小数
● 状态寄存器 (USART_SR)
● 数据寄存器 (USART_DR)
● 波特率寄存器 (USART_BRR) - 12 位尾数和 4 位小数。
1、相关引脚(两个没写的是关于硬件流的)
TX:发送数据输出引脚。
RX:接收数据输入引脚。
SW_RX:数据接收引脚,只用于单线和智能卡模式,属于内部引脚,没有具体外部引脚。
SCLK:发送器时钟输出引脚。这个引脚仅适用于同步模式。
2、数据寄存器:
(1)、USART 数据寄存器(USART_DR)只有低 9 位有效,并且第 9 位数据是否有效要取决于USART 控制寄存器 1(USART_CR1)的 M 位设置,当 M 位为 0 时表示 8 位数据字长,当 M位为 1 表示 9 位数据字长,我们一般使用 8 位数据字长。
(2)、USART_DR 包含了已发送的数据或者接收到的数据。 USART_DR 实际是包含了两个寄存器,一个专门用于发送的 可写 TDR,一个专门用于接收的可读 RDR。当进行发送操作时,往 USART_DR 写入数据会自动存储在 TDR 内;当进行读取操作时,向 USART_DR读取数据会自动提取 RDR 数据,TDR 和 RDR 都是介于系统总线和移位寄存器之间。串行通信是一个位一个位传输的,发送时把 TDR 内容转移到发送移位寄存器,然后把移位寄存器数据每一位发送出去,接收时把接收到的每一位顺序保存在接收移位寄存器内然后才转移到 RDR。
3、控制器:控制收发的寄存器,使用 USART 之前需要向 USART_CR1 寄存器的 UE 位置 1 使能 USART。
(1)发送器:当 USART_CR1 寄存器的发送使能位 TE 置 1 时,启动数据发送,发送移位寄存器的数据会在 TX 引脚输出,如果是同步模式 SCLK 也输出时钟信号。
USART以字符帧的方式发送数据:一个字符帧包括:起始位+数据帧+停止位,起始位是一个位周期的低电平,位周期就是每一位占用的时间;数据帧就是我们要发送的 8 位或 9 位数据,数据是从最低位开始传输的;停止位是一定时间周期的高电平。停止位时间长短是可以通过 USART 控制寄存器 2(USART_CR2)的 STOP[1:0]位控制,可选 0.5 个、 1 个、 1.5 个和 2 个停止位。默认使用 1 个停止位。 2 个停止位适用于正常USART 模式、单线模式和调制解调器模式。 0.5 个和 1.5 个停止位用于智能卡模式。
发送器的工作过程:当发送使能位 TE 置 1 之后,发送器开始会先发送一个空闲帧(一个数据帧长度的高电平),接下来就可以往 USART_DR 寄存器写入要发送的数据。在写入最后一个数据后,需要等待 USART 状态寄存器(USART_SR)的 TC 位为 1,表示数据传输完成,如果USART_CR1 寄存器的 TCIE 位置 1,将产生中断。
(2)接收器:
如果将 USART_CR1 寄存器的 RE 位置 1,使能 USART 接收,使得接收器在 RX 线开始搜索起始位。在确定到起始位后就根据 RX 线电平状态把数据存放在接收移位寄存器内,接收完成后就把接收移位寄存器数据移到 RDR 内,并把 USART_SR 寄存器的 RXNE 位置1,同时如果 USART_CR2 寄存器的 RXNEIE 置 1 的话可以产生中断。
4、波特率发生器
5、中断控制:USART中的中断请求
中断事件 | 中断标志 | 使能控制位 |
---|---|---|
发送数据寄存器为空 | TXE | TXEIE |
CTS 标志 | CTS | CTSIE |
发送完成 | TC | TCIE |
准备好读取接收到的数据 | RXNE | RXNEIE |
检测到上溢错误 | ORE | RXNEIE |
检测到空闲线路 | IDLE | IDLEIE |
奇偶校验错误 | PE | PEIE |
断路标志 | LBD | LBDIE |
多缓冲通信中的噪声标志 | NF/ORE/FE | EIE |
上溢错误和帧错误 |
1、实验目的:实现单片机通过串口向电脑发送数据(串口通过USB转串口连接电脑),发送字符、字符串、指定长度字符等。
2、重定向printf函数,scanf、getchar等函数向串口调试助手打印信息,或由串口调试助手向单片机发送数据。
3、通过中断的方式实现电脑向单片机发送数据,并显示到串口调试助手上面。
4、实现串口调试助手控制单片机LED灯。
1、因为用到了串口相关中断,所以要初始化NVIC以及中断优先级分组,
2、初始化串口。
3、编写发送字符、字符串函数(库函数提供了一个发送字符的函数)
4、编写printf等重定向函数
//中断相关函数的编写和初始化
static void NVIC_Configuration(void)
{
NVIC_InitTypeDef NVIC_InitStructure;
/* 嵌套向量中断控制器组选择 */
NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);
/* 配置USART为中断源 */
NVIC_InitStructure.NVIC_IRQChannel = DEBUG_USART_IRQ;
/* 抢断优先级为1 */
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 1;
/* 子优先级为1 */
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 1;
/* 使能中断 */
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
/* 初始化配置NVIC */
NVIC_Init(&NVIC_InitStructure);
}
//中断接收处理函数
void DEBUG_USART_IRQHandler(void)
{
uint8_t ucTemp;
if(USART_GetITStatus(DEBUG_USART,USART_IT_RXNE)!=RESET)//接收数据寄存器不为空的话,可以接收数据了,RXNE表示接收寄存器RDR的是否满了,满了则表示可以继续接收数据了。
{
ucTemp = USART_ReceiveData( DEBUG_USART );
USART_SendData(DEBUG_USART,ucTemp);
}
}
//串口初始化函数
void Debug_USART_Config(void)
{
//第一步:初始化GPIO,将GPIO设置成复用功能,连接到USART
GPIO_InitTypeDef GPIO_InitStructure;
//为了方便移植所以开两次时钟,现在发送和接收都是同一个端口
RCC_AHB1PeriphClockCmd(DEBUG_USART_RX_GPIO_CLK|DEBUG_USART_TX_GPIO_CLK,ENABLE);
/* GPIO初始化 */
GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;//推挽输出
GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_UP; //上拉
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;//输出速度
/* 配置Tx引脚为复用功能 */
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF;//设置为复用模式
GPIO_InitStructure.GPIO_Pin = DEBUG_USART_TX_PIN; //设置端口A
GPIO_Init(DEBUG_USART_TX_GPIO_PORT, &GPIO_InitStructure);//写入初始化函数
/* 配置Rx引脚为复用功能 */
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF;
GPIO_InitStructure.GPIO_Pin = DEBUG_USART_RX_PIN;
GPIO_Init(DEBUG_USART_RX_GPIO_PORT, &GPIO_InitStructure);
/* 连接 PXx 到 USARTx_Tx*/
GPIO_PinAFConfig(DEBUG_USART_RX_GPIO_PORT,DEBUG_USART_RX_SOURCE,DEBUG_USART_RX_AF);
/* 连接 PXx 到 USARTx__Rx*/
GPIO_PinAFConfig(DEBUG_USART_TX_GPIO_PORT,DEBUG_USART_TX_SOURCE,DEBUG_USART_TX_AF);
//第二步:初始化Usart,
USART_InitTypeDef USART_InitStructure;
/* 使能 USART 时钟 */
RCC_APB2PeriphClockCmd(DEBUG_USART_CLK, ENABLE);
/* 配置串DEBUG_USART 模式 */
/* 波特率设置:DEBUG_USART_BAUDRATE */
USART_InitStructure.USART_BaudRate = DEBUG_USART_BAUDRATE;
/* 字长(数据位+校验位):8 */
USART_InitStructure.USART_WordLength = USART_WordLength_8b;
/* 停止位:1个停止位 */
USART_InitStructure.USART_StopBits = USART_StopBits_1;
/* 校验位选择:不使用校验 */
USART_InitStructure.USART_Parity = USART_Parity_No;
/* 硬件流控制:不使用硬件流 */
USART_InitStructure.USART_HardwareFlowControl = USART_HardwareFlowControl_None;
/* USART模式控制:同时使能接收和发送 */
USART_InitStructure.USART_Mode = USART_Mode_Rx | USART_Mode_Tx;
/* 完成USART初始化配置 */
USART_Init(DEBUG_USART, &USART_InitStructure);
// //第三步:配置串口的接收中断
// //NVIC的配置
// NVIC_Configuration();
// /* 使能串口接收中断 */
// USART_ITConfig(DEBUG_USART, USART_IT_RXNE, ENABLE);
//第四步:使能串口
USART_Cmd(DEBUG_USART, ENABLE);
}
/******************** 发送字符串 *****************************/
void Usart_SendString( USART_TypeDef * pUSARTx, char *str)
{
unsigned int k=0;
do
{
Usart_SendByte( pUSARTx, *(str + k) );
k++;
} while(*(str + k)!='\0');//判断是否发送完成
/* 等待发送完成 */
while(USART_GetFlagStatus(pUSARTx,USART_FLAG_TC)==RESET)//获取
{}
}
重定向之后就可以使用printf等函数,但是还是要包含include“stdio.h” 这个库,重定向就是把信息打印到串口上去,在C语言中是打印到输出的文件流里面的
//重定向c库函数printf到串口,重定向后可使用printf函数,就是把printf和具体的硬件相连起来
int fputc(int ch, FILE *f)
{
/* 发送一个字节数据到串口 */
USART_SendData(DEBUG_USART, (uint8_t) ch);
/* 等待发送完毕 */
while (USART_GetFlagStatus(DEBUG_USART, USART_FLAG_TXE) == RESET);
return (ch);
}
///重定向c库函数scanf到串口,重写向后可使用scanf、getchar等函数
int fgetc(FILE *f)
{
/* 等待串口输入数据 */
while (USART_GetFlagStatus(DEBUG_USART, USART_FLAG_RXNE) == RESET);
return (int)USART_ReceiveData(DEBUG_USART);
}
参考书目《STM32F4XX野火书籍》《STM32F4XX中文参考手册》