
一、USART简介 1.1 UART 简介 通用同步异步收发器(USART:Universal Synchronous/Asynchronous Receiver/Transmitter) 特点:串行、全双工、同步/异步通信(USART可支持同步通信,UART只支持异步通信) 发送和接收共用的可编程波特率 可编程数据字长度(8位或9位)(常用8位) 可配置的停止位-支持1或2个停止位(常用1位停止位) 可配置奇偶校验位(一般不用) 1.2 物理拓补图 接口通过三个引脚与其他设备连接在一起。任何USART双向通信至少需要两个脚 RX:接收数据输入 TX:发送数据输出 GND:双方要共地,双方通过USART进行通信,两个设备必须要共地,因为逻辑1---3.3V电压(对于地的电压),如果两个设备不共地则对地电压的高电平(3.3V就可能不太一样)。共地的意义是让两个设备的通信电平对地电压相等 ![]() 1.3 数据帧格式 一帧数据=1bit起始位[低电平]+8bit数据位+1bit奇偶校验位[可以不用]+1bit停止位[高电平] USART总线空闲,即没有数据发生,TX线为高电平 <1>数据位:USART发送的1次数据量是1Byte=8bit;[5、6、7、8] <2>数据字:数据位+奇偶校验位;如果不用校验位,数据字=数据位=8bit;如果使用校验位,数据字=数据位+校验位=9bit 奇校验:数据位中的1的个数+校验位中的1的个数为奇数 偶校验:数据位中的1的个数+校验位中的1的个数为偶数 <3>停止位:可以被配置为1bit(默认);2个停止位(可用于常规USART模式、单线模式以及调制解调器模式);0.5个停止位:在智能卡模式下接收数据时使用;1.5个停止位:在智能卡模式下发送和接收数据时使用 <4>发送顺序:先发送低位,再发送高位 1.4 框图 ![]() 对于这个框图,最关键的是两个标志位TXE(发送为空标志位),RXNE(接收不为空标志位) 数据通过RX端口进入MCU的UART的接收移位寄存器,随后进入接收数据寄存器(RDR),进入后RXNE被置1,表明可以读 MCU通过数据总线获得数据,数据再到发送数据寄存器(TDR),若TXE=1,说明数据已经被转移到移位寄存器,表明可以发送 二、串口通信 配置UART 开启了接收中断和空闲中断 /**************************** *@brief uasrt1端口配置函数 *@param void *@return void *@NOTE PA10->RX PA9->TX PA10,PA9位于APB2上 *@time 2025-6-3 ******************************/ void usart1_Init(uint32_t Baud_Rate) { //1.打开引脚时钟PA RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA,ENABLE) ; //2.打开usart1时钟 RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1, ENABLE) ; //PA9->TX推挽复用输出 GPIO_InitTypeDef GPIO_InitStruct_TX ; GPIO_InitStruct_TX.GPIO_Mode = GPIO_Mode_AF_PP ; GPIO_InitStruct_TX.GPIO_Pin = GPIO_Pin_9 ; GPIO_InitStruct_TX.GPIO_Speed = GPIO_Speed_10MHz ; GPIO_Init(GPIOA,&GPIO_InitStruct_TX) ; //3.配置,PA10->RX浮空输入 GPIO_InitTypeDef GPIO_InitStruct_RX ; GPIO_InitStruct_RX.GPIO_Mode = GPIO_Mode_IN_FLOATING ; GPIO_InitStruct_RX.GPIO_Pin = GPIO_Pin_10 ; GPIO_Init(GPIOA,&GPIO_InitStruct_RX) ; //4.配置usart1, USART_InitTypeDef USART_InitStruct ; 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_BaudRate = Baud_Rate ; USART_InitStruct.USART_WordLength = USART_WordLength_8b ; USART_InitStruct.USART_HardwareFlowControl = USART_HardwareFlowControl_None ; USART_Init(USART1,&USART_InitStruct) ; USART_ITConfig(USART1,USART_IT_RXNE,ENABLE) ;//开启接收中断 RXNEIE=1 USART_ITConfig(USART1,USART_IT_IDLE,ENABLE) ;//开启空闲中断 IDLE=1 //初始化NVIC NVIC_InitTypeDef NVIC_InitStruct ; NVIC_InitStruct.NVIC_IRQChannel = USART1_IRQn ;//中断通道 NVIC_InitStruct.NVIC_IRQChannelCmd = ENABLE ;//中断使能 NVIC_InitStruct.NVIC_IRQChannelSubPriority = 2 ;//响应先级 NVIC_InitStruct.NVIC_IRQChannelPreemptionPriority = 2 ;//抢占优先级 NVIC_Init(&NVIC_InitStruct) ; //5.使能usart1 USART_Cmd(USART1,ENABLE) ; } 接收发送函数 /**************************** *@brief 发送字符函数 *@param void *@return void *@note MCU会将数据发送到DR寄存器中的TDR寄存器中, 当TXE==1时,TDR寄存器会将数据加载到移位寄存器中,可以发送 *@time 2025-6-3 ******************************/ void usart1_sendbyte(uint8_t str) { while(USART_GetFlagStatus(USART1,USART_FLAG_TXE)==0); USART_SendData(USART1,str); } /**************************** *@brief 发送字符串函数 *@param uint8_t *str *@return uint16_t len *@note 发送字符串本质上就是发送字符 *@time 2025-6-3 ******************************/ void usart1_sendstr(char *str,int len) { while(len) { usart1_sendbyte(*str++); len--; } } /**************************** *@brief 接收字符 *@param void *@return void *@note MCU接收到数据后先放在DR寄存器的接收移位寄存器 数据会到RDR寄存器中,当RXNE==1时,说明RDR有数据,可以读 *@time 2025-6-3 ******************************/ uint16_t usart1_receivebyte() { while(USART_GetFlagStatus(USART1,USART_FLAG_RXNE)==0); return USART_ReceiveData(USART1); } /**************************** *@brief 接收字符串函数(idle标志位) *@param void *@return void *@note void *@time 2025-6-3 ******************************/ void usart1_receivestr(char*buff) { uint8_t flag; while(1) { if(USART_GetFlagStatus(USART1,USART_FLAG_RXNE)==1) { *buff=USART_ReceiveData(USART1); buff++; flag=1; } if(USART_GetFlagStatus(USART1,USART_FLAG_IDLE)==1&&flag) { *buff='\0'; //当发送时 发送结束标志 //先读SR,再读DR将置IDLE位置0 USART1->SR; USART1->DR; break; } } } 打印函数 记得勾选微库,printf函数不涉及到中断,它是将内存中的数据输出到上位机 //printf()的底层借助fputc函数进行输出 int fputc(int ch,FILE*stream) { usart1_sendbyte(ch); return ch; } ![]() 中断函数 MCU接收到数据时,进入接收中断函数,将数据存到rx_buff[100]数组里;当上位机不发送数据时,说明空闲状态,进入空闲中断,将 rx_buff[100]数组里面的数据发到上位机 /**************************** *@brief usart1中断实验 *@param void *@return void *@note void *@time 2025-6-4 ******************************/ char rx_buff[1000]={0}; char cnt=0; void USART1_IRQHandler(void) { //当RXNE=1时,有数据接收 if(USART_GetITStatus(USART1,USART_IT_RXNE)==SET) { rx_buff[cnt++]=USART_ReceiveData(USART1); USART_ClearITPendingBit(USART1,USART_IT_RXNE);//清除标志位 } //当IDLE=1时, if(USART_GetITStatus(USART1,USART_IT_IDLE)==SET) { usart1_sendstr(rx_buff,strlen(rx_buff)); cnt=0; USART1->SR; USART1->DR; //清除标志位 } } ———————————————— |