こんにちは!東京理科大学Miceです。今回はロボスイープ競技に向けた実験ということで、RaspberryPi ZeroからSTM32のマイコンを操作してみました!
概要
- RaspberryPi ZeroとSTM32F446間でUART通信(前回記事)の続き
- 専用のコマンドを作成
- コマンドごとに動作をするようプログラムを組んだ!
前回の記事
使用器具
- PC(Windows11)
- 各種ソフト(STM Cube IDE, Teraterm等)
- STM32 Nucleo-F446RE(Nucleo)
- Raspberry Pi Zero 2 W)(Raspberry Pi OS,ラズベリーパイ Zero)
- ブレッドボード,ジャンプワイヤ
実験系

ブレッドボード経由でラズベリーパイ ZeroとNucleoを接続しています。また、Nucleoには追加でLEDを3つ接続しています。
コマンドの構造
コマンドは、「オペレーター」と「オペランド」の組み合わせで実装されます。オペレーターはコマンドの種類を決めるもので、3文字です。例)LED, MTR, MAP
オペランドは残りの部分です。LEDならどのLEDかや光らせ方を記述します。
例)LED1H … LED1番をHIGHにする
コマンドの最後は改行(\n)で締めます。
今後しばらくはこのフォーマットで開発していきます!
ラズベリーパイ Zeroからコマンドを送信する
import serial
import time
serial = serial.Serial('/dev/serial0', 115200, timeout=3)
while True:
msg = "LED1H\r\n"
serial.write(msg.encode())
time.sleep(0.5)
msg = "LED2H\r\n"
serial.write(msg.encode())
time.sleep(0.5)
msg = "LED3H\r\n"
serial.write(msg.encode())
time.sleep(0.5)
print("LED ON")
time.sleep(1)
msg = "LED1L\n\r"
serial.write(msg.encode())
time.sleep(0.5)
msg = "LED2L\r\n"
serial.write(msg.encode())
time.sleep(0.5)
msg = "LED3L\r\n"
serial.write(msg.encode())
time.sleep(0.5)
print("LED OFF")
time.sleep(1)
定期的にコマンドを送るだけです。
Nucleoで受信コマンドを処理する
USART受信割り込みで処理する
NucleoにはUSART信号を受信した際に割り込む設定ができるので、そこで使用するハンドラーを以下のように作成しました。ハンドラーはstm32f4xx_it.cで適用します。
// AL_communicateRaspberryPi.c
void RaspberryPi_UART_Handler()
{
// 改行が来たらメッセージを処理
if (rx_data == '\n')
{
SEGGER_RTT_Write(0, rx_buffer, rx_index + 1);
CommandProcessor((chat*) rx_buffer, rx_index + 1));
rx_index = 0;
}
else
{
// バッファに格納
rx_buffer[rx_index] = rx_data;
rx_index += 1;
}
// 次の1文字を受信開始
HAL_UART_Receive_IT(&huart1, &rx_data, 1);
SEGGER_RTT_Write(0, &rx_data, 1);
}
改行が来たら処理が走るようにしています。SEGGER_RTT_Write関数は便利なprintfみたいなものです。MiceではST-LINKをJ-LINK化して使っていることもあり、せっかくなので使ってみました。特に意味はないです。
// stm32f4xx_it.c
void USART1_IRQHandler(void)
{
/* USER CODE BEGIN USART1_IRQn 0 */
/* USER CODE END USART1_IRQn 0 */
HAL_UART_IRQHandler(&huart1);
/* USER CODE BEGIN USART1_IRQn 1 */
RaspberryPi_UART_Handler();
/* USER CODE END USART1_IRQn 1 */
}
受信したコマンドは以下のプログラムで分類します。
void CommandProcessor(char *command, int len) {
// オペレータ(コマンド識別子) 3文字
uint32_t operator_code = (command[0] << 16) | (command[1] << 8)
| command[2];
switch (operator_code) {
case ('L' << 16) | ('E' << 8) | 'D':
Command_LED_Handler(command, len);
break;
}
}
‘L’ << 16) | (‘E’ << 8) | ‘D’の部分は後々管理が面倒になりそうなので、今後別の書き方を考えるか、関数化したいと思っています。LEDコマンド個別の処理は以下のようにしています。
void Command_LED_Handler(char *command, int len) {
int out_state = 0;
if (command[4] == 'H') {
out_state = GPIO_PIN_SET;
} else if (command[4] == 'L') {
out_state = GPIO_PIN_RESET;
}
switch (command[3])
{
case '1':
HAL_GPIO_WritePin(LED1_GPIO_Port, LED1_Pin, out_state);
break;
case '2':
HAL_GPIO_WritePin(LED2_GPIO_Port, LED2_Pin, out_state);
break;
case '3':
HAL_GPIO_WritePin(LED3_GPIO_Port, LED3_Pin, out_state);
break;
}
}
コマンドを見て、どのLEDか、HIGH・LOWのどちらに設定するかを決めているだけです。
実行結果
編集中!
3つのLEDが順番に点灯し、その後順番に消灯することが確認できると思います。大成功ですね!
次の予定
とりあえず操作に成功しました!次回はモーターの制御をやりたいと思っています。また、今のままだと整備性が悪いので、関数や列挙子などを活用できないか模索する予定です!


コメント