こん○○は、よふかしわーくすの、よふかしさんです
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
コメント