1. 前言
USART是通用(U)同步(S)异步(A)收(R)发(T)器。
STM32F103VGT6上有3个USART和2个UART。
同步与异步的区别是:
通信时是否需要对外提供时钟输出。
官方的usart头文件为:
stm32f10x_usart.h
2. 关于结构体
USART有2个结构体:
与USART运行相关:
USART_InitTypeDef
成员有:
// 波特率
USART_BaudRate
// 字长
USART_WordLength
// 停止位
USART_StopBits
// 校验位
USART_Parity
// USART模式
USART_Mode
// 硬件流控制
USART_HardwareFlowControl
与该成员相关的宏定义有:
USART_WordLength
USART_WordLength_8b
USART_WordLength_9b
USART_Stop_Bits
USART_StopBits_1
USART_StopBits_0_5
USART_StopBits_2
USART_StopBits_1_5
USART_Parity
USART_Parity_No
USART_Parity_Even
USART_Parity_Odd
USART_Mode
USART_Mode_Rx
USART_Mode_Tx
USART_Hardware_Flow_Control
USART_HardwareFlowControl_None
USART_HardwareFlowControl_RTS
USART_HardwareFlowControl_CTS
USART_HardwareFlowControl_RTS_CTS
另一个结构体与同步通信相关。
USART_ClockInitTypeDef
成员有:
USART_Clock // 时钟使能控制
USART_CPOL // 时钟极性控制
USART_CPHA // 时钟相位控制
USART_LastBit // 最尾位时钟脉冲控制
该类成员相关的宏定义
USART_Clock
USART_Clock_Disable
USART_Clock_Enable
USART_CPOL
USART_CPOL_Low
USART_CPOL_High
USART_CPHA
USART_CPHA_1Edge
USART_CPHA_2Edge
USART_LastBit
USART_LastBit_Disable
USART_LastBit_Enable
3. 关于函数方法
// 使用输入的配置信息USART_InitStruct对于USARTx,进行初始化
USART_Init(USART_TypeDef* USARTx,USART_InitTypeDef* USART_InitStruct);
// 使能串口接收中断
USART_ITConfig(USART_TypeDef* USARTx,uint16_t USART_IT, FunctionalState NewState);
// 使能串口USARTx,NewState=>(ENABLE/DISABLE)
USART_Cmd(USART_TypeDef* USARTx, FunctionalState NewState);
// 在 USARTx 中发送数据Data
USART_SendData(USART_TypeDef* USARTx, uint16_t Data);
// 确认串口USARTx的一些标志位是 set状态还是reset状态
USART_GetFlagStatus(USART_TypeDef* USARTx, uint16_t USART_FLAG);
USART_FLAG有:
USART_FLAG_CTS
USART_FLAG_LBD
USART_FLAG_TXE 数据发送寄存器是否为空
USART_FLAG_TC 数据发送完成标志
USART_FLAG_RXNE 数据接收寄存器是否不为空
USART_FLAG_IDLE
USART_FLAG_ORE
USART_FLAG_NE
USART_FLAG_FE
USART_FLAG_PE
// 类似USART_GetFlagStatus,但是专门用来判断中断时间的状态
USART_GetITStatus(USART_TypeDef* USARTx, uint16_t USART_IT);
USART_IT有:
USART_IT_CTS
USART_IT_LBD
USART_IT_TXE
USART_IT_TC
USART_IT_RXNE 数据接收寄存器是否不为空
USART_IT_IDLE
USART_IT_ORE_RX
USART_IT_ORE_ER
USART_IT_NE
USART_IT_FE
USART_IT_PE
// 获取USARTx接收到的数据
USART_ReceiveData(USART_TypeDef* USARTx);
4. 可用模板
- 初始化USART1
USART_Config代码
void USART_Config(void)
{
GPIO_InitTypeDef GPIO_InitStructure;
USART_InitTypeDef USART_InitStructure;
// TODO0:初始化时钟
// 0.1打开串口GPIO的时钟
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);
// 0.2打开串口外设的时钟
RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1, ENABLE);
// TODO1:初始化GPIO
// TODO1.1:将USART Tx的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);
// TODO1.2:将USART Rx的GPIO配置为浮空输入模式
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_10;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;
GPIO_Init(GPIOA, &GPIO_InitStructure);
// TODO2: 初始化USART
// 配置串口的工作参数
// 配置波特率
USART_InitStructure.USART_BaudRate = 115200;
// 配置 针数据字长
USART_InitStructure.USART_WordLength = USART_WordLength_8b;
// 配置停止位
USART_InitStructure.USART_StopBits = USART_StopBits_1;
// 配置校验位
USART_InitStructure.USART_Parity = USART_Parity_No ;
// 配置硬件流控制
USART_InitStructure.USART_HardwareFlowControl = USART_HardwareFlowControl_None;
// 配置工作模式,收发一起
USART_InitStructure.USART_Mode = USART_Mode_Rx | USART_Mode_Tx;
// 完成串口的初始化配置
USART_Init(DEBUG_USARTx, &USART_InitStructure);
// TODO3:初始化NVIC
// 串口中断优先级配置
NVIC_InitTypeDef NVIC_InitStructure;
/* 嵌套向量中断控制器组选择 */
NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);
/* 配置USART为中断源 */
NVIC_InitStructure.NVIC_IRQChannel = DEBUG_USART_IRQ;
/* 抢断优先级*/
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 1;
/* 子优先级 */
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 1;
/* 使能中断 */
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
/* 初始化配置NVIC */
NVIC_Init(&NVIC_InitStructure);
// 使能串口接收中断
USART_ITConfig(USART1, USART_IT_RXNE, ENABLE);
// TODO4:使能串口
USART_Cmd(USART1, ENABLE);
}
备注:
如果想使用printf来打印调试信息,则生成项目时候需要如下勾选:
会生成两个文件:
syscalls.c和tiny_printf.c
修改 syscalls.c 中的 _write 函数如下:
int _write(int32_t file, uint8_t *ptr, int32_t len)
{
/* Implement your write code here, this is used by puts and printf for example */
int DataIdx;
for (DataIdx = 0; DataIdx < len;DataIdx++)
{
__io_putchar(*ptr++);
}
/* return len; */
return len;
}
并在开头加入:
#include "bsp_usart.h"
int __io_putchar(int ch)
{
/* 发送一个字节数据到串口 */
USART_SendData(DEBUG_USARTx, (uint8_t) ch);
/* 等待发送完毕 */
while (USART_GetFlagStatus(DEBUG_USARTx, USART_FLAG_TXE) == RESET);
return (ch);
}
这样就能使用printf了。
5. 样例项目
程序中自己编写“bsp_usart.c”,“bsp_usart.h”,“main.c”这三个文件:
“bsp_usart.c”文件如下:
#include "bsp_usart.h"
void USART1_Config(void)
{
GPIO_InitTypeDef GPIO_InitStructure;
USART_InitTypeDef USART_InitStructure;
// TODO0:初始化时钟
// 0.1打开串口GPIO的时钟
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);
// 0.2打开串口外设的时钟
RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1, ENABLE);
// TODO1:初始化GPIO
// TODO1.1:将USART Tx的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);
// TODO1.2:将USART Rx的GPIO配置为浮空输入模式
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_10;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;
GPIO_Init(GPIOA, &GPIO_InitStructure);
// TODO2: 初始化USART
// 配置串口的工作参数
// 配置波特率
USART_InitStructure.USART_BaudRate = 115200;
// 配置 针数据字长
USART_InitStructure.USART_WordLength = USART_WordLength_8b;
// 配置停止位
USART_InitStructure.USART_StopBits = USART_StopBits_1;
// 配置校验位
USART_InitStructure.USART_Parity = USART_Parity_No ;
// 配置硬件流控制
USART_InitStructure.USART_HardwareFlowControl = USART_HardwareFlowControl_None;
// 配置工作模式,收发一起
USART_InitStructure.USART_Mode = USART_Mode_Rx | USART_Mode_Tx;
// 完成串口的初始化配置
USART_Init(USART1, &USART_InitStructure);
// TODO3:初始化NVIC
// 串口中断优先级配置
NVIC_InitTypeDef NVIC_InitStructure;
// 嵌套向量中断控制器组选择
NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);
// 配置USART为中断源
NVIC_InitStructure.NVIC_IRQChannel = USART1_IRQn;
// 抢断优先级
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 1;
// 子优先级
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 1;
// 使能中断
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
// 初始化配置NVIC
NVIC_Init(&NVIC_InitStructure);
// 使能串口接收中断
USART_ITConfig(USART1, USART_IT_RXNE, ENABLE);
// TODO4:使能串口
USART_Cmd(USART1, ENABLE);
}
void Usart_SendByte( USART_TypeDef * pUSARTx, uint8_t ch)
{
/* 发送一个字节数据到USART */
USART_SendData(pUSARTx,ch);
/* 等待发送数据寄存器为空 */
while (USART_GetFlagStatus(pUSARTx, USART_FLAG_TXE) == RESET);
}
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)
{}
}
“bsp_usart.h”文件如下:
#ifndef __USART_H
#define __USART_H
#include "stm32f10x.h"
#include <stdio.h>
void USART1_Config(void);
void Usart_SendByte( USART_TypeDef * pUSARTx, uint8_t ch);
void Usart_SendString( USART_TypeDef * pUSARTx, char *str);
#endif
主函数如下:
#include "stm32f10x.h"
#include "bsp_usart.h"
int main(void)
{
/*初始化USART 配置模式为 115200 8-N-1,中断接收*/
USART1_Config();
/* 发送一个字符串 */
Usart_SendString( USART1,"hello\n");
printf("1234\r\n");
while(1)
{
Usart_SendString( USART1,"hello\n");
printf("1234\r\n");
}
}
TrueSTUDIO自带串口通信工具:
由此可见 \r\n
才是真正的回车。