Stm32 serial port related knowledge notes

The serial port of the single-chip microcomputer is really used very much, and there are many knowledge points. Here is a summary because of the recent review.

In the examples here, I use 103 as an example, 407 is just the configuration of the serial port is different.
Insert picture description here

USART initialization structure

typedef struct
{
    
    
  uint32_t USART_BaudRate;      //波特率 
  uint16_t USART_WordLength;    //字长 
  uint16_t USART_StopBits;      //停止位
  uint16_t USART_Parity;        //校验控制 
  uint16_t USART_Mode;          //模式选择 接收或者发送
  uint16_t USART_HardwareFlowControl;//有无硬件流控制
} USART_InitTypeDef;

Serial port operation related library functions

void USART_Init(); //串口初始化:波特率,数据字长,奇偶校验,硬件流控以及收发使能
void USART_Cmd();//使能串口
void USART_ITConfig();//使能相关中断

void USART_SendData();//发送数据到串口,DR
uint16_t USART_ReceiveData();//接受数据,从DR读取接受到的数据

FlagStatus USART_GetFlagStatus();//获取状态标志位
void USART_ClearFlag();//清除状态标志位
ITStatus USART_GetITStatus();//获取中断状态标志位
void USART_ClearITPendingBit();//清除中断状态标志位

Insert picture description here

General configuration steps of the serial port

串口时钟使能,GPIO时钟使能:RCC_APB2PeriphClockCmd();
串口复位:USART_DeInit(); 这一步不是必须的
GPIO端口模式设置:GPIO_Init(); 
串口参数初始化:USART_Init();
开启中断并且初始化NVIC(如果需要开启中断才需要这个步骤)
      NVIC_Init();
      USART_ITConfig();
使能串口:USART_Cmd();
编写中断处理函数:USARTx_IRQHandler();
串口数据收发:
void USART_SendData();//发送数据到串口,DR
uint16_t USART_ReceiveData();//接受数据,从DR读取接受到的数据
串口传输状态获取:
FlagStatus USART_GetFlagStatus(USART_TypeDef* USARTx, uint16_t USART_FLAG);
void USART_ClearITPendingBit(USART_TypeDef* USARTx, uint16_t USART_IT);

Let's take serial port one as an example

GPIO_InitTypeDef GPIO_InitStructure;
USART_InitTypeDef USART_InitStructure;
NVIC_InitTypeDef NVIC_InitStructure;
//①串口时钟使能,GPIO 时钟使能,复用时钟使能
RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1|
RCC_APB2Periph_GPIOA, ENABLE); //使能 USART1,GPIOA 时钟

//②串口复位
USART_DeInit(USART1); //复位串口 1

//③GPIO 端口模式设置
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_9; //ISART1_TX PA.9
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP; //复用推挽输出
GPIO_Init(GPIOA, &GPIO_InitStructure); //初始化 GPIOA.9

GPIO_InitStructure.GPIO_Pin = GPIO_Pin_10; //USART1_RX PA.10
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING; //浮空输入
GPIO_Init(GPIOA, &GPIO_InitStructure); //初始化 GPIOA.10

//④串口参数初始化
USART_InitStructure.USART_BaudRate = 115200; //波特率设置
USART_InitStructure.USART_WordLength = USART_WordLength_8b; //字长为 8 位
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); 

//⑤初始化 NVIC
NVIC_InitStructure.NVIC_IRQChannel = USART1_IRQn;
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority=3 ; //抢占优先级 3
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 3; //子优先级 3
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; //IRQ 通道使能
NVIC_Init(&NVIC_InitStructure); //中断优先级初始化

//⑤开启中断
USART_ITConfig(USART1, USART_IT_RXNE, ENABLE); //开启中断

//⑥使能串口
USART_Cmd(USART1, ENABLE); //使能串口

中断服务函数

Let's analyze step by step

Flag bit

The first is some important status flags

Insert picture description here
When the single-chip microcomputer sends data, it first sends the data to the sending data register, and then sends it to the TX pin one by one through the sending shift register. When receiving, it sends the data to the receiving shift register through rx, and then sends it to the receiving data register. , Giving the MCU

Flag bit effect
TXE Send data register is empty, send a single byte to use
TC Sending is complete, used when sending multiple bytes
TXIE Send complete interrupt enable
RXNE Receive data register is not empty
RXNEIE Receive buffer is not empty interrupt enable

Note: The reset value of TXE and TC is 1, while the reset value of RXNE is 0

Need to understand clearly here

Send data register

TXE为1:TDR里的数据全部到了移位寄存器,并且没有新的数据进TDR
TXE为0;TDR里有数据,非空,则TXE=0

Transmit shift register

TC为1:从TDR过来的数据全部被移送到TX引脚,并且TDR里也没有新的数据
TC为0:从TDR过来的数据还没有完全被移过去,或者之前TDR里的数据被移走了,但TDR里又来了新的数据

Let's try a few examples. The configuration of the serial port is omitted here, and the interrupt is not turned on.

USART_SendData(USART1,'d');
USART_SendData(USART1,'y');
USART_SendData(USART1,'k');

Result: k
Finally, only one k is printed on the serial port assistant.
Reason: When sending'd' to the sending data register, because there is no pause, the next sent'y' overwrites the'd', and the same reason shows that'y' 'Is also covered by'k', and finally sent to the transmit shift register, and the TX pin

USART_SendData(USART1,'d');
while(USART_GetFlagStatus(USART1,USART_FLAG_TXE)==RESET);
USART_SendData(USART1,'y');
while(USART_GetFlagStatus(USART1,USART_FLAG_TXE)==RESET);
USART_SendData(USART1,'k');
while(USART_GetFlagStatus(USART1,USART_FLAG_TXE)==RESET);

Result:
only dyk is printed on the last serial port assistant of dyk. The
second result is different because the loop judgment flag is added. If there is data in TDR and it is not empty, then TXE=0. If it is 0, it will stay in the loop until The data is sent to the transmit shift register before ending the loop

The last flag is all changed to TC

 USART_SendData(USART1,'d');
while(USART_GetFlagStatus(USART1,USART_FLAG_TC)==RESET);
USART_SendData(USART1,'y');
while(USART_GetFlagStatus(USART1,USART_FLAG_TC)==RESET);
USART_SendData(USART1,'k');
while(USART_GetFlagStatus(USART1,USART_FLAG_TC)==RESET);

Result: At the
end of yk, only yk is printed on the serial assistant.
Insert picture description here
You can see that TC is read first, then written, and then as emphasized above, the reset value of TXE and TC is 1,
so after writing'd', it will exit the loop directly. 'y' overwrites'd'

I found that the status flags are different, and the results produced are also different.
Then I will mention it here.

The difference between USART_GetITStatus and USART_GetFlagStatus

USART_GetITStatus
该函数不仅会判断标志位置1,同时还会判断是否使能了
相应的中断,所以在串口中断函数中,使用该函数

USART_GetFlagStatus
该函数只判断标志位

Encapsulation of sending function

Send a byte

void Usart_SendByte(USART_TypeDef* pUSARTx, uint8_t data)
{
    
    
	USART_SendData(pUSARTx, data);
	while( USART_GetFlagStatus(pUSARTx, USART_FLAG_TXE) == RESET );
}

Send an array

/* 发送8位数据的数组 */
void Usart_SendArray(USART_TypeDef* pUSARTx, uint8_t *array,uint8_t num)
{
    
    
	uint8_t i;
	for( i=0; i<num; i++ )
  {
    
    
		Usart_SendByte(pUSARTx, array[i]);
	}
	while( USART_GetFlagStatus(pUSARTx, USART_FLAG_TC) == RESET );
}

Send string

/* 发送字符串 */
void Usart_SendStr(USART_TypeDef* pUSARTx, uint8_t *str)
{
    
    
	uint8_t i=0;
	do
  {
    
    
		Usart_SendByte(pUSARTx, *(str+i));
		i++;
	}while(*(str+i) != '\0');
	while( USART_GetFlagStatus(pUSARTx, USART_FLAG_TC) == RESET );
}

Interrupt reception

u8 res;
	 if(USART_GetITStatus(USART1,USART_IT_RXNE))
 {
    
    
     res= USART_ReceiveData(USART1); 
     USART_SendData(USART1,res);   
  } 

Finally, don’t use while but use if

printf redirect

Insert picture description here
Be sure to check Use MicroLIB,
otherwise, add this code to usart.h

//加入以下代码,支持 printf 函数,而不需要选择 use MicroLIB
#if 1
#pragma import(__use_no_semihosting)
//标准库需要的支持函数
struct __FILE
{
    
    
int handle; 
};
FILE __stdout;
//定义_sys_exit()以避免使用半主机模式
_sys_exit(int x)
{
    
    
x = x;
} 
//重定义 fputc 函数
int fputc(int ch, FILE *f)
{
    
    
while(USART_GetFlagStatus(USART1,USART_FLAG_TC)==RESET);
 USART_SendData(USART1,(uint8_t)ch);
return ch;
}
///重定向c库函数printf到串口,重定向后可使用printf函数
int fputc(int ch, FILE *f)
{
    
    
		/* 发送一个字节数据到串口 */
		USART_SendData(DEBUG_USARTx, (uint8_t) ch);
		
		/* 等待发送完毕 */
		while (USART_GetFlagStatus(DEBUG_USARTx, USART_FLAG_TXE) == RESET);		
	
		return (ch);
}

///重定向c库函数scanf到串口,重写向后可使用scanf、getchar等函数
int fgetc(FILE *f)
{
    
    
		/* 等待串口输入数据 */
		while (USART_GetFlagStatus(DEBUG_USARTx, USART_FLAG_RXNE) == RESET);

		return (int)USART_ReceiveData(DEBUG_USARTx);
}

Guess you like

Origin blog.csdn.net/qq_44866153/article/details/113624473