概要
エコの時代の到来。戦後の窮乏の時代子供ながら近くの山に入って杉の落ち葉(すぎっぱ)を拾ってご飯の煮炊や風呂沸かしの燃料に使う経験をした。大量にエネルギーを使う今の生活は何か変だぞと多少なりとも後ろめたい気持ちを持ち続けてきた。
長屋の窓にもさんさんと太陽の光が当たるのでいつか集めて利用してみたいと考えていた。 太陽電池は折りにつけ見たり聞いたりしてきがどんなものか良く分からなかった。早速、たまたま開催中の太陽電池展に行って見分を広めてきた。小生なりの結論は”シリコンに頼らぬ太陽電池の出現などで近い将来価格が間違いなく急激に低下しそうだ”ということである。そんなわけでエコに役立ちそうな太陽電池に関係した電子工作をやってみることにした。
手初めに太陽追跡装置を試作してみた。家庭用の太陽電池パネルはほとんどが固定式で太陽の動きによって発電出力が大きく変化することが考えられるからである。
秋月電子で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
'*************** プログラムの終わり **************
+このプログラムは予想どおりに動作することを確認した。