こん○○は、よふかしわーくすの、よふかしさんです
5回目は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
で解説していきます
シリアル受信の動作確認方法の検討
LチカはLEDを見れば動作がわかりますし、
PCへのシリアル送信は、TeraTermの画面上に任意の文字列を表示させることで動作確認できました
マイコンでのシリアル受信の場合、受信したことを簡単に示すものが何もないので
(ArduinoだとRxのLEDが光ったりしますが、Black Pillにはない)
何らか目視でわかる動作をする様に設計していきたいと思います
といっても、まだまだBlack Pill単体で使っていきたいので、TeraTermとLEDだけで実現しよう、
ということで、今回は下記の仕様でやっていきたいと思います
- TeraTermからマイコンに文字列を送信する
- マイコンで受信した文字列が”LED ON\n”の場合、LEDを点灯する
- マイコンで受信した文字列が”LED OFF\n”の場合、LEDを消灯する
- 受信した文字列はPCにそのまま送信し返す
さらに前回からの続きとしては、
- 0.5s間隔のLチカはやめる
- 05s間隔のシリアル送信はやめる
とします
CubeIDEでシリアル受信コードを書いていく
まずは、前回までの処理をコメントアウトします
/* 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 */
今回は編集ファイルをミニマムにするために、usbd_cdc_if.cのみを編集していくことにします
まずは、受信バッファのサイズをdefine定義
/* USER CODE BEGIN PRIVATE_DEFINES */
#define RX_BUFFER_SIZE (64)
/* USER CODE END PRIVATE_DEFINES */
仕様に基づくオリジナルコードを追加
/* USER CODE BEGIN PRIVATE_FUNCTIONS_DECLARATION */
static void RxCommand(uint8_t* Buf, uint32_t *Len);
static void ProcessCommand(uint8_t *command);
/* USER CODE END PRIVATE_FUNCTIONS_DECLARATION */
static void RxCommand(uint8_t* Buf, uint32_t *Len)
{
uint8_t received_char;
static uint8_t USB_CommandBuffer[RX_BUFFER_SIZE + 1]; // 受信コマンドバッファ + ヌル文字
static uint32_t USB_CommandLength = 0; // 現在のコマンド長
for (uint32_t i = 0; i < *Len; i++)
{
received_char = Buf[i];
// 改行コード(\n または \r)でコマンドを判定
if (received_char == '\n' || received_char == '\r')
{
// 受信データをコマンドとして処理
USB_CommandBuffer[USB_CommandLength] = '\0'; // ヌル文字追加
ProcessCommand(USB_CommandBuffer);
// コマンドバッファをリセット
USB_CommandLength = 0;
}
else
{
// バッファにデータを追加(オーバーフロー防止)
if (USB_CommandLength < RX_BUFFER_SIZE)
{
USB_CommandBuffer[USB_CommandLength++] = received_char;
}
}
}
CDC_Transmit_FS(Buf, *Len); // 受信データをそのままPCに返す
}
static void ProcessCommand(uint8_t *command)
{
if (strcmp((char *)command, "LED ON") == 0)
{
HAL_GPIO_WritePin(LED_GPIO_Port, LED_Pin, GPIO_PIN_RESET); // LED ON
}
else if (strcmp((char *)command, "LED OFF") == 0)
{
HAL_GPIO_WritePin(LED_GPIO_Port, LED_Pin, GPIO_PIN_SET); // LED OFF
}
else
{
// 何もしない
}
}
USB VCPの受信関数にオリジナル関数のコールを追加
static int8_t CDC_Receive_FS(uint8_t* Buf, uint32_t *Len)
{
/* USER CODE BEGIN 6 */
RxCommand(Buf, Len); // 追加
USBD_CDC_SetRxBuffer(&hUsbDeviceFS, &Buf[0]);
USBD_CDC_ReceivePacket(&hUsbDeviceFS);
return (USBD_OK);
/* USER CODE END 6 */
}
解説
USB VCPは最大のバッファが64Byteなので、それに従ってバッファサイズは64Byteにしています
RxCommand関数では基本的に、
USB VCPで受信したデータを1ByteずつUSB_CommandBufferに溜めていくのと同時に、
CDC_Transmit_FS関数を使用して受信データをそのままPCに返していきます
改行コードを受信したらUSB_CommandBufferには改行コードを入れずにヌル文字を入れます
ProcessCommand関数では受信文字列に応じて、LEDをON/OFFします
ここでは、strcmp関数を使って文字列を判定しているので、先の通りヌル文字を追加しています
TeraTermの設定→端末を開いて、改行コードの受信、送信ともにLFに変更しておきます
(CRだと行頭に戻ってしまうので、表示上も改行させるためにLFにする)
TeraTermに”LED OFF”+Enterキー、”LED ON\n”+Enterキーを入力して、LEDがOFF/ONすること、
TeraTermで入力した文字が、そのままTeraTermに表示されれば成功です
終わりに
ひとまず、Black Pill単体でできる、PCとのシリアル通信 受信編でした
次回は実装系ではなく、Config等のTipsを書いておきたいと思います
公開日時:2024/12/23 0:30:28
コメント