STM32F4を弄る(4) PCとシリアル通信 送信編

STM32

こん○○は、よふかしわーくすの、よふかしさんです
4回目はBlack Pillと呼ばれるWeAct製かそれ系のSTM32F411を使って
Cube環境でPCとのシリアル通信 送信編をやってみます

特に今回はSTM32F411に搭載されているUSB機能と、
Black Pillに搭載されているUSB Type-Cポートを使用、それ以外のデバイスを使用しないで
VCP(Virtual COM Port)で通信してみたいと思います

今回使用している開発環境は、
CubeMX:Version 6.13.0
CubeIDE:Version 1.17.0
で解説していきます

CubeMXの設定

まずは、CubeMXでピン設定していきます
Categories→USB_OTG_FSを選択し、
ModeをDevice_Onlyに設定
PA11がUSB_OTG_FS_DPに、
PA12がUSB_OTG_FS_DMになっていればOKです

次に、Middoleware and Software Packs→USB_DEVICEを選択し、
Class For FS IPをCommunication Device Class (Virtual Port Com)に設定

ここで、Clock Configurationのタブに×マークがついているのがわかるかと思います
タブをクリックすると下記のポップアップが表示され、自動でクロックを修正するか聞かれるので、
Yesを選択します

そうすると、下記の様に自動修正されます

変更前は内蔵クロックを使用する設定でしたが、外部クロックを選択に変更されています
USBは通信速度が速く、高いクロック精度が求められるため、外部クロックを使用することが必要です
最も、VCPでゆっくりとしたボーレートで通信するのであれば、内蔵クロックでもイケちゃいますが、
Black Pillは外部クロックがついているので、どうせなら使っちゃいましょう
CubeMXでこの辺りのワーニングを通知してくれるのは親切ですね

Windows PCでシリアル通信するTera Termをインストール

PCでシリアル通信をするツールのうち、国産としてはメジャーなTera Termを入れていきます
2024/12現在、最新はVer5.3ですが、個人的にVer.5系は安定性に欠けるというか、
使いたい機能がうまく動作しなかったりなどあるので、
Ver.4系の最新版、Ver.4.108を入れていきます

公式ページにアクセス
https://teratermproject.github.io/

古いリリースはこちら、をクリック

少し下にスクロールしていくと、Tera Term 4.108が見つかります
Assetsの左の▶をクリックして開くと、下記の様になります
exeかzipの好きな方をDLしてインストールします

Tera Termを起動、シリアルのところで、任意のポートを選択します
STM32F411を先の通りVCP設定したものですと、USB シリアル デバイス、と表示されました

これで受信準備は終わりです
USB VCPの場合、シリアル通信のボーレート設定はしなくてOKです

CubeIDEでシリアル送信コードを書いていく

CubeMXでGENERATE CODEを実行、CubeIDEを立ち上げると、
USB_DEVICEフォルダ配下に、Appフォルダ→usbd_cdc_if.cがあり、
これを開くと、CDC_Transmit_FS関数が見つかります
これがUSB VCPでの送信関数になります

main.cで送信処理を実装します
前回の続きで実装する差分はこんな感じ

  /* USER CODE BEGIN 2 */

  char Tx_Buf[] = "Hello World\r\n";

  /* USER CODE END 2 */

  /* Infinite loop */
  /* USER CODE BEGIN WHILE */
  while (1)
  {
    /* USER CODE END WHILE */

    /* USER CODE BEGIN 3 */
	HAL_GPIO_TogglePin(LED_GPIO_Port, LED_Pin);

	CDC_Transmit_FS(Tx_Buf, strlen(Tx_Buf));

	HAL_Delay(500);
  }
  /* USER CODE END 3 */

解説

まずは、送信したいテキストを定義します

char Tx_Buf[] = "Hello World\r\n";

今回はWindows環境で通信するので、改行コードはCRLFとして\r\nを後尾に記述しています
配列サイズは明示的に定義せずに初期化して、コンパイラにサイズ定義をお任せしています
固定サイズ長でなければ、後々文字列を変更することを見越すと、この方が汎用性は高いです

固定サイズ長で定義したい場合に、

char Tx_Buf[13] = "Hello World\r\n";

としてしまうと、文字列後尾にヌル文字(\0)が追加されなくなってしまいます
文字列系の関数において、文字列の終わりはヌル文字で判定されるので基本的に必須です
(文字列長を固定してアクセスするとか、アドレス的に文字列後尾に0があるとかって場合もあるけど)
なので、

char Tx_Buf[14] = "Hello World\r\n";

または、より明示的に、

char Tx_Buf[14] = "Hello World\r\n\0";

とします
あとで文字列を変更したりという場合もあると思うので、
こういった運用では配列サイズを明示せずに、コンパイラに任せた方が便利です

送信関数は、

/**
  * @brief  CDC_Transmit_FS
  *         Data to send over USB IN endpoint are sent over CDC interface
  *         through this function.
  *         @note
  *
  *
  * @param  Buf: Buffer of data to be sent
  * @param  Len: Number of data to be sent (in bytes)
  * @retval USBD_OK if all operations are OK else USBD_FAIL or USBD_BUSY
  */
uint8_t CDC_Transmit_FS(uint8_t* Buf, uint16_t Len)

とある様に、第一引数に送信バッファのアドレスを、
第二引数に文字列の長さを与えてあげればよいです
ということで、下記のように記述

CDC_Transmit_FS(Tx_Buf, strlen(Tx_Buf));

第二引数はstrlen関数を使用して、文字列長が変わったときにも対応できるようにしています
今回はsizeof関数を使用しても同じ結果を得られますが、知りたいのは文字列長なので、strlenを使用

TeraTermでこんな感じになれば成功です

終わりに

ひとまず、Black Pill単体でできる、PCとのシリアル通信 送信編でした
次回は受信をやっていきたいと思います

公開日時:2024/12/22 14:26:09

コメント

タイトルとURLをコピーしました