Summary of stm32 serial port transceiver

The process of using the stm32 serial port:
1. Enable the serial port clock, and at the same time enable the GPIO clock corresponding to the serial port;
2. Set the input and output mode and rate of the serial port pin, and initialize the GPIO pin;
3. For the serial port that needs to receive data , configure the interrupt, and enable it;
4. Set the baud rate, data bits, stop bits, parity bits, flow control mode, and transceiver mode of the serial port;
5. Initialize the serial port;
6. Open the serial port to receive interrupts;
7. Enable the serial port;
8. Write the serial port interrupt service function;
9. Send data

Supplement: The registers related to the serial port in STM32 are mainly the status register SR and the data register register DR.
The figure is as follows:
insert image description here
The two most important bits of the status register are the sixth bit RXNE and the seventh bit TC, using USARTx->SR.
TC: Transmission complete (Transmission complete)
When a frame containing data is sent and TXE=1, the bit is set to '1' by the hardware. An interrupt is generated if TCIE in USART_CR1
is '1'. This bit is cleared by a software sequence (read USART_SR, then write USART_DR)
. The TC
bit can also be cleared by writing '0', this clearing procedure is only recommended for multi-buffer communication.
0: Sending has not been completed;
1: Sending is completed.

RXNE: Read data register not empty
When the data in the RDR shift register is transferred to the USART_DR register, this bit is set by hardware. An interrupt is generated if
RXNEIE in the USART_CR1 register is 1. A read of USART_DR clears this
bit
. The RXNE bit can also be cleared by writing 0, this clearing procedure is only recommended for multi-buffer communication.
0: The data has not been received;
1: The data has been received and can be read out.

Therefore, the sixth bit RXNE of SR is often used to judge whether the data is received. If the data is received, the data is read from the DR so that the DR can receive the next data.

insert image description here
DR[8:0]: Data value (Data value)
contains the data sent or received. Since it is composed of two registers, one for transmission (TDR) and one for reception
(RDR), this register has both read and write functions. The TDR register provides
a parallel interface between the internal bus and the output shift register (see Figure 248). The RDR register provides a parallel interface between the input shift register and the internal bus.
When the parity bit is enabled (the PCE bit in USART_CR1 is set), the value written to the MSB (according to
the MSB is the 7th or 8th bit) will be determined by the subsequent parity bit. replace.
When parity is enabled for reception, the MSB bit read is the received parity.

code show as below:

	//定义初始化变量
	GPIO_InitTypeDef GPIO_InitStructure;
	USART_InitTypeDef USART_InitStructure;
	NVIC_InitTypeDef NVIC_InitStructure;
	
	//使能串口2的时钟和GPIOA的时钟
	RCC_APB1PeriphClockCmd(RCC_APB1Periph_USART2, ENABLE);//PA2-TX,PA3-RX
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);
	
	//配置串口对应引脚的收发模式
	//USART2_RX    GPIOA.3初始化
	GPIO_InitStructure.GPIO_Pin = GPIO_Pin_3;//PA3
	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;//浮空输入
	GPIO_Init(GPIOA, &GPIO_InitStructure);/初始化GPIOA.3	
	//USART2_TX	  GPIOA.2初始化
	GPIO_InitStructure.GPIO_Pin = GPIO_Pin_2; //PA.2
	GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;	//复用推挽输出
	GPIO_Init(GPIOA, &GPIO_InitStructure);//初始化GPIOA.2	
	//注意:此处TX和RX引脚都要配置,否则可能无法通信

	//USART2 NVIC 配置
	NVIC_InitStructure.NVIC_IRQChannel = USART2_IRQn;
	NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority=3 ;//抢占优先级3
	NVIC_InitStructure.NVIC_IRQChannelSubPriority = 3;//子优先级3
	NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;//IRQ通道使能
	NVIC_Init(&NVIC_InitStructure);	//初始化NVIC寄存器

	//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;//收发模式

	//初始化USART2
	USART_Init(USART2, &USART_InitStructure);
	//开启USART2接收中断
	USART_ITConfig(USART2, USART_IT_RXNE, ENABLE);
	//使能串口2
	USART_Cmd(USART2, ENABLE); 
	
	//编写USART2的中断服务函数
	void USART2_IRQHandler(void) 
	{
		u8 Res;
		USART_PRINTF_FLAG=2;
		
		if(USART_GetITStatus(USART2, USART_IT_RXNE) != RESET)  //接收中断,判断读寄存器是否为空
		{
			Res =USART_ReceiveData(USART2);	//读取接收到的数据
			
			if((USART2_RX_STA&0x8000)==0)//接收未完成
			{
				if(USART2_RX_STA&0x4000)//接收到了0x0d
				{
					if(Res!=0x0a)
						USART2_RX_STA=0;//接收错误重新开始
					else 	
					{
						if(crc_check(USART2_RX_BUF,17))
							USART2_RX_STA|=0x8000;	//接收完成
						else
							USART2_RX_STA=0;//接受错误,重新开始
					}
				}
				else //未接收到0x0d
				{	
					if(Res==0x0d)
						USART2_RX_STA|=0x4000;
					else
					{
						USART2_RX_BUF[USART2_RX_STA&0X3FFF]=Res ;
						USART2_RX_STA++;
						if(USART2_RX_STA>(USART_REC_LEN-1))
							USART2_RX_STA=0;
					}		 
				}
			}   		 
	    } 
	} 
	//注:此处参考了正点原子所提供的源码,根据自己的需要对接收完成的判断进行了修改

	//发送数据
	USART_SendData(UART4, USART2_TX_BUF[t]);//向UART4发送数据
	while(USART_GetFlagStatus(UART4,USART_FLAG_TC)!=SET);//等待发送结束
	//注while语句必须存在,否则可能出现接收字符不完整的情况,且USART_SendData一次只能发送一个数据,对于数组需要用循环的方式进行发送
	//补充:如何用printf进行发送
	//参照正点原子,重定义fputc函数
	int fputc(int ch, FILE *f)
	{      
		if(USART_PRINTF_FLAG==2)
		{
			while((USART2->SR&0X40)==0){};
			USART2->DR = (u8) ch; 
		}
		else
		{
			while((USART3->SR&0X40)==0){};
			USART3->DR = (u8) ch; 		
		}
	     
		return ch;
	}
	//注意:与正点原子不同的是补充了一个发送标志(全局变量),判断是用哪个串口进行发送,用于处理多串口收发

Guess you like

Origin blog.csdn.net/weixin_44941350/article/details/123167637