Atmega328の湿度コントローラー

最近、私はささいな仕事に直面しました-自宅の浴室で換気扇を制御します。



それはよりシンプルに見え、照明スイッチに接続すれば完了です。 しかし、ライトの動作時間は可変であり、湿度を下げるのに十分ではないかもしれませんが、この問題はタイマーを設定することで解決できます。 加えて、私の愛する人は、「冷たい風を作り出す」ので、水の手順を取るとき、実際に働くファンが好きではありません。



2番目の明らかな解決策は、ファンを個別のスイッチに配置して、その人に制御を与えることです。 しかし、人的要因は、ファンが常にオンになることを忘れており、オンになっている場合はオフにすることです。 ファンの効率はすぐにゼロになる傾向がありました。



Arduinoとシンプルなマイクロコントローラーへの情熱をこの問題に結び付けなければなりませんでした。



処方されたポラキニン



制御デバイスの要件





  1. 制御デバイスは自動モードで動作するはずです。
  2. 湿度の上昇からファンをオンにする必要があります。
  3. ファンをオンにすることは、アパート内の現在の湿度レベルに依存するべきではありません。
  4. バスルームに誰もいないときにファンが動作するはずです。
  5. 制御装置はできるだけシンプルで安価でなければなりません。




要素ベースの選択



このデバイスのプロトタイプは、中国製のArduino Unoデバッグボードで作成されました。





その後、すべてがAtmega328マイクロコントローラーに転送され、標準のArduinoブートローダーでフラッシュされました。



最終的なデバイスは、「何があったかを知らない」という原則に基づいて作成されました。 すべての要素は、さまざまな予測のためにインターネットで以前に購入したか、アイドルデバイスから引き裂かれました。







3x1W LEDドライバーは照明器具に由来し、LM2596スイッチングスタビライザーの電源に完全に対応していました。

ケースとして、古い自動電話交換機のクロスボックスが使用されました。



接続



それは非常に怠laであるという事実のために、非標準の要素がデバイスで使用されていたため、私は一般的なスキームを描きませんでした。 接続要素の表をマイクロコントローラーに持ってきます:







データシートはCPS03621BRインディケーターに見つからなかったため、結論はバッテリーを突っ込んで使用して見つかりました。 インジケータは、共通のアノードであることが判明しました。 カソードのレイアウト:

画像



ファンはBT137トライアックによって制御されます。

サイトavr.ruから接続図を取得しました



誰かが繰り返すことを決めた場合-注意、トライアック本体の電圧は220Vです。







作業アルゴリズム





周波数が10秒に1回のマイクロコントローラーは、湿度と温度を測定します。

湿度は6つの値のアーカイブに周期的に蓄積されます。 現在の湿度がアーカイブの最初の湿度よりも3%以上高い場合、または絶対湿度値が85%より大きい場合は、ファンをオンにする必要があります。

フォトレジスタに光がない場合、ファンは20分間オンになります。

このボタンは、ファンが20分間強制的にオンになる(動作しない場合)か、オフになります(動作する場合)。

アルゴリズムのすべての定数は実験的に選択されました。



このインジケータは、現在の温度、湿度、カウントダウンタイマーを周期的に表示します。

湿度を下げる必要がある場合は2番目の放電ポイントが点灯し、ファンをオンにするコマンドが与えられると点滅します。



デバイスの完全なロジックは、有限決定性オートマトンによって記述できます。

マシンの入力アルファベットは、次のイベントで構成されます(優先度順):





多くの州:

  1. スタンバイモード、ファンが動作しない、タイムアウト。
  2. ファンをオンにする必要があります、ファンが動作しない、タイマー(いつ)が停止します。
  3. ファンは自動モードで動作し、タイマーはオンです。
  4. ファンは手動モードで動作し、タイマーはオンです。




さて、オートマトンの状態遷移表:





プログラミング



私はAVR-studioや他のモンスターをインストールしませんでしたが、それでもIDE Arduinoが必要でした。



board.txtファイルで、内部8MHzクォーツで実行される新しいコントローラーを作成します。



atmega328_8.name=Atmega328 (5V, 8 MHz internal)



atmega328_8.upload.protocol=arduino

atmega328_8.upload.maximum_size=30720

atmega328_8.upload.speed=57600



atmega328_8.bootloader.low_fuses=0xE2

atmega328_8.bootloader.high_fuses=0xDE

atmega328_8.bootloader.extended_fuses=0x05

atmega328_8.bootloader.path=optiboot

atmega328_8.bootloader.file=optiboot_atmega328.hex

atmega328_8.bootloader.unlock_bits=0x3F

atmega328_8.bootloader.lock_bits=0x0F



atmega328_8.build.mcu=atmega328p

atmega328_8.build.f_cpu=8000000L

atmega328_8.build.core=arduino

atmega328_8.build.variant=standard









安価なUSBASPプログラマーをArduino UNOボードのISCPコネクタに接続し、Atmega328Pをソケットに挿入した後、ブートローダーをフラッシュします。



これで、UNOボード上の標準ブートローダーを使用して、環境内の適切なボードを選択して、マイクロコントローラーをデバッグおよびプログラムできます。



このプロジェクトでは、Arduino用の既製のライブラリが使用されました。







完全なスケッチコード
 #include <DHT.h> #include <SevenSegmentDisplay.h> #define DEBUG 1 #define TIMER_PERIOD 2400 #define ctrPIN 13 //    #define dhtPIN 15 //     #define btnPIN 18 // //      void(* resetFunc) (void) = 0; // Reset MC function //    SevenSegmentDisplay<true, BiDigit<17, 16> > ss(4, 9, 8, 6, 7, 5, 2, 3); //  DHT11     8 DHT dht(dhtPIN, DHT11, 3);// 8 //DHT dht(dhtPIN, DHT11); //16 //  FSM enum TMode { tmWait, //  tmNeedPower, //   tmAutoPower, //     tmManualPower //     }; //   enum TDisplayMode { tdmTemp , //  tdmHum , //  tdmTimer //  }; //int h_prev; int t,h,a0; int h_arr[6]; void setup() { //    #ifdef DEBUG Serial.begin(9600); Serial.println("Humidity controller start ..."); #endif //    pinMode(ctrPIN, OUTPUT); //      digitalWrite(ctrPIN, LOW); //     pinMode(btnPIN, INPUT); //   digitalWrite(btnPIN, HIGH); //    DHT11 dht.begin(); //     h = dht.readHumidity(); for( int i=0; i<6; i++)h_arr[i] = h; } //  0.5   unsigned long cnt05 = 0; unsigned long ms1 = 0; //    boolean flag_light = false; //    boolean flag_btn = false; //   boolean flag_hum = false; //     unsigned int timer = 0; TMode mode = tmWait; TDisplayMode dmode = tdmTemp; boolean blink_stat = false; void loop () { unsigned long ms = millis(); int p = ms - ms1; //    if( digitalRead(btnPIN) == LOW ){ int n = 1; for( int i=0; i<9; i++ ){ if( digitalRead(btnPIN) == LOW )n++; delay(10); } if( n > 9 )flag_btn = true; delay(400); #ifdef DEBUG Serial.println("Button is press"); #endif }//end if // ,     0.5  if( p < 0 || p > 500 ){ cnt05++; ms1 = ms; //    a0 = analogRead(A0); if( a0 > 1000 )flag_light = false; else flag_light = true; //  10    DHT11     if( cnt05%20 == 0 ){ h = dht.readHumidity(); t = dht.readTemperature(); //     3%    85% if( h - h_arr[5] > 3 || h > 85 )flag_hum = true; //      for( int i=5; i>0; i--)h_arr[i] = h_arr[i-1]; h_arr[0] = h; #ifdef DEBUG Serial.print("VAL: Temp="); Serial.print(t); Serial.print(" H="); Serial.print(h); Serial.print(" A0="); Serial.print(a0); Serial.print(" X="); Serial.print(cnt05); Serial.print(" TM="); Serial.print(timer); Serial.print(" MODE="); Serial.print(mode); Serial.print(" DMODE="); Serial.print(dmode); Serial.println(""); #endif //   switch( dmode ){ case tdmTemp : dmode = tdmHum; break; case tdmHum : dmode = tdmTimer; break; default: dmode = tdmTemp; }//end switch }//end if( cnt05%20 == 0 ) blink_stat = !blink_stat; SetStatusFSM(); }//end if( p < 0 || p > 500 ){ DisplayStatus(); }//end loop() /** *     */ void DisplayStatus(){ //     int point = -1; switch( mode ){ case tmNeedPower: point = 0; break; case tmAutoPower: case tmManualPower: if( blink_stat )point = 0; break; } switch( dmode ){ case tdmTemp : ss.print((unsigned)t,point,50); break; case tdmHum : ss.print((unsigned)h,point,50); break; case tdmTimer: //   if( timer > 120 )ss.print((unsigned)(timer/120),point,50); //   else if( timer > 0 )ss.print((unsigned)(timer/2),point,50); //  0 else ss.print(0,point,50); // ss.print((unsigned)(a0/100),point,50); break; }//end switch } /** *     */ void SetStatusFSM(){ switch(mode){ //   case tmWait : digitalWrite(ctrPIN, LOW); //   if( flag_btn ){ timer = TIMER_PERIOD; mode = tmManualPower; } //     else if( flag_hum ){ timer = TIMER_PERIOD; mode = tmNeedPower; } break; //     case tmNeedPower: digitalWrite(ctrPIN, LOW); //   if( flag_btn ){ mode = tmManualPower; } //   else if( !flag_light ){ mode = tmAutoPower; } break; //  "   " case tmAutoPower: //   digitalWrite(ctrPIN, HIGH); //   if( timer > 0 )timer--; //   if( flag_btn ){ mode = tmWait; timer = 0; } //   else if( flag_light ){ mode = tmNeedPower; } //   else if( timer <= 0 ){ timer = 0; mode = tmWait; } break; //  "    " case tmManualPower: //   digitalWrite(ctrPIN, HIGH); //   if( timer > 0 )timer--; //   if( flag_btn ){ mode = tmWait; timer = 0; } //   else if( timer <= 0 ){ timer = 0; mode = tmWait; } break; } //      flag_btn = false; flag_hum = false; }
      
      









問題





実装で最初に遭遇した問題は、DHT11センサーが機能しなかったことです。 Arduino UNOではすべてが問題ありませんが、裸のマイクロコントローラーでは機能しません。 問題は、コントローラーの頻度とDHTポーリングプロトコルのタイミングにありました。

DHTライブラリで8 MHzの周波数で動作するコントローラーでは、「3」(クラスコンストラクターの3番目のパラメーター)の遅延を指定する必要があります。DHTdht(dhtPIN、DHT11、3)。



2番目の問題は、リセットボタンと手動ボタンの任意の操作でした。 障害は、これらの調査結果の近くを通る電力線からのリード線によって引き起こされました。 まず、対応する端子のマイクロコントローラーの内蔵プルアップ抵抗が外部10Kに置き換えられました。 干渉は減少しましたが、完全には消えませんでした。 コントローラは、ファンを個別にオン/オフすることで、定期的に寿命を過ごしました。

次に、干渉のソフトウェア抑制を実装しました-ボタンは10ミリ秒の遅延で10回連続してポーリングされ、10個すべての操作でのみボタンが認識されました。



完成したデバイスは次のようになります。





現在、ファン制御コントローラーは試運転中であり、キッチンのファンを制御することを考えています。ストーブをオンにして、煙とガスの臭いを嗅ぎます。



便利なリンクのリスト:





私の記事は私のブログsamopal.proで見つけることができます。



All Articles