以前「カミさんの育てている多肉植物が徒長している」とのことを書きましたが、その後いろいろ調べてある程度の事が分かってきましたので、「PowerLEDをPWM駆動」して「植物育成用LED照明」を作ることにしました。
 本当は品質上「国産」のLEDを使いたいのですが、さすがに趣味で使うには高価すぎ「大陸製」の物を使うことにしました。

仕様は

1. 使用するLEDは3W PowerLEDの「白色(4500k)」と「Deep Red(660nm)」を組み合わせる。(入手性と価格から)

2. PIC12F1501を使用

3. PWMの駆動は「2500kHz , Duty 33%」

4. 「なんちゃって24時間タイマー搭載」

5. 電源電圧24V ← 最終的には12Vで白色2個+DeepRed1個に落ち着きそうです。

6. LED駆動は「DW8501」を使用した定電流方式

とします。

※ PIC使用上の注意点

 ここで使用しないPinの処理ですが、入力に使う場合や接続しない場合内部PullUpの「WPUx」が良く利用されますが、経験上あまり安定していないことが多く、出来るだけハード的に処理しておく方が良いようです。思った通り動かなく、あーでもない・こーでもないと調べていると「入力信号が安定していなかった」といった事が何度かあります。大した手間ではないので、極力入力ピンの処理はハード的に行っておくことをお勧めします。

PICのアセンブラについて

 PICアセンブラの記述は色々あり、最初は戸惑うことが多いと思います。その中でもわかりにくい何種かについて書いてみます。

使用するPICの宣言

LIST    P=12F629(使用するPICを指定します)
INCLUDE    “P12F629.INC”(使用するPICのファイルを読み込みます)
ERRORLEVEL -302 (これは無くても良いのですが、アッセンブル時にBANK切替の確認メッセージを出さないようにする物です)

CONFIG:
 MPLAB X IDEでは自動で「CONFIG」を作成する機能がありますが、最初のうちはData Sheetを読みながら自分で作成した方が良いと思います。
 PIC12F1501はCONFIG1とCONFIG2の2種類を設定しなければなりませんが、CONFIG1は設定項目が多くソースファイルが長くなり、見難くなってしまいます。
 記述方法は3通りあり、CONFIG1についてそれぞれの方法で書いてみます。

1行で記述する方法:一般的に用いられている方法です。

__CONFIG␣_CONFIG1␣,␣_FOSC_INTOSC␣&␣_WDTE_OFF␣&␣_PWRTE_ON␣&␣_MCLRE_ON␣&␣_CP_OFF␣&␣_BOREN_OFF␣&␣_CLKOUTEN_OFF

複数行に分けて記述する方法:今回使用しています。

CB1␣=␣_FOSC_INTOSC␣&␣_WDTE_OFF␣&␣_PWRTE_ON␣&␣_MCLRE_ON
CB1␣&=␣_CP_OFF␣&␣_BOREN_OFF␣&␣_CLKOUTEN_OFF
__CONFIG␣_CONFIG1␣, ␣CB1

ひとつづつ記述する方法:各設定項目のコメントが書け、後で解り易いかもしれません。

CB1␣=␣_FOSC_INTCON
CB1␣&=␣_WDTE_OFF
CB1␣&=␣_PWRTE_ON
CB1␣&=␣_MCLRE_ON
CB1␣&=␣_CP_OFF
CB1␣&=␣_BODEN_ON
CB1␣&=␣_BOREN_OFF
CB1␣&=␣_CLKOUTEN_OFF
__CONFIG␣_CONFIG1␣, ␣CB1

 ここでCONFIGの前に書かれている長めの「__ 」(アンダーバー)は半角の「_ 」(アンダーバー)が2個です。またそれぞれを記述する際、「半角スペース(␣)等」には十分注意してください。

変数・定数の定義:
 プログラムを作るうえでどうしても必要になる変数ですが、BANK毎に設定する物と全てのBANKに共通するものとがあります。
 私が作るプログラムはそれほど大きな物を作らないため、全てのBANKで使用可能な様にしていますので、70Hから7FHすなわち128個使用できます。これだけ使えれば私の場合問題はないと思います。

BANKの切替方法:
 これも複数種有りますので、自分に合った方法を採用してください。BANK切替を間違いなく行える方法や、ステップ数を少なくするための方法等があります。

レジスタを指定してBANKを切り替える方法:

BANKSEL      PORATA           ;
BANKSEL      TRISA               ;

直接BANKを指定して切り替える方法:

SELBANK      1                          ;
MOVLB         1                          ; (私はこの記述を使用しています)

ソースファイル作成時の注意点:

 コメントを記入すると訳の分からないエラーが出ることがありますが、大体の場合「コメント」( ; 以降)以外で「全角」の「スペース」が入っていることが原因になっていることが多いようです。
 プログラムの基本は「半角文字」ですので、エラーの原因が見つからない場合、一度「コメント」を外して打ち込み直すとアッセンブルエラーが出なくなることが多いようです。

まずは制御系のプログラムから

 最近あまり見かけませんが、「ジサマ」には一般的な「C言語」ではなく「アセンブラ」がやさしいので、「アセンブラ」で製作します。なんのことはなく新しいことを始めるのがおっくなだけなのですが・・・・・

 「PWM」と「24時間タイマー」がキモになるので、それぞれについて確認実験をした後、一つにすることにします。

 構造&計算を単純にするため4MHzの内部発振を使います。これはサイクルタイムが4Fosc =  1uSecになり、計算が直感的になるため選択しました。また PIC12F1501は8ピンですので、「水晶発振」や「セラロック」等の外部発振を使うと2ピンを占有してしまうため内部発振を使用しました。

 ページ上で記載して説明できれば良いのですが、私の能力ではいかんともしがたい為、アッセンブラのソースファイルを圧縮して下記に置いておきます。解凍すると5つのソースファイルが出来上がります。使用しているのは「MPLAB XIDE Ver5.15」のアッセンブラですが、特殊なことはしていませんので、ほとんどの「MPLAB XIDE」で使用できると思います。
記述を見るだけであれば、段落等に乱れが出ますが「メモ帳」や「ワードパッド」等でも表示可能です。

アセンブラソースファイル

PIC12F1501_all.zip:全てのソースファイルを入れてあります。(入れる予定)

PIC12F1501_PWM.zip:PIC12F1501_PWM.asmのみ。←2021.05.04掲載

PIC12F1501_Timer.zip:PIC12F1501_Timer0.asm , PIC12F1501_Timer1.asm ,
                                      PIC12F1501_Timer2.asmを圧縮してあります。(後日追加) ← 2021.05.05 掲載

Plants GrowLights PWM Ver.2.0:Plants GrowLights PWM Ver.2.0.asmのみ。←2021.05.10掲載

手始めにPWMから

 植物を育成する照明は色々とあり、必要な光の波長はLEDで決まりますが、商業的に育成する場合は点灯方法でも工夫がなされているようで、学会等でも議論されていて、対象植物にもよりますが「2,500Hz ,Duty33%」での点灯が最も効率が良いというのが、定説になっているようです。

 PIC12F1501は設定できる周波数は1種ですが、PWM出力を4つ持っています。周波数は同じですがDutyを4種同時に出力できるので、このことを確認します。

 周波数は一般的に植物育成に有効だとされている2500Hz , Duty 33%を採用するつもりですので、周波数は2500Hzとして、Duty 75・50・33・10%とします。
 PIC12F1501のPWM出力はPWM1 = Pin5 , PWM2 = Pin7 , PWM3 = Pin3 , PWM4 = Pin2になりますので、PWM4(Pin2) = Duty33% , PWM3(Pin3) = Duty10% , PWM2(Pin7) = Duty75% , PWM1(Pin5) = Duty50%としてあります。比較としてPin6(RA1)にDuty100%を出力させました。(4種類の周波数・Dutyを別々に設定出来るPIC12F1572などもあります。)

 周波数の設定及びDutyの設定については、ソースファイル中でコメント欄に出来るだけ詳細に書いてありますので、参考にしてください。

PWM信号はTimer2を使って発生していますが、Timer2の設定は8bitになっています。

ここで判りにくいと思われる個所について書かせてもらいます。

PWM PERIOD:
 これは周期の事で、1÷f [ Hz ] になります。

PULSE WIDTH:
 これはPWM出力の内、出力がON(Hi)になる時間になりますが、実際には次のDUTY CYCLE RATIOで考える方が一般的になりますので、あまり気にしなくても良いと思います。

DUTY CYCLE RATIO:
 Duty%の値になります。この計算の中でPWMxDCを1/4にしますが、PWMxDCは10bitであるため、下二桁のPWMxDCLをB’00’としてPWMxDCHのみで考えると、1/4を考えなくても良いことになります。

 ※ ここで解っている方は当たり前なことなのですが、10bitのPWMxDCを左に2bit移動させるとx4したことになります。(桁上りがあった場合は別ですが・・・・・)
 例えば8bitのB’00000001’を1bit左にシフトするとB’00000001’ = D’1’ → B’00000010’ = D’2’ となり、さらに1bit左にシフトするとB’00000010 = D’2’ → B’00000100’ = D’4’ となります。つまり左に2bitシフトするとx4したことになりますので、PWMxDCLをB’00’ = H’00’としておきPWMxDCHを設定するとPWMxDCはPWMxDCHをx4したことになります。

 このことは私の様な初心者にはなかなかわかりにくいのですが、あまり他の方は書かれていないようなので、書いておきました。

PWM確認回路図

PWM確認回路図

 

LEDを点灯させたてみた回路は次の回路です。


PWM点灯確認

PWM点灯確認

 

 実際に点灯させた写真です。左からDuty 100 , 75 , 50 , 33 , 10 %になっています。左から右にかけて暗くなっていくのが分かると思います。

 オシロで確認した波形です。

ソースファイル名は「PIC12F1501_PWM.asm」です。

 

Timerについては、後日書き込みます。← 2021.05.05追加しました。

次はタイマーの動作確認

 PIC12F1501はTimer0・Timer1・Timer2の三種類のタイマー機能を持っています。そのうちのTimer2は先にPWM信号を作るために使いましたが、Timer2はちょっと変わった機能を持っていて、他のTimer0やTimer1とは設定の方法が違います。

 最初に各Timerを使って250uSecを作り、その250uSecを繰り返し50mSecにした物を繰り返すことで点滅時間を作り、Pin2(PWM 2,500Hz,Duty33%)とPin3(PWM ,500Hz,Duty10%)を交互に点灯させてみます。
 せっかくですからPin7,6,5を入力として点滅時間を0.1 , 0.25 , 0.5 , 1.0秒、点灯方法をPWMと定電圧の2種類が設定できるようにしています。

Pin7 , Pin6 = Lo , Lo → 0.1秒

Pin7 , Pin6 = Lo , Hi → 0.25秒

Pin7 , Pin6 = Hi, Lo → 0.5秒

Pin7 , Pin6 = Hi , Hi → 1.0秒

Pin5 = Lo → 定電圧

Pin5 = Hi → PWM

 但し Timer2をTimerとして使った場合は当然PWMでの点灯は出来ません。(他のTimerを使ったりソフトでPWM信号を作ることは可能ですが、今回は無しと云うことで・・・・・)50mSecタイマはある程度正確(サイクル数は)ですが、50mSecを繰り返して作る0.1秒,0.25秒,0.5秒,1.0秒は積算時に数マイクロ秒かかりますので、若干長くなっています。

Timer0使用:

 全てのPICに搭載されているTimer0を使って点滅させてみた物です。Timer0を使ううえで設定が必要な項目は

  •  タイマカウンタは8bit(256)の分解能です。
  • プリスケーラを使用できます。
  • 利用出来るクロックは、「RA4 / T0CKI ピンの遷移」と「内部命令サイクルクロック(FOSC/4)」の2種類から選択できます。
  • カウントアップしてきてFFhから00hになるオーバーフロー時に割り込みフラグ( TMR0 IF ) が0 →1になります。オーバーフローフラグはクリアするまで状態を保持します。
    また フラグが立ってもタイマーは動作し続けますので、フラグをクリアする必要があります。
     TMR0はカウントアップを開始する値に設定するため、求める時間が要する値をFFhから減算して求めます。
  • オーバーフローした後再度動作させるには、TMR0IFのクリアとTMR0の再設定が必要になります。また TMR0を設定すると、OPTION_REGがクリアされるため、OPTION_REGがB’00000000’以外の場合、その度毎にプリスケーラ値( OPTION_REGのbit2-0 )の再設定が必要になります。
  • 割り込みを発生するかどうかは[ TMR0 IE ]で選択します。
  • TimerのON・OFFは出来ません。

 時間設定は[ 256-作りたい時間 / タイマクロック( 整数 ) ]になりますので、正確な時間にはなかなかなりませんので、いろいろ工夫が必要です。

設定する項目;

OPTION_REG:

bit5 [ TMR0CS ]; Timer0 のクロック源選択ビット

1 = RA4 / T0CKI ピンの遷移
0 = 内部命令サイクルクロック(FOSC/4)

bit3 [ PSA ]       ;プリスケーラ割り当てビット

1 = プリスケーラをTimer0 モジュールに割り当てない
0 = プリスケーラをTimer0 モジュールに割り当てる
bit2-0 [ PS<2:0> ]; プリスケーラ比選択ビット

※ 使用上の注意点

      • Timer0がオーバーフローするとソフトでTMR0IFをクリアしなければ、Timer0は次の動作をしない。
      • Timer0がオーバーフローするとTMR0はリセットされるため、再度TMR0の設定が必要。
      • TMR0を設定するとOPTION_REGがクリアされるため、その度毎に再設定が必要になる。

                          ※ PIC16F1508 DataSheet P152より

INTCON:

bit5 [ TMR0IE ]: Timer0 オーバーフロー割り込みイネーブルビット

1 = Timer0 割り込みを有効にする
0 = Timer0 割り込みを無効にする

bit2 [ TMR0IF ]:Timer0 オーバーフロー割り込みフラグビット

1 = TMR0 レジスタがオーバーフローした
0 = TMR0 レジスタはオーバーフローしていない

TMR0:Timer0のカウントを開始する値

ソースファイル名は「PIC12F1501_Timer0.asm」です。

Timer1使用:

 Timer1を使って点滅させてみた物です。Timer1は高機能タイマになります。設定値が16bitになるのが大きな特徴です。

  • タイマカウンタが16bitの分解能になります。TMR1=TMR1H & TMR1L
  • プリスケーラを使用できます。
  • 利用出来るクロックは、「T1CKI ピンの遷移」・「システムクロック(Fosc)」・「内部命令サイクルクロック(Fosc/4)」・「LFINTOSC(31kHz)」・「SOSCI/SOSCO ピン」のオシレータ回路」の5種類から選択できます。
  • カウントアップしてきてFFFFhから0000hになるオーバーフロー時に割り込みフラグ( TMR1 IF ) が0 →1になります。オーバーフローフラグはクリアするまで状態を保持します。
    また フラグが立ってもタイマーは動作し続けますので、フラグをクリアする必要があります。
     TMR1で設定する値はTimer0と同様で、求める時間に必要な値をFFFFhから減算した値を設定します。
  • オーバーフローした後再度Timer1を動作させるためには、TMR1( TMR1H & TMR1L )の再設定とTMR1IFのクリアが必要です。
  • 割り込みを発生するかどうかはPIE1の[ TMR1 IE ]で選択します。
  • Timer1のON・OFFが選択可能です。
  • 時間設定は[ FFFFh-作りたい時間 / タイマクロック( 整数 ) ]になりますので、正確な時間にはなかなかなりませんので、いろいろ工夫が必要です。
設定する項目;

T1CON:

bit7-6 [ TMR1CS<1:0> ]:Timer1 クロック源選択ビット

11 = Timer1 クロック源にLFINTOSC(31kHz) を選択する
10 = Timer1 クロック源にピンまたはオシレータを選択する

T1OSCEN = 0 の場合:
    T1CKI ピンからの外部クロック( 立ち上がりエッジ)
T1OSCEN = 1 の場合:
   SOSCI/SOSCO ピンの水晶振動子

01 = Timer1 クロック源にシステムクロック(FOSC) を選択する
00 = Timer1 クロック源に命令クロック(FOSC/4) を選択する

bit5-4 [ T1CKPS<1:0> ]: Timer1 入力クロック プリスケール選択ビット

11 = 1:8 プリスケール値
10 = 1:4 プリスケール値
01 = 1:2 プリスケール値
00 = 1:1 プリスケール値

bit0 [ TMR1ON ]: Timer1 ON ビット

1 = Timer1を有効にする
0 = Timer1を停止しTimer1 ゲート フリップフロップをクリアする

T1GCON:

bit7 [ TMR1GE ]: Timer1 ゲート イネーブルビット

TMR1ON = 0 の場合:
  このビットを無視する

TMR1ON = 1 の場合:
  1 = Timer1のカウントをTimer1 ゲート機能で制御する
  0 = Timer1は、Timer1 ゲート機能とは無関係にカウントする

PIE1:

  bit0 [ TMR1IE ]: Timer1 オーバーフロー割り込みイネーブルビット

1 = Timer1 オーバーフロー割り込みを有効にする
0 = Timer1 オーバーフロー割り込みを無効にする

PIR1:オーバーフロー発生確認用

  bit0 [ TMR1IF ]:Timer1 オーバーフロー割り込みフラグビット

1 = 割り込みを保留中である
0 = 割り込みを保留中ではない

TMR1H:Timer1の設定値16bitの上位8bit

TMR1L:Timer1の設定値16bitの下位8bit

になります。ソースファイル名は「ソースファイル名は「PIC12F1501_Timer1.asm」です。

Timer2使用:

 Timer2を使って点滅させてみた物です。Timer0,Timer1とは違い、00hからカウントを始めPR2での設定値でオーバーフローします。PWM発生用で使用されることの多いタイマです。

  • タイマカウンタが8bitの分解能になります。
  • プリスケーラ・ポストスケーラを使用できます。
  • 利用出来るクロックは、「内部命令サイクルクロック(Fosc/4)」のみです。
  • 00hからカウントアップしてきて、PR2での設定値になるとPIR1の[ TMR2IF ]に一致信号を出します。この信号は、次のサイクルでTMR2 の値を00h にリセットします。
     PR2に設定する値はTimer0 & Timer1とは違い、求める時間になる値をそのまま設定します。
  • オーバーフロー後、再度Timer2を動作させるにはTMR2IFをクリアする必要がありますが、Timer0&1のようにTMR2の再設定は必要ありません。
  • 割り込みを発生するかどうかはPIE1の[ TMR2 IE ]で選択します。
  • Timer1のON・OFFが選択可能です。
  • 時間設定は[ 作りたい時間 / タイマクロック( 整数 ) ]になります。
設定する項目;

T2CON:

bit6-3 [ T2OUTPS<3:0> ]:Timer2 出力ポストスケーラ選択ビット

bit2 [ TMR2ON ]:Timer2 ON ビット
       1 = Timer2をON にする
       0 = Timer2をOFF にする

bit1-0 [ T2CKPS<1:0> ]:Timer2 クロック プリスケール値選択ビット

PIE1:

bit1 [ TMR2IE ]:TMR2/PR2 一致割り込みイネーブルビット
  1 = Timer2/PR2 一致割り込みを有効にする
  0 = Timer2/PR2 一致割り込みを無効にする

PIR1:

bit1 [ TMR2IF ]:Timer2/PR2 割り込みフラグビット
  1 = 割り込みを保留中である
  0 = 割り込みを保留中ではない

PR2:Timer2の設定値

※ 可能な限り正確な時間を設定したい場合は、各Timerの設定値とTimerを再セットする際に使う命令サイクルにかかる時間を考慮する必要があります。
 Timerに設定する値を求める時間より短くなるようにして、最終段階に命令サイクルで加算することで対応できると思います。
 私の場合それほど気になりませんが・・・・・

ソースファイル名は「PIC12F1501_Timer2.asm」です。

Timer確認回路図

Timer確認回路図

 

 全てのTimer使用回路は同じで、このようにしました。



 Timer0での動作波形を載せておきます。他のTimerもほぼ同様でした。点滅時間の波形は「定電圧」での点灯で、周波数の波形は「常時PWM」で点灯させたときの物です。

 PIC12F1501_Timer.zipを適当な場所に解凍してください。上記の3種のTimerを使ったソースファイルが展開されます。私なりに細かくコメント欄に記載してありますので参考にしてください。

次はいよいよ本プログラムになります。乞うご期待!!(なるべく早めに掲載します。)

いよいよ「なんちゃって24時間繰り返しタイマー」

 前の実験で作ったタイマーを基に「なんちゃって24時間繰り返しタイマー」を作ってみます。
 まず 前出のTimer0のプログラムで、赤色と青色のLEDを1時間毎に点灯・消灯を交互に繰り返して、長時間での動作を確認してみると、結構良さそうな感触です。

次に内部発振を使った「なんちゃってタイマー」でも、出来るだけ正確な時間になるようにしてみます。

 長時間用のTimerは一般的なTimer0を使用し、PWMはPWMモジュールを使っています。せっかくですから赤色LED(Pin2:PWM4)は2,500Hz Duty 33% , 青色LED(Pin3:PWM3)は2,500Hz Duty 10%にしてみます。
 ここでPWM信号のON / OFFですが、Timer2をOFFすることでPWM信号をOFFにすると、タイミングによっては出力Hiで停止してしまうので、最初は終了時にPWM出力を監視して、出力Loの時にTimer2をOFFするようにしたりしていました。

 もっとスマートな方法が無いかと思い、あーだこーだと設定をいじっていると、「PWMxCON」のbit6[ PWM2OE ]のSet / Clearで、PWM出力をON / OFF出来る事が分かりましたので、この方法で統一しています。

回路は前出のTimer確認で使用した回路と同じです。

繰り返しタイマーの精度

 実際の動作時間ですが、百均のタイマーを基準にして目視による確認ですが、以下のような結果になりました。1時間毎の切替しと、12時間毎の繰り返しで動作を確認してみました。実際に使う24時間タイマーで、設定を12時間毎のON / OFFデーターが下記です。
 すべてで確認出来ればよかったのですが、気が付かなうちに(飲んでいたため忘れていたのですが・・・・)切り替わっていたりしましたので、歯抜けのデーターになっています。

  初日 17:00:00 ON 翌日 04:59:50 OFF
  翌日 16:59:18 ON 2日目 04:58:55 OFF
  2日目     3日目 04:58:02 OFF
  3日目 16:57:25 ON 4日目 04:57:07 OFF
  4日目 16:56:43 ON 5日目 04:56:32 OFF
  5日目   ON 6日目    
  6日目 16:55:55 ON 7日目 04:55:41 OFF
  7日目 16:55:10 ON 8日目 04:54:51 OFF
  8日目 16:54:03 ON      

 

 CR発振であろう内部発振にしては優秀で、週に一回程度電源を入れ直せば使える範囲ではないかと思います。昔の機械式時計と比べると何とかなる範囲でしょうか。

 ソースファイル名は「Plants GrowLights PWM Ver.2.0.asm」です。

 次はいよいよ実機製作です。乞うご期待!!