DC モーターを可変速度制御してみた。
使うもの
- R5F10Y47ASP使用 RL78マイコンモジュール
- TB67H450モータドライバモジュール
- マイクロサーボ SG92R
- ロータリーエンコーダ(ノンクリックタイプ)
- ロータリーエンコーダ DIP 化基板
- DCモーター FA − 130RA − 2270L
- 金属板抵抗器 5W0.22 Ω
- 電池ボックス 単3 × 4本 リード線・フタ・スイッチ付
- コンデンサとか抵抗器とか単三電池とか
実験回路をブレッドボードに作る
前回までのソフトウェアを再利用するので、今回は実験回路を先に作る。
> AE-TB67H450 回路図
TB67H450FNG は、PWM チョッパ方式の DC ブラシモータドライバです。
TB67H450 データシート
実験回路図
FA-130RA は電圧範囲 1.5V ~ 3V だけど TB67H450 のモーター電源電圧下限が 4.5V なので電源は単 3 ニッケル水素充電池 4 本直列にする。
モーターの定格電圧より供給電圧が高いけど、モータードライバーの電流制限を 1A 位にしておけば(モーターストールしていなければ)大丈夫だろうと。

おもに モータのブラシで発生するノイズ で制御回路の動作不調を引き起こすので、 それを抑えるためにモーターの端子間とケース間はセラミックコンデンサーで高周波を短絡させておく。
VREF には電源電圧の半分を与えるので、TB67H450 データシートにある式で制限電流を計算すると
この程度ならモーター焼損しないだろうと。
実験回路
これは IN1,IN2 ともに H を入力してショートブレーキをかけている状態。

この状態で
- IN1 を H, IN2 を L の信号を入力するとモーターが正転
- IN1 を L, IN2 を H の信号を入力するとモーターが逆転
- IN1 を H, IN2 を H の信号を入力するとショートブレーキ
になることを確認しておく。
e2 studio で新規プロジェクトを作る。
新規 -> Renesas C/C++ Project -> Renesas RL78 から
Renesas CC-RL C/C++ Executable Project を選択して
ターゲット・デバイス: R5F10Y47 を選択して
Use 周辺コード作成にチェックを入れてプロジェクトを作る。
これはそのまま確定する。

クロックは基盤に 20MHz セラロックが載っているが、今回はオンチップオシレータ 20MHz を選択する。

周辺機能のシリアル・インターフェース IICA の転送モードはシングルマスタ

設定はそのままでいい

PWM のためにタイマーチャネル 0 を多重 PWM 出力(マスタ)、タイマーチャネル 1 を多重 PWM 出力(スレーブ)、タイマーチャネル 2 を多重 PWM 出力(スレーブ)にする。

チャネル 0 の周期は 1ms つまり PWM 周波数 1,000Hz

チャネル 1 とチャネル 2 のデューティは共に 0%

ロータリーエンコーダ読み取りとディレイのために 12 ビットインターバルタイマーを使用する。

ロータリーエンコーダを接続するポート P00, P01 を入力に設定して内蔵プルアップにチェックを入れる。

保存して「コードを生成する」をクリックする。
端子配置図を確認する。

- VSS(7 番ピン)を GND
- VDD(8 番ピン)を 5V
- TOOL0(2 番ピン)を書き込み器
- RESET#(3 番ピン)を書き込み器
- SCLA0(15 番ピン)を液晶モジュールの SCL
- SDAA0(16 番ピン)を液晶モジュールの SDA
- TO02(14 番ピン)を TB67H450 モータードライバーの IN2
- TO01(13 番ピン)を TB67H450 モータードライバーの IN1
- P00(9 番ピン)をロータリーエンコーダの B 相出力
- P01(10 番ピン)をロータリーエンコーダの A 相出力
に接続する。
(P00/P01 はマイコン内臓プルアップを SCL/SDA は液晶モジュールの変換基盤に載っているプルアップを利用した)

プロジェクト設定
プロジェクト設定は 前前前回と同じ。
GitHub リポジトリ
https://github.com/ak1211/R5F10Y47_dcmotor
コード
詳細はGitHub リポジトリ で確認してください。
/src/cg_src/r_cg_main.c
r_cg_main.c コードの一部を貼っておきます。
static void set_speed(int8_t speed) {
if (speed < -100 || 100 < speed) {
return;
}
// PWM出力の周期
uint32_t pwm_period = (TDR00H << 8 | TDR00L) + 1;
//
uint16_t forward = 0;
uint16_t backward = 0;
if (speed < 0) {
forward = 0;
backward = pwm_period * (uint32_t) (-speed) / 100;
} else if (speed > 0) {
forward = pwm_period * (uint32_t) speed / 100;
backward = 0;
}
TDR01H = (forward >> 8) & 0xFF;
TDR01L = forward & 0xFF;
TDR02H = (backward >> 8) & 0xFF;
TDR02L = backward & 0xFF;
}
void main(void)
{
R_MAIN_UserInit();
/* Start user code. Do not edit comment generated here */
// 100ms待つ
delay(100);
// LCDの初期化
AQM1602A_init();
// 1行目
AQM1602A_puts("RL78 DC motor");
//
gROTATION_COUNTER = 0;
while (1U) {
// 2行目
char message[17];
strcpy(&message[0], "ON duty = ");
to_string(&message[8], gROTATION_COUNTER);
strncat(message, " % ", 5);
//
AQM1602A_send_command(0x80 | 0x40); // アドレス設定
AQM1602A_puts(message);
//
set_speed(gROTATION_COUNTER);
//
delay(100);
}
/* End user code. Do not edit comment generated here */
}
static void R_MAIN_UserInit(void)
{
/* Start user code. Do not edit comment generated here */
R_IT_Start();
R_TAU0_Channel0_Start();
EI();
/* End user code. Do not edit comment generated here */
}
Renesas Flash Programmer で書き込む

実行
IN1/IN2(TB67H450)の入力
チャネル CH1(黄色): IN1 / CH2(緑色): IN2
マイナスのデューティは逆転と読み替えてください。
- オンデューティ 10%
- オンデューティ 25%
- オンデューティ 50%
- オンデューティ 75%
- オンデューティ 100%
- オンデューティ-10%
- オンデューティ-25%
- オンデューティ-50%
- オンデューティ-75%
- オンデューティ-100%
電流波形
PWM の OFF 期間中モーター電流を電源に回生しているので、トルクがよわよわ。
- CH1(黄色): IN1 の信号(IN2 は Low 固定)
- CH2(緑色): 回路図の抵抗 RS の電圧 ≒ モーターと電源間の電流
ON 時に上昇したモーター電流が OFF 時に逆向きの電流になって電源に回生されている。
SlowDecay 方式
トルクが弱いので /src/cg_src/r_cg_main.c を SlowDecay になるように変更する。
OFF 時にモーター端子間に電流を流すことで、モーター電流をできるだけ維持するように制御する方式。
具体的には IN1/IN2 のロジックを反転する。
static void set_speed_fast_decay(int8_t speed) {
if (speed < -100 || 100 < speed) {
return;
}
// PWM出力の周期
uint32_t pwm_period = (TDR00H << 8 | TDR00L) + 1;
if (speed > 0) {
//
// 正転
// IN1: PWM(Active High)
// IN2: Low
//
// タイマー出力論理(TO01/TO02共にアクティブハイ)
TOL0 &= (uint8_t)~0x06;
// TO01デューティ
uint32_t timer = pwm_period * (uint32_t)speed / 100;
TDR01H = (timer >> 8) & 0xFF;
TDR01L = timer & 0xFF;
// TO02デューティ
TDR02H = TDR02L = 0; // 出力Low固定
} else if (speed < 0) {
speed = -speed;
//
// 逆転
// IN1: Low
// IN2: PWM(Active High)
//
// タイマー出力論理(TO01/TO02共にアクティブハイ)
TOL0 &= (uint8_t)~0x06;
// TO01デューティ
TDR01H = TDR01L = 0; // 出力Low固定
// TO02デューティ
uint32_t timer = pwm_period * (uint32_t)speed / 100;
TDR02H = (timer >> 8) & 0xFF;
TDR02L = timer & 0xFF;
} else {
// タイマー出力論理(TO01/TO02共にアクティブハイ)
TOL0 &= (uint8_t)~0x06;
// TO01デューティ
TDR01H = TDR01L = 0;
// TO02デューティ
TDR02H = TDR02L = 0;
}
}
static void set_speed_slow_decay(int8_t speed) {
if (speed < -100 || 100 < speed) {
return;
}
// PWM出力の周期
uint32_t pwm_period = (TDR00H << 8 | TDR00L) + 1;
if (speed > 0) {
//
// 正転
// IN1: High
// IN2: PWM(Active Low)
//
// タイマー出力論理(TO01/TO02共にアクティブロー)
TOL0 |= (uint8_t)0x06;
// TO01デューティ
TDR01H = TDR01L = 0; // 出力High固定
// TO02デューティ
uint32_t timer = pwm_period * (uint32_t)speed / 100;
TDR02H = (timer >> 8) & 0xFF;
TDR02L = timer & 0xFF;
} else if (speed < 0) {
speed = -speed;
//
// 逆転
// IN1: PWM(Active Low)
// IN2: High
//
// タイマー出力論理(TO01/TO02共にアクティブロー)
TOL0 |= (uint8_t)0x06;
// TO01デューティ
uint32_t timer = pwm_period * (uint32_t)speed / 100;
TDR01H = (timer >> 8) & 0xFF;
TDR01L = timer & 0xFF;
// TO02デューティ
TDR02H = TDR02L = 0; // 出力High固定
} else {
// タイマー出力論理(TO01/TO02共にアクティブハイ)
TOL0 &= (uint8_t)~0x06;
// TO01デューティ
TDR01H = TDR01L = 0;
// TO02デューティ
TDR02H = TDR02L = 0;
}
}
void main(void)
{
R_MAIN_UserInit();
/* Start user code. Do not edit comment generated here */
// 100ms待つ
delay(100);
// LCDの初期化
AQM1602A_init();
//
gROTATION_COUNTER = 0;
while (1U) {
// 2行目
char message[17];
strcpy(&message[0], "ON duty = ");
to_string(&message[8], gROTATION_COUNTER);
strncat(message, " % ", 5);
//
AQM1602A_send_command(0x80 | 0x40); // アドレス設定
AQM1602A_puts(message);
// ポート2でfast decay / slow decay を切り替える
if(P0_bit.no2) {
set_speed_slow_decay(gROTATION_COUNTER);
// 1行目
AQM1602A_send_command(0x80); // アドレス設定
AQM1602A_puts("RL78 DC motor(S)");
} else {
set_speed_fast_decay(gROTATION_COUNTER);
// 1行目
AQM1602A_send_command(0x80); // アドレス設定
AQM1602A_puts("RL78 DC motor(F)");
}
//
delay(100);
}
/* End user code. Do not edit comment generated here */
}
実行
明らかにトルクが増えた。
IN1/IN2 の出力波形(Slow Decay)
チャネル CH1(黄色): IN1 / CH2(緑色): IN2
マイナスのデューティは逆転と読み替えてください。
- オンデューティ 10%
- オンデューティ 25%
- オンデューティ 50%
- オンデューティ 75%
- オンデューティ 100%
- オンデューティ-10%
- オンデューティ-25%
- オンデューティ-50%
- オンデューティ-75%
- オンデューティ-100%
電流波形(Slow Decay)
- CH1(黄色): IN2 の信号(IN1 は High 固定)
- CH2(緑色): 回路図の抵抗 RS の電圧 ≒ モーターと電源間の電流
OFF 期間中に抵抗 RS を通じて電源に流れる電流は無い。
ON 期間中に増加したモーター電流を OFF 期間中にモータ端子間に回生する制御によって、常にモーター電流が流れ続ける状態を作り、そのことでトルクが増えるということ。
コメント