一、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; //清除标志位
}
}
————————————————
版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
原文链接:https://blog.csdn.net/DK3314219995/article/details/149025676
|