LoginSignup
4

More than 1 year has passed since last update.

HALライブラリによるSTM32マイコンのUART機能使用方法

Last updated at Posted at 2022-02-20

記事の概要

STM32マイコンのUART機能をHALライブラリを用いて使用する方法を解説します。

一般的にはSTM32CubeMXコード生成ツールを使うことが多いと思いますが、ここでは直接HALライブラリから関数を呼び出して設定を行います。
また、通常のモードについてのみ解説し、DMA機能については解説していません。

USART

STM32ではUART機能をUSARTとも呼んでいます。
正確にはUSARTは非同期なUART通信、SPIマスター通信、LIN(ローカル内部ネットワーク)などの複数のシリアル通信機能を兼ね備えたモジュールです。

例えばSTM32F407には4つのUSARTモジュールと2つのUARTモジュールがあります。
UARTモジュールにはSPIマスター機能に対応していないことが分かります。

image.png

サンプルコード

例えばUSART3モジュールを使用する場合、以下のように設定します。
UART受信は割り込み処理しています。

#include "stm32f4xx.h"
#include "stm32f4_discovery.h"

uint8_t byte;
UART_HandleTypeDef huart3;

void USART3_IRQHandler(void)
{
  HAL_UART_IRQHandler(&huart3);
}

void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart)
{
  if (huart->Instance == USART3)
  {   
    HAL_UART_Transmit(&huart3, &byte, 1, 100);

    HAL_UART_Receive_IT(&huart3, &byte, 1);
  }
}

void uart_init(void)
{               
    __HAL_RCC_GPIOD_CLK_ENABLE();
    __HAL_RCC_USART3_CLK_ENABLE();

    GPIO_InitTypeDef GPIO_InitStruct;
    GPIO_InitStruct.Pin = GPIO_PIN_8 | GPIO_PIN_9;
    GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
    GPIO_InitStruct.Pull = GPIO_PULLUP;
    GPIO_InitStruct.Speed = GPIO_SPEED_LOW;
    GPIO_InitStruct.Alternate = GPIO_AF7_USART3;
    HAL_GPIO_Init(GPIOD, &GPIO_InitStruct);

    huart3.Instance = USART3;
    huart3.Init.BaudRate = 115200;
    huart3.Init.WordLength = UART_WORDLENGTH_8B;
    huart3.Init.StopBits = UART_STOPBITS_1;
    huart3.Init.Parity = UART_PARITY_NONE;
    huart3.Init.Mode = UART_MODE_TX_RX;
    huart3.Init.HwFlowCtl = UART_HWCONTROL_NONE;
    huart3.Init.OverSampling = UART_OVERSAMPLING_16;
    HAL_UART_Init(&huart3);

    HAL_NVIC_SetPriority(USART3_IRQn, 1, 0);
    HAL_NVIC_EnableIRQ(USART3_IRQn);

    HAL_UART_Receive_IT(&huart3, &byte, 1);
}

ポート端子設定

UART機能に使用するポート端子の設定を行います。

USART3の場合は、TX端子はPD8、RX端子はPD9です。

マイコンのモジュールは、初期状態では消費電力を抑えるために停止しています。
GPIODにクロック供給することで起動してやります。

__HAL_RCC_GPIOD_CLK_ENABLE();

GPIO_InitStructの設定を行います。
ポート8番と9番を指定します。

GPIO_InitStruct.Pin = GPIO_PIN_8 | GPIO_PIN_9;

プルアップ設定にしているのは、初期からポート出力をにしておき、ハイインピーダンス状態による不安定さを回避するためと私は解釈しています。

GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
GPIO_InitStruct.Pull = GPIO_PULLUP;

速度は低速にしていますが、高速にしても特に動作に支障はありませんでした。

GPIO_InitStruct.Speed = GPIO_SPEED_LOW;

1つの端子は複数の機能に使い分けることができます。
マイコン内部に選択回路があり、AFレジスタを設定することで、ポート端子と様々なモジュールとの接続を切り替えています。
その選択をするのがAlternateです。

マニュアルのPD8とPD9を見ると、UART機能を選択する設定はAF7です。
(もしPD8とPD9をFSMCのD13とD14として使用したい場合はAF12に設定します。)

image.png

GPIO_InitStruct.Alternate = GPIO_AF7_USART3;

UART通信設定

UARTの実体UART_HandleTypeDefを作成しておきます。

UART_HandleTypeDef huart3;

GPIODと同様にUSART3モジュールにクロックを供給します。

__HAL_RCC_USART3_CLK_ENABLE();

通信速度、データ長、ストップビット、パリティビットを設定します。
ここでは通信速度を115200bps、データ長8bit、ストップビット1bit、パリティビットなしに設定しています。

huart3.Instance = USART3;
huart3.Init.BaudRate = 115200;
huart3.Init.WordLength = UART_WORDLENGTH_8B;
huart3.Init.StopBits = UART_STOPBITS_1;
huart3.Init.Parity = UART_PARITY_NONE;

モードはRXモード、TXモード、TX_RXモードがあります。
送受信の機能を使用するのでTX_RXモードにします。

huart3.Init.Mode = UART_MODE_TX_RX;

ハードウェアコントロール(RTS端子とCTS端子)を使用するかを選択します。
ハードウェアコントロールを使用しないので、設定をUART_HWCONTROL_NONEにします。

huart3.Init.HwFlowCtl = UART_HWCONTROL_NONE;

オーバーサンプリングは8倍と16倍があります。
クロックずれによる最大受信耐性を増加させたいので、16倍を設定します。

huart3.Init.OverSampling = UART_OVERSAMPLING_16;

以上の設定を有効化します。

HAL_UART_Init(&huart3);

UART送信

以下の送信関数によりデータ送信できます。

uint8_t data;
byte = 'A';

HAL_UART_Transmit(&huart3, &data, 1, 100);

第1引数にはUSARTモジュールの実体であるUART_HandleTypeDefを代入します。
第2引数には送信データの先頭アドレスを代入し、第3引数には送信データサイズを代入します。
第4引数はタイムアウトの時間です。この時間を過ぎても通信できない場合、エラー終了します。

例えば、10文字のデータを送信したい場合は以下のようにします。

HAL_UART_Transmit(&huart3, (uint8_t *)"FreeRTOS\r\n", 10, 100);

UART受信

データをUART受信すると割り込み処理が発生するように設定します。

HAL_NVIC_SetPriority(USART3_IRQn, 1, 0);
HAL_NVIC_EnableIRQ(USART3_IRQn);

受信待機処理HAL_UART_Receive_ITを実行して、データ受信できるようにします。
ここではUART通信開始時に、1バイトデータを受信待機するように命令しておきます。
HAL_UART_Receive_ITを実行しないと、データ受信できないのでご注意ください。

HAL_UART_Receive_IT(&huart3, &byte, 1);

UART受信により以下のハンドラーが呼び出されます。

void USART3_IRQHandler(void)
{
  HAL_UART_IRQHandler(&huart3);
}

ハンドラーからコールバック関数HAL_UART_RxCpltCallbackが呼び出されます。
コールバック関数内で、USART3の実体Instanceであるかの確認をします。
そして、ユーザーのしたい処理を行います。

ここでは受信したデータをそのまま送信し返してから、再度1バイト受信待機処理を実行して、次のデータに備えます。
1バイト受信したことで最初に設定したHAL_UART_Receive_ITは無効になっているので、再度HAL_UART_Receive_ITを実行しないとデータ受信できなくなっているのでご注意ください。

void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart)
{
   if (huart->Instance == USART3)
   {      
       HAL_UART_Transmit(&huart3, &byte, 1, 100);

       HAL_UART_Receive_IT(&huart3, &byte, 1);
   }
}

参考

ここでは解説しなかったDMA通信については、以下をご参照ください。

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
4