目次
前
次
ソーラーパネル発電モニタ
手元には、数種類のソーラーパネルがあります。
晴天、曇天、降雨のときに、どれくらいの発電量と
なるのかを知りたいので、PICで発電モニタを開発
しました。
電圧測定になるので、次の外部回路を接続しています。
回路は単純で、ソーラーパネルの出力電圧を約1/10にし
OPアンプをバッファとして使い、A/Dコンバータで2進
に変換します。
A/D変換器内蔵のPICの手持ちは、PIC16F873A、PIC16F876A
があるので、どちらかをバッファに接続して、ノートPCの
端末ソフトで、発電状況をモニタします。
テスト基板は、28ピンのPICをのせるタイプを使います。
A/DコンバータはポートRAにあるので、RA0ピンを
電圧バッファから入力ピンとします。
入力ピンを決めたので、A/D変換値を入力する
専用関数get_adcを定義します。
A/D変換値を入力するタイミングは、3秒間として
タイマー割込みでフラグ通知し、すでに定義した
get_adcで入力します。その値を端末ソフトに渡す
とよいので、そのコードを定義します。
if ( tflag == ON ) {
/* clear flag */
tflag = OFF ;
/* get A/D value */
val = get_adc() ;
/* convert */
*(xmsg+0) = (val / 1000) + '0' ; val %= 1000 ;
*(xmsg+1) = (val / 100 ) + '0' ; val %= 100 ;
*(xmsg+2) = (val / 10 ) + '0' ;
*(xmsg+3) = (val % 10 ) + '0' ;
*(xmsg+4) = '\0' ;
/* show */
rs_puts( xmsg );
rs_putchar(' ');
/* judge new line */
state++ ;
if ( state == 8 ) {
state = 0 ;
crlf();
}
}
内蔵A/Dコンバータの精度は10ビットなので、最大でも
1023までになります。端末ソフトで数字として見える
ように、ASCIIコードに変換してから出力します。
また、1行に8データを表示して、比較しやすいよう
にしました。
タイマー割込みは、周期を1msごとにして、3000ms経過
したならが、フラグで通知します。
void interrupt(void)
{
/* generate 1ms */
if ( INTCON.TMR0IF == ON ) {
/* clear flag */
INTCON.TMR0IF = OFF ;
/* initialize */
TMR0 = 6 ;
/* increment */
timcnt++ ;
/* judge 3000ms pass */
timv = timcnt & MASKFFFF ;
if ( timv == 3000 ) { TFLAG = ON ; }
}
}
主な部分を定義したので、ソースコードにまとめます。
/* redefine data type */
typedef unsigned char UBYTE ;
typedef unsigned int UWORD ;
typedef unsigned long ULONG ;
#define OFF 0
#define ON OFF+1
#define MASKFFFF 0xffff
#define MASK3FF 0x3ff
#define START_BIT 1
UBYTE tflag ;
ULONG timcnt ;
UWORD timv ;
UBYTE state ;
UBYTE mystate ;
UWORD val ;
UBYTE xmsg[5];
/* function prototype */
void init_usr(void);
UWORD get_adc(void);
void rs_putchar(UBYTE x);
void rs_puts(UBYTE *ptr);
void crlf(void);
/* interrupt handler */
void interrupt(void)
{
/* generate 1ms */
if ( INTCON.TMR0IF == ON ) {
/* clear flag */
INTCON.TMR0IF = OFF ;
/* initialize */
TMR0 = 6 ;
/* increment */
timcnt++ ;
/* judge 3000ms pass */
timv = timcnt & MASKFFFF ;
if ( timv == 3000 ) { TFLAG = ON ; }
}
}
void main(void)
{
/* user initialize */
init_usr();
/* endless loop */
while ( ON ) {
/* 3 second handling */
if ( tflag == ON ) {
/* clear flag */
tflag = OFF ;
/* get A/D value */
val = get_adc() ;
/* convert */
*(xmsg+0) = (val / 1000) + '0' ; val %= 1000 ;
*(xmsg+1) = (val / 100 ) + '0' ; val %= 100 ;
*(xmsg+2) = (val / 10 ) + '0' ;
*(xmsg+3) = (val % 10 ) + '0' ;
*(xmsg+4) = '\0' ;
/* show */
rs_puts( xmsg );
rs_putchar(' ');
/* judge new line */
state++ ;
if ( state == 8 ) {
state = 0 ;
crlf();
}
}
}
}
/* define function body */
void init_usr(void)
{
/* enable A/D converter */
ADCON0 = 0x01 ;
ADCON1 = 0x8e ;
/* ADFRM = 1 (right justify) RA0 : analog input , others digital */
/* disable Analog comparator */
CMCON = 0x07 ;
/* I/O initial state */
PORTA = 0x00 ;
PORTB = 0x00 ;
PORTC = 0x00 ;
/* I/O direction */
TRISA = 0x01 ;
TRISB = 0x00 ;
TRISC = 0x80 ;
/* initialize Timer 0 */
{
/*
4MHz/4 = 1MHz -> 1MHz/4 = 250kHz prescaler = 1:4
all inputs are pull-up .
*/
OPTION_REG = 0x01 ;
/* 256 - 250 = 6 */
TMR0 = 6 ;
/* enable timer0 overflow interrupt */
INTCON.TMR0IE = ON ;
}
/* initialize serial interface */
{
/* BAUD rate */
SPBRG = 25 ; /* 9600bps */
/* TxD */
TXSTA.TXEN = ON ;
TXSTA.SYNC = OFF ;
TXSTA.BRGH = ON ;
/* RxD */
RCSTA.SPEN = ON ;
RCSTA.CREN = ON ;
}
/* enable general interrupt */
INTCON.GIE = ON ;
/* clear flag */
tflag = OFF ;
/* others */
timcnt = 0 ;
state = 0 ;
}
UWORD get_adc(void)
{
UWORD result ;
/* start conversion */
ADCON1 |= (1 << START_BIT) ;
/* wait */
while ( ADCON1 & (1 << START_BIT) ) ;
/* get data */
result = ADRESH ;
result <<= 8 ;
result |= ADRESL ;
/* mask */
result &= MASK3FF ;
return result ;
}
void rs_putchar(UBYTE x)
{
/* judge */
while ( !TXSTA.TRMT ) ;
/* set data */
TXREG = x ;
}
void rs_puts(UBYTE *ptr)
{
while ( *ptr ) {
rs_putchar( *ptr );
ptr++ ;
}
}
void crlf(void)
{
rs_putchar('\r');
rs_putchar('\n');
}
電圧バッファを除いた回路は、単純です。
目次
前
次