ベルトコンベアの自動制御

以下のような機構を作った。現時点はプロトタイプで、実際はM５Stack Basic等に変更予定。
![概念図.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/97061/a1aa01d4-c0ef-8bc1-a11c-d726414f0442.png)

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/97061/fd5064ef-2316-8348-6ee1-85f749176164.png)

#使用したもの
| 品名 | 備考 |URL|
|:-:|:-:|:-:|
| M5Stack　Fire  | GroveC端子はPS-RAMと排他的使用(コンパイラで無効にする必要あり）| | 
| リレー  || https://www.seeedstudio.com/Grove-Relay.html|
| ひずみゲージ  | 押す方向がマイナス |http://akizukidenshi.com/catalog/g/gP-12036/|
| ADコンバータ  | XH端子端子を付けています。<br/>ひずみゲージ側は7pのコネクタの不要な端子をラジオペンチで抜いたものを利用  |http://akizukidenshi.com/catalog/g/gK-12370/|
| Dual Button  |   |https://www.switch-science.com/catalog/4048/|

#参考にしたもの
[ProgramResource.net ESP8266/ESP32でEEPROMにデータを保存する（データチェック付き）](https://programresource.net/2020/02/21/2912.html)

ひずみゲージの部分は秋月電子のサンプルを改良して使っています。http://akizukidenshi.com/download/ds/akizuki/ae_hx711.zip
パルスの時間を1μsに、重量の読取りの回数
※データシートによるとパルスの時間のミニマム値はもっと小さいので、

#動作
1. M5Stackのボタンで、オフセット、設定重量を設定できます。
2. 青色のボタンを押すと、オフセット、設定重量が変更されている場合は疑似EEPSOM（Flashメモリ)に保存後リレーをオンにします。
3. ひずみゲージが設定重量を超えるとリレーがOFFになります。
4. 赤ボタンは緊急停止のリレーオフボタンです。

#スケッチ
**これではうまく動きませんでした**
重さが変わっていない時は表示の書き換えをしないとかしています。
随時表示する部分は、スプライト表示を利用
日本語表示の部分はStaticなのでXBitmapを利用しています。(ヘッダーファイルに画像を格納しています）

```
#include <M5Stack.h>
#include <EEPROM.h>

#include"Set_nega.h"
#include"Set_posi.h"
#include"Setting.h"
#include"Title.h"
#include"Zero.h"
#include"hizumi.h"

#define btnRed G26
#define btnBlue G36
#define Relay1 G16

float offset = 0;
float settei = 1;

TFT_eSprite spr = TFT_eSprite(&M5.Lcd);
TFT_eSprite sprSetting = TFT_eSprite(&M5.Lcd);
bool paraChange = false;
bool running = false;
Button BtnRed = Button(btnRed, true, 10);
Button BtnBlue = Button(btnBlue, true, 10);

#define DEFAULT_OFFSET 0.0
#define DEFAULT_SETTEI  20.0
#define DATA_VERSION    "DATA1.0"

struct DATA_SET {
  float offset;
  float settei;
  char check[10];
};
DATA_SET data;
void load_data() {
  EEPROM.get<DATA_SET>(0, data);
  if (strcmp(data.check, DATA_VERSION)) { //バージョンをチェック
    //保存データが無い場合デフォルトを設定
    data.offset = DEFAULT_OFFSET;
    data.settei = DEFAULT_SETTEI;
  }
  offset = data.offset;
  settei = data.settei;
}

//EEPROMへの保存
void save_data() {
  //EEPROMに設定を保存する。
  data.offset = offset;
  data.settei = settei;
  strcpy(data.check, DATA_VERSION);
  EEPROM.put<DATA_SET>(0, data);
  EEPROM.commit(); //大事
}

void setup() {
  // put your setup code here, to run once:
  M5.begin(true, false, false, false);
  //pinMode(btnRed, INPUT);
  //pinMode(btnBlue, INPUT);
  pinMode(Relay1, OUTPUT);
  digitalWrite(Relay1, LOW);
  EEPROM.begin(1024); //1kbサイズ
  load_data();
  spr.setColorDepth(8);
  spr.createSprite(320, 145);
  sprSetting.setColorDepth(8);
  sprSetting.createSprite(220, 50);
  M5.lcd.fillScreen(TFT_BLACK);
  AE_HX711_Init();
  AE_HX711_Reset();
  //  offset = AE_HX711_getGram(30);
  display0();
  display1();
}
void display0()
{
  M5.lcd.drawXBitmap(0, 0, Title_bits, Title_width, Title_height, TFT_WHITE);
  M5.lcd.drawXBitmap(40, 220, Zero_bits, Zero_width, Zero_height, TFT_WHITE);
  M5.lcd.drawXBitmap(130, 220, SetPosi_bits, SetPosi_width, SetPosi_height, TFT_WHITE);
  M5.lcd.drawXBitmap(220, 220, SetNega_bits, SetNega_width, SetNega_height, TFT_WHITE);
  M5.lcd.drawXBitmap(0, 165, Setting_bits, Setting_width, Setting_height, TFT_WHITE);
}
void display1()
{
  sprSetting.fillRect(0, 0, 220, 50, TFT_WHITE);
  sprSetting.setTextSize(0);
  sprSetting.setTextDatum(TR_DATUM);
  sprSetting.setTextColor( TFT_BLACK, TFT_WHITE);
  sprSetting.drawFloat(settei, 1, 150, 5, 6);
  sprSetting.setTextDatum(TL_DATUM);
  sprSetting.drawString("kg", 160, 20, 4);
  sprSetting.pushSprite(100, 165);
}
void display2_enable() {
  M5.lcd.drawXBitmap(40, 220, Zero_bits, Zero_width, Zero_height, TFT_WHITE);
  M5.lcd.drawXBitmap(130, 220, SetPosi_bits, SetPosi_width, SetPosi_height, TFT_WHITE);
  M5.lcd.drawXBitmap(220, 220, SetNega_bits, SetNega_width, SetNega_height, TFT_WHITE);
}
void display2_disable() {
  M5.lcd.drawXBitmap(40, 220, Zero_bits, Zero_width, Zero_height, TFT_DARKGREY);
  M5.lcd.drawXBitmap(130, 220, SetPosi_bits, SetPosi_width, SetPosi_height, TFT_DARKGREY);
  M5.lcd.drawXBitmap(220, 220, SetNega_bits, SetNega_width, SetNega_height, TFT_DARKGREY);
}

void move_start() {
  running = true;
  display2_disable();
  digitalWrite(Relay1, HIGH);
}
void move_stop() {
  running = false;
  digitalWrite(Relay1, LOW);
  display2_enable();
}
void loop() {
  // put your main code here, to run repeatedly:

  float data, omosa, omosa_old;
  char S1[20];
  char s[20];
  data = AE_HX711_getGram(2);
  omosa = -1 * (data - offset) / 1000;
  if (omosa != omosa_old) {
    omosa_old = omosa;
    //M5.lcd.fillRect(0, 20, 320, 145,TFT_BLACK);
    //M5.lcd.setTextSize(2);
    //M5.lcd.setTextDatum(TR_DATUM);
    //M5.lcd.setTextColor(TFT_WHITE,TFT_BLACK);
    //M5.lcd.drawFloat(omosa, 2, 320, 40, 7);

    spr.fillRect(0, 0, 320, 145, TFT_BLACK);
    spr.setTextSize(2);
    spr.setTextDatum(TR_DATUM);
    spr.setTextColor(TFT_WHITE, TFT_BLACK);
    spr.drawFloat(omosa, 2, 300, 20, 7);
    spr.pushSprite(0, 20);

  }

  if (running == true) {
    if (digitalRead(btnRed) == LOW) move_stop();
    if (omosa >= settei)      move_stop();
    BtnRed.read();
    if (BtnRed.isPressed()) {
      move_stop();
    }
  }
  else {
    M5.update();
    BtnBlue.read();

    if (M5.BtnA.pressedFor(200)) {
      paraChange = true;
      offset = AE_HX711_getGram(10);
    }
    else if (M5.BtnB.isPressed()) {
      paraChange = true;
      settei += 0.1;
      display1();
    }
    else if (M5.BtnC.isPressed()) {
      paraChange = true;
      settei -= 0.1;
      display1();
    }
    else if (BtnBlue.isPressed()) {
      if (paraChange) {
        save_data();
        paraChange = false;
      }
      move_start();
    }

  }
}
```

#改良の余地
緊急停止は割込みが使えたらもっと良い。
重さを量るのを別スレッドにするとか。。