Serie STM32CubeMX | Comunicación en serie

Comunicación serial

1. Introducción al puerto serie

En la comunicación serial, un carácter se transmite uno por uno, y cada carácter se transmite uno por uno. Cuando se transmite un carácter, siempre comienza con el "bit de inicio" y termina con el "bit de parada". Antes de transmitir, ambas partes deben utilizar la misma configuración de velocidad en baudios. La velocidad en baudios es el número de bits de datos transmitidos por segundo. Los dos métodos básicos de comunicación en serie que se utilizan comúnmente incluyen la comunicación sincrónica y la comunicación asincrónica. Lo que usamos habitualmente es la comunicación asíncrona, que estipula que el formato de datos de transmisión consta de un bit de inicio, un bit de datos, un bit de paridad y un bit de parada. La comunicación en serie tiene tres modos de comunicación: sondeo de biblioteca HAL, interrupción y DMA:

  • Modo de sondeo: la CPU consulta continuamente el dispositivo IO y lo procesa si el dispositivo lo solicita. Por ejemplo, la CPU sigue preguntando si la transmisión del puerto serie está completa y devuelve un error de tiempo de espera si la transmisión se excede. El método de sondeo consume tiempo de procesamiento de la CPU y es menos eficiente.
  • Método de control de interrupción: cuando se completa la operación de E / S, el controlador del dispositivo de entrada y salida envía una señal de interrupción al procesador a través de la línea de solicitud de interrupción. Después de que el procesador recibe la señal de interrupción, se transfiere al programa de procesamiento de interrupciones para manejar el trabajo de transferencia de datos en consecuencia. .
  • Método de tecnología de acceso directo a memoria (DMA): la llamada transferencia directa, es decir, en el proceso de transferir un bloque de datos entre la memoria y el dispositivo IO, sin ninguna intervención intermedia de la CPU, solo la CPU envía un "bloque de transferencia al dispositivo al comienzo del proceso" Data ", y luego use interrupciones para saber si el proceso ha terminado y si la siguiente operación está lista.
  • Diagrama de bloques de USART

Inserte la descripción de la imagen aquí

  • Proceso de comunicación en serie

Inserte la descripción de la imagen aquí

2. Diseño de hardware

En este experimento, el puerto serie 1 de STM32F1 se conecta con el puerto USB de la PC a través del chip CH340 para realizar la conexión del puerto serie. La comunicación en serie necesita una conexión cruzada de los pines de envío y recepción de datos, y las otras partes del circuito son las partes del circuito de descarga automática, el propósito es controlar el modo de arranque y reiniciar el BOOT
Inserte la descripción de la imagen aquí

3. Diseño de software

3.1 Configuración de STM32CubeMX
  • RCC establece HSE externo, el reloj está configurado en 72M
  • PC0 está configurado en modo de salida GPIO push-pull, pull-up, alta velocidad y el nivel de salida predeterminado es alto
  • USART1 se selecciona como modo de comunicación asíncrona, la velocidad en baudios se establece en 115200 Bits / s, la longitud de los datos de transmisión es de 8 bits, sin paridad, 1 bit de parada

Inserte la descripción de la imagen aquí

  • Si utiliza el método de comunicación de interrupción, también debe abrir la interrupción del puerto serie

Inserte la descripción de la imagen aquí

  • Si utiliza el método de acceso directo a memoria (DMA), además de los pasos anteriores (la interrupción del puerto serie debe estar activada; de lo contrario, el programa solo puede enviar datos una vez y no puede determinar si la transferencia DMA se completó, USART ha estado en estado de ocupado) también debe configurar la dirección de transferencia DMA Canal, prioridad, longitud de datos e incremento de puntero o no

Inserte la descripción de la imagen aquí

  • Ingrese el nombre del proyecto, seleccione la ruta del proyecto (no chino), seleccione MDK-ARM V5; marque Inicialización de periféricos generados como un par de archivos '.c / .h' por IP; haga clic en GENERAR CÓDIGO para generar el código del proyecto
3.2 Programación del software MDK-ARM
  • Método de sondeo
/*****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 */
  }
}

La función de salida estándar utilizada en la biblioteca estándar en el lenguaje C. El dispositivo de salida predeterminado es la pantalla de visualización. Para realizar la salida del puerto serie o LCD, debe redefinir las funciones relacionadas con la función de salida en la función de biblioteca estándar, como la salida printf al puerto serie. Apunte la salida en la función fputc al puerto serie (redirección)

/*****在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 */
}
  • Modo de interrupción
/*****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 */
  }
}

Encuentre el prototipo de la función de devolución de llamada para completar la recepción de interrupción de símbolo débil y personalice la función de devolución de llamada en 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 */
}
  • Método DMA
/*****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. Descarga la verificación

  • Método de sondeo

Inserte la descripción de la imagen aquí

  • Interrupción del puerto serie: utilice el asistente del puerto serie para enviar 10 caracteres, y el asistente del puerto serie hará eco de los datos enviados; el puerto serie debe enviar suficientes 10 caracteres para activar la interrupción; más de 10 caracteres, el puerto serie solo enviará 10 caracteres (tenga cuidado de no verificar el envío Nueva línea')

Inserte la descripción de la imagen aquí

  • Método DMA

Inserte la descripción de la imagen aquí

Supongo que te gusta

Origin blog.csdn.net/Chuangke_Andy/article/details/108583316
Recomendado
Clasificación