ほんまかいな、そーかいな、南アフリカ と ちょびっと シドニー そして日本だ!

南アフリカ(2004年)と、シドニー(2005年)での生活の近況報告です。そして日本でも(2007年から)

MPL115A2とPIC 16F1827で気圧計を作ってみた(その3)

2012年12月31日 | Gadgets
プログラムメモリに余裕ができたので、シリアル通信でPCにデータを送るようにしてみた。
データは、送信のみで、気圧と温度のデータを垂れ流しにしている。
とりあえず、データが取れれば、あとは、PC側で何とでもできる。
生データを300点ほど取ってグラフにしてみると、こんなグラフになった。

結構、大きくばらついている。
それで、このデータをもとに移動平均を取ってみた。
10点の移動平均を取るとこんなかんじ、

さらに、20点の移動平均にしてみると、こんなかんじ

このくらいになるとなんとなくいい感じに見える。
が、参考にしようと、このモジュールを使われているいろんな方のサイトを見ていて気がついた。
この気圧センサの精度は1kPaと書かれている。 で、あらためてデータシートを見てみると、確かに"1kPa Accuracy"と書かれている。1kPaというと、10hPaになる。
これは、結構ざっくりの値だなぁ~。 高度にするとプラスマイナスで20hPa差が出たとしたら、最大9x20m=180mもずれることになる。
とすると、今表示されているデータのばらつき具合だと、よくがんばっている方かもしれない。
そんなわけで、データは、20ポイントの移動平均の値を表示させることにした。
だいたい、2秒周期でデータをとっているので、20ポイントだと40秒くらい。 仮に時速60kmで走る車に乗って測定したすると、測り始めて結果が表示されるまでに700mくらい走ってしまう計算になるけど、まぁ、いいか。
そもそも、そんなシビアな測定に使えるものでもなさそうだ。

シリアル通信と移動平均を加えたプログラムは、以下に。
この通信プログラムも前述したように、”PICとC言語の電子工作”鈴木哲哉著 を使わせていただいている。

以下プログラム
/* Project Brometer
PIC16F1827 with Pressure Sensor MPL115A2, Temp.Sensor LM61CIZ and Liquid Crystal Display SC1602
Comm by I2C
*/

/*PIN of 16F1827 asign
RA0 : LCD DB4 (pin11) RB0 :
RA1 : LCD DB5 (pin12) RB1 : I2C SDA (pin7 of MPL115)
RA2 : LCD DB6 (pin13) RB2
RA3 : LCD DB7 (pin14) RB3 : ADC (LM61CIZ Vout)
RA4 : LCD RS (pin 4) RB4 : I2C SCL (pin8 of MPL115)
RA5 : ICSP MCLR RB5 : USART Tx (Reserved)
RA6 : LCD R/W (pin 5) RB6 : ICSPCLK (Header pin)
RA7 : LCD E (pin 6) RB7 : ICSPDAT (Header pin)
*/
#include <pic.h>
//#include <math.h>
#include "sc1602b.h"
#include "i2c.h"

#define _XTAL_FREQ 8000000 // delay用(クロック8MHzで動作時)

__CONFIG( WRT_OFF & MCLRE_OFF & PWRTE_ON & WDTE_OFF & FOSC_INTOSC & CP_OFF & CPD_OFF) ;
__CONFIG(PLLEN_OFF & STVREN_ON & BORV_25 & LVP_OFF);

void putch(unsigned char c){
while(TXIF == 0);
TXREG=c;
}

void putui(
unsigned int ui, unsigned char d){

unsigned char i;
unsigned char buf[5];

for(i = 0; i < 5; i++)
buf[i] = ' ';
i = 4;
do {
buf[i] = (ui % 10) + '0';
ui = ui / 10;
i--;
} while(ui > 0);

for(i = (5 - d); i < 5; i++)
putch(buf[i]);
}

void puts(const unsigned char *s){
while(*s) putch(*s++);
}

void sci_init(void){
BRGH=0;
SPBRG=12; //BRGH=0, 8MHz, 9600baud
SYNC=0;
SPEN=1;
TXEN=1;
TXCKSEL=1; // RB5 to be TX
}

void main(void){

unsigned char i,j,n;
unsigned char ack,Tsign,sgn,lsb;
float a0,b1,b2,c12;
float decPcomp,siPcomp,hight;
float d[20],td,fpress;
unsigned int uiPadc,uiTadc,v0,vdata,press,temp,ipress;

OSCCON = 0b01110010; // 内部クロックは8MHzとする
OPTION_REG = 0b00000000;
TRISA = 0b00100000; // 1で入力 0で出力 RA0-RA7全て出力に設定(RA5は入力専用)
TRISB = 0b00001000; // RB0-RB2,RB4-RB7を出力に設定 RB3を入力(for ADC)
ANSELA = 0b00000000; //汎用ポート
ANSELB = 0b00001000; //汎用ポート RB3(AN9)をADCにセット
PORTA = 0b00000000 ; // RA出力ピンの初期化(全てLOWにする)
PORTB = 0b00000000 ; // RB出力ピンの初期化(全てLOWにする)
ADCON0 = 0b00100100;
ADCON1 = 0b10010011; //右寄せ, Fosc/8, FVR
FVRCON = 0b11000010; //FVR=2.048V enabled
APFCON1=1;

WPUB3=0; //ADC用のピン(RB3)のWeek Pull-up をキャンセル

//センサの係数値(あらかじめデーターを読み込んで浮動小数点に変換したもの)
a0=1823.75;
b1=-2.109130859;
b2=-0.988586426;
c12=0.000768185;

press=0; n=0; td=0.0;

lcd_init();
i2c_init();
sci_init();


while(1) {

//-------------Read Padc, Tadc figure  I2Cで気圧、温度の値を取得 -----------------------
i2c_start();
i2c_write(0x60<<1);
i2c_write(0x12);
i2c_write(0x01);
i2c_stop();

__delay_ms(5);

i2c_start();
i2c_write(0x60<<1);
i2c_write(0x00);
i2c_repstart();
i2c_write((0x60<<1)|1);

uiPadc=i2c_read(0);
lsb=i2c_read(0);
uiPadc=((uiPadc<<8)|lsb)>>6;

uiTadc=i2c_read(0);
lsb=i2c_read(1);
uiTadc=((uiTadc<<8)|lsb)>>6;

i2c_stop();

siPcomp = a0+(b1+c12*uiTadc)*uiPadc+b2*uiTadc;
decPcomp = (((65.0/1023.0)*siPcomp)+50)*100;
// ipress=(int)decPcomp;

//Moving Average with 20 points
if(n<20){
d[n]=decPcomp;
td+=decPcomp;
n++;
fpress=td/n;
}
else{
n=20;
for(i=0;i<19;i++) d[i]=d[i+1];
d[19]=decPcomp;
td=0.0;
for(i=0;i<20;i++) td+=d[i];
fpress=td/n;
}
press=(int)fpress;

//Calcuration for Temp in MPL115
// temp=25-(uiTadc-472)/5.35;
// if(temp<0){Tsign='-';} else{Tsign=' ';}


//ADC for Temperature of LM61CIZ
// ADCON0=0b00100111;
ADON=1;
__delay_ms(1);
GO_nDONE=1;
while(GO_nDONE);
vdata=ADRESH;
vdata<<=8;
vdata|=ADRESL;
if((vdata*2)>=600){ //In case Temp. >= 0
v0=((vdata*2)-600); // Vref(2.48V/1024=2mv/bit)
sgn=0;
}
else{ //In case Temp. < 0
v0=(600-(vdata*2));
sgn=1; // For minus sign LED on flag
}

temp=v0;
if(sgn==1){Tsign='-';} else{Tsign='+';}

//標高の計算
// hight=(pow((1023.25/decPcomp),(1/5.256))-1)*((float)temp+273.15)/0.0065;

// Output to RS-232
putui(press/10,4);
putch('.');
putui(press%10,1);
putch(',');
putch(Tsign);
putui(temp/10,2);
putch('.');
putui(temp%10,1);
putch('\n');
putch('\r');

// Output to LCD
lcd_lclr(0);
lcd_putui(press/10,4);
lcd_putch('.');
lcd_putui(press%10,1);
lcd_puts("hPa");

lcd_lclr(1);
lcd_locate(0,1);
lcd_putch(Tsign);
lcd_putui(temp/10,2);
lcd_putch('.');
lcd_putui(temp%10,1);
lcd_putch(0xdf);
lcd_putch('C');
// lcd_locate(8,1);
// lcd_putui(hight,4);

for(j=0;j<200;j++)__delay_ms(10);

}
}

最新の画像もっと見る

コメントを投稿

ブログ作成者から承認されるまでコメントは反映されません。