電波社

  • HOME
  • 会社概要
  • お問い合わせ

//*****************************************************************************

// Prgram Name   : thp.c

// Start Date    : 1st.Nov.2019

// Author        : Yoshio Kato

// Description   : Measureing temperatur, Humidity, Pressure and get maximam, minimam value

//               : Display by 7 segment LED

//*****************************************************************************

#include <time.h>          //timeヘッダーファイルをインクルード

#include <stdio.h>         //stdioiヘッダーファイルをインクルード

#include <stdlib.h>        //stdlibヘッダーファイルをインクルード 

#include <wiringPi.h>      //wiringPiヘッダーファイルをインクルード 

#include <wiringPiI2C.h>   //wiringPiI2Cヘッダーファイルをインクルード 

#define sensor_adrs 0x76   //センサーのアドレスを定義

unsigned long int tmp_now ;

unsigned long int hum_now ;

unsigned long int prs_now ;

signed long int t_fine;

unsigned short tmp1;

signed short   tmp2;

signed short   tmp3;

unsigned short prs1;

signed short prs2;

signed short prs3;

signed short prs4;

signed short prs5;

signed short prs6;

signed short prs7;

signed short prs8;

signed short prs9;

unsigned char  hum1;

signed short   hum2;

unsigned char  hum3;

signed short   hum4;

signed short   hum5;

signed char    hum6;

int get_data[31] ;

static int fd;   // 

#define a  14    // a セグメント GPIO

#define b  15    // b セグメント GPIO

#define c  18    // c セグメント GPIO

#define d  23    // d セグメント GPIO

#define e  24    // e セグメント GPIO

#define f  25    // f セグメント GPIO

#define g  8     // g セグメント GPIO

#define dp 7     // 小数点 GPIO

#define shutdown_sw   26                    //シャットダウンスイッチのGPIO

char digit_gpio[6] = {19,21,20,16,12,13} ;  //デジット選択 GPIO D1,D2,D3,D4

char segment[15][8] ={{a,b,c,d,e,f,0,0},    //0のセグメントデータ

                      {b,c,0,0,0,0,0,0},    //1のセグメントデータ

                      {a,b,d,e,g,0,0,0},    //2のセグメントデータ

                      {a,b,c,d,g,0,0,0},    //3のセグメントデータ

                      {b,c,f,g,0,0,0,0},    //4のセグメントデータ

                      {a,c,d,f,g,0,0,0},    //5のセグメントデータ

                      {a,c,d,e,f,g,0,0},    //6のセグメントデータ

                      {a,b,c,f,0,0,0,0},    //7のセグメントデータ

                      {a,b,c,d,e,f,g,0},    //8のセグメントデータ

                      {a,b,c,d,f,g,0,0},    //9のセグメントデータ

                      {a,0,0,0,0,0,0,0},    //red LED  temperature

                      {b,0,0,0,0,0,0,0},    //yellow LED  humidity

                      {c,0,0,0,0,0,0,0},    //green LED   pressure

                      {d,0,0,0,0,0,0,0},    //orange LED  time

                      {g,0,0,0,0,0,0,0}};   //minus

char select_sw[8] = {17,27,22,10,9,11,5,6} ; //ロータリースイッチ接続GPIO

int max_min[14] ;    //0,2,4,6,8,10 is data  1,3,5,7,9,11 is time  12,13 is now time

time_t timer ;

struct tm *tim ;     //構造体の設定

 

//*****************************************************************************

// 初期設定

//*****************************************************************************

static int init(void){

     char i ;

     if ((fd = wiringPiI2CSetup(sensor_adrs)) == -1)

          return(-1) ;

     if(wiringPiSetupGpio() == -1)           //wiringPiの設定 戻り値が-1の時はエラー

          return(-1) ;                       //エラーリターン

     for(i=0; i<6; i++)                      //デジットのGPIO設定

          pinMode(digit_gpio[i],OUTPUT) ;    //デジットのGPIOを出力設定

     for(i=0; i<7;i++)

          pinMode(segment[8][i],OUTPUT) ;    //各セグメントのGPIOを出力設定

     for(i=0; i<8 ; i++){

          pinMode(select_sw[i],INPUT) ;      //ロータリースイッチのGPIOを入力設定

          pullUpDnControl(select_sw[i],PUD_UP) ;  //ロータリースイッチのGPIOをプルアップ

     }

     pinMode(dp,OUTPUT) ;                    //小数点のGPIOを出力設定

     pinMode(shutdown_sw,INPUT) ;            //シャットダウンスイッチのGPIOを入力設定

     pullUpDnControl(shutdown_sw,PUD_UP) ;   //シャットダウンスイッチのGPIOをプルアップ

     return(0) ;

}

 

 

//*****************************************************************************

// キャリブレーションデータの取得

//*****************************************************************************

void get_cal_dt(){

     unsigned char data[32] ; 

     unsigned char data_pos = 0 ;

     unsigned char adrs ;

     char i ;

     for(adrs=0x88;adrs<0xa0;adrs++)  //キャリブレーションデータの読み込み

          data[data_pos++] = wiringPiI2CReadReg8(fd,adrs) ;  

     data[data_pos++] = wiringPiI2CReadReg8(fd,0xA1) ;  

     for(adrs=0xE1;adrs<0xE8;adrs++)

          data[data_pos++] = wiringPiI2CReadReg8(fd,adrs) ;

     i = 0 ;  

     for(data_pos=0;data_pos<=22;data_pos+=2) 

          get_data[i++] = data[data_pos] | data[data_pos+1]*256 ;

     tmp1 = get_data[0] ;

     tmp2 = get_data[1] ;

     tmp3 = get_data[2] ;

     prs1 = get_data[3] ;

     prs2 = get_data[4] ;

     prs3 = get_data[5] ;

     prs4 = get_data[6] ;

     prs5 = get_data[7] ;

     prs6 = get_data[8] ;

     prs7 = get_data[9] ;

     prs8 = get_data[10] ;

     prs9 = get_data[11] ;

     hum1 = data[24];

     hum2 =data[25] | data[26] << 8 ; 

     hum3 = data[27];

     hum4 = (data[29] & 0x0F) | (data[28] << 4) ;  

     hum5 = ((data[29] >> 4) & 0x0F) | (data[30] << 4) ; 

     hum6 = data[31];  

 }

 

 

//*****************************************************************************

// センサーから測定データの読み込み

//*****************************************************************************

void get_BME280(){

     char i = 0;

     char adrs ;

     unsigned char data[8];

     for(adrs=0xF7; adrs<0xF7+8 ; adrs++)  

          data[i++]=wiringPiI2CReadReg8(fd,adrs) ;  //レジスターから読み込み

     prs_now = (data[0] << 8) | data[1];

     prs_now = (data[2] >> 4)  | (prs_now << 4) ; 

     tmp_now=(data[3] << 8) | data[4]  ;

     tmp_now = (data[5] >> 4) | (tmp_now << 4) ;    

     hum_now  = data[6] << 8 ;

     hum_now = data[7] | hum_now ;  

}

 

 

//*****************************************************************************

// 気温の補正

//*****************************************************************************

signed long int cal_temp(signed long int adc_T){

    signed long int wk1, wk2;

    wk1 = ((((adc_T >> 3) - ((signed long int)tmp1<<1))) * ((signed long int)tmp2)) >> 11;

    wk2 = (((((adc_T >> 4) - ((signed long int)tmp1)) * ((adc_T>>4) - ((signed long int)tmp1)))

           >> 12) * ((signed long int)tmp3)) >> 14;

    t_fine = wk1 + wk2;

    return((t_fine*5+128) >> 8); 

}

 

//*****************************************************************************

// 気圧の補正

//*****************************************************************************

unsigned long int cal_press(signed long int arg_prs){

     signed long int wk1, wk2;

     unsigned long int p;

     wk1 = (((signed long int)t_fine)>>1) - (signed long int)64000;

     wk2 = (((wk1>>2) * (wk1>>2)) >> 11) * ((signed long int)prs6);

     wk2 = wk2 + ((wk1*((signed long int)prs5))<<1);

     wk2 = (wk2>>2)+(((signed long int)prs4)<<16);

     wk1 = (((prs3 * (((wk1>>2)*(wk1>>2)) >> 13)) >>3) + ((((signed long int)prs2) * 

            wk1)>>1))>>18;

     wk1 = ((((32768+wk1))*((signed long int)prs1))>>15);

     if (wk1 == 0)

          return(0);

     p = (((unsigned long int)(((signed long int)1048576) - arg_prs)-(wk2>>12))) * 3125;

     if(p<0x80000000)

          p = (p << 1) / ((unsigned long int) wk1);   

       else

          p = (p / (unsigned long int)wk1) * 2;    

     wk1 = (((signed long int)prs9) * ((signed long int)(((p>>3) * (p>>3))>>13)))>>12;

     wk2 = (((signed long int)(p>>2)) * ((signed long int)prs8))>>13;

     return((unsigned long int)((signed long int)p + ((wk1 + wk2 + prs7) >> 4)));

}

 

//*****************************************************************************

// 湿度の補正

//*****************************************************************************

unsigned long int cal_humi(signed long int arg_hum){

     signed long int wk1;

     wk1 = (t_fine - ((signed long int)76800));

     wk1 = (((((arg_hum << 14) -(((signed long int)hum4) << 20) - (((signed long int)hum5) * wk1))

             + ((signed long int)16384)) >> 15) * (((((((wk1 * ((signed long int)hum6)) >> 10) * 

              (((wk1 * ((signed long int)hum3)) >> 11) + ((signed long int) 32768))) >> 10) + 

              (( signed long int)2097152)) * ((signed long int) hum2) + 8192) >> 14));

     wk1 = (wk1 - (((((wk1 >> 15) * (wk1 >> 15)) >> 7) * ((signed long int)hum1)) >> 4));

     wk1 = (wk1 < 0 ? 0 : wk1);

     wk1 = (wk1 > 419430400 ? 419430400 : wk1);

     return((unsigned long int)(wk1 >> 12));   

}

 

 

//*****************************************************************************************

//  7セグメント表示器の表示を消去

//*****************************************************************************************

void erase_7seg_led(){

     int i ;

     for(i=0; i<7; i++)

          digitalWrite(segment[8][i],1) ;  //a〜gセグメントをオフ

     for(i=0; i<6; i++)

          digitalWrite(digit_gpio[i],0) ;  //全てのSA1015をオフ

     digitalWrite(dp,1) ;                  //秒点滅LEDをオフ

 }

 

//*****************************************************************************************

//  指定したデジットに数字を表示

//*****************************************************************************************

void display_data(char dgt, char disp_dt,char itm){

     int i = 0 ;

     erase_7seg_led() ;                   //全ての表示を消去

     while(segment[disp_dt][i] != 0)      //数字を構成するデータが0でない間繰り返す

          digitalWrite(segment[disp_dt][i++],0) ;  //対応するセグメントをオン

     digitalWrite(digit_gpio[dgt],1) ;    //指定したデジットをオン 数字が表示

     switch(itm){

        case 1:

        case 3:if(dgt == 3)    //気温

                  digitalWrite(dp,0) ;

                break;

        case 2: break;          //湿度

        case 4:if(dgt == 2)     //時間

                  digitalWrite(dp,0) ;

                break;

    }

    delay(3) ;                  //3ms時間をおく

}

 

//*****************************************************************************************

//  時と分の表示

//*****************************************************************************************

 void display(int dt, char itm){

     char digit = 5;

     char minus_flag = 0 ;

     if(dt < 0){             //データはマイナスか?

          dt = dt*-1 ;        //プラスへ変換

          minus_flag = 1 ;    //マイナスフラグを立てる

     }

     while(dt){

          if(digit == 5){     //何を表示しているかのLEDのデジット

               display_data(digit,itm+9,itm) ;

               digit-- ;     

            }

           else{

               display_data(digit--, dt % 10, itm) ;

               dt = dt / 10 ;

          }

     }

     if((itm == 4) && (digit == 1))  //now time display

         display_data(digit,0,itm) ;     //now time is less than 10:00,display '0' on digit 1

     if(minus_flag)

         display_data(digit,13, itm) ;  //display minus

}

 

//*****************************************************************************

// 一桁あたりの表示時間を決める処理

//*****************************************************************************

int get_loop_count(int dt){

     char count = 0 ; ;

     if(dt <0 ){

          dt=dt*-1 ;

          count = 1 ;

     }

     if(dt < 10)

          count++ ;

     while(dt){

          dt = dt/10 ;

          count++ ;

     }

     return(2000/(count*3)) ;

}

    

//*****************************************************************************

// 引数で与えられたデータを表示

//*****************************************************************************

int disp_item(int dt, char itm) {

     int loop_count ;

     loop_count = get_loop_count(dt) ;

     while(loop_count){

          display(dt,itm) ;

          loop_count-- ;

          if(digitalRead(shutdown_sw)==0)   //shutdownスイッチが押されたらリターン

               return(1) ;                  //shutdownスイッチが押された 

     }

     erase_7seg_led() ;                    //7セグメントLED表示器の表示を消去

     delay(300) ;                          //300ms休止

     return(0) ;

}

 

//*****************************************************************************

// 最高・最低の値を表示

//*****************************************************************************

void display_max_min(int dt,int tm,char itm){

     int loop_count ;

     loop_count = get_loop_count(dt) ;

     while(loop_count--)

          display(dt,itm) ;      //表示処理をコール

     erase_7seg_led() ;          //7セグメントLED表示器の表示を消去

     if(itm != 4)

          delay(300) ;           //300ms休止

     loop_count = get_loop_count(tm) ;

     while(loop_count--)

          display(tm,4) ;        //max or min occured time

     erase_7seg_led() ;          //7セグメントLED表示器の表示を消去

     if(itm != 4)

          delay(300) ;           //300ms休止

}

 

//*****************************************************************************

// スイッチの情報を読み込み

//*****************************************************************************

void check_select_sw(){

    int i = 0 ;

    while(i < 9){

        if(digitalRead(select_sw[i++]) == 0){

            if(i == 1)

                return ;

              else

                display_max_min(max_min[(i-2)*2],max_min[(i-2)*2+1],i/2) ;

        }

    }

}

 

 

//*****************************************************************************

// 各項目の最高最低値の初期化

//*****************************************************************************

void init_item(){

     max_min[0] = -999 ;   //最高気温

     max_min[2] = 9990 ;   //最低気温

     max_min[4] = 0 ;      //最高湿度

     max_min[6] = 999 ;    //最低湿度

     max_min[8] = 100 ;    //最高気圧 

     max_min[10] = 19999 ; //最低気圧

}

 

//*****************************************************************************

// メイン処理

//*****************************************************************************

int main(){  

     double temperature ;

     double pressure ;

     double humidity ;

     int tt ;

     int pp ;

     int hh ; 

     int now_time ;

     int count ;

     if(init() == 1)       //初期化処理でエラーならば終了する  

         return(1) ;

     init_item() ;         //最高最低値の初期化

     wiringPiI2CWriteReg8(fd,0xf2,0x01);   //湿度オーバーサンプリングに設定

     wiringPiI2CWriteReg8(fd,0xf4,0x27);   //気温オーバーサンプリングに設定

     wiringPiI2CWriteReg8(fd,0xf5,0xa0);   //スタンバイタイム設定

     get_BME280() ;        //設定後の空読み

     delay(1000) ;         //1秒間おく

     while(1){

         get_BME280() ;   //BME280からデータを取得

         get_cal_dt();    //キャリブレーションデータを取得

         time(&timer) ;

         tim = localtime(&timer) ;          //現在時刻を求める

         now_time = tim->tm_hour * 100 ;

         now_time = now_time + tim->tm_min ;

         max_min[12] = now_time ;

         max_min[13] = now_time ;

         if((now_time == 0) && (tim->tm_sec == 0))

              init_item() ;   //0時0分0秒に最高最低値を初期設定する

         temperature = (cal_temp(tmp_now)) /100.0 ;

         pressure = (cal_press(prs_now)) / 100.0 ;

         humidity = (cal_humi(hum_now))/ 1024.0 ;

         temperature = (temperature+0.05) ;

         pressure = (pressure + 0.05) ;

         humidity = (humidity + 0.5) ;

         tt=(int)(temperature *10);

         pp=(int)(pressure*10) ;

         hh=(int)(humidity) ;

        if(tt > max_min[0]){     //最高気温がどうか調べる

             max_min[0] = tt ;   //最高気温を更新

             max_min[1] = now_time ;  //その時の時間を保存

        }

        if(tt < max_min[2]){

             max_min[2] = tt ;

             max_min[3] = now_time ;

        }

        if(hh > max_min[4]){

             max_min[4] = hh ;

             max_min[5] = now_time ;

        }

        if(hh < max_min[6]){

             max_min[6] = hh ;

             max_min[7] = now_time ;

        }

        if(pp > max_min[8]){

             max_min[8] = pp ;

             max_min[9] = now_time ;

        }

        if(pp < max_min[10]){

             max_min[10] = pp ;

             max_min[11] = now_time ;

        }

       if(digitalRead(select_sw[0]) != 0){ //最高・最低表示スイッチが操作されたか

            check_select_sw() ;            //ロータリースイッチの状態を調べる

         }

        else{

            if(disp_item(tt,1))            //気温の表示処理をコール

                 break ;                   //表示処理でshutdownスイッチが押されたらループを抜ける

            if(disp_item(hh,2))            //湿度の表示処理をコール

                 break ;                   //表示処理でshutdownスイッチが押されたらループを抜ける

            if(disp_item(pp,3))            //気圧の表示処理をコール

                 break ;                   //表示処理でshutdownスイッチが押されたらループを抜ける

            if(disp_item(now_time,4))      //時刻の表示処理をコール

                 break ;                   //表示処理でshutdownスイッチが押されたらループを抜ける 

       }

       if(digitalRead(shutdown_sw)==0)     //shutdownスイッチがおされたか

          break;   //shutdownスイッチが押されたらループを抜ける

     }

     erase_7seg_led() ;                    //7セグメントLED表示器の表示を消去

     count = 0 ;

     while(digitalRead(shutdown_sw) == 0){ //shutdownスイッチが離されるまでの間実行

          delay(100) ;                     //100msのdelay

          count ++ ;                       //100ms毎にcountをプラスする

     }

     if(count >= 30)                       //countが30(3秒)以上か

          system("sudo shutdown -h now") ; //3秒以上なのでshutdownコマンドを実行し終了する

       else

          return(1) ;                      //shutdownではないのでOSへ戻る

 }

 

//******************************* End of Program ******************************************