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
main.cpp
- Committer:
- tkry
- Date:
- 2020-05-10
- Revision:
- 1:b0b5e0e70af8
- Parent:
- 0:cd74549e4be2
File content as of revision 1:b0b5e0e70af8:
/*
基板: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); // スイッチのプルアップ
// 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の代入
// 起動後の処理
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用の一時変数
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;
}
}
// 電圧範囲の設定(範囲1.0で設定)
TargetVoltage = 1.0*(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);
stp=cmd;
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));
}
Voltage = 0;
Tcnt = 0;
a = 0;
}
// t1の変更
if (data[0]=='t' && data[1]=='1' && data[2]=='=') {
float cmd = cmd2num(data);
t1=cmd;
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);
t2=cmd;
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);
f1=cmd;
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);
f2=cmd;
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
}