STM32CubeMX Series|Serial Communication

Serial communication

1. Introduction to the serial port

In serial communication, one character is transmitted one by one, and each character is transmitted one by one. When a character is transmitted, it always starts with the "start bit" and ends with the "stop bit". Before transmitting, both parties must use the same baud rate setting. The baud rate is the number of data bits transmitted per second. The two basic serial communication methods commonly used include synchronous communication and asynchronous communication. What we usually use is asynchronous communication. Asynchronous communication stipulates that the transmission data format consists of a start bit, a data bit, a parity bit, and a stop bit. Serial communication has three communication modes: HAL library polling, interrupt, and DMA:

  • Polling mode: The CPU continuously queries the IO device and processes it if the device requests it. For example, the CPU keeps inquiring whether the serial port transmission is complete, and returns a timeout error if the transmission exceeds. The polling method consumes CPU processing time and is less efficient.
  • Interrupt control method: When the I/O operation is completed, the input and output device controller sends an interrupt signal to the processor through the interrupt request line. After the processor receives the interrupt signal, it transfers to the interrupt processing program to handle the data transfer work accordingly .
  • Direct memory access technology (DMA) method: the so-called direct transfer, that is, in the process of transferring a data block between the memory and the IO device, without any intermediate intervention of the CPU, only the CPU sends a "transfer block to the device at the beginning of the process" Data" command, and then use interrupts to know whether the process is over and whether the next operation is ready.
  • USART block diagram

Insert picture description here

  • Serial communication process

Insert picture description here

2. Hardware design

In this experiment, the serial port 1 of STM32F1 is connected with the USB port of the PC through the CH340 chip to realize the serial port connection. Serial communication needs to cross-connect the data receiving and sending pins, and the other part of the circuit is the automatic download circuit part, the purpose is to control the boot mode and reset of the BOOT
Insert picture description here

3. Software design

3.1 STM32CubeMX settings
  • RCC set external HSE, clock is set to 72M
  • PC0 is set to GPIO push-pull output mode, pull-up, high-speed, and the default output level is high
  • USART1 is selected as the asynchronous communication mode, the baud rate is set to 115200Bits/s, the transmission data length is 8Bit, no parity, 1 stop bit

Insert picture description here

  • If you use the interrupt communication method, you also need to open the serial port interrupt

Insert picture description here

  • If you use the direct memory access (DMA) method, in addition to the above steps (serial port interruption must be turned on, otherwise the program can only send data once, and can not determine whether the DMA transfer is completed, USART has been in busy state) also need to set the DMA transfer direction, Channel, priority, data length, and pointer increment or not

Insert picture description here

  • Enter the project name, select the project path (no Chinese), select MDK-ARM V5; check Generated periphera initialization as a pair of'.c/.h' files per IP; click GENERATE CODE to generate the project code
3.2 MDK-ARM software programming
  • Polling method
/*****usart.c文件中的UART初始化函数以及IO口配置函数*****/
void MX_USART1_UART_Init(void){
    
    
  huart1.Instance = USART1;
  huart1.Init.BaudRate = 115200;
  huart1.Init.WordLength = UART_WORDLENGTH_8B;
  huart1.Init.StopBits = UART_STOPBITS_1;
  huart1.Init.Parity = UART_PARITY_NONE;
  huart1.Init.Mode = UART_MODE_TX_RX;
  huart1.Init.HwFlowCtl = UART_HWCONTROL_NONE;
  huart1.Init.OverSampling = UART_OVERSAMPLING_16;
  if (HAL_UART_Init(&huart1) != HAL_OK){
    
    
    Error_Handler();
  }
}

void HAL_UART_MspInit(UART_HandleTypeDef* uartHandle){
    
    
  GPIO_InitTypeDef GPIO_InitStruct = {
    
    0};
  if(uartHandle->Instance==USART1){
    
    
  /* USER CODE BEGIN USART1_MspInit 0 */
  /* USER CODE END USART1_MspInit 0 */
    /* USART1 clock enable */
    __HAL_RCC_USART1_CLK_ENABLE();  
    __HAL_RCC_GPIOA_CLK_ENABLE();
    /**USART1 GPIO Configuration    
    PA9     ------> USART1_TX
    PA10     ------> USART1_RX*/
    GPIO_InitStruct.Pin = GPIO_PIN_9;
    GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
    GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_HIGH;
    HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);

    GPIO_InitStruct.Pin = GPIO_PIN_10;
    GPIO_InitStruct.Mode = GPIO_MODE_INPUT;
    GPIO_InitStruct.Pull = GPIO_NOPULL;
    HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);
  /* USER CODE BEGIN USART1_MspInit 1 */
  /* USER CODE END USART1_MspInit 1 */
  }
}

The standard output function used in the standard library in the C language. The default output device is the display screen. To realize the output of the serial port or LCD, you must redefine the functions related to the output function in the standard library function, such as printf output to the serial port. Point the output in the fputc function to the serial port (redirection)

/*****在usart.c中添加如下函数*****/
int fputc(int ch, FILE *f){
    
    
	HAL_UART_Transmit(&huart1, (uint8_t *)&ch, 1, 0xffff);
	return ch;
}
/*****main.c文件中编写相关代码*****/
while (1){
    
    
    HAL_UART_Transmit(&huart1,"HAL_UART_Transmit Test...",25,0xffff);
    printf("\r\n printf test...\r\n");
    HAL_GPIO_TogglePin(GPIOC,GPIO_PIN_0);
	HAL_Delay(1000);
    /* USER CODE END WHILE */
}
  • Interrupt mode
/*****usart.c文件中的UART初始化函数以及IO口配置函数*****/
void MX_USART1_UART_Init(void){
    
    
	//....该函数与轮询方式的UART初始化函数相同....
}

void HAL_UART_MspInit(UART_HandleTypeDef* uartHandle){
    
    
  GPIO_InitTypeDef GPIO_InitStruct = {
    
    0};
  if(uartHandle->Instance==USART1){
    
    
  /* USER CODE BEGIN USART1_MspInit 0 */
  /* USER CODE END USART1_MspInit 0 */
    /* USART1 clock enable */
    __HAL_RCC_USART1_CLK_ENABLE();  
    __HAL_RCC_GPIOA_CLK_ENABLE();
    /**USART1 GPIO Configuration    
    PA9     ------> USART1_TX
    PA10     ------> USART1_RX*/
    GPIO_InitStruct.Pin = GPIO_PIN_9;
    GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
    GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_HIGH;
    HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);

    GPIO_InitStruct.Pin = GPIO_PIN_10;
    GPIO_InitStruct.Mode = GPIO_MODE_INPUT;
    GPIO_InitStruct.Pull = GPIO_NOPULL;
    HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);
    /* USART1 interrupt Init */
    HAL_NVIC_SetPriority(USART1_IRQn, 0, 0);
    HAL_NVIC_EnableIRQ(USART1_IRQn);
  /* USER CODE BEGIN USART1_MspInit 1 */
  /* USER CODE END USART1_MspInit 1 */
  }
}

Find the callback function prototype for weak symbol interrupt reception completion, and customize the callback function in usart.c
__weak void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart)

void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart){
    
    
	if(huart->Instance == USART1){
    
    
		HAL_UART_Transmit(&huart1,RxMsg,10,0xffff);	//将接收的数据通过串口1发送回去
		HAL_UART_Receive_IT(&huart1,RxMsg,10);		//再次开启接收中断
	}
}
/*****main.c文件中编写相关代码*****/
/* USER CODE BEGIN PV */
uint8_t TxMsg[] = "\r\n*****USART communication based on IT*****\r\n";
uint8_t RxMsg[20];
/* USER CODE END PV */
/* USER CODE BEGIN 2 */
	HAL_UART_Transmit_IT(&huart1,TxMsg,sizeof(TxMsg));
	HAL_UART_Receive_IT(&huart1,RxMsg,10);
/* USER CODE END 2 */
while (1){
    
    
    HAL_GPIO_TogglePin(GPIOC,GPIO_PIN_0);
	HAL_Delay(1000);
    /* USER CODE END WHILE */
}
  • DMA method
/*****dma.c文件中的DMA初始化函数*****/
void MX_DMA_Init(void) {
    
    
  /* DMA controller clock enable */
  __HAL_RCC_DMA1_CLK_ENABLE();
  /* DMA interrupt init */
  /* DMA1_Channel4_IRQn interrupt configuration */
  HAL_NVIC_SetPriority(DMA1_Channel4_IRQn, 0, 0);
  HAL_NVIC_EnableIRQ(DMA1_Channel4_IRQn);
  /* DMA1_Channel5_IRQn interrupt configuration */
  HAL_NVIC_SetPriority(DMA1_Channel5_IRQn, 0, 0);
  HAL_NVIC_EnableIRQ(DMA1_Channel5_IRQn);
}
/*****usart.c文件中的UART初始化函数以及IO口和DMA配置函数*****/
void MX_USART1_UART_Init(void){
    
    
	//....该函数与轮询方式的UART初始化函数相同....
}

void HAL_UART_MspInit(UART_HandleTypeDef* uartHandle){
    
    
  GPIO_InitTypeDef GPIO_InitStruct = {
    
    0};
  if(uartHandle->Instance==USART1){
    
    
  /* USER CODE BEGIN USART1_MspInit 0 */
  /* USER CODE END USART1_MspInit 0 */
    /* USART1 clock enable */
    __HAL_RCC_USART1_CLK_ENABLE();  
    __HAL_RCC_GPIOA_CLK_ENABLE();
    /**USART1 GPIO Configuration    
    PA9     ------> USART1_TX
    PA10     ------> USART1_RX */
    GPIO_InitStruct.Pin = GPIO_PIN_9;
    GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
    GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_HIGH;
    HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);

    GPIO_InitStruct.Pin = GPIO_PIN_10;
    GPIO_InitStruct.Mode = GPIO_MODE_INPUT;
    GPIO_InitStruct.Pull = GPIO_NOPULL;
    HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);
    /* USART1 DMA Init */
    /* USART1_RX Init */
    hdma_usart1_rx.Instance = DMA1_Channel5;
    hdma_usart1_rx.Init.Direction = DMA_PERIPH_TO_MEMORY;
    hdma_usart1_rx.Init.PeriphInc = DMA_PINC_DISABLE;
    hdma_usart1_rx.Init.MemInc = DMA_MINC_ENABLE;
    hdma_usart1_rx.Init.PeriphDataAlignment = DMA_PDATAALIGN_BYTE;
    hdma_usart1_rx.Init.MemDataAlignment = DMA_MDATAALIGN_BYTE;
    hdma_usart1_rx.Init.Mode = DMA_NORMAL;
    hdma_usart1_rx.Init.Priority = DMA_PRIORITY_LOW;
    if (HAL_DMA_Init(&hdma_usart1_rx) != HAL_OK){
    
    
      Error_Handler();
    }

    __HAL_LINKDMA(uartHandle,hdmarx,hdma_usart1_rx);
    /* USART1_TX Init */
    hdma_usart1_tx.Instance = DMA1_Channel4;
    hdma_usart1_tx.Init.Direction = DMA_MEMORY_TO_PERIPH;
    hdma_usart1_tx.Init.PeriphInc = DMA_PINC_DISABLE;
    hdma_usart1_tx.Init.MemInc = DMA_MINC_ENABLE;
    hdma_usart1_tx.Init.PeriphDataAlignment = DMA_PDATAALIGN_BYTE;
    hdma_usart1_tx.Init.MemDataAlignment = DMA_MDATAALIGN_BYTE;
    hdma_usart1_tx.Init.Mode = DMA_NORMAL;
    hdma_usart1_tx.Init.Priority = DMA_PRIORITY_LOW;
    if (HAL_DMA_Init(&hdma_usart1_tx) != HAL_OK){
    
    
      Error_Handler();
    }

    __HAL_LINKDMA(uartHandle,hdmatx,hdma_usart1_tx);
    /* USART1 interrupt Init */
    HAL_NVIC_SetPriority(USART1_IRQn, 0, 0);
    HAL_NVIC_EnableIRQ(USART1_IRQn);
  /* USER CODE BEGIN USART1_MspInit 1 */
  /* USER CODE END USART1_MspInit 1 */
  }
}
/*****main.c文件中编写相关代码*****/
/* USER CODE BEGIN PV */
uint8_t TxMsg[] = "\r\n*****USART communication based on DMA*****\r\n";
/* USER CODE END PV */
while (1){
    
    
    HAL_UART_Transmit_DMA(&huart1,TxMsg,sizeof(TxMsg));
    HAL_GPIO_TogglePin(GPIOC,GPIO_PIN_0);
	HAL_Delay(1000);
    /* USER CODE END WHILE */
}

4. Download verification

  • Polling method

Insert picture description here

  • Serial port interruption: Use the serial port assistant to send 10 characters, and the serial port assistant will echo the sent data; the serial port must send enough 10 characters to trigger the interrupt; more than 10 characters, the serial port will only send 10 characters (be careful not to check the'send New line')

Insert picture description here

  • DMA method

Insert picture description here

Guess you like

Origin blog.csdn.net/Chuangke_Andy/article/details/108583316