電子工作 29 – 太陽光追跡装置の試作

 

概要

エコの時代の到来。戦後の窮乏の時代子供ながら近くの山に入って杉の落ち葉(すぎっぱ)を拾ってご飯の煮炊や風呂沸かしの燃料に使う経験をした。大量にエネルギーを使う今の生活は何か変だぞと多少なりとも後ろめたい気持ちを持ち続けてきた。

          長屋の窓にもさんさんと太陽の光が当たるのでいつか集めて利用してみたいと考えていた。 太陽電池は折りにつけ見たり聞いたりしてきがどんなものか良く分からなかった。早速、たまたま開催中の太陽電池展に行って見分を広めてきた。小生なりの結論は”シリコンに頼らぬ太陽電池の出現などで近い将来価格が間違いなく急激に低下しそうだ”ということである。そんなわけでエコに役立ちそうな太陽電池に関係した電子工作をやってみることにした。

  手初めに太陽追跡装置を試作してみた。家庭用の太陽電池パネルはほとんどが固定式で太陽の動きによって発電出力が大きく変化することが考えられるからである。

秋月電子で1000円で販売されているソーラーバッテリーチャージャー(Model No. ES885、3,6,9,12V を切替えで出力できる)を入手し実験に使うことにした。ついでに 円形のシリコン太陽電池モジュール(ETM500-2V(RQ)、2V 500mA) 3枚を後日使う目的で入手した。価格(@650円)がてごろで、1枚当たりの出力が2Vというのも扱いやすいようである。

 

回路

  全体回路を下に示す。主要コンポーネントは太陽電池(ソーラーバッテリーチャージャー)、それを回転させるDCモータ、2個のリミットスイッチ、周囲の明暗を検知するCdS明るさセンサ、それに、全体を制御する16F819である。DCモータはMotor driver ICで制御する。全体の電源はACアダプタと三端子レギュレータでつくるDC+5Vである。

  太陽電池の出力電圧は切換えられる。その値が晴天下、太陽に直すぐに面している時+5V以下になるように切替えて使う。これは16F819のADC(アナログーデジタルコンバータ)の基準電圧としてDC+5Vの電源電圧を使っているからである。2個のリミットスイッチ(Limit SW (West)/(East): LSWw/LSWe とも表示)にはノイズ防止用の0.1uFコンデンサが必ず必要で、それらがないと誤動作でシステムが動かない(2週間ほど苦しめられた)。DCモータはMotor driver IC (TA7267BP) の2つのピンに0 や1(High や Low)を送って正転/逆転を制御する。このギヤモータは12V32rpmの仕様であるがDC+5Vで0.3秒間の通電にもきれいに応答する。その回転スピードはVR 100 ohmで制御できる。そして動作時には50−55mA程度の電流が流れる。DCモータを使う利点は通電時以外電気を消費しないことである。つまり太陽電池が太陽に当たっている15分間毎にせいぜい10秒間弱ほど通電されるだけである。下に使用した Motor driver TA7267BPの機能を示す。

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 下に実験の様子を示す。光源として100Wの白熱電球を用いた。それを可動アーム付きスタンドに取付けいろんな方向から太陽電池にあて、それがどう動くか調べた。光源が約20センチ上にある時、太陽電池の表面での明るさは600−700Lux位であった(cf. 太陽光は40,000Lux 以上)。 この状態で、16F819が取り込む太陽電池からの入力電圧Vscellが5.0V以下になるように太陽電池の電圧切換えSWで調整した。図で左下にDCモータ、その上に太陽電池が見える。両者間はシャフトでつながれているがリミットスイッチに接触した時などのために、モータの回転力に対して一定以上の逆の力がかかるとスリップするように工夫してある。16F819はボードのほぼ中央に見える。

 

プログラミング

フローチャート

  太陽光追跡装置のフローチャートを下に示す。今回のものは単純に太陽電池パネルを東より西方向に回転させて太陽を追うだけで、南北方向には動かない。 

動作は次のような原理に基づく。

1) CdS明るさセンサで周囲の明るさを電圧として読み取り、その値が設定値より高くなった時次のステップに進む。そうでなければ待つ。

2) モータを回して太陽電池を最も東寄りに戻す(リミットスイッチLSWeで検知)。ここが出発点になる。

3) モータを0.3秒間西方向に回わして停止し、太陽電池の出力電圧Vscellを測定しこの値をVscell1とする。

4) さらにモータを0.3秒間西方向に回わして停止し、太陽電池の出力電圧Vscellを測定しこの値をVscell2とする。

5) Vscell1とVscell2とを比較し2通りに分ける。

a)         Vscell2が大きい場合、2値の差の絶対値を求め、その値が3−5(0.015 -0.024Vに相当し、太陽光にどれだけ直角に向いているかの指標に使う)以下なら、太陽電池を15分間停止して太陽にあてる。そうでない場合は上記3)に戻ってさらに西方向に回転させ前と同様のステップを繰り返えさせる。これらの動作を西端のLSWw(リミットスイッチ西)に接触するまで続けさせ、接触したらSTARTに戻る。

b)         一方、Vscell1が大きい場合、上記と同様に2値の差の絶対値を求め、その値が3−5以下なら15分間停止して太陽にあてる。LSWwへの接触チェックをして、接触していたらSTARTに戻る。そうでない場合、つまり2値の差の絶対値が3−5以上の場合は、太陽電池が回転し過ぎ(西に傾き過ぎ)と考え、モータを逆転させ元に戻す動作をさせる。

 以上のような動作を太陽が照って明るいうち繰り返えさせる。なお、ここではVscell1とVscell2の差だけを動作原理に利用しているので各値の大きさは原則関係しない。

 

プログラム

************ 備忘録 ************

'Name of program: SolarPrG.bas (08.4.14)   modified from SolarPrB.bas

‘プログラム作成が思うようにいかず1か月位かかってしまった。

‘今回のプログラミングの要点はサブルーチンを出来るだけ多く使ってプログラム本体の部分の構造を簡単にしたことである。

Vcds (16bits) などをWord型で宣言することを忘れ思いつくまで大変だった。

‘サブルーチン、例えばMoveWestSamp(West方向へ回転しサンプル2個採取)の中で別のサブルーチン(例えば、Gosub Vscellread)に2重にアクセスしたが問題なかった。

 

 

'************* Pin connection **************

'Pin 14 - Vdd (+5V)

'Pin 5 - Vss (1GND)

'Pin 4 - /MCLR for reset

'Pin 17 - RA0/AN0 - voltage input from CdS sensor

'Pin 18 - RA1/AN1 - voltage input from Solar cell

'Pin 12 - RB6 - H/L input from limit SW (East), pulled up with 10K

'Pin 13 - RB7 - H/L input from limit SW (West), pulled up with 10K

'Pin 7 - RB1 - H/L output to Pin 1 of motor driver

'Pin 8 - RB2 - H/L output to Pin 2 of motor driver

'Pin 11 - RB5 - Output to LED as CdS indicator

 

'************* プログラム本体 **************

'---- Initial setting ----

Start:

 

Define ADC_BITS 10      '10-bit ADC used

Define ADC_CLOCK 3     'Internal clock used

Define ADC_SAMPLEUS 50 'Sample timing

 

INTCON.7=0        'Disable all PORTB pins to be used as digital pins 重要!

OSCCON=%01100000 '(=$60) Internal 4MHz selected 重要!

ADCON1=%10000000 'Right justified, ADCS2=0, PA0-AN4=analog, RA6-RA7=digital? 重要!

   

TRISA=%00100111  'RA0-2 and RA5=inputs

TRISB=%11000000  'RB6-7=inputs

 

Vcds var word        'Very very important - Vcds is 16-bit data 重要!

Vscell var word       'Vscell - voltage from Solar cell

Vscell1 var word

Vscell2 var word

Motorp1 var PORTB.1    'Motor driver pin1

Motorp2 var PORTB.2    'Motor driver pin2

LimSWe Var PORTB.6    'East-end Limit Switch

LimSWw Var PORTB.7    'West-end Limit Switch

LEDcds var PORTB.5     'LED Red

t var byte               'Variable for timer

 

'---- Wake-up in the morning ----

Motorp1=0

Motorp2=0

LEDcds=0

t=0

 

'---- Outside brightness check routine 周囲の明るさをチェックしOKなら動作開始

Cdsloop:      

Gosub Vcdsread   ‘Read Vcds from CdS sensor

Gosub Vscellread  ‘Read Vscell from Solar cell   

If (Vcds>300) then ‘300 (equivalent to 1.46V) = brightness

Pause 2000

High LEDcds      'LED Red -> ON when Vcds exceeds 300

Goto Jump0

Else

Goto Cdsloop

Endif

 

'---- Moving Motor to LSWe then toward West 東端リミットSWに当たっているか?

Jump0:

Motorp1=0

Motorp2=0

 

LSWeLoop:         'LSWe contact check

Gosub ToEast      'Move motor toward East until LSWe

If LimSWe=0 then

Gosub Motorstop  

Gosub ToWest      'Move motor a little toward West

Pause 1000         '1 sec

Gosub Motorstop

Pause 1000

Else

Goto LSWeLoop

Endif

 

'---- Measuring Vscell 太陽電池の出力電圧を測定する

Motorp1=0

Motorp2=0

 

ToWestmove:

'Pause 500

Gosub MoveWestSamp  'West move & sample Vscell1/2西方向へ移動しVscell1/2を測定する

Jump1:

If  (Vscell2>=Vscell1) then  2値の比較

Pause 100

  If ABS (Vscell2-Vscell1) <3 then ‘2値の差の絶対値をチェックする

  Gosub ExposeSun           ‘太陽にあてるサブルーチン

     If LimSWw=0 then         ‘西端リミットSWに当たっているか?

     Pause 100

     Goto Start             ‘START へ戻る

     Else

     Pause 500

     Goto ToWestmove

     Endif

  Else

  Goto ToWestmove

  Endif

Else

  If ABS (Vscell2-Vscell1) <3 then

     Pause 500

     Gosub ExposeSun

       If LimSWw=0 then

       Pause 100

       Goto Start

       Else

       Pause 500

       Goto ToWestmove

       Endif

     Else

     Pause 1000

     Gosub MoveEastSamp

     Goto Jump1

     Endif

Endif

 

'***** Subroutines サブルーチン群 

'--- Move to West/East to sample Vscell1 & Vscell2 - these subrs works OK!

MoveWestSamp:   'Moves to West, stops for 0.3 sec and sample Vscell1

Gosub ToWest   '西方向へ0.3秒ずつ2回動いてVscell1とVscell2を測定する

Pause 300  '0.3 sec

Gosub Motorstop

Gosub Vscellread

Vscell1=Vscell

Pause 1000

Gosub ToWest

Pause 300  '0.3 sec

Gosub Motorstop

Gosub Vscellread

Vscell2=Vscell

Pause 1000

Return

 

MoveEastSamp:  'Moves to East, stops for 0.5 sec and sample Vscell1

Gosub ToEast  '東方向へ0.3秒ずつ2回動いてVscell1とVscell2を測定する

Pause 300  '0.3 sec

Gosub Motorstop

Gosub Vscellread

Vscell2=Vscell    'Note: 2 instead of 1  MoveWestSampの場合と逆である

Pause 1000

Gosub ToEast    'Moves to East, stops for 0.5 sec and sample Vscell2

Pause 300   '0.3 sec

Gosub Motorstop

Gosub Vscellread

Vscell1=Vscell    'Note:  1 instead of 2

Pause 1000

Return

 

'--- Vcds & Vscell calculation subroutines  VcdsとVscellを読取るサブルーチン

Vcdsread:            'CdS voltage reading subroutine

ADCON0=%10000101   'Read from ch0 

ADCIN 0, Vcds        ‘Read from ch0 (Pin17) and store data in Vcds

Pause 50

Return

 

Vscellread:           ‘Vscell reading subroutine

ADCON0=%10001101   'Read from ch1 重要!

ADCIN 1, Vscell       ‘Read from ch1 (Pin18) and store data in Vscell

Pause 50

Return

 

'--- Motor rotation & stop subroutines モータを西・東方向へ回すサブルーチン

ToEast:     'Move to East

Motorp1=1

Motorp2=0

Return

 

ToWest:     'Move to West

Motorp1=0

Motorp2=1

Return

 

Motorstop:  'Stop motor  モータの回転を止めるサブルーチン

Motorp1=0

Motorp2=0

Return

 

'--- Exposing to Sun for 15 min 太陽電池を太陽に15分あてるサブルーチン

ExposeSun:

For t=1 to 15   ’15-min timer            

Pause 60000   ’60 sec

Next

Return

 

End

'*************** プログラムの終わり **************

 

AKI Programmer で書き込み時のConfig. setting

FOSC    INTRC_RA6=I/O

WDTE    Enable

PWRTE   Disable

MCLRE   RA5=MCLR

BODEN   Enable

LVP      RB3=I/O

CPD      Not_Protect

WRT      All_Enable

DEBUG   Disable

CCPMX   CCPI1=RB2

CP       Not_Protect

 

結論・余談

  この試作機は一応動作するが光源を捕えて停止する位置精度がまだ低く完ぺきではない。こん簡単な回路でただ光を大雑把に追跡するだけなのにかくもプログラムをつくるのが大変だとは思なかった。光源(太陽)を追跡する簡単で確実なプログラムロジックがつくれるかどうかがカギになる。代案として、東端から西端へスキャン(電池パネルを回転させる)した後、最大Vscell値が得られた位置で太陽電池に露光させる、といったこと方式が考えられるがプログラムロジックが頭の中で構成できない。

  オシロ測定で、2値間つまり Vscell1とVscell2の電圧差が意外に小さいことが分かった。これも問題の一つのようだ。

  いずれにして実際に実験してみるといろいろなことが経験できる。次につなげたい。 ツカレター!

 

    

改良したプログラム(2008.5.11追加)

  前のSolarPrG.basプログラムでは光源を捕えて停止する位置精度が低くかった。最初の回路図のハードウエアをほぼそのまま用いプログラムの動作原理を以下のように変えたところ、かなり満足できるものになった。すなわち、このスキャン方式は、太陽電池パネルを回転してデータを集め、最大値を探し、その位置にパネルを移動して止める、というものである。

 

動作原理の詳細:  

(1) 太陽電池を、東端(LSWe)より一定の間隔で動かし(例えば0.6 sec動かして1個のデータ採取)、全部で15個の電圧データ A(0)-A(14)を採取しメモリに記憶する。

(2) 次いで、それらのデータの最大値 Maxvalue を計算する。

(3) その最大値に対応するCounter値 “I” を求める。

(4)     再び太陽電池を東端に戻し、(一定の間隔) X I だけ移動し停止する。

(5)     この位置で太陽電池を一定時間(例えば15分間)露光し集電させる。

(6)     露光が終了したら、プログラムの最初 Start から再出発させる。

 

 

 

プログラム

************ 備忘録 ************

'Name of program: SolarSCAN2.bas (2008.5.11)   Completely new method  Works OK!

‘作成に3週間ほどかかった。最大値Maxvalue とそのCounter値“I”を求めるアルゴリズムがなかなか作成できなかったのが原因

‘今回は西端のLSWwはReset SW (Pin 4 /MCLR)につないで、まんいち接触した場合はシステムが停止するように配線する (LSWwのPICのPin 13との結線を外しそれをPICのPIN 4につなぐ)。

 

'******* Pin connection ********

'Pin 14 - Vdd (+5V)

'Pin 5 - Vss (1GND)

'Pin 4 - /MCLR for reset

'Pin 17 - RA0/AN0 - voltage input from CdS sensor

'Pin 18 - RA1/AN1 - voltage input from Solar cell panel (via divider)

'Pin 12 - RB6 - H/L input from limit SW (East), pulled up with 10K

'Pin 13 - RB7 - H/L input from limit SW (West), pulled up with 10K

'Pin 7 - RB1 - H/L output to Pin 1 of motor driver

'Pin 8 - RB2 - H/L output to Pin 2 of motor driver

'Pin 11 - RB5 - Output to LED as CdS indicator

 

'************* プログラム本体 **************

'---- Setting ----

Start:

 

Define ADC_BITS 10     '10-bit ADC used

Define ADC_CLOCK 3     'Internal clock used

Define ADC_SAMPLEUS 50 'Sample timing

 

INTCON.7=0       'Disable all PORTB pins' to be used as digital pins

OSCCON=%01100000 '(=$60) Internal 4MHz selected

ADCON1=%10000000 'Right justified, ADCS2=0, PA0-AN4=analog, RA6-RA7=digital?

   

TRISA=%00100111  'RA0-2 and RA5=inputs

TRISB=%11000000  'RB6-7=inputs

 

A var WORD [14]   'Declair an Array for 15 16-bit data - very important 配列を使う

Max1 var word     '"MAX" and "MIN" (parameters in PBP) cannot be used (Max1). 

Maxvalue var word  'Maximum value found

Vcds var word     'Vcds is 16-bit data

n var BYTE        'Counter

l var BYTE         'Counter

I var byte          'Counter

t var byte          'Counter

m var Byte         'Counter

Motorp1 var PORTB.1     'Motor driver pin1

Motorp2 var PORTB.2     'Motor driver pin2

LimSWe Var PORTB.6     'East-end Limit Switch

LimSWw Var PORTB.7     'West-end Limit Switch

LEDcds var PORTB.5      'LED Red

 

Motorp1=0

Motorp2=0

LEDcds=0

t=0

 

'---- Wake-up routine - Outside brightness check ---- 明るくなったら起動する

Cdsloop:      

Gosub Vcdsread

if (Vcds>300) then '300(1.46V)/brightness

Pause 2000

High LEDcds    'LED Red -> ON when Vcds exceeds 300

Goto Jump0

Else

Goto Cdsloop

Endif

 

'---- Moving Motor to LSWe and then toward West ---- 東端にパネルを移動する

Jump0:

Motorp1=0

Motorp2=0

 

LSWeLoop:         'LSWe contact check

Gosub ToEast      'Move motor toward East

If LimSWe=0 then

Gosub Motorstop

Goto Jump1        'If contacted, go to Jump1

Else

Goto LSWeLoop

Endif

 

'---- Collection of Vscell data at designated points ----

Jump1:        ‘配列を使って0.6 sec ずつ移動しながら合計15個のデータ採取。 この個数は西端LSWwに接触しないようにモータ速度制御VRなどを調整して決める。

n=0

For n=0 To 14         'Read and collect 15 data   太陽電池からの入力を抵抗などを使って2.0−2.5V位に調整すると良い

ADCON0=%10001101   'Read from ch1

ADCIN 1, A(n)         'Store them in A(n) array

Pause 50

Pause 100

Gosub ToWest         'Move to West

Pause 600            '0.6 sec interval  適当に調整する

Gosub Motorstop

Pause 200

Next n

 

Pause 2000

 

'---- Seeking Maxvalue among the collected A(n) array data ----

Max1=0

l=0

Maxvalue=0

 

‘############# 15個のデータの最大値を求めるルーチン ########### : ここから下の<<A>>まで最重要部分

Max1=A(0)                'First data A(0) assumed to be Max1 A(0)を最大値Max1と仮定

For l=1 To 14          

  IF Max1 < A(l) Then     'Comparing Max1 with 2nd data     2番目以下のA(l)と比較して、入替えていく。 最後に得られたMaX1が最大値になる

  Max1=A(l)                                   この値をMaxvalue とする

  Endif

Next l

Maxvalue=Max1           'Max1 is the maximum value found.

 

'---- Return the solar panel to LSWe ----  東端にパネルを戻す

LSWeLoop1:        'LSWe contact check

Gosub ToEast       'Move motor toward East

If LimSWe=0 then

Gosub Motorstop

Goto Jump4        'If contacted, go to Jump4

Else

Goto LSWeLoop1

Endif

 

'---- Seeking "I" value corresponding to Maxvalue ---- Counter値 “I”を求めるルーチン: この部分最難関だった

Jump4:

If Maxvalue=A(0) then goto I0   'A(0)-A(14) data are stored in an array A

If Maxvalue=A(1) then goto I1

If Maxvalue=A(2) then goto I2

If Maxvalue=A(3) then goto I3

If Maxvalue=A(4) then goto I4

If Maxvalue=A(5) then goto I5

If Maxvalue=A(6) then goto I6

If Maxvalue=A(7) then goto I7

If Maxvalue=A(8) then goto I8

If Maxvalue=A(9) then goto I9

If Maxvalue=A(10) then goto I10

If Maxvalue=A(11) then goto I11

If Maxvalue=A(12) then goto I12

If Maxvalue=A(13) then goto I13

If Maxvalue=A(14) then goto I14

 

I0: I=0: goto Jump5     'Ignore the first value and return to Start 最初に戻る

I1: I=1: goto JumpX     'If I=1, go to JumpX.

I2: I=2: goto JumpX

I3: I=3: goto JumpX

I4: I=4: goto JumpX

I5: I=5: goto JumpX

I6: I=6: goto JumpX

I7: I=7: goto JumpX

I8: I=8: goto JumpX

I9: I=9: goto JumpX

I10: I=10: goto JumpX

I11: I=11: goto JumpX

I12: I=12: goto JumpX

I13: I=13: goto JumpX

I14: I=14: goto JumpX

 

JumpX:

For m=0 to I     得られたこの “I”を使って “I” x 0.6 sec だけ太陽電池を動かす

Gosub ToWest

Pause 600

Gosub Motorstop

Pause 200

Next m

 

############### ここまでが最も重要な部分 #############:           ----- <<A>> -----

 

Pause 2000

 

Jump3:

Gosub ExposeSun    '15 min   太陽にあてる

 

Jump5:

Goto Start           'Return to "Start" of the program

 

'****** Subroutines ****** サブルーチン群

Vcdsread:

ADCON0=%10000101   'Read from ch0

ADCIN 0, Vcds

Pause 50

Return

 

ToEast:

Motorp1=1

Motorp2=0

Return

 

ToWest:

Motorp1=0

Motorp2=1

Return

 

Motorstop:

Motorp1=0

Motorp2=0

Return

 

ExposeSun:   

For t=1 to 5   'actually 15 min  ここでは実験の都合で10秒間だが、実際には、一度に15分間ほど露光する ( For t=1to 15, Pause 60000と変える)。         

Pause 2000

Next

Return

'*************** プログラムの終わり **************

 

AKI Programmer で書き込み時のConfig. Setting

前のものと同じ

 

追跡精度

 太陽電池パネルが光源に対してどれくらい正確に停止するか測定してみた。上記写真の実験装置を使い、40W白熱電球を上下東西方向の適当な位置に固定し測定した。電球を上下に動かすと測定電圧値(太陽電池からの)も上下する。 5,15,20,30 cm は電球と太陽電池パネルの間の距離である。10個のデータを採取した。Scan中の最大値とは固定光源の下でパネルが回転してスキャン中にデジタルテスターに表示される目測最大値である。 得られた平均値と最大値の差や標準偏差値から追跡精度はかなり良いことが分かる。

                                                                                           単位: V

 

1

2

3

4

5

6

7

8

9

10

平均値 (標準偏差)

Scan中の最大値

5 cm

3.46

3.46

3.32

3.47

3.47

3.46

3.43

3.40

3.45

3.43

3.44 (0.046)

    3.48 

15 cm

2.57

2.47

2.60

2.54

2.58

2.61

2.57

2.47

2.57

2.59

2.56 (0.049)

    2..61  

20 cm

1.79

1.85

1.86

1.79

1.83

1.79

1.86

1.80

1.86

1.86

1.83 (0.033)

    1.87

30 cm

1.01

1.04

1.02

1.04

0.93

0.99

1.02

1.03

0.98

0.99

1.01 (0,034)

1.04

 

余談

 配列の使い方、集めたデータから最大値Maxvalueを求め、それに対応する“I”の値(counter値)を求めるアルゴリズムを考えだすのがジジイには最もエライ (hard) ことであった。

 上記写真の模擬実験で太陽電池パネルは白熱電球光源軸より多少早めに停止する傾向があるが、光源の動きをかなり正確に追跡することが分かった。

 

 

更に改良したプログラム(2008.5.16追加)

  :上記のSolarSCAN2.bas (2008.5.11)で、太陽電池パネルが回転し西端のLSWwに接触し無理に回転しようとする事態が時折発生することが分かった。そこで、(1)初めのスキャン中にパネルがLSWwに接触したら1.8秒間East方向に戻し停止させLEDalarm (yellow) を15分間点滅させ、その後Startに戻って再出発させる。また(2)求めたCounter値“I”に従ってWest方向に向かっていてパネルがLSWwに接触したらLSWeに戻しStartから再出発させるように変えた。

 

プログラム

************ 備忘録 ************

'Name of program: SolarSCAN2a.bas (2008.5.16)

‘最初の回路図 (2008.4.9) を1個所を除いてそのまま使う。その1個所とはRB3 (Pin 9) にLEDalarm (yellow) を追加したことである。

‘フローチャートはSolarSCAN2,bas のものとは多少違うが, ここでは省略した。

'Modified from SolarSCAN2 - introducing an escape routine for accidental contact with LSWw.

'Namely, if contacted with LSWw in scanning, move backward for 1.8 sec, wait 15 min

'while blinking LEDyellow and finally return to Start again.  

 

'******* Pin connection ********

'Pin 14 - Vdd (+5V)

'Pin 5 - Vss (1GND)

'Pin 4 - /MCLR for reset

'Pin 17 - RA0/AN0 - voltage input from CdS sensor

'Pin 18 - RA1/AN1 - voltage input from Solar cell panel (via divider)

'Pin 12 - RB6 - H/L input from limit SW (East), pulled up with 10K

'Pin 13 - RB7 - H/L input from limit SW (West), pulled up with 10K

'Pin 7 - RB1 - H/L output to Pin 1 of motor driver

'Pin 8 - RB2 - H/L output to Pin 2 of motor driver

'Pin 11 - RB5 - Output to LED as CdS indicator

'Pin 9 - RB3 - Output to LED as LSWw contact alarm indicator  08.5.16

 

'****** Main program ******

 

'---- Setting ----

Start:

 

Define ADC_BITS 10     '10-bit ADC used

Define ADC_CLOCK 3     'Internal clock used

Define ADC_SAMPLEUS 50 'Sample timing

 

INTCON.7=0       'Disable all PORTB pins' to be used as digital pins

OSCCON=%01100000 '(=$60) Internal 4MHz selected

ADCON1=%10000000 'Right justified, ADCS2=0, PA0-AN4=analog, RA6-RA7=digital?

   

TRISA=%00100111  'RA0-2 and RA5=inputs

TRISB=%11000000  'RB6-7=inputs

 

A var WORD [14]   'Declair an Array for 15 16-bit data - very importatnt

Max1 var word     '"MAX" and "MIN" (parameters in PBP) cannot be used (Max1).

Maxvalue var word 'Maximum value found

Vcds var word     'Vcds is 16-bit data

n var BYTE        'Counter

l var BYTE        'Counter

I var byte        'Counter

t var byte        'Counter

m var Byte        'Counter

k var byte        'Counter

p var byte        'Counter

Motorp1 var PORTB.1    'Motor driver pin1

Motorp2 var PORTB.2    'Motor driver pin2

LimSWe Var PORTB.6     'East-end Limit Switch

LimSWw Var PORTB.7     'West-end Limit Switch

LEDcds var PORTB.5     'LED Red

LEDalarm var PORTB.3   'LED Yellow   08.5.16 追加

 

Motorp1=0

Motorp2=0

LEDcds=0

LEDalarm=0       '08.5.16

t=0

k=0              '08.5.16

 

'---- Wake-up routine - Outside brightness check ----

Cdsloop:      

Gosub Vcdsread

if (Vcds>300) then '300(1.46V)/brightness

Pause 2000

High LEDcds    'LED Red -> ON when Vcds exceeds 300

Goto Jump0

Else

Goto Cdsloop

Endif

 

'---- Moving Motor to LSWe then toward West ----

Jump0:

Motorp1=0

Motorp2=0

 

LSWeLoop:         'LSWe contact check

Gosub ToEast      'Move motor toward East

If LimSWe=0 then

Gosub Motorstop

Goto Jump1        'If contacted, go to Jump1

Else

Goto LSWeLoop

Endif

 

'---- Collection of Vscell data at designated points ----

Jump1:

n=0

For n=0 To 14      'Read and collect 15 data

ADCON0=%10001101   'Read from ch1

ADCIN 1, A(n)      'Store them in A(n) array

Pause 50

Pause 100

Gosub ToWest       'Move to West

Pause 600          '0.6 sec interval

Gosub Motorstop

Pause 200

  If LimSWw=0 then  '08.5.16  Contact-to-LSWw check ここではスキャン中のLSWwへの接触をチェック

  Goto Jump6       '08.5.16

  Endif             '08.5.16

Next n

 

Pause 2000

 

'---- Seeking Maxvalue among the collected A(n) array data ----

Max1=0

l=0

Maxvalue=0

 

Max1=A(0)               'First data A(0) assumed to be Max1

For l=1 To 14          

  IF Max1 < A(l) Then   'Comparing Max1 with 2nd data

  Max1=A(l)

  Endif

Next l

Maxvalue=Max1           'Max1 is the maximum value found.

 

'---- Return the solar panel to LSWe ----

LSWeLoop1:        'LSWe contact check

Gosub ToEast      'Move motor toward East

If LimSWe=0 then

Gosub Motorstop

Goto Jump4        'If contacted, go to Jump4

Else

Goto LSWeLoop1

Endif

 

'---- Seeking "I" value corresponding to Maxvalue ----

Jump4:

If Maxvalue=A(0) then goto I0   'A(0)-A(14) data are stored in an array A

If Maxvalue=A(1) then goto I1

If Maxvalue=A(2) then goto I2

If Maxvalue=A(3) then goto I3

If Maxvalue=A(4) then goto I4

If Maxvalue=A(5) then goto I5

If Maxvalue=A(6) then goto I6

If Maxvalue=A(7) then goto I7

If Maxvalue=A(8) then goto I8

If Maxvalue=A(9) then goto I9

If Maxvalue=A(10) then goto I10

If Maxvalue=A(11) then goto I11

If Maxvalue=A(12) then goto I12

If Maxvalue=A(13) then goto I13

If Maxvalue=A(14) then goto I14

 

I0: I=0: goto Jump5     'Ignore the first value and return to Start

I1: I=1: goto JumpX     'If I=1, go to jumpX.

I2: I=2: goto JumpX

I3: I=3: goto JumpX

I4: I=4: goto JumpX

I5: I=5: goto JumpX

I6: I=6: goto JumpX

I7: I=7: goto JumpX

I8: I=8: goto JumpX

I9: I=9: goto JumpX

I10: I=10: goto JumpX

I11: I=11: goto JumpX

I12: I=12: goto JumpX

I13: I=13: goto JumpX

I14: I=14: goto JumpX

 

JumpX:

For m=0 to I

  If LimSWw=0 then  '08.5.16  Contact-to-LSWw check ここでは“I”だけ進行中のLSWwへの接触をチェック

  Goto Jump5       '08.5.16

  Endif             '08.5.16

Gosub ToWest

Pause 600

Gosub Motorstop

Pause 200

Next m

 

Pause 2000

 

Jump3:

Gosub ExposeSun    '15 min

 

Jump5:

Goto Start         'Return to "Start" of the program

 

Jump6:           'If contacted, move backward and wait for 15 min while '08.5.16 この部分は新たに追加された

Gosub ToEast     'blinking LEDyellow, and start again

Pause 1800       '1.8 sec reverse move

Gosub Motorstop

For k=1 to 15    '900 sec (15 min) timer 15分タイマ

  For p=1 to 60  '60 sec timer

  High LEDalarm

  Pause 500

  Low LEDalarm

  Pause 500

  Next p

Next k

Goto Start

End

 

'****** Subroutines ******

Vcdsread:

ADCON0=%10000101   'Read from ch0

ADCIN 0, Vcds

Pause 50

Return

 

ToEast:

Motorp1=1

Motorp2=0

Return

 

ToWest:

Motorp1=0

Motorp2=1

Return

 

Motorstop:

Motorp1=0

Motorp2=0

Return

 

ExposeSun:   

For t=1 to 5  'actually 15 min            

Pause 2000

Next

Return

 

'*************** プログラムの終わり **************

 

+このプログラムは予想どおりに動作することを確認した。

 

Menu Pageへ戻る 

Topへ戻る