目次

ソーラーパネル発電モニタ

 手元には、数種類のソーラーパネルがあります。

 晴天、曇天、降雨のときに、どれくらいの発電量と
 なるのかを知りたいので、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');
}

 電圧バッファを除いた回路は、単純です。




目次

inserted by FC2 system