はじめに
このページは「マイコンLチカ道場 Arduino編」の「1-5:ふわっとLチカをスイッチでオンオフ」に対応するページです。PWMでふわっと点滅しているLEDをスイッチでオンオフするような動作をさせてみます。
今回は、MsTimer2ライブラリを使用して、割り込みでスイッチ入力を使う方法を試してみました。
前回の「1-4:ふわっとLチカ」と「1-2:ボタンを押す度にLチカの状態が反転」の合わせ技のようなイメージです。
回路図とブレッドボード接続図
今回の回路図・接続は上記の「1-2:ボタンを押す度にLチカの状態が反転」と同じです。
1個の青色LEDと、1個のタクトスイッチを使用します。プルアップ抵抗は内蔵ではなく、外付けとしています。
ピン9に並列で追加しているコンデンサと抵抗は、PWM波形を鈍らせてオシロで見るためのCRフィルタです。(C=1μF、R=10kΩ)オシロで見ない場合は無くても問題ありません。
プログラムを書いてみる
今回のプログラムが下記になります。
#include <MsTimer2.h>
const int LED1 = 9; //LEDを接続するピン(PWM出力490Hz:3,9,10,11、980Hz:5,6)
const int wait = 2; // 点滅の速さを決めるウェイト時間(ms)
int led_width = 0; //ledのPWM幅用の変数
const int SW1 = 2; //スイッチを接続するピン
int sw_state = HIGH; //スイッチの状態保存用の変数
int sw_latch = HIGH; //スイッチのラッチ用の変数
int led_state = LOW; //LEDの状態保存用の変数
void setup() {
pinMode(LED1, OUTPUT); //LED1ピンを出力にする
pinMode(SW1, INPUT); //SW1を入力に設定
MsTimer2::set(50, sw_time); //50ms毎に関数sw_timeを実行
MsTimer2::start(); //割り込み有効
}
void loop() {
for (led_width = 0; led_width <= 255; led_width +=1){
if (led_state == HIGH){ //led_stateがHIGHの場合
analogWrite(LED1, led_width); //LED1をPWMで点灯させる
} else {
analogWrite(LED1, 0); //LED1を消灯
}
delay(wait); //ウェイト時間
}
for (led_width = 255; led_width >= 0; led_width -=1){
if (led_state == HIGH){ //led_stateがHIGHの場合
analogWrite(LED1, led_width); //LED1をPWMで点灯させる
} else {
analogWrite(LED1, 0); //LED1を消灯
}
delay(wait); //ウェイト時間
}
}
void sw_time(){
sw_state = digitalRead(SW1); //SW1の状態を読み込み、sw_stateに代入
if (sw_latch == HIGH && sw_state == LOW){
led_state = !led_state; //led_stateの変数を反転
}
sw_latch = sw_state; //sw_stateの状態をsw_latchに代入
}
主な動作の説明はコメント文に記載しています。今回は、ミリ秒単位で指定した時間で関数を呼び出すことが出来る、MsTimer2ライブラリを使用しています。初っ端に「#include <MsTimer2.h>」でライブラリを呼び出します。インストールされていない方は下記の方法でライブラリをインストールできます。
「MsTimer2::set(50, sw_time)」で50ms毎に関数sw_timeを実行させています。関数はvoid sw_time()で記載している部分になります。ここで、スイッチの入力関係を処理しています。
なぜそうしたかと言うと、void loop()内のfor文のウェイト2ms×255で0.5秒以上、それが2つで1秒以上for文の中のループに捕まっていることになり、その間スイッチの入力判定が止まることになるからです。
MsTimer2で50ms毎にスイッチの処理を割り込ませることで、スイッチを押した時に直ちにLEDの点滅をON・OFFすることが出来ます。
実際の動作波形が下記になります。今回は50ms毎に割り込みを行っているので、その分のタイムラグがあります。
補足:上記スケッチの「analogWrite(LED1, 0);」がないとスイッチを押したら明るさの「増減が止まる」というような動作になります。
また、上記のプログラムだと点滅ON・OFFに関係なくマイコン内部のled_widthの値は増減しているため、スイッチを押したタイミングで光り初めの状態が安定しません。押したらふわっと光り始めるようにスケッチを直してみました。void loop()内の「if (led_state == HIGH)」をfor文のループの外に出しただけです。
#include <MsTimer2.h>
const int LED1 = 9; //LEDを接続するピン(PWM出力490Hz:3,9,10,11、980Hz:5,6)
const int wait = 2; // 点滅の速さを決めるウェイト時間(ms)
int led_width = 0; //ledのPWM幅用の変数
const int SW1 = 2; //スイッチを接続するピン
int sw_state = HIGH; //スイッチの状態保存用の変数
int sw_latch = HIGH; //スイッチのラッチ用の変数
int led_state = LOW; //LEDの状態保存用の変数
void setup() {
pinMode(LED1, OUTPUT); //LED1ピンを出力にする
pinMode(SW1, INPUT); //SW1を入力に設定
MsTimer2::set(50, sw_time); //50ms毎に関数sw_timeを実行
MsTimer2::start(); //割り込み有効
}
void loop() {
if (led_state == HIGH){ //led_stateがHIGHの場合
for (led_width = 0; led_width <= 255; led_width +=1){
analogWrite(LED1, led_width); //LED1をPWMで点灯させる
delay(wait); //ウェイト時間
}
for (led_width = 255; led_width >= 0; led_width -=1){
analogWrite(LED1, led_width); //LED1をPWMで点灯させる
delay(wait); //ウェイト時間
}
} else {
analogWrite(LED1, 0); //LED1を消灯させる
}
}
void sw_time(){
sw_state = digitalRead(SW1); //SW1の状態を読み込み、sw_stateに代入
if (sw_latch == HIGH && sw_state == LOW){
led_state = !led_state; //led_stateの変数を反転
}
sw_latch = sw_state; //sw_stateの状態をsw_latchに代入
}
この時の動作波形が下記になります。スイッチを押してからPWM信号が増加し始めていることがわかります。
ただし、このプログラムではスイッチを押してからLEDがオフするまで、PWM信号が減少して0になるまで待つ必要が有ります。実際の動作を見ると、LEDがふわっと消えて終了するのでこちらのプログラムの方が自然な感じがしました。
まとめ
PWMでふわっと点滅しているLEDをスイッチでオンオフするような動作をさせることが出来ました。今回は、MsTimer2ライブラリを使用して、割り込みでスイッチ入力を使う方法を試してみました。
引き続き難しいLチカに挑戦していきましょう。