プログラムを書き込んだマイコンをつかって、LEDを光らせました。
光センサをつなげて、明るさに応じてオンオフを切り替えられます。
プログラムを書き込むための道具
今回使ったのは、下記の道具です。
- マイコン
- ライター
- プログラムソフト
- その他(PC,ケーブル、回路素子)
プログラムソフトで書いたプログラムを、ライターを通して、マイコンに書き込みます。
マイコン
写真の黒い素子がマイコンです。
型番はPIC16F1829です。
ライター
PICKit4というライターを使いました。
フリスクの箱くらいの大きさです。
プログラムソフト
MPLAB X IDEという、開発ソフトウェアを使いました。
Microship Technologyという会社の無料ソフトです。
アセンブリ言語とC言語が使えます。
その他(PC,ケーブル,ワイヤ)
プログラムを書くPC、PCとライターをつなぐケーブル、ライターとマイコンをつなぐジャンプワイヤが必要です。
LEDをオンにする
LEDをつなぐピンの出力をオンにすれば、LEDがつきます。
例えばマイコンの「RC2」というピンにLEDをつなげる場合、
RC2=1;
と書けばいいです。
大電流を防ぐために、抵抗をはさもう!
「RC2-LED-抵抗-グラウンド」のようにつなげばOK
タイマーでオンオフを切り替える
PIC16F1829にはタイマー機能が搭載されています。
クロック周波数を8MHzにしている場合には、TMR0IFという値が32μsごとに1になります。
以下、少し難しい話
命令サイクルが1進むごとにTMR0というレジスタに1ずつ加算されていきます。TMR0は255のつぎには0にもどります。もどるときにTMR0IFが0だった場合には、TMR0IFが1になります。もどるときにTMR0IFが1だった場合には、TMR0IFは1のままです。
難しい話おわり。
以下は、1秒ごとにオンオフをくり返すソースコードです。
#pragma config FOSC = INTOSC // 発振
#pragma config WDTE = OFF // WDT 無効
#pragma config MCLRE = OFF
#pragma config PLLEN = ON // PLL 有効
#pragma config LVP = OFF
#include <xc.h>
void main()
{
PORTC = 0b00000000; // クリア
OSCCON = 0b11110000; // 動作クロック:32MHz
TRISC = 0b00000000; // 全て出力モード
ANSELC = 0b00000000; // 全てデジタルモード
OPTION_REG=0b11011000; //プリスケーラはオフ
while(1)
{
RC2 = 1; // RC2 を HIGH に
TMR0IF=0;
for(int i=0;i<31250;i++)
{
while(TMR0IF==0){}
TMR0IF=0; //TMR0IFが1になったら0に戻して、i++
}
RC2 = 0; // クリア
TMR0IF=0;
for(int i=0;i<31250;i++)
{
while(TMR0IF==0){}
TMR0IF=0;
}
} // 無限ループ
}
ちなみに上6行くらいは、「おまじない」です。私にもわかりません。
パルスで明るさを調整する
原理:オンオフを高速で切り替える
LEDは、基本的には明るさを調整できません。
例えば0~0.6Vまではオフ、0.6V以上はオン、というようになっています。0.6V以上に電圧を上げても、より明るくなったりはしません。
(オンオフの境目で電圧を動かすのならばできますが、シビアです)
そこで、電圧をパルス波形にすることで明るさが変わるように「見せ」ます。
パルス波形というのは例えば、
「4秒オンにして1秒オフ、4秒オンにして1秒オフ」
というようにオンオフをくり返していく波形です。
オンオフの間隔をもっと短くすると、人間にはLEDがつきっぱなしに見えます。
上の例は周期5秒ですが、この周期を5msくらいにすれば、オフになっていることはわかりません。
さらに、オンオフの時間の割合を変えることで、明るさを変えていきます。
上の例ではオンオフの比が8:2でした(デューティー比80%といいます)。
これを2msオン、3msオフというようにすると暗くなったように見えます(デューティー比40%)。
実装
PR2の値でパルス波の周期を、CCPR1Lの値でデューティー比を決めます。
(PR2+1)が1周期のサイクル数、CCPR1L/256がデューティー比になります。
以下は、約1秒ごとに明るくなったり暗くなったりをくり返すプログラムです。LEDへの出力はCCP1というピンです。
void main()
{
OSCCON = 0b11110000; // 内臓クロックを 32MHz に設定
ANSELC = 0x00; // PORTC はすべてデジタル設定
TRISC = 0x00; // PORTC はすべて出力モード
CCP1CON = 0b1100; // CCP1 を PWM モードに設定
// CCP1X, CCP1Y はともに 0
T2CON = 0b111; // タイマ 2 の分周比を 1:64 に設定
PR2 = 0xff; // タイマ 2 のカウンタと比較する値
CCPR1L = 160; // デューティサイクルを設定
OPTION_REG=0b11010111;//8.192msでTMR0が一周
int i=0;
while(1){
CCPR1L=254;
for(i=1;i<250;i++)//TMR0で時間を計る
{
while(TMR0IF==0){}
CCPR1L--;
TMR0IF=0; //TMR0IFが1になったら0に戻して、i++
}
for(i=0;i<250;i++)//TMR0で時間を計る
{
CCPR1L++;
while(TMR0IF==0){}
TMR0IF=0; //TMR0IFが1になったら0に戻して、i++
}
}
}
「おまじない」は省略しています。
照度センサーで暗いときだけオンにする
原理:フォトダイオードでオンオフの時間を調整する
フォトダイオードを照度センサーにして、明るさを変えます。
フォトダイオードに入る光が明るいと電流が大きくなり、暗いと小さくなります。
基本的にはフォトダイオードに流れる電流が大きいほどデューティー比を小さくし、電流が小さいほどデューティー比を大きくします。
実装:フォトダイオードの電流値を読み取らせる
実装の際には、フォトダイオードの電流の入力にアナログ/デジタル変換(AD変換)を行う必要があります。
PIC16F1829のAD変換機能を利用します。
AD変換の準備ができたあとにADGO=1を入力するとAD変換がはじまります。
AD変換が終わると変換結果がADRESHに出力され、ADGOの値が1から0に戻ります。
ADRESHの値は0~255の範囲です。
以下がソースコードです。フォトダイオードの電流入力はAN2で、LEDの出力はCCP1です。
「電源-フォトダイオード-CCP1-抵抗1-グラウンド」、
「CCP1-LED-抵抗2-グラウンド」のようにつなぐよ!
void main()
{
OSCCON = 0b11110000; // 内臓クロックを 32MHz に設定
ANSELC = 0x00; // PORTC はすべてデジタル設定
TRISC = 0x00; // PORTC はすべて出力モード
CCP1CON = 0b1100; // CCP1 を PWM モードに設定
// CCP1X, CCP1Y はともに 0
T2CON = 0b111; // タイマ 2 の分周比を 1:64 に設定
PR2 = 0xff; // タイマ 2 のカウンタと比較する値
CCPR1L = 160; // デューティサイクルを設定
OPTION_REG=0b11011000; //8.192msでTMR0が一周
ANSELA = 0b00000100; // AN2(RA2) をアナログモードに設定
TRISA = 0b00000111; // RA2 を入力モードに設定
ADCON0 = 0b00001001; // AN2(bit6-2:00010) + ADC enable(bit0:1)
ADCON1 = 0b00110000; // ADC に内部 RC 発振を利用
OPTION_REG=0b11010111;
TMR0IF=0;
while(TMR0IF==0){} //AD変換の準備ができるまでの時間稼ぎ
TMR0IF=0;
while(TMR0IF==0){}
TMR0IF=0;
while(1){
while(!ADGO){ //ADGOが0になるたびにAD変換
CCPR1L=155-ADRESH;
ADGO=1;
}
}
}
さいごのwhile構文の中については、フォトダイオードの出力が明るいときでも150程度だったことを反映させています。
「おまじない」は省略です。
結果
フォトダイオードの値に応じて、LEDのデューティー比をかえるプログラムをマイコンに入れました。
すぐ上に書いたソースコードです。
フォトダイオードを指で覆ってみます。
↑before↓after
成功です。光りました。
おわりー!
コメント