Learning and experience of STM32 USART serial port

Publisher:lidong4069Latest update time:2016-06-07 Source: eefocusKeywords:STM32  USART Reading articles on mobile phones Scan QR code
Read articles on your mobile phone anytime, anywhere
1. Basic concepts of serial ports

I have read a lot of STM32 USART coding, but I think that although they all say the middle point, they are not written very well! As a rookie who has just learned STM, I have read a lot of information and written the knowledge of serial communication that I think is quite satisfactory.

Of course, I have learned a lot from the efforts of my predecessors and the official library function templates of STM. This is also my first time to write a blog on csdn!

In the STM32 reference manual, the serial port is described as a universal synchronous asynchronous receiver and transmitter (USART), which provides a flexible method for full-duplex data exchange with external devices using the industry standard NRZ asynchronous serial data format. USART uses a fractional baud rate generator to provide a wide range of baud rate selection. It supports synchronous unidirectional communication and half-duplex single-line communication, as well as LIN (local Internet), smart card protocol and IrDA (infrared data organization) SIR ENDEC specification, and modem (CTS/RTS) operation. It also allows multi-processor communication. DMA can also be used to achieve high-speed data communication.

USART is connected to other devices through 3 pins. Any USART bidirectional communication requires at least 2 pins: receive data input (RX) and transmit data output (TX).

RX: Receives data serial input. Uses oversampling technology to distinguish data from noise and recover data.

TX: Transmit data output. When the transmitter is disabled, the output pin reverts to its I/O port configuration. When the transmitter is enabled and not transmitting data, the TX pin is at a high level. In single-wire and smart card modes, this I/O port is used for both data transmission and reception.

2. How does the serial port work?

There are generally two ways: query and interrupt.

(1) Query: The serial port program continuously queries in a loop to see if there is any data to be transmitted. If there is, it helps to transmit it (from PC to STM32 board, or from STM32 board to PC).

(2) Interrupt: Normally, the serial port only needs to enable interrupts. If an interrupt is found, it means that it needs to help transmit data - it will immediately transmit the data. Similarly, it can be from PC to STM3 board, and from STM32 board to PC.

3. Serial port hardware connection

The STM32 V3 development board I use has two RS-232 interfaces. The CPU's PA9-US1-TX (P68), PA10-US1-RX (P69), PA9-US2-TX (P25), and PA10-US2-RX (P26) use MAX3232 to implement two RS-232 interfaces, which are connected to the XS5 and XS17 interfaces respectively. In the system storage area startup mode, USART1 will use this port to perform ISP on the CPU on the board through the PC. This port can also be used as a normal serial port. If the short-circuit caps of JP3 and JP4 are removed, the second RS232 communication will be disconnected and it will only be used as a TTL communication channel.

4. Programming Examples

To operate the serial port, we must first connect the STM32 serial port to the CPU. In the Windows operating system, there is a built-in system software called "HyperTerminal". This software is removed from VISTA and above operating systems, but in the XP system, you can copy "hypertrm.dll" and "hypertrm.exe" to the "windows/system32" folder, and then double-click to run hypertrm.exe, and you can see the running interface of the HyperTerminal.

After running the HyperTerminal, the "Connection Description" will pop up. Enter a name and select an icon. You can write any name here. Then the "Connect to" setting will pop up. In "Use when connecting", select COMx that connects your PC and STM32. If you don't know which COM port it is, you can find it in the device manager of the PC. After selecting the COM port, a "Properties" dialog box will pop up. In "Bits/Second", select the same baud rate as set in your STM32. The data bit is also selected according to the STM32 settings. Select None for parity, 1 for stop bit, and None for data flow control. Note that the above options must match the serial port settings in the STM32, otherwise some unknown errors may occur.

After configuring the HyperTerminal, we can start programming the STM32. Programming generally follows the following steps:

(1) RCC configuration;

(2) GPIO configuration;

(3) USART configuration;

(4) NVIC configuration;

(5) Send/receive data.

In the RCC configuration, in addition to the regular clock settings, we must remember to turn on the IO port clock corresponding to the USART, the USART clock, and the pin function multiplexing clock.    

In the GPIO configuration, configure the pins on the transmitting end as multiplexed push-pull outputs and the pins on the receiving end as floating inputs.

In the USART configuration, initialize the USART through the USART_InitTypeDef structure and configure it according to the functions you need. Note that the settings in the hyperterminal need to correspond to the configuration in this structure. Since I use the interrupt to receive data, remember to open the serial port interrupt in the USART configuration, and finally open the serial port.

 

In the configuration of NVIC, the main thing is the configuration of USART1_IRQChannel, which is similar to the interrupt configuration described in the previous notes. If you don’t know how to configure it, you can refer to the previous notes.

 

After all configurations are done, you can start sending/receiving data. Use USART_SendData() function to send data and USART_ReceiveData() function to receive data. For specific function functions, please refer to the reference file of the firmware library. According to the configuration of USART, 8 bits are used for one frame when sending and receiving. Therefore, when sending, a buffer area is first opened, the data to be sent is sent into the buffer area, and then the data in the buffer area is sent out. When receiving, it is also received into the buffer area first, and then the corresponding operation is performed.

Note that when sending or receiving data, you need to check the status of USART. Only after the data is sent or received can the next frame of data be sent or received. Use USART_GetFlagStatus() function.

At the same time, it should be noted that at the beginning of sending data, the USART flag bit needs to be cleared, otherwise, the first bit of data will be lost. Because after the hardware reset, the USART status bit TC is set. When a frame containing data is sent, the hardware sets this bit. As long as the USART status bit TC is set, data can be sent. Then the TC bit is cleared by the software sequence. The specific steps are "read USART_SR first, then write USART_DR". Only in this way can the flag bit TC be cleared, but when sending the first frame of data, the USART_SR is not read, but the write operation is performed directly, so the TC flag bit is not cleared. Then, when sending the first frame of data, and then using USART_GetFlagStatus() to check the status, it returns that it has been sent (because the TC bit is set to 1), so the program will immediately send the next frame of data, so the first frame of data is overwritten by the second frame of data, so the first frame of data cannot be seen.

After programming according to the above method, we can view the specific status of serial port communication on the hyperterminal. In my example, after the hardware is reset, you can immediately see the "Welcome>

     RCC_cfg();

     GPIO_cfg();

     NVIC_cfg();

     USART_cfg();

     // Clear the flag, otherwise the first bit of data will be lost

     USART_ClearFlag(USART1,USART_FLAG_TC);

     //send data

     //PB5 is used to show that data is being sent

     //When data is being sent, PB5 will light up

     for(>

     {

            USART_SendData(USART1,TxBuf1[i]);

            GPIO_SetBits(GPIOB,GPIO_Pin_5);

            //Wait for data to be sent

            while(USART_GetFlagStatus(USART1,USART_FLAG_TC)==RESET);

            GPIO_ResetBits(GPIOB,GPIO_Pin_5);

     }

     while(1);

}

//RCC clock configuration

void RCC_cfg()

{

     //Define error status variable

     ErrorStatus HSEStartUpStatus;

     //Reset the RCC register to the default value

     RCC_DeInit();

     // Turn on the external high-speed clock crystal

     RCC_HSEConfig(RCC_HSE_ON);

     //Wait for the external high-speed clock crystal to work

     HSEStartUpStatus = RCC_WaitForHSEStartUp();

     if(HSEStartUpStatus == SUCCESS)

     {

            //Set AHB clock (HCLK) as system clock

            RCC_HCLKConfig(RCC_SYSCLK_Div1);

            //Set the high-speed AHB clock (APB2) to HCLK clock

            RCC_PCLK2Config(RCC_HCLK_Div1);

            //Set the low-speed AHB clock (APB1) to 2 times the frequency of HCLK

            RCC_PCLK1Config(RCC_HCLK_Div2);

            //Set FLASH code delay

            FLASH_SetLatency(FLASH_Latency_2);

            // Enable prefetch cache

            FLASH_PrefetchBufferCmd(FLASH_PrefetchBuffer_Enable);

            //Set the PLL clock to 9 times the HSE frequency 8MHz * 9 = 72MHz

            RCC_PLLConfig(RCC_PLLSource_HSE_Div1, RCC_PLLMul_9);

            // Enable PLL

            RCC_PLLCmd(ENABLE);

            //Wait for PLL to be ready

            while(RCC_GetFlagStatus(RCC_FLAG_PLLRDY) == RESET);

            //Set PLL as system clock source

            RCC_SYSCLKConfig(RCC_SYSCLKSource_PLLCLK);

            //Judge whether PLL is the system clock

            while(RCC_GetSYSCLKSource() != 0x08);

     }

      //Turn on the GPIO clock, multiplexing function, the clock of serial port 1

      RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA>

     GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;

     GPIO_Init(GPIOA , &GPIO_InitStructure);

     //PA10 is the RX end of US1, responsible for receiving data

     GPIO_InitStructure.GPIO_Pin = GPIO_Pin_10;

     GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;

     GPIO_Init(GPIOA, &GPIO_InitStructure);

     //LED shows that the serial port is sending/receiving data

     GPIO_InitStructure.GPIO_Pin = GPIO_Pin_5;

     GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;

     GPIO_Init(GPIOB, &GPIO_InitStructure);

}

//Serial port initialization

void USART_cfg()

{

     USART_InitTypeDef USART_InitStructure;

     //Set the structure to the default state

     USART_StructInit(&USART_InitStructure);

   //Set the baud rate to 115200

     USART_InitStructure.USART_BaudRate = 115200;

     //The width of a frame of data is set to 8 bits

     USART_InitStructure.USART_WordLength =USART_WordLength_8b;

     //Transmit 1 stop bit at the end of the frame

     USART_InitStructure.USART_StopBits = USART_StopBits_1;

     //Parity disabled mode, no parity check

     USART_InitStructure.USART_Parity = USART_Parity_No;

     //Send/receive enable

     USART_InitStructure.USART_Mode = USART_Mode_Rx>

     //Set serial port 1

     USART_Init(USART1,&USART_InitStructure);

     //Open the interrupt response function of serial port 1

     USART_ITConfig(USART1, USART_IT_RXNE, ENABLE);

     //Open serial port 1

     USART_Cmd(USART1, ENABLE);

}

//Abort placement

void NVIC_cfg()

{

      NVIC_InitTypeDef NVIC_InitStructure;

      NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2); //Select interrupt group 2

      NVIC_InitStructure.NVIC_IRQChannel=USART1_IRQChannel; //Select serial port 1 interrupt

      NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority=0; //Set the preemptive interrupt priority to 0

      NVIC_InitStructure.NVIC_IRQChannelSubPriority=0; //Set the responsive interrupt priority to 0

      NVIC_InitStructure.NVIC_IRQChannelCmd=ENABLE; //Enable interrupt

      NVIC_Init(&NVIC_InitStructure);

}

Then find the corresponding interrupt handling function in the stm32f10x_it.c file and fill in the following content. Note that in stm32f10x_it.c, you need to declare the external variable RX_status

 

 

extern FlagStatus  RX_status;

void USART1_IRQHandler(void)

{

     GPIO_SetBits(GPIOB, GPIO_Pin_5);

     //Confirm whether data is received

     RX_status = USART_GetFlagStatus(USART1,USART_FLAG_RXNE);

     //Receive data

     if(RX_status == SET)

     {

            //Send data back to the HyperTerminal

            USART_SendData(USART1, USART_ReceiveData(USART1));

            //Wait for data to be sent

            while(USART_GetFlagStatus(USART1, USART_FLAG_TC) ==RESET);

            GPIO_ResetBits(GPIOB, GPIO_Pin_5);

     }

}

 

Keywords:STM32  USART Reference address:Learning and experience of STM32 USART serial port

Previous article:Detailed explanation of baud rate calculation under STM32
Next article:stm32 USART serial communication operation register + library function

Recommended ReadingLatest update time:2024-11-15 13:22

STM32 learning record - printf function relocation
Function:  Relocate the printf function to use it as the serial port print output function. Replace the usart_send_string() function step:  usart.c contains the USART initialization function  1. USART initialization (enable clock, enable GPIO, GPIO and USART initialization)  2. Open USART  3. Add the following code
[Microcontroller]
Understanding STM32 input and output modes
When I was reading the data sheet recently, I found that there are 8 types of GPIO configurations in Cortex-M3: (1) GPIO_Mode_AIN analog input  (2) GPIO_Mode_IN_FLOATING floating input (3) GPIO_Mode_IPD pull-down input (4) GPIO_Mode_IPU pull-up input (5) GPIO_Mode_Out_OD open-drain output (6) GPIO_Mode_Out_PP pus
[Microcontroller]
Understanding STM32 input and output modes
stm32 timer 3 generates a specified number of pulses
1. Scenario description: Use PB5 to generate a certain number of pulse signals. PB5 is the second channel of timer 3. 2. Generate PWM code: void Timer3_Configuration(void ) {  TIM_TimeBaseInitTypeDef  TIM_TimeBaseStructure; TIM_OCInitTypeDef  TIM_OCInitStructure;   TIM_DeInit(TIM3); // ƵÂÊ30K //Õ¼¿Õ±È50%  //
[Microcontroller]
stm32 timer 3 generates a specified number of pulses
Problems encountered when porting cjson to stm32
1. The cJSON object root created does not have cJSON_Delete(root); the system crashes after executing it once 2. The string char *str obtained by cJSON parsing root, free(str), returns an error message after executing n times. After changing to myfree(str), it runs normally.
[Microcontroller]
STM32 system clock base timer
The STM32F10x core has a system clock base timer, which is a 24-bit down counter. After it is set and enabled, the count value decreases by 1 every time a system clock cycle passes. When the count value decreases to 0, the system time base timer will automatically reload the initial value. The system time base timer g
[Microcontroller]
PWM frequency and duty cycle setting in stm32
For 72M frequency, the pwm frequency is calculated as: frequency: //Fpwm = 72M / ((arr+1)*(psc+1))(unit: Hz) Duty Cycle: //duty circle = TIM3- CCR1 / arr (unit: %) This way, you have to manually calculate each time you change the frequency and duty cycle, which is very inconvenient. Let’s make the following
[Microcontroller]
STM32 Experiment 1: Timer interrupt generates two signals of different frequencies simultaneously
1. Experimental Purpose Use STM32 to generate two signals with different frequencies at the same time, and observe the flashing speed of the two LEDs on the development board, as well as view the waveforms in the software simulation logic analysis in MDK5 to reflect the difference in the frequencies of the two signals
[Microcontroller]
STM32 pin mode GPIOMode_TypeDef
① Floating input_IN_FLOATING //Serial port input ② Input with pull-up_IPU ③ Input with pull-down_IPD ④ Analog input_AIN ⑤ Open-drain output_OUT_OD ⑥ Push-pull output_OUT_PP //Set ⑦ Push-pull output of multiplexing function_AF_PP //Serial port output ⑧ Open-drain output of multiplexing function_AF_OD The differe
[Microcontroller]
Latest Microcontroller Articles
Change More Related Popular Components

EEWorld
subscription
account

EEWorld
service
account

Automotive
development
circle

About Us Customer Service Contact Information Datasheet Sitemap LatestNews


Room 1530, 15th Floor, Building B, No.18 Zhongguancun Street, Haidian District, Beijing, Postal Code: 100190 China Telephone: 008610 8235 0740

Copyright © 2005-2024 EEWORLD.com.cn, Inc. All rights reserved 京ICP证060456号 京ICP备10001474号-1 电信业务审批[2006]字第258号函 京公网安备 11010802033920号