

PIC 18F4553で大気圧センサーLPS331APを制御
LPS331APではマイコンインターフェースとしてI2C, SPIが使えますが、今回はI2Cで接続してみました。
表示にはI2C制御の小型のキャラクタLCD AQM0802Aを使用しました。
マイコンはPIC 18F4553です。
すべて電源電圧は3.3Vで統一。制御もすべてI2Cで行えます。
開発環境はMPLAB XIDEとXC18コンパイラ Pickit3です。
今回のような電源電圧がMax 3.3vのデバイスを使う場合、Pickit3をICSPに接続して書き込むとき、電圧生成機能をONで、設定電圧が5Vになっているような場合、デバイスを壊してしまう恐れがありますので、注意が必要です。
LPS331APは超小型で、パッケージがHCLGA-16なので、実装は個人では手に負えません。幸い秋月電子がDIP化したモジュールを販売しているので使用しました。
LPS331AP DIP化モジュールにはI2Cのプルアップ抵抗が搭載されていますが使用せず(J1, J2はオープン)、今回は外付けで5.6KΩを接続しました。
インターラプトは使わず1Hzの周期ポーリングとしました。このためINT1, INT2は使いません。
I2CモードにするためCSはVddにつないでおきます。
Vdd(3.3V), Vss(GND), I2Cの制御信号SCL, SDAをつないでおきます。PIC18F4553側はRB0, RB1を使用しました。
I2C制御小型キャラクタLCD AQM0802Aの制御プログラムは省略します。関連記事をご参照ください。
オンボード I2C 8x2 キャラクタLCD AQM0802A
デジタル大気圧センサーLP331APの制御方法
I2Cによるハンドリングは一般的な方法と同じですが、例によってタイミング的なところをカットアンドトライしなければなりませんでした。
タイミング(適当なディレイ)が合っていないと、気圧760.00Hpが読み込こまれ、一見故障しているように見えますが、執念深く調整します。
ネットを調べると、760.00Hpで変化しない場合は壊れているとのことですが、あきらめるのは早いようです。気圧が760.00Hpを示していても、WHO_AM_I(0x0F)レジスタを読み込むと、ちゃんと0xBBが返ります。
結局ソースコードにようにI2Cのハンドラ内でdelay_us()を適当に挿入することによって解決しました。
制御はまず、WHO_AM_Iレジスタ(0x0F)を読み込んで0xBBが返ることを確認します。
次にCTRL_REG1に0x90を書きます。これでパワーオンするとともに、周期を1Hzに設定します。
簡易的な使い方では、設定はこれだけで、このあとSTATUS_REGのステータスビット(温度用と気圧用が別になっている)を確認し、1がセットされたらPRESS_POUT_XL_REH, PRESS_OUT_L, PRESS_OUT_Hを読み込み、それらをLONG(4byte)の変数下位3byteに読み込んで、4096で割りfloatの変数に代入するだけです。
今回は平均化処理は行わずに表示しています。(このため少数以下がめまぐるしく変わります。)
ソースコード
i2c_lcd.c、 i2c.c、ftostring()、delay_ms()、dilay_us()は省略
ftostring()関数は、電子工作の実験室 後閑氏によります。
main.c
#include <xc.h>
#include <p18f4553.h>
#define SW1 PORTEbits.RE0
#define SW2 PORTEbits.RE1
#define LED PORTEbits.RE2 //Sens Time
#define REF_P_XL 0x08
#define REF_P_L 0x09
#define REF_P_H 0x0A
#define WHO_AM_I 0x0F
#define RES_CONF 0x10
#define CTRL_REG1 0x20
#define CTRL_REG2 0x21
#define CTRL_REG3 0x22
#define INT_CFG_REG 0x23
#define INT_SOURCE_REG 0x24
#define THS_P_LOW_REG 0x25
#define THS_P_HIGH_REG 0x26
#define STATUS_REG 0x27
#define PRESS_POUT_XL_REH 0x28
#define PRESS_OUT_L 0x29
#define PRESS_OUT_H 0x2A
#define TEMP_OUT_L 0x2B
#define TEMP_OUT_H 0x2C
#define AMP_CTRL 0x30
#pragma config PLLDIV = 5 // (20MHz crystal)
#pragma config CPUDIV = 0 // 1/2 Fosc = 10MHz
#pragma config USBDIV = 2 // Clock source from 96MHz PLL/2
#pragma config FOSC = HS
#pragma config FCMEN = OFF
#pragma config IESO = OFF
#pragma config PWRT = OFF
#pragma config BOR = ON
#pragma config BORV = 3
#pragma config VREGEN = ON //USB Voltage Regulator = ON
#pragma config WDT = OFF
#pragma config WDTPS = 32768
#pragma config MCLRE = ON
#pragma config LPT1OSC = OFF
#pragma config PBADEN = OFF
#pragma config CCP2MX = OFF
#pragma config STVREN = ON
#pragma config LVP = OFF
#pragma config ICPRT = OFF // Dedicated In-Circuit Debug/Programming = OFF
#pragma config XINST = OFF // Extended Instruction Set = OFF
#pragma config CP0 = OFF
#pragma config CP1 = OFF
#pragma config CP2 = OFF
#pragma config CP3 = OFF
#pragma config CPB = OFF
#pragma config CPD = OFF
#pragma config WRT0 = OFF
#pragma config WRT1 = OFF
#pragma config WRT2 = OFF
#pragma config WRT3 = OFF
#pragma config WRTB = OFF // Boot Block Write Protection = OFF
#pragma config WRTC = OFF
#pragma config WRTD = OFF
#pragma config EBTR0 = OFF
#pragma config EBTR1 = OFF
#pragma config EBTR2 = OFF
#pragma config EBTR3 = OFF
#pragma config EBTRB = OFF
void delay_us(int);
void delay_ms(int);
void i2c_init(void);
void i2c_enable(void);
void lcd_init(void);
void lcd_clear(void);
void lcd_write(unsigned char, unsigned char, const unsigned char*);
unsigned char ADT7410_Get_regvalue(unsigned char);
void LPS331AP_Put_regvalue(unsigned char, unsigned char);
unsigned char LPS331AP_Get_regvalue(unsigned char);
void itostring(unsigned char, int, unsigned char*);
void ftostring(int, int, float, unsigned char*);
unsigned char interval_flag = 0;
int temp_value;
int loop_cnt, stop_cnt, total_time;
char string[10];
float temp, pressure;
void interrupt isr(void){
interval_flag = 1;
LED = 1;
INTCONbits.TMR0IF = 0; // Clear Interrupt Flag
TMR0H = 255 - 76 + 1; // 1s
TMR0L = 0;
}
void init(void){
ADCON1 = 0b00001111; // All Digital
CMCON = 0b00000111; // No Comparator
TRISA = 0b00000000;
TRISB = 0b00000000;
TRISC = 0b00000000;
TRISD = 0b00000000;
TRISE = 0b00000011;
LATA = 0b00000000;
LATB = 0b00000000;
LATC = 0b00000000;
LATD = 0b00000000;
LATE = 0b00000000;
}
void main(void){
unsigned char high_byte, low_byte, dummy;
union pressuer_data {
unsigned char pressure_byte[4];
unsigned long pressure_LONG;
} s;
init();
i2c_init();
i2c_enable();
lcd_init();
lcd_clear();
lcd_write(0, 0, "JF1VRR");
delay_ms(1000);
T0CON = 0x87; //10bit mode, 1:256
TMR0H = 255 - 76 + 1;
TMR0L = 0;
INTCONbits.TMR0IE = 1;
temp = 0.0;
interval_flag = 1;
INTCONbits.PEIE = 1;
INTCONbits.GIE = 1;
dummy = LPS331AP_Get_regvalue(WHO_AM_I);
if(dummy != 0xBB) {
lcd_write(0, 0, "Fail 331");
while(1);
} else
lcd_write(0, 0, "OK 331 ");
delay_ms(1000);
LPS331AP_Put_regvalue(CTRL_REG1, 0x90);
while(1){
if(interval_flag){
while((LPS331AP_Get_regvalue(STATUS_REG) & 0x01) == 0);
high_byte = LPS331AP_Get_regvalue(TEMP_OUT_H);
low_byte = LPS331AP_Get_regvalue(TEMP_OUT_L);
temp_value = (high_byte << 8) + low_byte;
temp = 42.5 + ((float)temp_value / 480.0);
while((LPS331AP_Get_regvalue(STATUS_REG) & 0x02) == 0);
s.pressure_byte[3] = 0;
s.pressure_byte[2] = LPS331AP_Get_regvalue(PRESS_OUT_H);
s.pressure_byte[1] = LPS331AP_Get_regvalue(PRESS_OUT_L);
s.pressure_byte[0] = LPS331AP_Get_regvalue(PRESS_POUT_XL_REH);
pressure = s.pressure_LONG / 4096.0;
ftostring(4, 2, temp, string);
string[7] = 0;
lcd_write(0, 0, string);
lcd_write(7, 0, "C");
ftostring(4, 2, pressure, string);
string[7] = 0;
lcd_write(0, 1, string);
lcd_write(7, 1, "H");
interval_flag = 0;
LED = 0;
} //if
} //while
} //main
i2c_lps331ap.c
#include <xc.h>
#include <p18f4553.h>
#define LPS331AP_I2C_ADDR 0xB8
#define WRITE_MODE 0x00
#define READ_MODE 0x01
void delay_us(int);
void delay_ms(int);
void LPS331AP_Put_regvalue(unsigned char reg_address, unsigned char data);
unsigned char LPS331AP_Get_regvalue(unsigned char reg_address);
void LPS331AP_Put_regvalue(unsigned char reg_address, unsigned char byte){
SSPCON2bits.SEN = 1;
while(SSPCON2bits.SEN == 1);
SSPBUF = LPS331AP_I2C_ADDR | WRITE_MODE;
while(SSPSTATbits.BF);
if (SSPCON2bits.ACKSTAT){
SSPCON2bits.PEN = 1;
while(SSPCON2bits.PEN);
return;
}
delay_us(100);
SSPBUF = reg_address;
while(SSPSTATbits.BF);
if (SSPCON2bits.ACKSTAT){
SSPCON2bits.PEN = 1;
while(SSPCON2bits.PEN);
return;
}
delay_us(100);
SSPBUF = byte;
while(SSPSTATbits.BF);
if (SSPCON2bits.ACKSTAT){
SSPCON2bits.PEN = 1;
while(SSPCON2bits.PEN);
return;
}
delay_us(100);
SSPCON2bits.PEN = 1;
while(SSPCON2bits.PEN);
return;
}
unsigned char LPS331AP_Get_regvalue(unsigned char reg_address){
unsigned char reg_value;
SSPCON2bits.SEN = 1;
while(SSPCON2bits.SEN == 1);
SSPBUF = LPS331AP_I2C_ADDR | WRITE_MODE;
while(SSPSTATbits.BF);
if (SSPCON2bits.ACKSTAT){
SSPCON2bits.PEN = 1;
while(SSPCON2bits.PEN);
return(0);
}
delay_us(10);
SSPBUF = reg_address;
while(SSPSTATbits.BF);
if (SSPCON2bits.ACKSTAT){
SSPCON2bits.PEN = 1;
while(SSPCON2bits.PEN);
return(0);
}
delay_us(10);
SSPCON2bits.RSEN = 1;
while(SSPCON2bits.RSEN);
SSPBUF = LPS331AP_I2C_ADDR | READ_MODE;
while(SSPSTATbits.BF);
if (SSPCON2bits.ACKSTAT){
SSPCON2bits.PEN = 1;
while(SSPCON2bits.PEN);
return(0);
}
delay_us(10);
SSPCON2bits.RCEN = 1;
while(SSPCON2bits.RCEN);
reg_value = SSPBUF;
while(SSPSTATbits.BF);
SSPCON2bits.ACKDT = 1;
delay_us(10);
SSPCON2bits.PEN = 1;
while(SSPCON2bits.PEN);
return(reg_value);
}
(JF1VRR)