引言
串口通信,全称串行通信接口,是嵌入式系统中最基础、最常用的通信方式之一。如同人与人之间的对话需要共同的语言,设备间的数据交换也需要遵循特定的通信协议,而USART(Universal Synchronous Asynchronous Receiver/Transmitter,通用同步异步收发器)是一种广泛使用的串行通信接口。
一、串口通信相关概念
1.通信分类
并行通信:指使用多条数据线传输数据,数据字节的各位同时传送的通信方式。
串行通信:指使用一条数据线,数据字节的各位一位一位地依次传送的通信方式。
2.串行通信方式
(1)按照数据的传递方式
单工通信:数据只允许一个方向进行传送,即数据发送设备只能发送数据,数据接收设备只能接收数据。
半双工通信:数据允许向两个方向进行传送,但传送数据的过程与接收数据的过程不能同时进行。
全双工通信:数据允许向两个方向进行传送,并且发送数据的过程与接收数据的过程可以同时进行。
(2)按照串行数据的时钟控制方式
串行异步通信:一次通信传送一个字符帧。在发送字符时,发送的字符之间的时间间隔可以是任意的,接收端时刻做好接收的准备。
串行同步通信:要求发送频率和接收频率要同步。由一个统一的时钟控制发送端的发送。
3.串行异步通信的数据传输形式和传输速率
(1)数据传输形式是按照一定格式打包成帧,以帧为单位在物理链路上进行传输的。USART的数据格式由起始位、数据位、校验位、停止位和空闲位等构成。其中,起始位(1位-低电平)、数据位(8位/9位)、校验位(若有则以数据位最后一位作为校验位)和停止位(1位-高电平),构成了一个数据帧。见下图。
(2)数据传输速率,可以用波特率(比特率)来表示。
波特率:数据的传送速率,在串行异步通信中,每秒钟传送的二进制的位数,单位是比特/秒(bit/s),或波特(baud)。常用的波特率:2400、4800、7200、9600、19200、38400、···、115200等。
二、USART功能说明
USART双向通信均需要至少两个引脚:接收数据输入引脚(RX)和发送数据引脚输出(TX)。
USART内部结构有数据寄存器(USART_DR),该寄存器包含了发送数据寄存器(TDR--Transmitter Data Register)和接收数据寄存器(RDR-Receiver Data Rsgister);发送/接收移位寄存器;波特率寄存器(USART_BRR);时钟控制、发送控制、接收控制、中断控制等。USART结构见下图。
发送数据时,在USART_DR寄存器中写入要发送的数据,该操作将清零TXE位(状态寄存器USART_SR中的第7位),当TDR寄存器中的数据传输到发送移位寄存器时,TXE置1,并且发送移位寄存器中的数据在TX引脚输出。当数据发送完成,TC位(状态寄存器USART_SR中的第6位,0-发送未完成,1-发送完成)置1。向USART_DR写入最后一个数据时,必须等待至TC=1。TXE置1和TC置1都可通过设置对应的中断位产生中断。
三、USART常用库函数
参数1:USARTx,x=1~8
typedef struct
{
uint32_t USART_BaudRate; //波特率
uint16_t USART_WordLength; //字长
uint16_t USART_StopBits;//停止位
uint16_t USART_Parity; //奇偶校验
uint16_t USART_Mode;//发送/接收使能
int16_t USART_HardwareFlowControl;//硬件流控制
}USART_InitTypeDef;
(1)USART_BaudRate:波特率,可以设置为常用的波特率
(2)USART_WordLength:字长
USART_WordLength_8b:8位数据
USART_WordLength_9b:9位数据
(3)USART_StopBits:停止位
USART_StopBits_1:在帧结尾传输1个停止位
USART_StopBits_0.5:在帧结尾传输0.5个停止位
USART_StopBits_1.5:在帧结尾传输1.5个停止位
USART_StopBits_2:在帧结尾传输2个停止位
(4)USART_Parity:奇偶校验
USART_Parity_No:无奇偶
USART_Parity_Even:偶模式
USART_Parity_Odd:奇模式
5)USART_HardwareFlowControl:硬件流控制
USART_HardwareFlowControl_None:硬件流控制失能
USART_HardwareFlowControl_RTS:发送请求RTS使能
USART_HardwareFlowControl_CTS:清除发送CTS使能
USART_HardwareFlowControl_RTS_CTS:RTS和CTS使能
6)USART_Mode:发送、接收使能
USART_Mode_Tx:发送使能
USART_Mode_Rx:接收使能
使用方法:
USART_InitTypeDefUSART_InitStructure;//定义结构体
USART_InitStructure. USART_BaudRate = 9600;//设置波特率
USART_InitStructure. USART_WordLength = USART_WordLength_8b;//选择字长
USART_InitStructure. USART_StopBits = USART_StopBits_1;//选择停止位
USART_InitStructure. USART_Parity = USART_Parity_Odd;//选择奇偶
USART_InitStructure. USART_HardwareFlowControl =
USART_HardwareFlowControl_None;//无硬件流
USART_InitStructure. USART_Mode = USART_Mode_Tx | USART_Mode_Rx; //发送、接收使能
USART_Init(USART1,&USART_InitStructure);//完成初始化
2、函数原型
void USART_Cmd(USART_TypedDef *USARTx,FunctionalState NewState)
函数功能:使能或禁止指定USART。
使用方法:USART_Cmd(USART1,ENABLE);//使能串口
3、函数原型
void USART_SendData(USART_TypeDef * USARTx, u8 Data)
函数功能:通过USART发送单个字节数据
使用方法:USART_SendData(USART1,0x23);
4、函数原型
u8 USART_ReceiveData(USART_TypeDef * USARTx)
函数功能:返回指定USART最近接收到的单个字节数据。
使用方法:
u8 RxData;
RxData = USART_RexeiveData(USART1);
5、函数原型
void USART_ITConfig(USART_TypeDef * USARTx, u16 USART_IT, FunctionalState NewState)
函数功能:使能或禁止指定的USART中断。
USART_IT取值:
USART_IT_PE //奇偶错误中断
USART_IT_TXE //发送中断
USART_IT_TC //传输完成中断
USART_IT_RXEN //接收中断
例:USART_ITConfig(USART1, USART_IT_RXNE, ENABLE);//串口1接收中断使能
6、函数原型
void USART_ClearITPendingBit(USART_TypeDef* USARTx, USART_IT_RXNE)
函数功能:清除指定的中断标志位(USART_IT取值同上)
例:USART_ClearITPendingBit(USART1, uint16_t USART_IT) //清除接收中断标志位
7、函数原型
FlagStatus USART_GetFlagStatue(USART_TypeDef * USARTx, u16 USART_FLAG)
函数功能:查询指定USART的标志位状态。
USART_FLAG取值:
USART_FLAG_TXE //发送数据寄存器空标志位
USART_FLAG_TC //发送完成标志位
USART_FLAG_RXEN //接收数据寄存器非空标志位
例:FlagStatus Status;Status = USART_GetFlagStatue(USART1,USART_FLAG_TXE);//获取发送寄存器的状态
8、函数原型
四、USART使用流程
USART最基本的功能就是发送和接收数据。该功能的实现需要串口工作方式配置、串口发送和串口接收三部分程序。
/*1-串口配置*/void Usart_Init(){/*1-定义结构体 GPIO、USART*/USART_InitTypeDef USART_InitStruct;GPIO_InitTypeDef GPIO_InitStruct;/*2-使能时钟 GPIO、USART时钟*/RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOA,ENABLE);RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1, ENABLE);/*3-配置GPIO引脚*/GPIO_InitStruct.GPIO_Pin = GPIO_Pin_9 | GPIO_Pin_10;// PA9作为USART1_TX,PA10作为USART1_RXGPIO_InitStruct.GPIO_Mode = GPIO_Mode_AF; // 复用功能GPIO_InitStruct.GPIO_Speed = GPIO_Speed_50MHz;GPIO_InitStruct.GPIO_OType = GPIO_OType_PP; // 推挽输出GPIO_InitStruct.GPIO_PuPd = GPIO_PuPd_UP; // 上拉GPIO_Init(GPIOA, &GPIO_InitStruct);/*4-引脚复用映射*/GPIO_PinAFConfig(GPIOA, GPIO_PinSource9, GPIO_AF_USART1);GPIO_PinAFConfig(GPIOA, GPIO_PinSource10, GPIO_AF_USART1);/*5-配置串口*/USART_InitStruct.USART_BaudRate = 115200; //波特率USART_InitStruct.USART_WordLength = USART_WordLength_8b;//8位字长USART_InitStruct.USART_StopBits = USART_StopBits_1;//停止位1位USART_InitStruct.USART_Parity = USART_Parity_No;//无奇偶校验USART_InitStruct.USART_Mode = USART_Mode_Rx | USART_Mode_Tx;//使能发送和接收模式USART_InitStruct.USART_HardwareFlowControl = USART_HardwareFlowControl_None;//无硬件流USART_Init(USART1, &USART_InitStruct);//初始化/*6-使能串口*/USART_Cmd(USART1, ENABLE);}
//发送与接收数据程序 ,包括printf重定向输出到串口/*1-单个字符发送-查询方式*/void USART_SendChar(uint8_t ch){// 等待发送寄存器空while(USART_GetFlagStatus(USART1, USART_FLAG_TXE) == RESET);// 发送数据USART_SendData(USART1, ch);}/*2-字符串发送-查询方式*/void USART_SendString(char *str){while(*str){USART_SendChar(*str++);}}/*3-重定向c库函数printf到串口包含#include<stdio.h>在Keil中,还需勾选“Use MicroLIB”以使用此微库优化*/int fputc(int ch, FILE *f) {USART_SendData(USART1, (uint8_t)ch); // 发送字符while(USART_GetFlagStatus(USART1, USART_FLAG_TXE) == RESET); // 等待发送完成return ch;}/*4-接收单个字符-查询方式*/uint8_t USART_ReceiveChar(){// 等待接收到数据while(USART_GetFlagStatus(USART1, USART_FLAG_RXNE) == RESET);return USART_ReceiveData(USART1);}
//主函数测试int main(void){u8 temp = 10;Usart_Init();while (1){printf("Send a character:");USART_SendChar('A');delay_ms(1000);USART_SendString("Easy Single Chip");delay_ms(1000);printf("Send a character %d :",temp);delay_ms(1000);}}
/*中断方式-中断配置函数*/void USART_IT_Config(){NVIC_InitTypeDef NVIC_InitStruct;// 使能接收中断USART_ITConfig(USART1, USART_IT_RXNE, ENABLE);// 配置NVICNVIC_InitStruct.NVIC_IRQChannel = USART1_IRQn; //中断通道NVIC_InitStruct.NVIC_IRQChannelPreemptionPriority = 0; //抢占优先级NVIC_InitStruct.NVIC_IRQChannelSubPriority = 0;//子优先级NVIC_InitStruct.NVIC_IRQChannelCmd = ENABLE;//中断使能NVIC_Init(&NVIC_InitStruct);//初始化}// 中断服务函数void USART1_IRQHandler(void){uint8_t received_data;if(USART_GetITStatus(USART1, USART_IT_RXNE) != RESET){// 读取接收到的数据received_data = USART_ReceiveData(USART1);// 处理数据(回传数据)USART_SendData(USART1, received_data);// 清除中断标志USART_ClearITPendingBit(USART1, USART_IT_RXNE);}}

