STM32 (1) - Simple implementation of serial port transceiver and communication

This article uses the serial port to send and receive experiments to illustrate the specific use of the serial port, and communicate with other peripherals through the serial port to achieve related functions.


Preface
In STM32, the serial port communication is USART, and STM32 can transmit parallel data through the serial port and other devices. It is full-duplex, asynchronous clock control, and point-to-point transmission between devices. The corresponding STM32 pins are the RX and TX terminals respectively. The serial port resources of STM32 are USART1, USART2, USART3.

Several important parameters of the serial port:

Baud rate, the rate of serial port communication
Idle, generally high level
Start bit, marking the beginning of a data frame, fixed at low level. A falling edge is generated when data starts to be sent. (idle –> start bit)
data bit, send data frame, 1 is high level, 0 is low level. Low end first.
For example, the sending data frame 0x0F in the data frame is the low-order linearity, that is, 1111 0000
check digit, which is used for data verification and calculated according to the data bits. There are odd parity, even parity and no parity.
Stop bit, used for data interval, is fixed at high level. After the data frame is sent, a rising edge is generated. (data transfer –> stop bit)

1. Create header files and source files of the serial port

Open keil5, here I choose Brother Atom's marquee experiment code as the basis for expansion:

Add .c and .h files to Hardware on the left, the address is /hardware, confirm to add.
insert image description here

2. Write source files

First, write the function to initialize serial port 2:
1. Configure the clock RCC to open the GPIO port corresponding to USART and TX/RX

 RCC_APB1PeriphClockCmd(RCC_APB1Periph_USART2,ENABLE);//USART2挂载APB1总线
  RCC_APB1PeriphClockCmd(RCC_APB2Periph_GPIOA,ENABLE);//GPIOA挂载APB2总线
  //对于哪个应用挂载哪个APB总线,可以根据代码自动补全功能快捷判断

2. Initialize
the corresponding pins of GPIO port usart2 as PA2 and PA3. The RX pin mode should be configured as a floating input or a pull-up input. The TX pin mode is configured as a multiplexed push-pull output.
First you need to set up the structure: observe the GPIO structure variable:
insert image description here
then perform different configurations for TX/RX. as follows:


	GPIO_InitTypeDef  GPIO_InitStructure;//声明一个结构体对象
	//TX端口-PA2
	GPIO_InitStructure.GPIO_Pin = GPIO_Pin_2;//这个对象的成员变量GPIO_Pin取值为pin2
	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;//模式为复用推挽输出
	GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;//50MHZ速度
	GPIO_Init(GPIOA,&GPIO_InitStructure);
	
	//RX端口-PA3
	GPIO_InitStructure.GPIO_Pin = GPIO_Pin_3;//这个对象的成员变量GPIO_Pin取值为pin3
	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;//模式为浮空输入模式
	GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;//50MHZ速度
	GPIO_Init(GPIOA,&GPIO_InitStructure);

3. Initialize the serial port
The above is the initialization of the ports of the sending and receiving ends, here it is necessary to initialize the serial port to enable the serial port function. Similar to GPIO, first instantiate a serial port structure object, and then configure member variable information.

Its member variables include:
USART_BaudRate: The baud rate used for serial communication is generally 9600 or 115200, here is 9600
USART_HardwareFlowControl: Whether to choose hardware flow trigger, generally this is not selected, so choose no hardware flow trigger.
USART_Mode: The mode of the serial port, the sending mode or the receiving mode, or both.
USART_Parity: Parity bit, you can choose parity check or no check. If there is no requirement, there is no verification directly.
USART_StopBits: There are 1, 0.5, and 2 stop bits. We choose 1 stop bit here.
USART_WordLength: There are 8 and 9 data bits to choose from

USART_InitTypeDef  USART_InitStructure;
USART_InitStructure.USART_BaudRate = 9600;
USART_InitStructure.USART_HardwareFlowControl = USART_HardwareFlowControl_None;//
USART_InitStructure.USART_Mode = USART_Mode_Tx | USART_Mode_Rx;//收发模式并存
USART_InitStructure.USART_Parity = USART_Parity_No;//无奇偶校验位
USART_InitStructure.USART_StopBits = USART_StopBits_1;//1位停止位
USART_InitStructure.USART_WordLength = USART_WordLength_8b;//八位数据位
USART_Init(USART2,&USART_InitStructure);

4. Introducing the interrupt mechanism
The purpose of the serial port initialization interrupt is to ensure that when the serial port receives data, it can respond and process in time. If the interrupt is not initialized, the program can only detect whether there is data coming to the serial port in the polling mode, which will take up more CPU resources and may cause missing data. After the initialization interrupt, when the serial port receives data, the system will immediately enter the interrupt service routine for processing, thus improving the processing efficiency and accuracy of the serial port data.
When the data is received, a receiving interrupt is triggered, and the main program suspends execution. After receiving the data, the main program resumes execution. When data is received, an interrupt is triggered.
Initialize the interrupt and configure the member variables:

	USART_ITConfig(USART2,USART_IT_RXNE,ENABLE);//开启串口2的中断接收
	NVIC_InitTypeDef NVIC_InitStructure;
	NVIC_InitStructure.NVIC_IRQChannel =USART2_IRQn;//选择串口2的中断通道
	NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
	NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 1;//抢占优先级
	NVIC_InitStructure.NVIC_IRQChannelSubPriority = 1;//子优先级
	NVIC_Init(&NVIC_InitStructure);

Write the interrupt service function
When the serial port receives data, it will trigger the interrupt service routine of USART2. Inside this function, first judge whether the RXNE flag is set, if it is, it means that the data is received, store the data in the RX_Data variable, and set the Flag to 1. Then clear the RXNE flag bit by calling the USART_ClearITPendingBit function, so that it can correctly detect whether there is new data coming to the serial port next time.

void USART2_IRQHandler(void){
    
    
	if(USART_GetITStatus(USART2,USART_IT_RXNE)==SET)   //RXNE 标志位为1 表示可以接收数据
	{
    
    
		u8 RX_Data=USART_ReceiveData(USART2);
		u8 Flag=1;
		USART_ClearITPendingBit(USART2,USART_IT_RXNE);  //清除RXNE标志位
	}
	}
	

In addition, the USART1 serial port function written by Atomic Brother is as follows:

void USART1_IRQHandler(void)                	//串口1中断服务程序
	{
    
    
	u8 Res;
#if SYSTEM_SUPPORT_OS 		//如果SYSTEM_SUPPORT_OS为真,则需要支持OS.
	OSIntEnter();    
#endif
	if(USART_GetITStatus(USART1, USART_IT_RXNE) != RESET)  //接收中断(接收到的数据必须是0x0d 0x0a结尾)
		{
    
    
		Res =USART_ReceiveData(USART1);	//读取接收到的数据
		
		if((USART_RX_STA&0x8000)==0)//接收未完成
			{
    
    
			if(USART_RX_STA&0x4000)//接收到了0x0d
				{
    
    
				if(Res!=0x0a)USART_RX_STA=0;//接收错误,重新开始
				else USART_RX_STA|=0x8000;	//接收完成了 
				}
			else //还没收到0X0D
				{
    
    	
				if(Res==0x0d)USART_RX_STA|=0x4000;
				else
					{
    
    
					USART_RX_BUF[USART_RX_STA&0X3FFF]=Res ;
					USART_RX_STA++;
					if(USART_RX_STA>(USART_REC_LEN-1))USART_RX_STA=0;//接收数据错误,重新开始接收	  
					}		 
				}
			}   		 
     } 
#if SYSTEM_SUPPORT_OS 	//如果SYSTEM_SUPPORT_OS为真,则需要支持OS.
	OSIntExit();  											 
#endif
} 

This code is the interrupt handler function of USART1. When the serial port receives data, it will trigger the interrupt service routine of USART1. Inside this function, first judge whether the RXNE flag is set, if so, it means that the data is received, and the data is stored in the Res variable. Then, by operating the USART_RX_STA status flag bit, it is judged whether a complete frame of data has been received and stored in the USART_RX_BUF buffer. At the same time, it is also necessary to pay attention to the situation of receiving errors. If an error occurs, the receiving needs to be restarted. Finally, if the operating system is supported, the OSIntEnter and OSIntExit functions need to be called at the beginning and end of the function so that the operating system can properly manage interrupt handling.

Also note that when instantiating the structure, it should be placed at the beginning of the function, otherwise an error will be reported. Moreover, the interrupt is mainly used to receive data, and the serial port does not need to be interrupted to send data.

Write the serial port send data function

void USART2_SendByte(USART_TypeDef * USARTx,uint8_t data){
    
    //串口收发每次都是一个字节,即8位数据
	
		USART_SendData(USARTx,data);
	//0 表示数据还未转移到移位寄存器 循环等待 1 数据已经被转移到了移位寄存器可以发送数据
	while(!USART_GetFlagStatus(USARTx,USART_FLAG_TXE)); 
	}

This code is a function used to send a byte of data to the USARTx serial port. In the function, first call the USART_SendData function to write data into the USARTx register. Then check whether the USART_FLAG_TXE flag is set by means of circular waiting. If it has been set, it means that the data has been successfully transferred to the shift register, and the next transmission can be performed. Otherwise, you need to continue to wait until the TXE flag is set. The function of this function is to realize the simple serial port sending function.

3. The main program

#include "sys.h"
#include "delay.h"
#include "usart.h"
#include "led.h"
#include "usart2.h"
/************************************************
 ALIENTEK精英STM32开发板实验1
 跑马灯实验
 技术支持:www.openedv.com
 淘宝店铺:http://eboard.taobao.com 
 关注微信公众平台微信号:"正点原子",免费获取STM32资料。
 广州市星翼电子科技有限公司  
 作者:正点原子 @ALIENTEK
************************************************/
 int main(void)
 {
    
    	
	delay_init();	    //延时函数初始化	  
	LED_Init();		  	//初始化与LED连接的硬件接口
	NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2); 
	Init_USART2();
	while(1)
	{
    
    
		USART2_SendByte(USART2,0x08);
	}
 }
 

It can be seen that 8 is continuously sent to the serial port.

Summarize

This article briefly introduces the relevant methods of stm32 to write serial communication, but does not involve more complex applications. The next article will go deep into the application of serial ports, using stm32 and esp8266 to complete communication through serial ports.

Guess you like

Origin blog.csdn.net/qq_53092944/article/details/130154861