Arduinoでステッピングモーターを指定周波数で制御するmemo

#概要
　１年半前くらいですが、ステッピングモーターを使ったマイクロポンプを扱うことがあり、流量制御するためにポンプ周波数を5Hzなどの低周波数で変更させる必要があったのでAVRのタイマを使ってPWMを作りモーター制御した時のメモになります。

#構成
モータードライバーは駆動電圧が2.7～6VなのでArduinoから電圧を取っても駆動でき使いやすいです。ただし2個以上使用する場合は別電源推奨。

マイコン：ArduinoUnoまたはArduinonano
モータードライバ：[TB6608FNG](http://akizukidenshi.com/catalog/g/gI-10636/)
ピッチ変換基板：[SSOP20ピン(0.65mm)/SOP20ピン(1.27mm)DIP変換基板](http://akizukidenshi.com/catalog/g/gP-10497/)
モーター：バイポーラ4線式
抵抗：470Ω×3個、2Ω×2個
コンデンサー：220pF×1個
←リンクは秋月電子です

[回路]
![図1.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/542127/e2864da6-72de-7ca9-8d41-a6be3d0329bd.png)


#スケッチ
AVRの8bitタイマ設定については後述の参考を見ていただくとよいかと思います。
モータードライバが正転逆転(CWCCW)やResetなどに対応しているのでそれぞれkeyを割り振り、シリアル入力したら変更されるようにしています。
任意周波数はz17xのように指定したい周波数をzとxの間に挟んでシリアル入力すると指定できます。
Node-REDのserialノードを使ってDashboardから打ち込むなど、応用が効きます。

```ruby:motordrive.ino
#include <avr/io.h>
#define PWMPin 10

int frq = 100; // 周波数
float duty = 0.5; // デューティ比

unsigned int xpin4 = 1;
unsigned int xpin5 = 1;
unsigned int xpin6 = 1;
unsigned int xpin7 = 1;

void setup() {
  pinMode(4, OUTPUT);
  pinMode(5, OUTPUT);
  pinMode(6, OUTPUT);
  pinMode(7, OUTPUT);
  pinMode(PWMPin, OUTPUT);
  Serial.begin(9600);

  digitalWrite(4, HIGH);
  digitalWrite(5, HIGH);
  digitalWrite(6, HIGH);
  digitalWrite(7, HIGH);
}

void loop() {
  int input1;
  input1 = Serial.read();

  TCCR1A = 0b00100001;  // モード指定
  TCCR1B = 0b00010010;

  if (input1 == 'q') {
    Serial.write("keyq  ");
    frq = 10;
    Serial.println(frq);
    Serial.write("\n");

    OCR1A = (unsigned int)(1000000 / frq);  // TOP値指定
    OCR1B = (unsigned int)(1000000 / frq * duty); // Duty比指定

  } else if (input1 == 'w') {
    Serial.write("keyw  ");
    frq = 100;
    //  if (frq < 10) frq = 10;
    Serial.println(frq);
    Serial.write("\n");

    OCR1A = (unsigned int)(1000000 / frq);  // TOP値指定
    OCR1B = (unsigned int)(1000000 / frq * duty); // Duty比指定

  } else if (input1 == 'e') {
    Serial.write("keye  ");
    frq = frq - 10;
    if (frq < 10) frq = 10;
    Serial.println(frq);
    Serial.write("\n");

    OCR1A = (unsigned int)(1000000 / frq);  // TOP値指定
    OCR1B = (unsigned int)(1000000 / frq * duty); // Duty比指定

  } else if (input1 == 'r') {
    Serial.write("keyr  ");
    frq = frq + 10;
    if (frq > 500) frq = 500;
    Serial.println(frq);
    Serial.write("\n");

    OCR1A = (unsigned int)(1000000 / frq);  // TOP値指定
    OCR1B = (unsigned int)(1000000 / frq * duty); // Duty比指定

  } else if (input1 == 't') {
    Serial.write("keyt  ");
    frq = frq + 100;
    if (frq > 500) frq = 500;
    Serial.println(frq);
    Serial.write("\n");

    OCR1A = (unsigned int)(1000000 / frq);  // TOP値指定
    OCR1B = (unsigned int)(1000000 / frq * duty); // Duty比指定

  } else if (input1 == 'y') {
    frq = 500;
    Serial.write("keyy  ");
    Serial.println(frq);
    Serial.write("\n");

    OCR1A = (unsigned int)(1000000 / frq);  // TOP値指定
    OCR1B = (unsigned int)(1000000 / frq * duty); // Duty比指定

  } else if (input1 == 'u') {
    if (xpin4 == 1) {                   //Speed×10
      digitalWrite(4, LOW);
      xpin4 = 0;
    } else {
      digitalWrite(4, HIGH);
      xpin4 = 1;
    }
  } else if (input1 == 'i') {
    if (xpin5 == 1) {                 //CWCCW切り替え
      digitalWrite(5, LOW);  
      xpin5 = 0;
    } else {
      digitalWrite(5, HIGH);  
      xpin5 = 1;
    }

  } else if (input1 == 'o') {
    if (xpin6 == 1) {                         //ONOFF
      digitalWrite(6, LOW);
      xpin6 = 0;
    } else {
      digitalWrite(6, HIGH);
      xpin6 = 1;
    }


  } else if (input1 == 'p') {
    if (xpin7 == 1) {                         //Reset
      digitalWrite(7, LOW);
      xpin7 = 0;
    } else {
      digitalWrite(7, HIGH);
      xpin7 = 1;
    }


  } else if (input1 == 'z') {
//    String str;
    if (Serial.available() > 1) {     //任意周波数
      String str = Serial.readStringUntil('x');
      Serial.println(str);
      Serial.write("keyz  ");
      frq = str.toInt();
      Serial.println(frq);
      Serial.write("\n");

    OCR1A = (unsigned int)(1000000 / frq);  // TOP値指定
    OCR1B = (unsigned int)(1000000 / frq * duty); // Duty比指定

    }
  } else {

    Serial.write(".\n");
  }
  delay(500);
}
```

#参考
デジモノ覚書
http://blog.kts.jp.net/arduino-pwm-change-freq/
うしこのblog
http://usicolog.nomaki.jp/engineering/avr/avrPWM.html