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

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

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

2012年12月29日 | Gadgets
前回作成したプログラムのサイズを小さくして、高度の表示を考えた。
結論から言うと、サイズは小さくなったが、高度の表示は失敗。
というのは、計算のための累乗(POW)の関数が使えないことによる。
プログラムサイズは、前回の82%程度から、52.6%まで縮小できたが、同じようにMath.hをincludeして、pow関数を使うと、メモリオーバーしてしまった。
で、この関数にどれくらい食われているか見るために、簡単な式、pow(1.2,0.19) とやってみると、コンパイルはできたが、これだけで76.6%までいっていることがわかった。これでは、この計算で高度を出すのは難しそうなので、別の方法を考えることにする。
考えてみたら、実際、海面の気圧は、いつも1013.25hpではないわけだから、この式にこだわってもあまり意味がないかもしれない。
というわけで今回はプログラムの縮小に専念。
その前に、これまでのところの回路図を

プログラムの縮小化に関しては、係数の読み込みと計算をやめてしまうことにした。
と、いうのも、このセンサの係数は、単品毎(ロットごと?)によって異なっているようだが、いったん読んでしまえば、後は変わることはないわけだから、毎回読み込んで面倒な固定小数点の計算をしなくてもはじめからプログラムで変数に入れてしまえば良い。
というわけで、自分のセンサの係数の計算から始めた。
係数の読み込み値は、前回のプログラムでそれぞれを表示させればわかる。
自分のは、次のような値になっていた
a0=14590(38FE) 0011 1000 1111 1110
b1=48258(BC82) 1011 1100 1000 0010
b2=49339(C0BB) 1100 0000 1011 1011
C12=12888(3258) 0011 0010 0101 1000
C11=0
C22=0
これを小数に変換するには、

a0は、符号ビットが1ビット、整数部が12ビット、小数部が3ビットで
符号ビットはゼロなので正数(プラス)となり
値は、0*2048+1*1024+1*512+1*256+0*128+0*64+0*32+1*16+1*8+1*4+1*2+1*1+1*0.5+1*0.25+0*0.125 = 1823.75 となる。

b1は、符号ビットが1ビット、整数部が2ビット、小数部が13ビットで
符号ビットが1なので、負数(マイナス)となり、続くビットを2の補数にするのに、ビットを反転させて1を加える。
したがって、011 1100 1000 0010 -> 100 0011 0111 1101 +1 = 100 0011 0111 1110
値は、1*2+0*1+0*0.5+0*0.25+0*0.125+1*0.0625+1*0.03125+0*0.015625+1*0.0078125+1*0.0039062+1*0.0019531+1*0.0009765+1*0.0004882+1*0.0002441+0*0.000122 = -2.109130859 となる。

b2は、符号ビットが1ビット、整数部が1ビット、小数部が14ビットで
符号ビットが1なので、負数(マイナス)となり、続くビットを2の補数にするのに、ビットを反転させて1を加える。
したがって、100 0000 1011 1011 -> 011 1111 0100 0100 +1 = 011 1111 0100 0101
値は、0*1+1*0.5+1*0.25+1*0.125+1*0.0625+1*0.03125+1*0.015625+0*0.0078125+1*0.0039062+0*0.0019531+0*0.0009765+0*0.0004882+1*0.0002441+0*0.000122+1*0.000061 = -0.988586426 となる。

c12は、符号ビットが1ビット、整数部が0ビット、小数部が13ビットで小数点以下にゼロが9個続いた後にデータの小数部が始まる。
また、データは14ビットだが、左寄せなので、LSB側2ビットは、無視。
符号ビットが0なので、正数(プラス)となり、9個のゼロを加えるから、
000000000 011 0010 0101 10 = 00 0000 0000 1100 1001 0110
値は、0*0.5+0*0.25+0*0.125+0*0.0625+0*0.03125+0*0.015625+0*0.0078125+0*0.0039062+0*0.0019531+0*0.0009765+1*0.0004882+1*0.0002441+0*0.000122+0*0.000061035+1*0.00003052+0*0.00001526+0*0.000007630+1*0.000003815+0*0.000001907+1*0.0000009537+1*0.0000004768+0*0.0000002384 = 0.000768185 となる。

以上の値をプログラムの中で変数に代入してやると良い。
ふぅ~。 手計算もなかなか大変。 もちろん計算自体は、エクセルを使ってやったけど・・・。

今日は、このくらいにしといたろ。

以下、改訂プログラム
/* 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 main(void){

unsigned char i,j;
unsigned char ack,Tsign,sgn,lsb;
float a0,b1,b2,c12;
float decPcomp,siPcomp,hight;
unsigned int uiPadc,uiTadc,v0,vdata,press,temp;

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;

lcd_init();
i2c_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;
press=(int)decPcomp;

//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 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(v0/10,2);
lcd_putch('.');
lcd_putui(v0%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);

}
}

最新の画像もっと見る

コメントを投稿

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