前記事で触れたN-VANで使っている自作サブバッテリーモニターです。SBC-004とSMF31MS-850の間に入れています。機能は以下のとおり。
・サブバッテリー電圧、充電電流表示
・長時間タイマー付サブバッテリー電源供給回路
・インバーターON/OFF用リレーコントロール(30分で自動OFF)
![](https://cdn-ak.f.st-hatena.com/images/fotolife/t/tsuru3/20240527/20240527195947.jpg)
・起動するとサブバッテリーの電圧と充電電流を表示します。
・長時間タイマー付サブバッテリー電源供給回路はサブバッテリーからPower MOSFET経由で出力しています。ACC ONで自動ON、サブバッテリーの過放電を防ぐためACC OFF後24時間で自動OFFします。残り時間は液晶右下に表示。ENGELのポータブル冷蔵庫、ルームランプ、車載USB電源などに使っています。電源供給中は液晶のバックライトがONになり、LEDが点滅します。
・中央のプッシュスイッチで12V→100Vインバーター制御用のリレーをON/OFFします。サブバッテリーの過放電を防ぐためON後30分で自動OFFします。残り分数は液晶右上に表示。インバーターにコントロール端子が無い場合はリレー出力をインバーターの電源スイッチと並列にはんだ付けします。リレーON時は液晶のバックライトがONになり、OFFタイマー付電源供給回路もその後24時間ONになり、液晶下のLEDが点灯します。
回路図は以下のとおり。使っている液晶パネルは秋月のAQM0802A-FLW-GBWです。
![](https://cdn-ak.f.st-hatena.com/images/fotolife/t/tsuru3/20240527/20240527200448.png)
サブバッテリーモニター回路図
制御プログラムは以下のとおり(少し大きい)。消費電力を抑えるためにClockは1MHzで動作。初期化後は125msおきのタイマー割り込みで電源OFFタイマーを減算。フォアグラウンド側で電圧・電流測定、タイマー値を見て電源・リレーON/OFF、ACC電圧とプッシュスイッチON/OFFの確認などを行っています。
#include#pragma config FCMEN=OFF #pragma config IESO=OFF #pragma config CPD=OFF #pragma config CP=OFF #pragma config BOREN=ON #pragma config MCLRE=OFF #pragma config PWRTE=OFF #pragma config LVP=OFF // #pragma config WDTE=OFF #pragma config FOSC=INTOSCIO #define _XTAL_FREQ 1000000 #define TMR1H_VAL 0x85 // 65536-31250=34286=0x85ee #define TMR1L_VAL 0xee // 31250 * 4us = 125ms period #define RELAY_TIME 30 // relay on time 30min. #define EXT_POW_TIME 24 // ext. power on time 24H. #define RELAY RA7 #define ACC RA6 #define PUSH_SW RA5 #define EXT_POW RA1 #define LED_R RB5 #define SCL RB4 #define LED_BL RB2 #define SDA RB1 #define PANEL_POW RB0 #define TRIS_SDA TRISB1 #define LCD_ADDR 0x7c #define ON 1 #define OFF 0 unsigned char t_rm=0, t_rs=0; // relay-on counter t_rm:minute, t_rs:second unsigned char t_ph=0; // external power-on counter unsigned int t_ps=0; unsigned char timer_flag=0, disp_refresh=0; void pic_init(void) { OSCCON = 0x40; // INTOSC 1MHz ANSEL = 0x09; // RA3:VSB, RA0:CSNS PORTA = 0x00; PORTB = 0x12; // SCL=1, SDA=1 TRISA = 0x79; // RA7:RELAY, RA6:ACC, RA5:PUSH-SW, RA4: // RA3:VSB, RA2:, RA1:Ext_Pow, RA0:CSNS TRISB = 0x00; // RB5:LED_R, RB4:SCL, RB1:SDA, RB0:PANAL_POW OPTION_REG = 0xff; // PORT B weak pull up disable // adc setup ADCON0 = 0b00000001; // clock=fosc/2, a/d enable ADCON1 = 0b10000000; // right justified, Vdd/Vss ref // timer1 setup T1CON = 0b00000100; // T1CKPS:1/1 T1OSCEN:F *T1SYNC:F TMR1CS:INT TMR1ON:F // timer1 clock freq. is 1MHz/4/1=250KHz PEIE = ON; // all peripheral interrupts enable GIE = ON; // global interrupt enable TMR1H = TMR1H_VAL; // set timer1 interrupt period TMR1L = TMR1L_VAL; TMR1IE = ON; // timer1 interrupt enable TMR1ON = ON; // timer1 start return; } // read adc 'sample' times, return value: 0x0000-0xffff unsigned int adc_read( unsigned char ch, unsigned char sample ) { unsigned int value; // adc value unsigned char i; ADCON0 = (unsigned char)( (ch<<3) | 0b00000001); // right justified, VDD ref, ADON // measure 'sample' times for noise reduction for( i = 0, value = 0; i < sample; i++ ){ GO_nDONE = 1; // ADC start while( GO_nDONE ) continue; value += ADRESH*256+ADRESL; } return value; } void i2c_start(){ SDA = 1; SCL = 1; SDA = 0; SCL = 0; return; } unsigned char i2c_write(unsigned char d){ unsigned char i, ack; for (i=0; i<8; i++){ SDA = (d & 0x80)? 1: 0; SCL = 1; // send 1bit SCL = 0; d <<= 1; // next bit } TRIS_SDA = 1; // SDA input mode SCL = 1; ack = SDA; SCL = 0; TRIS_SDA = 0; // SDA output mode return(ack); } void i2c_stop(){ SDA = 0; SCL = 1; SDA = 1; return; } void lcd_cmd(unsigned char cmd){ i2c_start(); i2c_write(LCD_ADDR); i2c_write(0x00); i2c_write(cmd); i2c_stop(); __delay_us(30); return; } void lcd_putc(unsigned char data){ i2c_start(); i2c_write(LCD_ADDR); i2c_write(0x40); i2c_write(data); i2c_stop(); __delay_us(30); return; } void lcd_puts(unsigned char pos, unsigned char* s){ lcd_cmd( pos ); while(*s){ lcd_putc(*s++); } return; } void lcd_init(){ TMR1IE = OFF; // timer1 interrupt disable TMR1ON = OFF; // timer1 stop PANEL_POW = 1; // LCD power on __delay_ms(40); lcd_cmd(0x38); lcd_cmd(0x39); lcd_cmd(0x14); lcd_cmd(0x70); lcd_cmd(0x52); lcd_cmd(0x6c); __delay_ms(200); lcd_cmd(0x38); lcd_cmd(0x0c); lcd_puts(0x80, (unsigned char*)"SUB BATT"); lcd_puts(0xc0, (unsigned char*)" MONITOR"); __delay_ms(1000); lcd_cmd(0x01); __delay_ms(2); lcd_puts(0x84, (unsigned char*)"V"); lcd_puts(0xc4, (unsigned char*)"A"); TMR1ON = ON; // timer1 start TMR1IE = ON; // timer1 interrupt enable return; } void bin2str4(unsigned int val, unsigned char *b){ union{ unsigned long int bd32; struct{ unsigned bd8l : 8; unsigned bd8h : 8; unsigned bcd0 : 4; unsigned bcd1 : 4; unsigned bcd2 : 4; unsigned bcd3 : 4; }bcd; }work; char i; work.bd32 = (unsigned long int)val; for(i = 0; i < 16; i++){ if(work.bcd.bcd0 >= 5) work.bcd.bcd0 += 3; if(work.bcd.bcd1 >= 5) work.bcd.bcd1 += 3; if(work.bcd.bcd2 >= 5) work.bcd.bcd2 += 3; if(work.bcd.bcd3 >= 5) work.bcd.bcd3 += 3; work.bd32 <<= 1; } b[0] = (work.bcd.bcd2)? work.bcd.bcd2 + '0': ' '; b[1] = work.bcd.bcd1 + '0'; b[2] = '.'; b[3] = work.bcd.bcd0 + '0'; b[4] = 0x00; return; } void bin2str2(unsigned char val, unsigned char *b){ union{ unsigned short int bd16; struct{ unsigned bd8 : 8; unsigned bcd0 : 4; unsigned bcd1 : 4; }bcd; }work; char i; work.bd16 = (unsigned short int)val; for(i = 0; i < 8; i++){ if(work.bcd.bcd0 >= 5) work.bcd.bcd0 += 3; if(work.bcd.bcd1 >= 5) work.bcd.bcd1 += 3; work.bd16 <<= 1; } b[0] = (work.bcd.bcd1)? work.bcd.bcd1 + '0': ' '; b[1] = work.bcd.bcd0 + '0'; b[2] = 0x00; return; } void __interrupt() timer1_overflow(void) { static unsigned char freerun=0; TMR1ON = OFF; // stop timer1 TMR1IF = OFF; // clear timer1 interrupt flag TMR1H = TMR1H_VAL; // reset timer1 TMR1L = TMR1L_VAL; TMR1ON = ON; // restart timer1 timer_flag = 1; freerun++; if(!(freerun & 0x07)){ // once per 8 interrupts disp_refresh = 1; if(t_rm){ t_rs++; // count up relay timer if(t_rs >= 60){ t_rs = 0; t_rm--; } } if(t_ph){ t_ps++; // count up ext.pow timer if(t_ps >= 3600){ t_ps = 0; t_ph--; } } } return; } void main(void) { unsigned char state; unsigned char s_flag=OFF, s_ctr=16; unsigned int batt, csns; // sub battery voltage and charge current unsigned char disp[5]; // LCD display buffer pic_init(); lcd_init(); while(1){ while(!timer_flag) ; timer_flag = 0; if(disp_refresh){ disp_refresh = 0; batt = (adc_read(3, 72)+0x80)>>8; //voltage:175mV/V bin2str4(batt, disp); lcd_puts(0x80, disp); csns = adc_read(0, 63)>>6; //csns:50mV/A bin2str4(csns, disp); lcd_puts(0xc0, disp); bin2str2(t_rm, disp); // relay on timer lcd_puts(0x86, disp); bin2str2(t_ph, disp); // ext.power on timer lcd_puts(0xc6, disp); if(t_rm){ RELAY = ON; // relay power on LED_R = ON; }else{ RELAY = OFF; // relay power off LED_R = OFF; } if(t_ph){ EXT_POW = ON; // ext.power on LED_BL = ON; // backlight on if(!t_rm){ LED_R = ON; // LED on __delay_ms(10); LED_R = OFF; // LED off } }else{ EXT_POW = OFF; // ext.power off LED_BL = OFF; // backlight off } } if(!PUSH_SW){ // switch pushed if(s_flag&&s_ctr){ // pushed continuously s_ctr--; } s_flag=ON; }else{ if(s_flag){ // switch pushed->released if(s_ctr){ // pushed less than 2 sec. if(!t_rm){ // relay is off? t_rm = RELAY_TIME; // turn on relay 30min. t_ph = EXT_POW_TIME; // turn on ext.pow 24h }else{ t_rm = 0; // turn off relay } t_rs = t_ps = 0; }else{ // pushed more than 2 sec. t_rm = t_rs = t_ph = t_ps = 0; // clear relay & ext_pow. timer lcd_init(); // initialize LCD __delay_ms(100); // prevent sw. chattering } } s_flag=OFF; s_ctr=16; // 16*125ms=2sec } if(ACC){ t_ph = EXT_POW_TIME; // hold ext.power 24h after ACC-OFF t_ps = 0; } } return; }