//*****************************************************************************
// 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 ******************************************