STM32でシリアル通信してみる ポーリング編

  • 2020.02.01
  • HAL
STM32でシリアル通信してみる ポーリング編

今回はSTM32マイコンでポーリングによるシリアル通信を行ってみます。

投稿時の開発環境を記しておきます。

PC:Windows10 OS
IDE: STM32CubeIDE Version1.1.0
Configurator: STM32CubeMX Version5.4.0
Board: STM32Nucleo-F401RE

シリアル通信は比較的簡単に通信を行うことができる手段ですので、扱ったことがない方はこの機会に試してみてはいかがでしょうか。

その前にIDEプロジェクトの削除について少しだけお話しておきます。

プロジェクトの削除について

これから、いろいろなプロジェクトを作成していく予定です。
機能別にプロジェクトを分けておいた方がわかりやすいと思います。
IDE上で複数のプロジェクトを管理することは可能ですが、わずらわしいことがあります。
例えば Build All を選択したら、IDE上に見えている全てのプロジェクトをビルドしてしまうので無駄に時間がかかってしまいます。
(あるプロジェクトを選択した状態で Build Project すればそのプロジェクトだけがビルドされます)
また開いているファイルがどのプロジェクトのものなのか、わからなくて混乱してしまいます。

そんなわけで、IDE上に見えるプロジェクトはひとつにしておいた方がトラブルが起きにくくなります。

プロジェクトをIDE上から削除しても実際のプロジェクトファイルはディスク上に残しておく方法があるので説明します。
(せっかくつくったプロジェクトですから、ディスク上からも削除してしまってはもったいないです)

IDEのProject Explorer でプロジェクト名(ここでは前回つくっている F401)を右クリックし、出てきたメニューから Delete を選択します。
すると次のウィンドウが出てきます。

ここでチェックボックスにチェックを入れてしまうと、実際にディスク上からプロジェクトファイルを削除してしまいます。
そして元に戻すことはできませんのでご注意ください。

チェックせずにOKボタンを押せば、ファイルは削除されずに IDE上からは見えなくなります。
このようにしてIDE上ではひとつのプロジェクトだけを表示させておくと便利です。

(注)この方法は誤ってプロジェクトファイルを削除してしまう危険性がありますので、この操作前にプロジェクトファイルのバックアップをとっておくことをお勧めします。

削除したプロジェクトをインポートする

ファイルがディスク上から削除されていないプロジェクトはインポートすることで IDE上に表示することができます。

File – Import を選択します。

General – Existing Projects into Workspace を選択して Nextボタンを押します。

Select root directory が選択された状態で右側の Browse…ボタンを押してインポートするプロジェクトを選択して。Finishボタンを押します。

これで見えなくなっていたプロジェクトをIDE上に表示させることができました。

今回は新しいプロジェクトを作成しますので、もう一度 Delete して IDE上からF401のプロジェクトが見えないようにしておいてください。

シリアル通信用のプロジェクトを作成する

メニューから File – New – STM32 Project を選択します。

Boart Selector で Boart List から NUCLEO-F401RE をクリックして選択し Nextボタンを押します。

Project Name にプロジェクト名(例えばここでは) F401UartPolling を入力し Finishボタンを押します。

Initialize all peripherals with their default Mode? と聞いてきますので Yesボタンを押します。

Project Explorer で F401UartPolling – Core – Src – main.c をダブルクリックしてファイルを開きます。

main()関数の中に MX_USART2_UART_Init() という関数があります。

デフォルトモードで初期化したことによって、この関数が生成されています。

初期化によって PA2 が USART2 の TX (送信)に、 PA3 が USART2 の RX (受信)に割り当てられています。

回路図を見ると、これらの端子はデバッガ用のマイコンとつながっていることがわかります。

そして USBケーブルでパソコンと接続すると、パソコン側で仮想COMポートとして認識されます。

そしてそのままでシリアル通信できる環境ができあがっているのです。

一般的には

マイコン – RS232CのドライバIC <---RS232Cクロスケーブル---> RS232CのドライバIC – マイコン

のような接続になるのですが、STマイクロのボードを使うとUSBケーブルでつなぐだけですむのでシリアル通信のテストを行うのに便利です。

ボードを選んでデフォルトモードで周辺機能を初期化した状態で、USARTの機能を使える準備ができているわけです。

パソコン側の準備を行う

パソコン側もデータを送受信できるアプリを準備しなければなりません。
ここでは Tera Term を使います。

Tera Termを起動してシリアル(E)を選択し、ポート(R):で STLink Virtual Com Port が含まれているCOMポートを選択しOKボタンを押します。
こちらの環境では COM4 が Virtual Com Port に割り当てられていました。
STのシステムが仮想的にCOMポートの環境をつくってくれているので使わせて頂きましょう。

次に メニューの 設定 – シリアルポート から通信パラメータを以下のように設定しOKボタンを押します。
これらは MX_USART2_UART_Init() の中で設定された値に合わせてください。

もうひとつ 設定 – 端末 画面でローカルエコーにチェックを入れておきます。
これでキーを押すと、その文字を送り画面に表示します。

マイコンボードとパソコンをUSBケーブルで接続しておいてください。

コーディングしてみる

それでは通信部分のプログラムを実装してみましょう。
プロジェクト名にもあるように、今回はポーリングを使った通信方式になります。
ポーリングは割り込みを使わない方法で、ここでは定期的に受信データがないか見に行きます。

まずmain()の先頭に変数の定義を行います。


int main(void)
{
  /* USER CODE BEGIN 1 */
  uint8_t buffer[256];
  HAL_StatusTypeDef s;
  /* USER CODE END 1 */

次に while()ループの部分を以下のように記述してください。


  /* USER CODE BEGIN WHILE */
  while (1)
  {
    /* USER CODE END WHILE */
    /* USER CODE BEGIN 3 */
    s = HAL_UART_Receive(&huart2, buffer, 1, 3000);
    if (s == HAL_TIMEOUT)
    {
      HAL_UART_Transmit(&huart2, "UART Timeout.\r\n", 15, 10);
    }
    else if (s == HAL_OK)
    {
      HAL_UART_Transmit(&huart2, buffer, 1, 10);
    }
  }
  /* USER CODE END 3 */

コーディングが終わったらビルドしてエラーがないことを確認してください。

プログラムの概要

パソコン側で何かキーを押します。

s = HAL_UART_Receive(&huart2, buffer, 1, 3000); で受信を開始します。

HAL_UART系 関数の詳細は HALのマニュアルを参照してください。

STM32F4系のHALマニュアルは こちら からダウンロードできます。

HAL_UART_Receive()

第1引数:UARTの構造体へのポインタを指定します。
huart2 は MX_USART2_UART_Init() で使っている構造体の変数です。

第2引数:uint8_t型のバッファへのポインタを指定します。
第3引数:受信データのサイズを指定します。練習なので1バイトにしています。
第4引数:タイムアウト値を指定します。単位はmsecです。
戻り値:HAL_StatusTypeDef型の値が返ってきます。

1バイトのデータを受信するか、タイムアウトすると関数から戻ってきます。
ここではタイムアウト値を3秒にしています。

タイムアウトした場合は “UART Timeout.\r\n” を送り返します。
何か受信した場合には、受信した値をそのまま HAL_UART_Transmit() で送信します。

HAL_UART_Transmit()

第1引数:UARTの構造体へのポインタを指定します。
第2引数:uint8_t型のバッファへのポインタを指定します。
第3引数:送信データのサイズを指定します。
第4引数:タイムアウト値を指定します。単位はmsecです。
戻り値:HAL_StatusTypeDef型が返ります。

通信時間の見積

ここで通信時間がどのくらいかかるのか見積もってみます。
UARTによる通信方式は調歩同期式と言われていてフォーマットは以下の図のようになっています。
先頭のS : スタートビット
D0-7 : データビット(7ビットの場合はD0-6までになります)
P : パリティビット
ST : ストップビット

今回はデータ長を8ビットに設定しているので1バイトのデータは11ビットで構成されることになります。

データ長を8ビットに設定しているのでパリティを含めると1バイトのデータは11ビットになりますが、今回はパリティなしなので10ビットです。

タイムアウトの場合に送るデータは15バイトです。
通信速度の単位は bps で、ビットパーセカンドの略です。これは1秒間に送るビット数を表しています。
ですから1ビットあたりの時間は逆数をとればよいので 1/115200 [sec]となります。

15バイトのデータを送る通信時間は(1/115200)×11×15=約1.4[msec] になります。

15バイトのデータを送る通信時間は(1/115200)×10×15=約1.3[msec] になります。

送信する際の HAL_UART_Transmit() のタイムアウト値 10 は 1.3msec に比べて充分大きいので、そこそこ妥当な値でしょう。
通信時間よりタイムアウト値が小さいと全てのデータを送れないことになるので HAL_UART_Transmit() を使う場合には通信時間を見積もっておくと良いでしょう。

プログラムを動かしてみる

それでは Run – Resume してプログラムを動かしてみましょう。

概要で説明したとおりに動けば成功です。

マニュアルによると HAL_UART_Transmit(), HAL_UART_Receive() は Polling mode IO operation の項目に書かれています。
ポーリングモードで使う関数ということですね。
ポーリングは受信したかどうか時々見に行く方法で割り込みを使いません。
注意点は処理を完了しないと関数から戻ってこないことです。
このように処理が完了しないと戻ってこないモードをブロッキングモードと言います。

次回は割り込みを使ったノンブロッキングモードでシリアル通信してみます。

この続きを読むには こちら からどうぞ。

HALカテゴリの最新記事