STM32CubeMXシリーズ|シリアル通信

シリアル通信

1.シリアルポートの概要

シリアル通信では、1文字ずつ送信し、1文字ずつ送信しますが、送信時には必ず「スタートビット」で始まり「ストップビット」で終わります。送信する前に、両方の当事者が同じボーレート設定を使用する必要があります。ボーレートは、1秒あたりに送信されるデータビット数です。一般的に使用される2つの基本的なシリアル通信方法には、同期通信と非同期通信があります。普段は非同期通信を使用していますが、非同期通信では、送信データのフォーマットはスタートビット、データビット、パリティビット、ストップビットで構成されています。シリアル通信には、HALライブラリのポーリング、割り込み、DMAの3つの通信モードがあります。

  • ポーリングモード:CPUはIOデバイスに継続的にクエリを実行し、デバイスが要求した場合はそれを処理します。たとえば、CPUはシリアルポートの送信が完了したかどうかを問い合わせ続け、送信が超過するとタイムアウトエラーを返します。ポーリング方式はCPU処理時間を消費し、効率が低下します。
  • 割り込み制御方法:I / O操作が完了すると、入出力デバイスコントローラーは、割り込み要求ラインを介して割り込み信号をプロセッサに送信します。プロセッサは、割り込み信号を受信した後、割り込み処理プログラムに転送して、それに応じてデータ転送作業を処理します。 。
  • ダイレクトメモリアクセステクノロジー(DMA)方式:いわゆるダイレクト転送、つまりメモリとIOデバイス間でデータブロックを転送するプロセスで、CPUの介在なしに、CPUのみが「プロセスの最初にデバイスに転送ブロック」を送信します。データ」コマンドを入力し、割り込みを使用してプロセスが終了したかどうか、次の操作の準備ができているかどうかを確認します。
  • USARTブロック図

ここに画像の説明を挿入

  • シリアル通信プロセス

ここに画像の説明を挿入

2.ハードウェア設計

この実験では、STM32F1のシリアルポート1をCH340チップを介してPCのUSBポートに接続し、シリアルポート接続を実現しています。シリアル通信はデータの受信ピンと送信ピンを相互接続する必要があり、回路の他の部分は自動ダウンロード回路部分であり、目的はブートモードとブートのリセットを制御することです
ここに画像の説明を挿入

3.ソフトウェア設計

3.1 STM32CubeMX設定
  • RCCは外部HSEを設定、クロックは72Mに設定
  • PC0はGPIOプッシュプル出力モード、プルアップ、高速に設定され、デフォルトの出力レベルは高
  • USART1は非同期通信モードとして選択され、ボーレートは115200ビット/秒に設定され、送信データ長は8ビット、パリティなし、1ストップビットです。

ここに画像の説明を挿入

  • 割り込み通信方式を使用する場合は、シリアルポートの割り込みも開く必要があります

ここに画像の説明を挿入

  • 上記の手順に加えて、ダイレクトメモリアクセス(DMA)方式を使用する場合(シリアルポートの割り込みをオンにする必要があります。そうしないと、プログラムはデータを1回しか送信できず、DMA転送が完了したかどうかを判断できません。USARTはビジー状態です)、DMA転送方向を設定する必要があります。チャネル、優先度、データ長、およびポインターの増分

ここに画像の説明を挿入

  • プロジェクト名を入力し、プロジェクトパス(中国語以外)を選択し、MDK-ARM V5を選択します。IPごとに「.c / .h」ファイルのペアとして生成されたペリフェラルの初期化を確認します。「コードを生成」をクリックしてプロジェクトコードを生成します
3.2 MDK-ARMソフトウェアプログラミング
  • ポーリング方法
/*****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 */
  }
}

C言語の標準ライブラリで使用される標準出力関数。デフォルトの出力デバイスは表示画面です。シリアルポートまたはLCDの出力を実現するには、シリアルポートへのprintf出力など、標準ライブラリ関数で出力関数に関連する関数を再定義する必要があります。 fputc関数の出力をシリアルポートに向ける(リダイレクト)

/*****在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 */
}
  • 割り込みモード
/*****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 */
  }
}

弱いシンボル割り込みの受信完了のコールバック関数プロトタイプを見つけ、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メソッド
/*****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.ダウンロードの確認

  • ポーリング方法

ここに画像の説明を挿入

  • シリアルポートの中断:シリアルポートアシスタントを使用して10文字を送信すると、シリアルポートアシスタントは送信されたデータをエコーし​​ます。シリアルポートは、割り込みをトリガーするのに十分な10文字を送信する必要があります。10文字を超えると、シリアルポートは10文字しか送信しません(送信を確認しないように注意してください)改行')

ここに画像の説明を挿入

  • DMAメソッド

ここに画像の説明を挿入

おすすめ

転載: blog.csdn.net/Chuangke_Andy/article/details/108583316