Goertek_Mito_Lab / Mbed 2 deprecated ServoTensionerV3

Dependencies:   mbed

Revision:
0:cd74549e4be2
Child:
1:b0b5e0e70af8
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/main.cpp	Sun May 10 18:10:57 2020 +0000
@@ -0,0 +1,543 @@
+/*
+基板:4/3モデル,SB16とSB18はカット
+
+参考文献
+HX711ロードセルのライブラリ,Read meにインポート方法記載あり
+https://github.com/atoy40/mbed-hx711
+7セグのアルゴリズム,正負などを変更
+https://forum.arduino.cc/index.php?topic=351609.0
+https://zhuanlan.zhihu.com/p/73846629
+EEPROMのプログラム
+https://os.mbed.com/users/bborredon/code/eeprom/docs/925096a4c7f0/classEEPROM.html
+
+変更箇所
+ステップ増加とリニア増加の両方をサポート
+*/
+
+// ライブラリ
+#include "mbed.h"
+#include "HX711.h"
+
+// EEPROMのアドレス定義
+#define min_address 0
+#define stp_address 20
+#define t1_address 40
+#define t2_address 60
+#define f1_address 80
+#define f2_address 100
+
+// ピンの初期設定
+Serial pc(USBTX,USBRX);             // シリアル通信
+HX711 loadcell(D7, D8, 128);        // ロードセル(Data, Sck)
+I2C eeprom(D4, D5);                 // EEPROM(sda, scl)
+DigitalOut datapin(D2);             // 7セグのDIO
+DigitalOut latchpin(D3);            // 7セグのRCLK
+DigitalOut clockpin(D0);            // 7セグのSCLK
+DigitalOut FET(D1);                 // モーター電源のFET駆動信号
+DigitalIn sw1(D9);                  // スイッチ入力1
+DigitalIn sw2(D10);                 // スイッチ入力2
+DigitalOut Rled(D11);               // 赤LED
+DigitalOut Gled(D12);               // 緑LED
+AnalogOut aout3(A3);                // アナログ出力
+AnalogIn analog_value5(A5);         // オペアンプ非反転入力(+)読み込み
+AnalogIn analog_value6(A6);         // オペアンプ反転入力(-)読み込み
+
+// タイマー割り込み
+Ticker LED_IRQ;                     // LEDの割り込み(1kHz)
+Ticker DAC_IRQ;                     // DACの割り込み(100Hz)
+
+// グローバル変数
+unsigned int LedNum = 0;            // LEDの桁の切り替え用変数
+int Data = 0;                       // LPF後のロードセルデータ
+bool ReadSign1 = 0;                 // 圧力計の代入完了サイン
+bool ReadSign2 = 0;                 // LEDディスプレイの出力完了サイン
+double Tcnt = 0;                    // DAC用の時間カウント変数
+double a = 0;                       // DAC用の傾き変数(1/Ts)
+double t = 0;                       // 処理用の立上り時間(Time_start)
+double t1;                          // sw1の立上り時間(Time_start)
+double t2;                          // sw2の立上り時間(Time_start)
+double f1;                          // 張力の減少量
+double f2;                          // 張力の減少量
+double stp;                         // ステップ分解数
+double gain = 0;                    // 張力の減少量を操作するゲイン
+double Voltage = 0;                 // DAC用の電圧[V]
+double ZeroVoltage = 0.0;           // リセット後の初期位置の電圧
+double BiasVoltage = 0.25;          // 線形範囲に収めるためのバイアス電圧
+double TargetVoltage = 0.0;         // ポテンショメーター上の目標電圧値
+double CommandVoltage = 0.0;        // 目標電圧を出力するためのA3の指令電圧
+bool Scnt = 0;                      // DAC用のスイッチカウント変数
+bool rewrite = 0;                   // EEPROMの上書きフラグ
+char data[100];                     // コマンド入力のバッファ
+
+// 関数のプロトタイプ宣言
+void seg(int num, int d);                       // 1桁の出力
+void LED4_Display();                            // 4桁の出力
+void DAC_switch();                              // DACの切り替え
+void DAC_linear();                              // DACのリニア出力
+void DAC_step();                                // DACのステップ出力
+void pc_rx();                                   // シリアルでのグローバル変数書き換え
+void eeprom_update();                           // シリアル入力を判定し,EEPROMのメモリを書き換え
+char RomRead(int address);                      // EEPROMの単文字読み取り関数
+float RomRead_address(int address);             // EEPROMのデータ読み取り関数
+void RomWrite(int address, char c);             // EEPROMの単文字書き込み関数
+void RomWrite_address(int address, char c[]);   // EEPROMのデータ読み込む関数
+float cmd2num(char c[]);                        // コマンドと数値の変換
+
+// 7セグの対応表
+const int state[15][8]= {
+    {1, 1, 0, 0, 0, 0, 0, 0}, // 0
+    {1, 1, 1, 1, 1, 0, 0, 1}, // 1
+    {1, 0, 1, 0, 0, 1, 0, 0}, // 2
+    {1, 0, 1, 1, 0, 0, 0, 0}, // 3
+    {1, 0, 0, 1, 1, 0, 0, 1}, // 4
+    {1, 0, 0, 1, 0, 0, 1, 0}, // 5
+    {1, 0, 0, 0, 0, 0, 1, 0}, // 6
+    {1, 1, 1, 1, 1, 0, 0, 0}, // 7
+    {1, 0, 0, 0, 0, 0, 0, 0}, // 8
+    {1, 0, 0, 1, 0, 0, 0, 0}, // 9
+    {1, 1, 1, 1, 1, 1, 1, 1}, // NA
+    {0, 0, 0, 0, 0, 0, 0, 1}, // 1桁
+    {0, 0, 0, 0, 0, 0, 1, 0}, // 2桁
+    {0, 0, 0, 0, 0, 1, 0, 0}, // 3桁
+    {0, 0, 0, 0, 1, 0, 0, 0}, // 4桁
+};
+
+int main()
+{
+    sw1.mode(PullUp);                           // スイッチのプルアップ
+    sw2.mode(PullUp);                           // スイッチのプルアップ
+
+    // 起動後の処理
+    Rled = 0;                                   // 動作チェック用の赤LED点灯
+    Gled = 1;                                   // 動作チェック用の緑LED点灯,外部電源駆動の場合シリアル割り込み内のgetcで処理が止まる?
+    wait(0.8);                                  // モーター電源オンの待ち時間
+    FET = 1;                                    // モーター電源オン,EEPROM書き込み時はオフ
+
+    // 割り込みの定義
+    pc.attach(pc_rx,Serial::RxIrq);             // シリアルデータ受信時の割り込み
+    LED_IRQ.attach(&LED4_Display, 1e-3);        // 5msecごとに桁を更新
+    DAC_IRQ.attach(&DAC_switch, 1e-2);           // 10msecごとにDACを変動
+
+    // メイン処理内の変数
+    float lpf = 0.8;                            // 値が大きいほどに平滑化
+    double raw_data = 0.0;                      // LPF用の一時変数
+    double lpf_data = 0.0;                      // LPF用の一時変数
+    double pre_data = 0.0;                      // LPF用の一時変数
+
+    // EEPROMの読み込み
+    ZeroVoltage = RomRead_address(min_address);
+    stp = RomRead_address(stp_address);             // stpの代入
+    t1 = RomRead_address(t1_address);               // t1の代入
+    t2 = RomRead_address(t2_address);               // t2の代入
+    f1 = RomRead_address(f1_address);               // f1の代入
+    f2 = RomRead_address(f2_address);               // f2の代入
+
+    int offset = loadcell.read();               // ロードセルの初期値取得
+
+    while (true) {
+        Rled = 1;                                   //動作チェック用の赤LED点灯
+        Gled = 0;                                   //動作チェック用の緑LED点灯
+
+        if(rewrite == 1) {
+            eeprom_update();
+            rewrite = 0;
+        }
+        else {
+            if( ReadSign2 == 0 ) {                  // LEDの出力処理後に実行(LEDの出力処理中(データ送信中)に実行されない)
+                raw_data = (float)(loadcell.read()-offset)*0.003525f;      // 実測で調節した方が良さそう?(4.2987/16777216.0/128)/(0.001*8.9/2000.0)
+                lpf_data = (1.0f - lpf)*raw_data + lpf*pre_data;
+                pre_data = lpf_data;
+                ReadSign1 = 1;                      // 読み込む直前で圧力計変数をtrue(読み込み前)にする(データ代入中の値を出力しない)
+                Data = (int)lpf_data;
+            }
+            ReadSign1 = 0;                          // 読み込み完了で圧力計変数をfalse(読み込み後)にする
+
+            //Arduino Serial plotterでのLPFの比較用
+            //pc.printf("%f", raw_data);
+            //pc.printf(",");
+            //pc.printf("%f\n", lpf_data);
+        }
+    }
+}
+
+// 1桁出力関数
+void seg(int num, int d)
+{
+    // 数値データの送信
+    for(int i=0; i<=7; i++) {
+        datapin=state[num][i];
+        clockpin=1;
+        clockpin=0;
+    }
+
+    // 桁データの送信
+    for(int i=0; i<=7; i++) {
+        datapin=state[d+10][i];
+        clockpin=1;
+        clockpin=0;
+    }
+    latchpin=0;
+    latchpin=1;
+}
+
+// 4桁出力関数
+void LED4_Display()
+{
+    if(ReadSign1 == 0) {            // 圧力計の読み込み処理後に実行(圧力計の読み込み処理中に実行されない)
+        ReadSign2 = 1;              // 出力直前でLED計変数をtrue(読み込み前)にする
+        if( Data < 0) {             // 0以下の場合に値を0にする
+            Data = 0;
+        }
+
+        LedNum++;                   // 桁変え
+        if(LedNum>4) {
+            LedNum=1;
+        }
+        switch(LedNum) {            // 桁ごとに出力
+            case 1:
+                seg((int)Data%10/1,1);
+                break;
+            case 2:
+                if(Data < 10) {
+                    seg(10,2);
+                } else {
+                    seg((int)Data%100/10,2);
+                }
+                break;
+            case 3:
+                if(Data < 100) {
+                    seg(10,3);
+                } else {
+                    seg((int)Data%1000/100,3);
+                }
+                break;
+            case 4:
+                if(Data < 1000) {
+                    seg(10,4);
+                } else {
+                    seg((int)Data%10000/1000,4);
+                }
+                break;
+        }
+
+        // 出力完了でLED変数をfalse(読み込み後)にする
+        ReadSign2 = 0;
+    }
+}
+
+// DACの切り替え
+void DAC_switch()
+{
+    if(stp=='1') {
+        DAC_linear();
+    } else {
+        DAC_step();
+    }
+}
+
+void DAC_linear()
+{
+    if(sw1==false) {
+        t = t1;                     // sw1の変動時間
+        gain = f1;                  // sw1の変動割合
+    }
+    if(sw2==false) {
+        t = t2;                     // sw2の変動時間
+        gain = f2;                  // sw2の変動割合
+    }
+    // SWの動作
+    if((sw1==false||sw2==false) && Tcnt<t*1e2 ) {
+        // 立ち上がり状態,ボタンは押されている,他の状態でない
+        Tcnt += 1;
+        a = +1/t;
+    } else if(sw1==false||sw2==false) {
+        // 継続状態,ボタンは押されている
+        Tcnt += 1;
+        a = 0;
+    } else {
+        Voltage = 0;
+        Tcnt = 0;
+        a = 0;
+    }
+    // 電圧範囲の設定
+    TargetVoltage = gain*(ZeroVoltage-1.692) + 1.692;         // 50%の電圧
+    CommandVoltage = 1.539*TargetVoltage - 2.360 - BiasVoltage;
+    Voltage = Voltage + CommandVoltage*a*1e-2;
+    aout3.write((Voltage+BiasVoltage)/3.3);
+}
+
+void DAC_step()
+{
+    // SWの動作
+    if(sw2==false) {
+        Voltage = 0;
+        Tcnt = 0;
+        a = 0;
+        Scnt = false;
+    } else if(Scnt == false && sw1==false && Tcnt<stp ) {
+        // 立ち上がり状態,ボタンは押されている,他の状態でない
+        Tcnt += 1;
+        a = +1/stp;
+        Scnt = true;
+    } else {
+        // 継続状態,ボタンは押されている
+        a = 0;
+        if(sw1==false) {
+            Scnt = true;
+        } else {
+            Scnt = false;
+        }
+    }
+    // 電圧範囲の設定(範囲はgain:1.0で調節可能)
+    TargetVoltage = gain*(ZeroVoltage-1.692) + 1.692;                // 全範囲の電圧
+    CommandVoltage = (1.539*TargetVoltage - 2.360) - BiasVoltage;   // 最大値の電圧
+    Voltage = Voltage + CommandVoltage*a;
+    aout3.write((Voltage+BiasVoltage)/3.3);
+}
+
+// シリアルデータ受信時の処理,グローバル変数の書き換え
+void pc_rx ()
+{
+    // 文字列受信用の配列
+    int data_index = 0;
+    // 配列に受信したASCIIを代入
+    while(1) {
+        if (!pc.readable()) continue;
+        char c = pc.getc();
+        data[data_index] = c;
+        if (c == '\n') {
+            data[data_index+1] = '\0';
+            pc.printf(">");
+            pc.puts(data);                  //エコーしないと割り込みが終了しない?
+            break;
+        }
+        data_index++;
+    }
+    rewrite = 1;
+}
+
+void eeprom_update()
+{
+
+    // minの変更
+    if (data[0]=='z' && data[1]=='e' && data[2]=='r' && data[3]=='o') {
+        pc.puts("Calibration done\n");
+        int AnalogVal = 100*3.3*analog_value6.read();
+        ZeroVoltage = AnalogVal/100.0;
+        int Num1 = AnalogVal/100;
+        int Num2 = (AnalogVal%100)/10;
+        int Num3 = (AnalogVal%10)/1;
+        // EEPROMへの書き込み
+        RomWrite(min_address+0, 'z');
+        RomWrite(min_address+1, 'e');
+        RomWrite(min_address+2, 'r');
+        RomWrite(min_address+3, 'o');
+        RomWrite(min_address+4, '=');
+        RomWrite(min_address+5, (char)Num1+'0');
+        RomWrite(min_address+6, '.');
+        RomWrite(min_address+7, (char)Num2+'0');
+        RomWrite(min_address+8, (char)Num3+'0');
+        RomWrite(min_address+9, '\n');
+        RomWrite(min_address+10, '\0');
+    }
+
+    // stpの変更
+    if (data[0]=='s' && data[1]=='t' && data[2]=='p' && data[3]=='=') {
+        float cmd = cmd2num(data);
+        if(cmd<=0) {
+            pc.puts("Error 0 < stp\n");
+        } else {
+            RomWrite_address(stp_address, data);
+            pc.puts("change stp=");
+            pc.printf("%f\n",RomRead_address(stp_address));
+        }
+    }
+
+    // t1の変更
+    if (data[0]=='t' && data[1]=='1' && data[2]=='=') {
+        float cmd = cmd2num(data);
+        if(cmd<=0.01f) {
+            pc.puts("Error 0.01 <= t1\n");
+        } else {
+            RomWrite_address(t1_address, data);
+            pc.puts("change t1=");
+            pc.printf("%f\n",RomRead_address(t1_address));
+        }
+    }
+
+    // t2の変更
+    if (data[0]=='t' && data[1]=='2' && data[2]=='=') {
+        float cmd = cmd2num(data);
+        if(cmd<=0.01f) {
+            pc.puts("Error 0.01 <= t2\n");
+        } else {
+            RomWrite_address(t2_address, data);
+            pc.puts("change t2=");
+            pc.printf("%f\n",RomRead_address(t2_address));
+        }
+    }
+
+    // f1の変更
+    if (data[0]=='f' && data[1]=='1' && data[2]=='=') {
+        float cmd = cmd2num(data);
+        if(cmd<=0.01f || cmd>=0.99f) {
+            pc.puts("Error 0.01 <= f1 <= 0.99\n");
+        } else {
+            RomWrite_address(f1_address, data);
+            pc.puts("change f1=");
+            pc.printf("%f\n",RomRead_address(f1_address));
+        }
+    }
+
+    // f2の変更
+    if (data[0]=='f' && data[1]=='2' && data[2]=='=') {
+        float cmd = cmd2num(data);
+        if(cmd<=0.01f || cmd>=0.99f) {
+            pc.puts("Error 0.01 <= f2 <= 0.99\n");
+        } else {
+            RomWrite_address(f2_address, data);
+            pc.puts("change f2=");
+            pc.printf("%f\n",RomRead_address(f2_address));
+        }
+    }
+
+    // 変数の確認
+    if (data[0]=='p' && data[1]=='a' && data[2]=='r' && data[3]=='a' && data[4]=='m') {
+        pc.puts("zero=");
+        pc.printf("%.2lf \n",RomRead_address(min_address));
+        pc.puts("stp=");
+        pc.printf("%.2lf \n",RomRead_address(stp_address));
+        pc.puts("t1=");
+        pc.printf("%.2lf \n",RomRead_address(t1_address));
+        pc.puts("t2=");
+        pc.printf("%.2lf \n",RomRead_address(t2_address));
+        pc.puts("f1=");
+        pc.printf("%.2lf \n",RomRead_address(f1_address));
+        pc.puts("f2=");
+        pc.printf("%.2lf \n",RomRead_address(f2_address));
+    }
+}
+
+float cmd2num(char c[])
+{
+    char t_data[16];
+    int t_equal_index=0;
+    int t_point_index=0;
+    int t_end_index=0;
+
+    // データとインデックスの代入
+    for(int i=0; i<16; i++) {
+        t_data[i] = c[i];
+        if(t_data[i]=='=') {
+            t_equal_index=i;
+        }
+        if (t_data[i]=='.') {
+            t_point_index = i;
+        }
+        if((t_data[i]=='\r')||(t_data[i]=='\n')) {
+            t_end_index = i;
+            break;
+        }
+    }
+
+    // Asciiと数値の変換
+    double t_command_num = 0;
+    if(t_equal_index!=0) {
+        // 小数の有無で分岐
+        if(t_point_index==0) {
+            // 整数部の処理
+            for(int i=t_equal_index+1; i<t_end_index; i++) {
+                t_command_num += (t_data[i] - '0')*pow((double)10,(double)t_end_index-i-1);
+            }
+        } else {
+            // 整数部の処理
+            for(int i=t_equal_index+1; i<t_point_index; i++) {
+                t_command_num += (t_data[i] - '0')*pow((double)10,(double)t_point_index-i-1);
+            }
+            // 小数部の処理
+            for(int i=t_point_index+1; i<t_end_index; i++) {
+                t_command_num += (t_data[i] - '0')*pow((double)10,(double)t_point_index-i);
+            }
+        }
+    }
+    return t_command_num;
+}
+
+// 指定のアドレスにデータを書き込む
+void RomWrite_address(int address, char c[])
+{
+    for(int i=0; i<15; i++) {
+        RomWrite(i+address,c[i]);
+    }
+    RomWrite(15+address,'\0');
+}
+
+// 指定のアドレスからデータを読み込む
+float RomRead_address(int address)
+{
+    char r_data[16];
+    int r_equal_index=0;
+    int r_point_index=0;
+    int r_end_index=0;
+
+    // データとインデックスの代入
+    for(int i=0; i<16; i++) {
+        r_data[i] = RomRead(address+i);
+        if(r_data[i]=='=') {
+            r_equal_index=i;
+        }
+        if (r_data[i]=='.') {
+            r_point_index = i;
+        }
+        if((r_data[i]=='\r')||(r_data[i]=='\n')) {
+            r_end_index = i;
+            break;
+        }
+    }
+
+    // Asciiと数値の変換
+    double r_command_num = 0;
+    if(r_equal_index!=0) {
+        // 小数の有無で分岐
+        if(r_point_index==0) {
+            // 整数部の処理
+            for(int i=r_equal_index+1; i<r_end_index; i++) {
+                r_command_num += (r_data[i] - '0')*pow((double)10,(double)r_end_index-i-1);
+            }
+        } else {
+            // 整数部の処理
+            for(int i=r_equal_index+1; i<r_point_index; i++) {
+                r_command_num += (r_data[i] - '0')*pow((double)10,(double)r_point_index-i-1);
+            }
+            // 小数部の処理
+            for(int i=r_point_index+1; i<r_end_index; i++) {
+                r_command_num += (r_data[i] - '0')*pow((float)10,(float)r_point_index-i);
+            }
+        }
+    }
+    return r_command_num;
+}
+
+// 指定のアドレスからchar型で一文字を返す
+char RomRead(int address)
+{
+    char data[3];
+    data[0] = 0;                   // MSB address
+    data[1] = address;                   // LSB address
+    eeprom.write(0xA0, data, 2);
+
+    char response[1];
+    eeprom.read(0xA0, response, 1);
+    return response[0];
+}
+
+// 指定のアドレスにint型で一文字書き込む
+void RomWrite(int address, char c)
+{
+    char data[3];
+    data[0] = 0;            // MSB address
+    data[1] = address;      // LSB address
+    data[2] = c;            // data
+    eeprom.write(0xA0, data, 3);
+    while(eeprom.write(0xA0, NULL, 0)); // wait to complete
+}
\ No newline at end of file