ATtiny13AのIRリモート制御リレー

こんにちは、Habr!



ソファから立ち上がらずに、テレビのリモコンから非常に機能する古いスピーカーシステムをオフにする必要がありました。 考えてから、古いテレビからネジを外したIRレシーバーを使用することにしました。 IRレシーバーには識別マークがありませんでした。 pokeメソッドによって出力を決定した後、写真によると、彼はTSOP4xxxシリーズのものであることがわかりました。







Arduino UNOでグーグルとトレーニングを行い、 このコードを使用してセンサーが機能していることを確認して、ATtiny13でコードを書き直しました。 振り返ってみると、フラッシュとRAMの両方のリソースが非常に限られていることがわかりました。 最初は、ファームウェアのサイズを最適化するのに苦労しましたが、コントローラーはまだ動作しませんでした。コードで使用されているコードが64バイトをはるかに超えていることに気付いたとき、最適化を行う必要がありました。 その結果、悲しみとともに、コードを半分に最適化し、ブレッドボード上にプロトタイプをまとめました。 子供のように喜んだ! 必要に応じて点滅しました。



一般的なビュー:

ブレッドボード




スキーム:

ネタバレ




ブレッドボード全体をテクストライトに翻訳する時です。 ボードはLUT法で製造されました。 彼らが言うように、最初のパンケーキはゴツゴツしています。 最初の図を作成し、印刷して組み立てたところ、何も機能していないことに気付きました。 LM317Tを正しく接続しませんでした。 さらに、ニッケルを破壊し、薄すぎるトラックを引きちぎって、2枚目のボードを作ることにしました。 その中で、0.7mmのトラックを作成し、ニッケルを増やして、なんとか問題の一部に対処することができました。 ここでも、LM317Tを誤って接続したため、問題がなかったわけではなく、ボードの以前のバージョンでさえ、12Vを供給してレシーバーを焼き付けました。



ちなみに、このビジネスは12Vで動作します(低電力の変圧器があったので使用しました)。 電圧の選択も、12Vリレーの存在によるものでした。 マイクロコントローラーの電圧を5Vに下げるには、LM317Tスタビライザーを使用し、リレーを制御するには、手元にあるKT819トランジスターnpnを使用します。



SprintLayoutの最終ボード:

ネタバレ




使用部品:





コードに関しては。



初期バージョンは非常に「重く」、ATtiny13でも動作しませんでした。 重い2次元配列を取り除く必要がありました。 コードは非常に奇妙でした。「低」パルスも記録されましたが、決して使用されませんでした。 一般的に、彼は2次元配列を投げて、少なくとも64バイトのRAMを解放しました。 その場で信号を計算しましたが、これでは十分ではなく、タイマー機能を追加した後、できるだけ変数をカットする必要がありました。



Arduino IDEのコード
#define IRpin_PIN PINB #define IRpin 2 #define rLedPin 3 #define gLedPin 4 #define relayPin 1 #define MAXPULSE 5000 #define NUMPULSES 32 #define RESOLUTION 2 #define timeN1 1800000 #define timeN2 3600000 #define timerInterval 500 bool relayState = false; unsigned long timer = 0; unsigned long shift = timeN1;//30 min timer by default unsigned long previousMillis = 0; bool timerN = false; byte i = 0; void setup() { //default states DDRB |= (1<<relayPin); DDRB |= (1<<rLedPin); DDRB |= (1<<gLedPin); PORTB &= ~(1<<relayPin);//relay off PORTB &= ~(1<<rLedPin);//red led off PORTB |= (1<<gLedPin);//green led on /* //for debug Serial.begin(9600); Serial.println("Start | "+String(millis())); //*/ /* //for debug without ir receiver pinMode(5, INPUT); pinMode(6, INPUT); //*/ } void shutDown(){ relayState = true; PORTB |= (1<<relayPin); PORTB &= ~(1<<gLedPin); PORTB |= (1<<rLedPin); //Serial.println("turining off |"+String(millis())); } void startUp(){ relayState = false; PORTB &= ~(1<<relayPin); PORTB |= (1<<gLedPin); PORTB &= ~(1<<rLedPin); //Serial.println("turining on |"+String(millis())); } void loop() { unsigned long irCode = listenForIR(); // Wait for an IR Code //Serial.println("ir code: "+String(irCode)); if(irCode == 3359105948){//green button //Serial.println("Pressed green btn |"+String(millis())); if(timer == 0){//on off mode if(relayState == true){ startUp(); }else{ shutDown(); } }else{//cancel timer mode timer = 0; PORTB &= ~(1<<rLedPin);//turn off red led //Serial.println("timer canceled |"+String(millis())); } }//end green btn if(3359101868 == irCode){//red btn //Serial.println("pressed red btn |"+String(millis())); if(timer == 0){ if(relayState == 0){ timer = millis(); //Serial.println("timer started |"+String(millis())); }/*else{ Serial.println("already shutdown |"+String(millis())); } //*/ }else{//changing time mode timerN = !timerN; if(timerN){ //Serial.println("change 30sec |"+String(millis())); shift = timeN1;//30 min }else{ //Serial.println("change 60sec |"+String(millis())); shift = timeN2;//60 min } } }//end red btn } // loop end void checkTimer(){ unsigned long time = millis(); if(time - previousMillis >= timerInterval || previousMillis > time ) { previousMillis =time; timer1(); } } unsigned long listenForIR() {// IR receive code byte currentpulse = 0; // index for pulses we're storing unsigned long irCode = 0; // Wait for an IR Code irCode = irCode << 1; while (true) { unsigned int pulse = 0;// temporary storage timing //bool true (HIGH) while (IRpin_PIN & _BV(IRpin)) { // got a high pulse (99% standby time have HIGH) if(++i > 150){//check timer every 150 iterations (high frequency break ir code timing) i = 0; checkTimer(); } pulse++; delayMicroseconds(RESOLUTION); if (((pulse >= MAXPULSE) && (currentpulse != 0)) || currentpulse == NUMPULSES ) { return irCode; } } //make irCode irCode = irCode << 1; if ((pulse * RESOLUTION) > 0 && (pulse * RESOLUTION) < 500) { irCode |= 0; }else { irCode |= 1; } currentpulse++; pulse = 0; //bool false (LOW) while (!(IRpin_PIN & _BV(IRpin))) {//wait before new pulse //checkTimer(); pulse++; delayMicroseconds(RESOLUTION); if (pulse >= MAXPULSE || currentpulse == NUMPULSES ) { //Serial.println(irCode); return irCode; } } }//end while(1) }//end listenForIR //executing every timerInverval void timer1() { if(timer != 0){ if(timerN == true){//timeN1 or timeN2 PORTB |= (1<<rLedPin); }else{//blinking 30min PORTB ^= (1<<rLedPin);//invert } //Serial.println(String((timer+shift - millis())/1000)); } if(timer != 0 &&(timer+shift < millis() || timer > millis())){ timer = 0; shutDown(); } }
      
      







ビデオデモ:







私は、Arduino UNOを使用してATtiny13をフラッシュし、それをプログラマーとして使用し、出版物「Arduinoを使用したATtiny13のフラッシュとプログラミング」にガイドされていました。 9.6 MHz構成で使用されるファームウェアの場合。



私はほとんど写真を撮りませんでしたが、そこにあるもの、つまり:

写真
2番目のバージョンのスペアTSOPの別のピン配置のため、配線にそれを転送し、接着剤で固定する必要がありました(後でケースに取り付けただけです)。



側面の2番目のボード:







2番目のボードは上にあります(IRセンサーが転送されます):







2番目のボードの下:







エンドデバイス:









Yandexディスクのソースとファームウェア。



使用材料



myrobot.ru/wiki/index.php?n=Components.TSOP TSOP IRレシーバーに関するすべて

www.atmel.com/images/doc2535.pdf ATtiny13データシート

habrahabr.ru/post/234477 ATtiny13ファームウェアマニュアル

payalo.at.ua/c_fuse/calc.html?part=ATtiny13ATtiny13用の融合電卓

github.com/nathanchantrell/TinyPCRemote/tree/master/TinyPCRemote_CodeReader 、私が基礎として使用したリモートコントロールコードリーダーコード。



// UPD:更新されたスキーマ。 リレーのコンデンサをダイオードに置き換えました。



All Articles