みなさん、今晩は、トドお父さんです。

本日は、今回 電子工作してDIYで作ったこたつタイマーのソフトについて説明します。

こないだまで、ArduinoのLEDをチカチカさせて喜んでいるレベルでしたので

期待しないで下さいねー。 (半分は自分備忘録です、スミマせんね)


// 【こたつタイマー 6分単位 Arduinoプログラム】

const int cathode_pins[] = {1,2,3,4,5,0,6}; // カソードに接続
const int buttonPin = 7; // the number of the pushbutton pin
const int LED1 = 13 ; // LED blink 1sec duration
const int speker = 8 ; //speker on pin 8
const int digit1 = 9; // Display digit 1
const int digit2 = 10; // Display digit 2
const int RELAY_ON = 12; // AC Relay Control

⇒ ここまでは、Arduinoの入出力ピンの設定です。ArduinoのCPUは28ピンのIC
なので、入出力ピンはそんなにたくさん持っていません。
デジタル入出力用 0-13P までの14ピン、アナログ入力専用 A0-A5 6ピン

ピンは3、5、6、9-11Pまでの6ピンと、色々と制限があります。 (ここでいうピン数は、実際の28Pのピンとは違うのでちゃんと確認してくださいね)

今回は、LEDのカソード(-側)に接くピンが、[0,1,2,3,4,5,6] の7個です。

 これは標準のArduino基板です

終了時のブザーにつなぐのが8P、こたつON/OFFのリレー制御につなぐのが12P 1秒ごとに点滅するのは、現在と同じ13Pです。 スイッチ入力の7Pだけが入力につかっているピンになります。 これ以降は、変数の設定。

これ以降の動作に必要な定数・変数を宣言します。

//int ledState = HIGH; // the current state of the output pin int k=0 ; // Buzzer counter int Count_up =0 ; // Count up state int buttonState; // the current reading from the input pin int lastButtonState = LOW; // the previous reading from the input pin const int number_of_cathode_pins = sizeof(cathode_pins) / sizeof(cathode_pins[0]);// 配列の数 int start_num=2 ; // Number to countdown from 20min=20*600sec initial 2HOURS int start_num1 = start_num; // the following variables are long's because the time, measured in miliseconds, // will quickly become a bigger number than can be stored in an int. long lastDebounceTime = 0; // the last time the output pin was toggled long debounceDelay = 50; // the debounce time; increase if the output flickers unsigned long time;

次のSetupはコメントにあるように、電源ONでリセットがかかって起動時に1回だけ通るプログラムです。

入力ピンをINPUTに、出力ピンをINPUTに設定し、リレーをONします。

// setup() は,最初に一度だけ実行される

void setup() { for (int i = 0; i < number_of_cathode_pins; i++) { pinMode(cathode_pins[i], OUTPUT); // cathode_pinsを出力モードに設定する } pinMode(digit1, OUTPUT); pinMode(digit2, OUTPUT); pinMode(speker, OUTPUT); // speker on pin 8 pinMode(RELAY_ON, OUTPUT); pinMode(LED1, OUTPUT); pinMode(buttonPin,INPUT); // Button Input // set initial AC Relay State digitalWrite(RELAY_ON,HIGH); }


つぎに説明する loop() {  }  からが プログラム本体です。

カッコの中が順番に実行され、終わりまで行くと最初に戻って何度も実行します。だから loop() なんですね。

まず、最初の部分はSWの入力をチェックする部分です。

押しボタンSWが押されたら、カウンターを +5します。(x6分= +30分)


ハード的に、ONすると、HIGHレベルに、OFF(通常)はLOWレベルになるように、

SWの上接点を+5Vに、下接点をCPUの7ピンにつなぎます。7ピンは10kΩでプルダウンします。


SWを押した瞬間、チャッタリングといって多重にONを検出しないように、ある間隔

で2重読みして、同じ レベルなら、押された(あるいはボタンが押されなくなった)て検出します。

これを英語の世界では Button Debounce って呼んでいるようです。


Arduino本家から、このデバウンスのプログラムを移植します。

色々と先人の力作を持ってこれるところが、オープンソースのだいご味ですね。

http://arduino.cc/en/Tutorial/Debounce

時間待ちには、Millis() という関数を使います。 前に参照のHPではDelay()を使ってました。

Delay()は、その待ち時間の間、プログラムが止まってしまいますが、Millis()はCPU

の内部タイマーをmS単位で持ってくるだけです。

Delay()を使うと、LEDの表示が止まってしまいます。

Millis()では、時間を渡した後にループが高速に続きますから、全く問題ありません。

void loop() {
// read the state of the switch into a local variable:   int reading = digitalRead(buttonPin);   // If the switch changed, due to noise or pressing:
   if (reading != lastButtonState) {       // reset the debouncing timer      lastDebounceTime = millis();
}
if ((millis() - lastDebounceTime) > debounceDelay) {     // whatever the reading is at, it's been there for longer     // than the debounce delay, so take it as the actual current state:     // if the button state has changed:
if (reading != buttonState) {       buttonState = reading;       // only increment ciunrter if the new button state is HIGH
      if (buttonState == HIGH) {//         ledState = !ledState;//     If button is pressed, increase timer number          if (Count_up == 0 ) {
start_num = start_num + 5 ;// If button is pushed add 30min
//             if ((start_num -  (millis()/1000))> 50) {
//              start_num = 50 + (millis()/1000) ;//         360sec =6min,  Upper Limit = 50 * 6min = 300min(5 Hourrs)
           if (start_num - (millis()/360000) > 50 ) {            start_num = 50 + (millis()/360000) ;            }
}//     If state is count up, restart from initial.
else
         {         Count_up = 0;         k = 0;      // Buzzer is Initialized         digitalWrite(RELAY_ON,HIGH); // Power_Relay is ON
//         start_num = 10 + (millis()/1000);         start_num = 10 + (millis()/360000);         }        }     }
}
// save the reading.  Next time through the loop,
// it'll be the lastButtonState:
lastButtonState = reading; 

2行目まではLoop文ですね。


それから先は、まったくの本家サイトよりのチャタリング防止の移植です。

4行目、readingって変数に、ボタンの状況を読ませます。押されたら、”HIGH"
通常は”LOW"ですね。(7P入力はプルダウンしているので)

reading はBottonState とLastBottonStateって2つの変数にバックアップされます。

LastBottonStateは、現在、ボタンが押されているとシステムが認識していれば”1(=HIGH)"
そうでなでれば、”0(=LOW)"になっています。(後ででてきます)

ここで、ボタンが押されると、readingが0”⇒”1”になるので、6行目以降のif文が起動します。

lastDebounceTime = millis()  で現在の時間をlastDebounceTimeに保存します。

if ((millis() – lastDebounceTime) > debounceDelay) {
ここで、ボタンが押された状態が、debounceDelay時間以上になったら初めて押されたと

判断するわけです。これで、ノイズや、ONしたのに何度もON/OFFしたとご検出されて

OFFになってしまう(チャタリング)現象が除去できますよね。


(最初の変数設定のところで、debounceDelay=50(mS) になっています)

ここで、ボタンが押されたので、カウンタを+5します。


if (Count_up == 0 ) {
start_num = start_num + 5 ;


start_num って変数を使ってカウントダウンしてます。

初期値は20 (秒または2時間(20x6分))です。

+5して、50(秒または5時間(50x6分)を超えたら、50に制限します。


//でコメントしている行は、デバッグ時 1秒単位で動作させる部分です。

実際のプログラムは、6分=1秒 x 360倍しています。


else Count_up = 0;

時間切れカウントアップした時にボタンが押されると、カウンターを10に戻して、

リレーをまたONします。後に説明するブザーのカウンタを0に戻します。

   // it'll be the lastButtonState:        lastButtonState = reading;

スイッチの処理が終わったら、忘れずLastButtonStateに この値を保存します。

こんどはボタンを押し終わって”HIGH”から、”LOW”になる時も、同様のチャッタ防止の

動作をするためです。(説明は割愛します)

  //start_num limitation 50
//long startTime = millis();
//  if((millis()/1000) < start_num){
//    displayNumber(start_num -(millis()/1000));
// 360sec =6 min
  if((int(millis()/1000)/360) < start_num){    displayNumber((start_num - (millis()/360000));         if ((millis()/500)% 2 == 1 ) {      digitalWrite(LED1, HIGH);     }    else {      digitalWrite(LED1, LOW);      }  }  else  {        // reached zero, flash the display    Count_up =1; // count up state    k=k+1;   // count_up buzzer count    time=millis();    while(millis() < time+200) {      displayNumber(0);  // display 0 for 0.2 second      digitalWrite(RELAY_ON,LOW); //TIME UP Relay OFF     if(k<6) { tone (8, 1000, 100);     }    }    time=millis();        while(millis() < time+200) {      lightNumber(10);  // Turn display off for 0.2 second    }  }  

2行目、現在の時間とstart_num表示値から、残り時間を計算して7セグメント

のLEDに表示します。 (残り時間が0でカウントアップ以外 の場合)


4行目以降は、mSカウント値の500mSの剰余(mod)により、LEDをONしたり

OFFしたりする処理です。(これ考えた人、頭いいですね)

else {
// reached zero, flash the display
Count_up =1; // count up state

ここで、タイマー終了の検出をするんでしたね。

残り時間が0でカウントアップしたら、ブザーを6回鳴らして、リレーを”L”にして

こたつの電源を切ります。

また、LEDには00表示を0.8秒ON、0.2秒OFFにして点滅し、

タイマーが終了したことを知らせます。

また、ここでボタンを押すと10(=1時間)から、再度 リレーONして動作を始めるのは

先に説明したとおりです。

ここからは、2桁の7セグメントLED表示器への表示プログラムですね。

前に紹介したHPに詳しく説明していますから、ここでは省略します。

// 2ケタの表示を計算する
void displayNumber(int toDisplay) {
long beginTime = millis();
for(int digit = 2 ; digit > 0 ; digit–) {
//Turn on a digit for a short amount of time
switch(digit) {
case 1:
digitalWrite(digit1, HIGH);
break;
case 2:
digitalWrite(digit2, HIGH);
break;
}
//Turn on the right segments for this digit
// lightNumber(toDisplay % 6);
// toDisplay /= 6;
lightNumber(toDisplay % 10);
toDisplay /= 10;
// delayMicroseconds(DISPLAY_BRIGHTNESS);
//Display digit for fraction of a second (1us to 5000us, 500 is pretty good)
//Turn off all segments
delay(2) ;
lightNumber(0);
//Turn off all digits
digitalWrite(digit1, LOW);
digitalWrite(digit2, LOW);
}
//
// while( (millis() – beginTime) < 10) ;
//Wait for 20ms to pass before we paint the display again
}
// 7SEG表示パターン
const int digits[] = {
0b00111111, // 0
0b00000110, // 1
0b01011011, // 2
0b01001111, // 3
0b01100110, // 4
0b01101101, // 5
0b01111101, // 6
0b00100111, // 7
0b01111111, // 8
0b01101111, // 9
0b00000000, // 10
};
// 1けたの数字(n)を表示する
void lightNumber (int n) {
for (int i = 0; i < number_of_cathode_pins; i++) {
digitalWrite(cathode_pins[i], digits[n] & (1 << i) ? LOW : HIGH);
}
}

この説明で、わかりましたかね?

後で、この説明を読んでプログラム思い出せないようでしたら、また書き加えますね。

(2015年12月28日に加筆修正しました(^v^))

digitalWrite(cathode_pins[i], digits[n] & (1 << i) ? LOW : HIGH)

この式の意味を忘れていました、ググって回答をゲト。

この式は三項演算子っていって、<条件式> ? <真式> : <偽式>
digit[n]で定義したdigit[5] = 0b01101101 を1ビットずつシフト比較してcathode_pins[i]

の[1]~[7] までのON/OFFを入れていく式ですね、年取って頭固くなってますね。



またまた、長文・駄文で失礼しました。

それでは、まったねー  (^u^)

おやすみなさい。

コメントを残す

メールアドレスが公開されることはありません。 が付いている欄は必須項目です