20210420_monitor

Dependencies:   mbed SB1602E TextLCD MSCFILESytem FatFileSystemCpp

main.cpp

Committer:
yayoi24
Date:
2022-05-23
Revision:
4:b9669a9feabd
Parent:
3:d10c0110f1f0

File content as of revision 4:b9669a9feabd:


//20210722モニタリングシステム kikkawa //積算発電積算消費

#include "mbed.h"                       // 必須
#include "stdio.h"                      // ファイル操作
#include "SB1602E.h"                    // デカ文字LCD
#include "TextLCD.h"                    // 4*20LCD
#include "MSCFileSystem.h"              // USBメモリ
#include <string>                       // 文字列操作

/* タイマの設定 */
Timer tm1;                              // タイマー時間の初期化(処理時間計測に使用)   
Timer time0t5s;                         // main関数での処理に使用
Timer time0t2s;                         // main関数での処理に使用
               
//Ticker tick;                          // 繰り返しタイマ割り込みの初期化
TextLCD lcd1(p15,p16,p17,p18,p19,p20);  // 4行LCDのポート設定(RS,E,DB4,DB5,DB6,DB7)
SB1602E lcd2(p28,p27);                  // デカ文字LCDのポート設定(SDA,SCL)
Serial pc(USBTX,USBRX);                 // USBシリアルポートの設定
Serial im920(p13, p14);                 // p13(tx),p14(rx)をIM920とのシリアル通信ポートに設定
CAN can(p30, p29);                      // CANのポート設定

DigitalOut led1(LED1);                  // LPC1768ボード上1番目のLEDの設定
DigitalOut led2(LED2);                  // LPC1768ボード上2番目のLEDの設定
DigitalOut led3(LED3);                  // LPC1768ボード上3番目のLEDの設定
DigitalOut led4(LED4);                  // LPC1768ボード上4番目のLEDの設定

/* 変数の宣言 */
bool LED = 1;                           // 1のときLPC1768ボード上のLED(1~4)の点灯・点滅処理を実行. 0のとき点灯・点滅させない
int MPPTerror=0;                        // MPPT1のエラー信号を格納する変数
int MPPTerror_2=0;                      // MPPT2のエラー信号を格納する変数
int direc=0;                            // 進行方向(direction)を格納する変数
float Vmot=0, Cmot=0, Pmot=0;           // 消費電圧、電流、電力を格納する変数
float Vsol=0, Csol=0, Psol=0;           // 発電電圧・電流・電力を格納する変数
float Vbat=0,  Cbat=0, Pbat=0;          // バッテリ電圧・電流・電力を格納する変数
float VcelMax=0,VcelAve=0,VcelMin=0;    // セル最大・平均・最小電圧を格納する変数
float speed=0;                          // 走行速度を格納する変数
signed char duty=0;                     // スロットル開度を格納する変数

int cntTera = 0;

/* ユーザ定義関数の宣言 */
void init(void);                        // 初期化を行う関数を宣言
void printTera(void);                   // Teraterm表示を行う関数を宣言

//灯火類の設定
/*
DigitalIn indiR_IN(p15);            // 方向指示器(右)の入力の設定
DigitalIn indiL_IN(p14);            // 方向指示器(左)の入力の設定
DigitalIn head_IN(p13);            // ヘッドライトの入力の設定
DigitalIn horn_IN(p12);            // ホーンの入力の設定
DigitalIn brake_IN(p11);            // ブレーキランプの入力の設定

PwmOut indiR_OUT(p20);              // 方向指示器(右)の出力の設定
PwmOut indiL_OUT(p19);               // 方向指示器(左)の出力の設定
PwmOut headt_OUT(p18);                   // ヘッドライトの出力の設定
DigitalOut horn_OUT(p17);               // ホーンの出力の設定
DigitalOut brake_OUT(p16);              // ブレーキランプの出力の設定
*/
/* IM920(テレメトリ)の設定 */
int cntIM920 = 0;
void printIM920(void);                  // PC(teraterm), IM920(テレメトリシステム), LCDへのprintf処理を行う関数 

/* LCDの設定 */
int cntLCD=0;
void printLCD(void);                    // LCDにデータ表示する関数

/* CAN通信の設定 */
char cntCAN = 0;                        // CAN受信でカウントアップする変数
CANMessage bufCAN;             // CAN受信用バッファの初期化(バッファ(buf): データを一時的に格納するためのメモリー領域)
//void readCAN(void);

/* USBメモリ(MSC:マスストレージクラス)の設定 */
MSCFileSystem msc("usb");       // Mount flash drive under the name "usb"
char *str1 = "/usb/log";        // 保存先("usb")とファイル名の一部(log)を指定
char *str2 = ".csv";            // ファイルの拡張子を指定
char fileName[30];              // ファイル名を格納する配列
char oxMSC;                     // 接続有無("o"か"x")を格納する変数(1文字用)
int cntMSC=0;                   // 処理を行うごとにカウントアップする変数
void initMSC(void);             // MSC(USB Mass Storage Class)の初期設定関数
void saveMSC(void);             // MSCへデータを書き込む関数
FILE *fp2;                      // ファイル構造体の定義

void initMSC(){                                     // USBメモリの初期設定関数
    FILE *fp1;                                      // ファイル構造体を定義
    int fileNumber = 0;                             // csvファイル命名に使用する変数を宣言
    
    fp1 = fopen( "/usb/fileNumber.txt", "r" );      // USBメモリ内の"fileNumber.txt"を読み取りモードで開く
    if( fp1 == NULL ){                              // アクセスできなかったとき, ...error( "Could not open main0\n\r" );を入れても良い
        pc.printf("USB init error\n\r" );           // teratermに"USB ini error"を表示
        oxMSC = 'x';                                // MSCが接続されていないため"x"を格納(1文字なのでシングルクォーテーション)
    }
    else {                                          // アクセスできたとき ...sbhost_lpc17xx.cppでの処理につながる
        oxMSC = 'o';                                // 1文字だからシングルクォーテーションで囲む
        fscanf( fp1,"%d",&fileNumber );             // "fileNumber.txt"の数字を読み取り,変数"fileNumber"に格納する
        fclose( fp1 );                              // "fileNumber.txt"を閉じる
        
        fp1 = fopen( "/usb/fileNumber.txt", "w" );  // "fileNumber.txt"を書き込みモードで開く  //exit(1);でBlueLightsOfDeath
        fprintf( fp1,"%d\n", fileNumber+1 );        // 読み込んだ数値に+1してfileNumber.txtに書き込み
        fclose(fp1);
        
        sprintf(fileName,"%s%d%s\n", str1, fileNumber, str2);   // 文字列の結合(データログ用ファイル名の作成)
        pc.printf( "\n\rUSB fileName: %s\n\r", fileName );      // 作成したファイル名をteratermに表示
        
        fp2 = fopen( fileName, "w" );                           // ファイルの新規作成後書き込み, ファイルがある場合上書き
        if(fp2 != NULL){                                        // NULLじゃないとき(ファイルを開けた時)
            fprintf( fp2,"Speed(km/h),dutyCycle,Vmot(V),Cmot(A),Pmot(W),Vsol(V),Csol(A),Psol(W),Vbat(V),Cbat(A),Pbat(W),VcelMax(V),VcelAve(V),VcelMin(V)\n" ); //ファイル書き込み
            fclose(fp2);                                        // csvファイル1行目にデータ項目を入力してファイルを閉じる
        }  
    }
}

void saveMSC(){                             // 処理時間50ms以上(MBED Timerで計測,データ量による)
    ++cntMSC;                               // MSCカウンタをインクリメント
    if( cntMSC >= 255){ cntMSC = 0; }       // 255になったらリセット
    if( oxMSC == 'o' ){
        fp2 = fopen( fileName, "a");            // ファイルを上書きモードで開く(ファイルがなければ新規作成)
        if ( fp2 == NULL ){                     // ファイルを開けなかったとき,
            oxMSC = 'x';                        // MSCが接続されていないため"x"を格納(1文字なのでシングルクォーテーション)
        }else {                                 // USBメモリ内のファイルを開くことができたとき,
            fprintf( fp2,"%5.1f,%3d,%5.1f,%5.1f,%6.1f,%5.1f,%5.1f,%6.1f,%5.1f,%5.1f,%6.1f,%5.3f,%5.3f,%5.3f\n",
                            speed, duty, Vmot, Cmot, Pmot, Vsol, Csol, Psol, Vbat, Cbat, Pbat, VcelMax, VcelAve, VcelMin ); 
            fclose(fp2);                                    // データを書き込んだ後,ファイルを閉じる
            pc.printf("MSC: %d\n", cntMSC);     //   
        }
    }
}

void readCAN(){                 // CANデータを受信したときに実行される関数(特定ID選択:https://os.mbed.com/questions/74230/about-ID-selectable-CAN-receive/, filter関数でも)
     ++cntCAN;                          // CANカウンタをインクリメント
    if( cntCAN >= 255 ){ cntCAN = 0; }    // 255を超えたらリセット
    
    if( can.read(bufCAN) ){                         // モタコンからデータが来たとき,    
        if( bufCAN.id == 0x20 ){                    // MPPTからデータがきたとき,
            if( LED ){ led2 = !led2; }              // led2を点滅させる処理. !はNOTの意味
            Vsol = ( (float)( (bufCAN.data[0]*100) + bufCAN.data[1]) ) / 10;            
            Csol = ( (float)( (signed int)((signed char)bufCAN.data[2]*100) + (signed char)bufCAN.data[3] ) + ((signed char)bufCAN.data[6]*100) + (signed char)bufCAN.data[7] ) / 100;   
            MPPTerror = bufCAN.data[4];
            MPPTerror_2 = bufCAN.data[5];
            Psol = Vsol * Csol;
        }
        else if( bufCAN.id == 0x10 ){
            if( LED ){ led1 = !led1; }              // led1を点滅させる(!はNOT)
            Vmot = ( (float)( (bufCAN.data[0]*100) + bufCAN.data[1]) ) / 10;        // 15 43を1500 43にして足すと「1543」となり、÷10すると154.3 [V]
            Cmot = ( (float)( ((signed char)bufCAN.data[2]*100) + (signed char)bufCAN.data[3] ) ) / 100; 
                                                                                    // 5 54を500 54にして足すと5「554」となり、÷100すると5.54 [A]
            Pmot = Vmot * Cmot;
            speed = ( (float)( (bufCAN.data[4]*100) + bufCAN.data[5]) ) / 10;       //「856」を85.6[km/h]にするため,÷10する
            duty = (signed char)bufCAN.data[6];     // アクセル開度は0~100表示のため,そのまま
            direc = (int)bufCAN.data[7];
        }

        else if( bufCAN.id == 0x30 ){                    // BMSからデータが来たとき,
            if( LED ){ led3 = !led3; }              // led3を点滅させる処理. !はNOTの意味
            Vbat = ( (float)( (bufCAN.data[0]*100) + bufCAN.data[1]) ) / 10;     
            Cbat = ( (float)( (signed int)((signed char)bufCAN.data[2]*100) + (signed char)bufCAN.data[3] ) ) / 100;
            Pbat = Vbat * Cbat;
            VcelMin = ( (float)( (bufCAN.data[4]*100) + bufCAN.data[5] ) ) / 100;      
            VcelMax = ( (float)( (bufCAN.data[6]*100) + bufCAN.data[7] ) ) / 100;    
            VcelAve = Vbat / 27;                    // バッテリ電圧をセルの直列数(20200807現在、27直列)で割って平均電圧を算出する
        }
    
    }
}
void printLCD(){                                                    // LCDにデータを表示する関数
     ++cntLCD;                                    // IM920カウンタをインクリメント
    if( cntLCD >= 255){ cntLCD = 0; }            // 255以上でリセット
    
    lcd1.locate(0, 0);                                              // 4行LCDの1行目1番目に表示位置を指定し,
    lcd1.printf("%5.3fv %5.3fv %5.3fv", VcelMax, VcelAve, VcelMin); // バッテリセルの最大・平均・最小の電圧を表示
    lcd1.locate(0, 1);                                              // 4行LCDの2行目1番目に表示位置を指定し,
    lcd1.printf("B:%5.1fv%5.1fA%5.0fw", Vbat, Cbat, Pbat);          // バッテリ電圧・電流・電力を表示
    lcd1.locate(0, 2);                                              // 4行LCDの3行目1番目に表示位置を指定し,
    lcd1.printf("M:%5.1fv%5.1fA  d:%d", Vmot, Cmot, direc);         // モータ電圧・電流, 進行方向を表示
    lcd1.locate(0, 3);                                              // 4行LCDの4行目1番目に表示位置を指定し,                           
    if( MPPTerror || MPPTerror_2 ){                                 // MPPTからエラー信号を受け取っていたとき,
        if( MPPTerror ){                                            // MPPT1がエラーなら
            lcd1.printf("S:X%2.1fv%5.1fA", Vsol, Csol);             // 先頭に"X"を入れて発電電圧・電流を表示
        }else{                                                      // MPPT2がエラーなら
            lcd1.printf("S:XX%1.1fv%5.1fA", Vsol, Csol);            // 先頭に"XX"を入れて発電電圧・電流を表示
        }
    }else{                                                          // MPPTからエラー信号を受け取っていないとき
        lcd1.printf("S:%5.1fv%5.1fA", Vsol, Csol);                  // 発電電力・電流を表示
    }
    lcd1.locate(15, 3);                                             // 4行LCDの4行目16番目に表示位置を指定し,
    lcd1.printf("USB:%c", oxMSC);                                   // USBの接続状態を表示("o"か"x") 
    lcd2.printf( 0, "%5.1fkm/h %5.1fv\r", speed, Vmot );            // デカ文字LCDの1行目1番目に表示(速度,システム電圧)
    lcd2.printf( 1, "%5.0fw %4.0fw %3d\r", Pmot, Psol, duty );      // デカ文字LCDの1行目2番目に表示(消費電力,発電電力,スロットル開度)
    pc.printf("LCD:%d\n",cntLCD);                  // 無線送信処理を行ったことをPC(teraterm)へ知らせる
}

void printIM920(){                                  // 処理時間16ms~(MBED Timerで計測)
     ++cntIM920;                                    // IM920カウンタをインクリメント
    if( cntIM920 >= 255 ){ cntIM920 = 0; }            // 255以上でリセット
    im920.printf("TXDA%.1f,%.3f,%.3f,%.3f,%.1f,%.1f,%.1f,%.1f,%d,%d\r",
        Vmot, VcelMax, VcelAve, VcelMin, Cbat, Cmot, Csol, speed, duty, cntIM920);  
                                                    // TXDAに続く文字が無線送信される. データ間を","で区切る. 最後に"\r"必須
    pc.printf("IM920:%d\n",cntIM920);                  // 無線送信処理を行ったことをPC(teraterm)へ知らせる
}

void printTera(){
    ++cntTera;                                    // Teratermカウンタをインクリメント
    if( cntTera >= 255){ cntTera = 0; }           // 255以上でリセット
    //pc.printf("Tera:%d\n",cntTera);                  // 無線送信処理を行ったことをPC(teraterm)へ知らせる
    pc.printf("SP:%.1f DT:%d Vm:%.1f Im:%.2f Pm:%.1f Vs:%.1f Is: %.2f Ps:%.1f\n\r", speed, duty, Vmot, Cmot, Pmot, Vsol, Csol, Psol );
    pc.printf("Vb:%.1f Cb:%.2f Pb:%.1f max:%.3f avg:%.3f min:%.3f\n\r", Vbat, Cbat, Pbat, VcelMax, VcelAve, VcelMin );  
}

void init(){                        // 初期化(初期設定)を行う関数
    pc.baud(115200);                // pcとのシリアル通信ボーレートを115200bpsに設定(数字が大きい方が通信速度高い)
    pc.printf("main() start\n");
    wait(3);                        // MBED電源投入から安定するまで3秒待つ(待たないと電源再投入後にUSBメモリの初期化・ファイル作成ができない)
    im920.baud(19200);              // IM920とのシリアル通信ボーレートを19200bpsに設定(19200はIM920の初期値)
    initMSC();                      // USBマスストレージクラス(USBメモリ)を初期化する関数を実行
}
    
int main() {
    init();                                 // 初期化関数を実行

    MPPTerror_2 = 0;
    Vmot=0;
    Cmot=0;
    Pbat=0;
    
    tm1.start();
    time0t5s.start();                       //https://os.mbed.com/media/uploads/yueee_yt/text_h24csee.pdf(p.21)
    time0t2s.start();                       //https://os.mbed.com/media/uploads/yueee_yt/text_h24csee.pdf(p.21)
    
    can.attach(&readCAN, CAN::RxIrq);     //CAN受信割り込みの設定
    while(1) {
        //readLights();
        if( time0t5s.read() < 0.5 ){
            //readCAN();                          // CANデータを読み込む関数を実行
            if( time0t2s.read() >= 0.2 ){  
                time0t2s.reset();           // time0t2sをリスタートさせる
                printLCD();               // LCDの表示を更新する関数を実行
                printTera();                // Teratermに表示する関数を実行
            }
        }   
        if( time0t5s.read() >= 0.5 ){       // 0.5秒毎に実行する処理
            time0t5s.reset();               // time0t5sをリスタートさせる
            if( LED ){ led4 = !led4; }      // led4を点滅させる(!はNOT)
            pc.printf("TheTime: %d(us)\n", tm1.read_us());    // 処理時間確認用プログラム(1/2)
            tm1.reset();                                      // 処理時間確認用プログラム(2/2)
            saveMSC();                      // MSCにデータを保存する関数を実行
            printIM920();                   // IM920に無線送信させる関数を実行
        }
        
    }
}