Important changes to repositories hosted on mbed.com
Mbed hosted mercurial repositories are deprecated and are due to be permanently deleted in July 2026.
To keep a copy of this software download the repository Zip archive or clone locally using Mercurial.
It is also possible to export all your personal repositories from the account settings page.
Dependencies: mbed
Diff: main.cpp
- 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