STM32 learning notes II. UART serial communication data transceiver based on STM32F103C8T6 and STM32CubeMX

Catalogue of series articles

1, Based on the STM32F103C8T6 minimum system board and stm32subemx, the LED light flashes circularly
2, UART serial communication data transceiver based on STM32F103C8T6 and stm32subemx


The board I use this time is a data acquisition card with STM32F103C8T6 as the main control chip. The pins connected by the two LED lights are PB3 and PB4, and the TX and RX pins are PA9 and PA10 respectively.

1, Configuring CubeMX

1. New construction;
2. The clock source is configured, and the crystal oscillator clock is configured for HSE in RCC;
3. Configure the program burning pin SYS to SWD mode;
4. Configure GPIO port and an LED light (my board is PB3) to indicate when the serial port successfully receives data;
5. Configure serial port transceiver pin

The communication mode we adopt here is UART communication (asynchronous full duplex serial port communication), PA9 is used as TX and PA10 is used as RX. Directly click the corresponding pin in the visual block diagram for configuration.

Up to now, the effect picture is:

It can be found that the TX and RX pins are yellow after configuration, which means that the configuration has not been completed. Continue to configure below.

6. Select asynchronous full duplex communication mode in USART1 mode in "Connectivity" on the left
⮚ click USATR1
⮚ set MODE to asynchronous
⮚ basic parameters: the baud rate is 115200 Bits/s. The transmission data length is 8 bits. Parity check is none, stop bit is 1, and both reception and transmission are enabled
⮚ GPIO pin setting USART1_RX/USART_TX
⮚ enable receiving interrupt in NVIC Settings column

Here is a simple extension:
STM32F103 series single chip microcomputer has five serial ports, of which 1-3 are universal synchronous / asynchronous serial interface USART(Universal Synchronous/Asynchronous Receiver/Transmitter), 4 and 5 are universal asynchronous serial interface UART(Universal Asynchronous Receiver/Transmitter).

7. When configuring the clock tree, I still drive it to the highest 72MHz
8. Set up the project and finally generate the code, and the CubeMX part is completed

2, Introduction to UART related functions of HAL Library

2.1 serial port send / receive function

HAL_UART_Transmit();//Serial port sends data, using timeout management mechanism 
HAL_UART_Receive();//The serial port receives data and uses the timeout management mechanism
HAL_UART_Transmit_IT();//Serial port interrupt mode transmission  
HAL_UART_Receive_IT();//Serial port interrupt mode reception
HAL_UART_Transmit_DMA();//Serial port DMA mode transmission
HAL_UART_Transmit_DMA();//Serial port DMA mode reception

The parameters of these six functions are basically the same. Select a common function for transmission / reception to briefly introduce:

Serial port sending data:

HAL_UART_Transmit(UART_HandleTypeDef *huart, uint8_t *pData, uint16_t Size, uint32_t Timeout)


The serial port sends data of the specified length. If the timeout is not completed, it will not be sent again, and the timeout flag (HAL_TIMEOUT) will be returned.


⮚ uart_handletypedef * the alias of UART, such as UART_HandleTypeDef huart1; the alias is huart1
⮚ * pData data to be sent
⮚ Size number of bytes sent
⮚ Timeout is the maximum sending time. If the sending data exceeds this time, the sending will exit
Example: hal_uart_transmit (& huart1, (uint8_t *) Zzx, 3, 0xffff); / / the serial port sends three bytes of data, and the maximum transmission time is 0xffff

Serial port receiving data:

HAL_UART_Receive_IT(UART_HandleTypeDef *huart, uint8_t *pData, uint16_t Size)


Serial port interrupt receiving receives data of specified length in an interrupt mode.
The general process is to set the data storage location, receive the data length, and then enable the serial port to receive the interrupt. When the data is received, the serial port interrupt will be triggered. Then, the serial port interrupt function will process until the data of the specified length is received, then close the interrupt, enter the interrupt connection to recover the function, and no longer trigger the receive interrupt. (only one interrupt is triggered)


⮚ uart_handletypedef * alias of huart UART
⮚ * pData received data storage address
⮚ Size number of bytes received
Example: hal_uart_receive_it (& huart1, (uint8_t *) & value, 1); / / interrupt receiving a character and store it in value

2.2 serial port interrupt function

HAL_UART_IRQHandler(UART_HandleTypeDef *huart);  //Serial port interrupt processing function
HAL_UART_TxCpltCallback(UART_HandleTypeDef *huart);  //Serial port sending interrupt callback function
HAL_UART_TxHalfCpltCallback(UART_HandleTypeDef *huart);  //Half interrupt callback function sent by serial port (not commonly used)
HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart);  //Serial port receive interrupt callback function
HAL_UART_RxHalfCpltCallback(UART_HandleTypeDef *huart);//Half callback function received by serial port (not commonly used)
HAL_UART_ErrorCallback();//Serial port receiving error function

Serial port receive interrupt callback function:

HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart);  


After the interrupt of HAL library is completed, it will not exit directly, but will enter the interrupt callback function. You can set the code in it. After the serial port interrupt is received, it will enter the function. The function is empty and needs to be modified by the user.


⮚ uart_handletypedef * alias of huart uatr
Example: hal_uart_rxcpltcallback (& huart1) {/ / user set code / /}

Serial port interrupt processing function:

HAL_UART_IRQHandler(UART_HandleTypeDef *huart);  


Judge and process the received data, judge whether to send interrupt or receive interrupt, and then send and receive the data, which is used in the interrupt service function.

If data is received, the receive interrupt processing function will be performed

 /* UART in mode Receiver ---------------------------------------------------*/
  if((tmp_flag != RESET) && (tmp_it_source != RESET))

If data is sent, the send interrupt processing function will be performed

  /* UART in mode Transmitter ------------------------------------------------*/
  if (((isrflags & USART_SR_TXE) != RESET) && ((cr1its & USART_CR1_TXEIE) != RESET))

2.3 serial port query function

  HAL_UART_GetState();  judge UART Whether the reception of is over, or whether the sending of data is busy

give an example:

While (hal_uart_getstate (& huart4) = = hal_uart_state_busy_tx) / / detect the end of UART sending

3, Logic code part

3.1 UART receiving interrupt

Because the interrupt receiving function can only trigger a receive interrupt once, we need to call the interrupt receiving function again in the interrupt callback function.

Specific process:

1. Initialize serial port

2. Call the receive interrupt function for the first time in main

3. Enter the receive interrupt. After receiving the data, enter the interrupt callback function

4. Modify HAL_UART_RxCpltCallback interrupt callback function to process the received data,

5. HAL_UART_Receive_IT function shall be called once in the callback function, so that the program can trigger the receiving interrupt again

Function flow:

① HAL_UART_Receive_IT - >
② USART2_IRQHandler(void) - >
③ HAL_UART_IRQHandler(UART_HandleTypeDef *huart) (interrupt handler) - >
④ UART_Receive_IT(UART_HandleTypeDef *huart) (receiving function) - >
⑤ HAL_UART_RxCpltCallback(huart) (interrupt callback function)

HAL_UART_RxCpltCallback function is the callback function to be rewritten in main.c.

Code implementation:

Add the following definitions in main.c:

#include <string.h>
#Define rxbuffer_maxsize 256 / / maximum bytes received
char RxBuffer[RxBuffer_MaxSize];   //receive data 
uint8_t aRxBuffer;			//Receive interrupt buffer
uint8_t UART1_Rx_Cnt = 0;		//Receive buffer count

In the main() main function, the call interrupt function is called once.

	HAL_UART_Receive_IT(&huart1, (uint8_t *)&aRxBuffer, 1);

Add interrupt callback function under main.c

void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart)


 	if(UART1_Rx_Cnt >= 255)  //Overflow judgment
		UART1_Rx_Cnt = 0;
		HAL_UART_Transmit(&huart1, (uint8_t *)"data overflow ", 10,0xFFFF); 	
		RxBuffer[UART1_Rx_Cnt++] = aRxBuffer;   //Receive data transfer
			if((RxBuffer[UART1_Rx_Cnt-1] == 0x0A)&&(RxBuffer[UART1_Rx_Cnt-2] == 0x0D)) //Judgment end bit
					HAL_UART_Transmit(&huart1, (uint8_t *)&RxBuffer, UART1_Rx_Cnt,0xFFFF); //Send the received information
          while(HAL_UART_GetState(&huart1) == HAL_UART_STATE_BUSY_TX);//Detect UART sending end
				  HAL_GPIO_TogglePin(GPIOB,GPIO_PIN_3);//LED indicator status flip
					UART1_Rx_Cnt = 0;
					memset(RxBuffer,0x00,sizeof(RxBuffer)); //Empty array
		HAL_UART_Receive_IT(&huart1, (uint8_t *)&aRxBuffer, 1);   //Restart receive interrupt


Use USB to TTL (CH340) for data transmission, XCOM V2.6 serial port assistant for debugging, and send "1" (note that baud rate and other parameters should be set the same as those configured before)

In debug mode, set the buffer count value UART1_Rx_Cnt is added to the monitor. After the serial port receives the sent data, the count value is + 1

At the same time, you can also see that the LED status is reversed

3.2 UART sending

Redefine printf function

In stm32f1xx_hal.c contains #include < stdio. H >

#include "stm32f1xx_hal.h"
#include <stdio.h>
extern UART_HandleTypeDef huart1;   //Declaration serial port

In stm32f1xx_ Rewriting fget and fput functions in Hal. C

  * Function function: redirect c library function printf to DEBUG_USARTx
  * Input parameters: None
  * Return value: None
  * Description: None
int fputc(int ch, FILE *f)
  HAL_UART_Transmit(&huart1, (uint8_t *)&ch, 1, 0xffff);
  return ch;
  * Function function: redirect c library functions getchar and scanf to DEBUG_USARTx
  * Input parameters: None
  * Return value: None
  * Description: None
int fgetc(FILE *f)
  uint8_t ch = 0;
  HAL_UART_Receive(&huart1, &ch, 1, 0xffff);
  return ch;

Add in main.c

 #define RxBuffer_MaxSize  256
char RxBuffer[RxBuffer_MaxSize]; 
  while (1)
			printf("Hello, world\r\n");//The blogger here can't change the line when he only writes. Baidu can use it once. It's estimated that it's a problem with the compilation system
    /* USER CODE BEGIN 3 */


Reference blog: [STM32] HAL library STM32CubeMX tutorial IV - detailed explanation of UART serial port communication

Tags: Embedded system Single-Chip Microcomputer stm32 ARM

Posted on Sun, 21 Nov 2021 03:22:17 -0500 by gregor171