STM32F446RE 複数マイコン連携技術資料 - CAN通信によるセンサ・モータ制御
STM32F446REマイコンを用いて、CAN通信で複数マイコンを連携させる実装方法を解説する。
目標
- STM32F446REを使って CAN2通信(B13, B12) を設定する
- マイコン1:リミットスイッチの状態を定期的に送信する
- マイコン2:受信した情報に応じてモータ制御・エンコーダPID制御を行う
必要なもの
種類 | 内容 |
---|---|
MCU | STM32F446RE(NUCLEO-F446RE) × 2台 |
ライブラリ | sken_library (CAN Legacy対応版) |
接続 | CAN通信線(TX: B13, RX: B12) |
その他 | リミットスイッチ、モータ、モータドライバ、エンコーダなど |
STEP 1: 開発環境セットアップ
HALとプロジェクト設定
- SW4STM32でC++プロジェクトを作成
- ボードは
NUCLEO-F446RE
を選択 HAL_CAN_MODULE_ENABLED
を無効化し、HAL_CAN_LEGACY_MODULE_ENABLED
を有効化
sken_library導入
#include "sken_library/include.h"
sken_system.init();
をmain()
冒頭に記述
(詳しくはこちら参照)
STEP 2: 配線図
[マイコン1] ----------- CAN2 (B13, B12) ----------- [マイコン2]
| A6,A7,A8 : リミットスイッチ入力 | A0,A1 : エンコーダ入力
| C11 : スイッチ入力 | B14,B15 : MD1(PWM)
| A8,A11 : MD2(PID制御)
STEP 3: マイコン1 - スイッチ送信処理
概要
- 3つのリミットスイッチと1つのユーザースイッチ状態を読み取り、CANで送信
コード
#include "stm32f4xx.h"
#include "sken_library/include.h"
Gpio limit1, limit2, limit3, button;
uint8_t can_data[4];
int main() {
sken_system.init();
limit1.init(A6, INPUT_PULLUP);
limit2.init(A7, INPUT_PULLUP);
limit3.init(A8, INPUT_PULLUP);
button.init(C11, INPUT_PULLUP);
sken_system.startCanCommunicate(B13, B12, CAN_2);
while (1) {
can_data[0] = limit1.read();
can_data[1] = limit2.read();
can_data[2] = limit3.read();
can_data[3] = button.read();
sken_system.canTrancemit(CAN_2, 0x101, can_data, 4);
sken_system.delayMillis(10);
}
}
解説
INPUT_PULLUP
:スイッチ未押下でHIGHになるようにするcanTrancemit
:最大8バイト送信可能(ここでは4バイト使用)
STEP 4: マイコン2 - モータとPID制御
制御仕様
- C11スイッチが偶数回押されたら制御が有効に
- A6:ONになるまでMD1順転
- A7:ONになるまでMD1逆転
- A8スイッチがON:エンコーダを使いMD2を90度へPID制御(OFF時は0度)
コード
#include "stm32f4xx.h"
#include "sken_library/include.h"
Motor md1, md2;
Encoder enc;
Encoder_data e_data;
Pid pid;
Can_data can_rx;
int c11_count = 0;
bool last_c11 = 1;
double target_angle = 0;
double output = 0;
void control_loop() {
enc.interrupt(&e_data);
output = pid.control(target_angle, e_data.deg, 1);
}
int main() {
sken_system.init();
enc.init(A0, A1, TIMER5);
md1.init(Apin, B14, TIMER12, CH1);
md1.init(Bpin, B15, TIMER12, CH2);
md2.init(Apin, A8, TIMER1, CH1);
md2.init(Bpin, A11, TIMER1, CH4);
pid.setGain(1.0, 0.0, 0.1, 10);
sken_system.addTimerInterruptFunc(control_loop, 0, 1);
sken_system.startCanCommunicate(B13, B12, CAN_2);
sken_system.addCanRceiveInterruptFunc(CAN_2, &can_rx);
while (1) {
if (can_rx.rx_stdid == 0x101) {
bool a6 = can_rx.rx_data[0] == 0;
bool a7 = can_rx.rx_data[1] == 0;
bool a8 = can_rx.rx_data[2] == 0;
bool c11 = can_rx.rx_data[3] == 0;
if (last_c11 == 1 && c11 == 0) c11_count++;
last_c11 = c11;
if (c11_count % 2 == 0) {
if (!a6) md1.write(50);
else if (!a7) md1.write(-50);
else md1.stop();
} else {
md1.stop();
}
target_angle = a8 ? 90.0 : 0.0;
md2.write(output);
}
}
}
トラブル対処
CAN通信が動かない
HAL_CAN_LEGACY_MODULE_ENABLED
を有効にしているか?- 配線(B13, B12)が逆ではないか?
- ターミネータ抵抗(120Ω)が両端にあるか?
スイッチが効かない
INPUT_PULLUP
の設定漏れ- GNDとの接続確認
Note
著者:Shion Noguchi