📜 ⬆️ ⬇️

Relay with IR remote control at ATtiny13A

Hi, Habr!

There was a need to turn off the old, but quite working speaker system from the TV remote, without getting up from the sofa. Thinking, I decided to use the IR receiver, which was once unscrewed from the old TV. IR receiver turned out to be unmarked. Having determined the outputs using the spear method, I found out that he is from the TSOP4xxx series, according to the picture:



Googling and having trained on the Arduino UNO, using this code and making sure that the sensor is working, I switched to rewriting the code on ATtiny13. Turning to it, I realized that it is very limited resources, both in flash and in RAM. At first, it was difficult to optimize for the size of the firmware, the controller still did not work, and when I realized that the memory used in the code is much more than 64 bytes, I had to specifically take up the optimization. As a result, with a grief in half, I optimized the code and assembled a prototype on a breadboard. Glad as a child! It blinked as I need.
')
General form:
Mockup


Scheme:
Spoiler


The time has come to translate the entire breadboard into textolite. The board was manufactured by the LUT method. The first pancake, as they say, lumpy. Having made the first scheme, having printed and assembled, I realized that nothing works. I incorrectly connected the LM317T. Besides, having broken Pyataks and tearing off some too thin tracks, I decided to make a second board. I made 0.7mm tracks in it and, having increased the pennies, somehow coped with a part of the problems. Here, too, it was not without problems, because again LM317T was connected incorrectly, and in the previous version of the board the receiver was also burned by submitting 12V to it.

By the way, this case is powered by 12V (I had a low-power transformer, so I used it). The choice of voltage was also due to the available 12V relay. To reduce the voltage for the microcontroller to 5V, the LM317T stabilizer is used, and the KP819 transistor at hand is used to control the relay.

SprintLayout final fee:
Spoiler


Used parts:


As for the code.

The original version was very weighty and could not work on ATtiny13 either. It was necessary to get rid of a heavy two-dimensional array. The code was very strange: “low” pulses were also recorded, but they were not used at all. In general, I threw out a two-dimensional array and this freed up at least 64 bytes of RAM. I calculated signals on the fly, but this was not enough and after adding the timer functionality, I had to cut variables as much as possible.

Code for 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(); } } 


Video Demonstration:



I stitched ATtiny13 with the help of Arduino UNO, using it as a programmer, guided by the publication "Firmware and Programming ATtiny13 with the help of Arduino" . For firmware I used a 9.6 MHz configuration.

I almost didn’t take photos, but what is there, that is:
A photo
Because of another pinout of the spare TSOP in the second version, I had to transfer it to the wiring and fix it with glue (later I just attached it to the case).

Second side board:



The second board is on top (IK moved the sensor):



The second board below:



End device:




Sources and firmware on the Yandex disk .

Materials used


myrobot.ru/wiki/index.php?n=Components.TSOP Everything about the TSOP IR receiver
www.atmel.com/images/doc2535.pdf Datasheet by ATtiny13
habrahabr.ru/post/234477 Instructions on firmware ATtiny13
payalo.at.ua/c_fuse/calc.html?part=ATtiny13A fyuzov calculator for ATtiny13
github.com/nathanchantrell/TinyPCRemote/tree/master/TinyPCRemote_CodeReader , the code of the remote control code reader that I took as the basis.

// UPD: Updated schemas. Replaced the capacitor on the relay diode.

Source: https://habr.com/ru/post/244349/


All Articles