IR remote на atmega8
- Войдите на сайт для отправки комментариев
Ср, 06/11/2013 - 07:56
Задача, казалось бы, тривиальная - включать/выключать лампу накаливания с ик пульта. Примеров масса. В самой бибилиотеке IR remote есть такой пример (IRrecvDemo). И на atmega328 (arduino uno) все прекрасно работает. Но если захотеть залить IRrecvDemo в atmega8, то облом! Не хватает 8 кб. Хотя головой понимаю, что для этой задачи atmega8 должно хватить с избытком.
Отсюда вопрос - как решить проблему включения нагрузки с ик пульта на atmega8?
Для себя вижу 2 пути решения:
1. Как то "ужать" библиотеку IR remote.
2. Писать скетч без этой библиотеки.
Подскажите в каком направлении двигаться правильнее?
Может есть готовые решения в среде Arduino IDE?
Только если переписать прошивку на чистом Си.
Для меня на данный момент это сложновато :(
Какая именно библиотека IR remote используется ? Ссылка ?
Задача, казалось бы, тривиальная - включать/выключать лампу накаливания с ик пульта. Примеров масса. В самой бибилиотеке IR remote есть такой пример (IRrecvDemo).
ну, и включайте лампу - зачем для этого нужно что-то в компорт писать?
Может есть готовые решения в среде Arduino IDE?
писал себе для одной лампы - одной кнопкой включается, другой выключается.
#include <IRremote.h> IRrecv irrecv(4); decode_results results; unsigned long ir; void setup() { pinMode(14, OUTPUT); digitalWrite(14, LOW); irrecv.enableIRIn(); // включить приемник ir = results.value; } void loop() { if (irrecv.decode(&results)) {if ((results.value > 0) && (results.value < 0xFFFFFFFF)) {unsigned long nir = results.value; if (nir != ir) {ir = nir; LED();}} irrecv.resume();} } void LED() { if (ir == 50168445) {if (digitalRead(14) != HIGH) {digitalWrite(14, HIGH);}} if (ir == 50156205) {if (digitalRead(14) != LOW) {digitalWrite(14, LOW);}} }и, сделать "Step 2" отсюда(на пару байтов некс похудеет) - там чел много чего ещё делал, но я не понял
http://ubiyubix.wordpress.com/2012/05/05/porting-the-arduino-irremote-library-to-the-attiny4313/
вот ссылка на библиотеку
https://github.com/shirriff/Arduino-IRremote
Да,кстати , если убрать все упоминания сериал порта,то скетч меньше вроде бы на пару кб :)
ну, и включайте лампу - зачем для этого нужно что-то в компорт писать?
Вот верно в народе говорят "Утро вечера мудреннее" :)
Сел переписал свой код (подобен Вашему) и мой скетч стал меньше 8 кб. Вчера вечером-ночью у меня это не удавалось. Точно косяк у меня в мозгу.
Вот мой код:
#include <IRremote.h> int RECV_PIN = 11; int LED_PIN = 13; IRrecv irrecv(RECV_PIN); decode_results results; int x=0; int power=0; void setup() { irrecv.enableIRIn(); pinMode(LED_PIN, OUTPUT); } void loop() { if (irrecv.decode(&results)) { delay (50); if (results.value==0xFFB24D) { x=1; power=!power; } if (x==1) { digitalWrite(LED_PIN, power); } irrecv.resume(); } }Спасибо за помощь!
kiril22? обратитесь к уважаемому камраду kisoft, он перелопатил библиотеку IRremote, под atmega16, и теперь мой скетч занимает всего 8 с небольшим килобайт, а в нем задействовано 11 кнопок.
Вот скрин: http://clip2net.com/s/675xdG
Вот код:
#include <IRremote.h> //#include <IRremote.h> //Зацепили библиотеку /////////////////////Секция переменных////////////////////// int RECV_PIN = 10; //Назначили пин для ИР приемника /* * Храним индекс пина (только для PWM) который выбран последним */ int8_t g_index = -1; /* * Код последней нажатой кнопки. Используется для выдачи кода при получении кода повтора */ unsigned long last_button = 0; /* * Начальная яркость LEDов с PWM */ #define START_BRIGHT 200 /* * Шаг изменения яркости */ #define BRIGHT_STEP 10 /* * Обработка IR сигналов с пульта */ IRrecv irrecv(RECV_PIN); decode_results results; /* * Если нужна отладка на Serial, закомментарь эту строку (код будет больше по объему) */ #define USE_RELEASE 1 #if !defined(USE_RELEASE) #define INIT_SERIAL(x) Serial.begin( (x) ) #define PRINT_DEBUG(x) Serial.print( (x) ) #define PRINTLN_DEBUG(x) Serial.println( (x) ) #define PRINTLNHEX_DEBUG(x) Serial.println( (x), HEX ) #else #define INIT_SERIAL(x) #define PRINT_DEBUG(x) #define PRINTLN_DEBUG(x) #define PRINTLNHEX_DEBUG(x) #endif /////////////////////Секция констант//////////////////////// /* * Это мои коды от Yamaha пульта #define BTN_0 0x3EC1C936 #define BTN_1 0x3EC129D6 #define BTN_2 0x3EC1A956 #define BTN_3 0x3EC16996 #define BTN_4 0x3EC1E916 #define BTN_5 0x3EC119E6 #define BTN_6 0x3EC19966 #define BTN_7 0x3EC159A6 #define BTN_8 0x3EC1D926 #define BTN_9 0x3EC139C6 #define BTN_UP 0x3EC12DD2 #define BTN_DOWN 0x3EC1CD32 #define BTN_LEFT 0x3EC1AD52 #define BTN_RIGHT 0x3EC16D92 #define BTN_POWER 0x3EC101FE #define BTN_VOL_UP 0x5EA158A7 #define BTN_VOL_DOWN 0x5EA1D827 #define BTN_STOP 0x3EC1A15E #define BTN_EQ 0x3EC11DE2 #define BTN_REPT 0x3EC141BE #define BTN_RETENTION 0xFFFFFFFF */ #define BTN_0 16593103L // Определяем константы для кнопок пульта. (коды кнопок) #define BTN_1 16582903L #define BTN_2 16615543L #define BTN_3 16599223L #define BTN_4 16591063L #define BTN_5 16623703L #define BTN_6 16607383L #define BTN_7 16586983L #define BTN_8 16619623L #define BTN_9 16603303L #define BTN_UP 16601263L #define BTN_DOWN 16584943L #define BTN_LEFT 16589023L #define BTN_RIGHT 16605343L #define BTN_POWER 16580863L #define BTN_VOL_UP 16613503L #define BTN_VOL_DOWN 16617583L #define BTN_STOP 16597183L #define BTN_EQ 16625743L #define BTN_REPT 16609423L #define BTN_RETENTION 4294967295L ////////////////////Секция массивов///////////////////////// /* * Под массив пинов выделяем N + 1 байт. Мы обрабатываем N кнопок, но поскольку удобно индекс с 1, то 0 элемент не используется */ #define MAX_PINS (9+1) /* * Внимание! Сейчас нельзя использовать PWM на выводе PD7 (пин 7), поскольку этот таймер используется для формирования прерываний для распознавания кодов PWM */ enum PinState { pdIS_OFF = 0, pdIS_ON = 0x01, pdPWM_ENABLED = 0x02 }; /* * Информация об одном пине */ struct PinInfo { /* Номер пина */ uint8_t pin_number; /* Состояние пина */ uint8_t pin_state; // PinState /* Яркость пина (только для PWM) */ int16_t pin_bright; /* * Возвращает признак, что LED включен */ uint8_t isOn() const { return pin_state & pdIS_ON; } /* * Возвращает признак, что LED выключен */ uint8_t isOff() const { return !isOn(); } /* * Возвращает признак, что LED может управляться PWM */ uint8_t isPWMEnabled() const { return pin_state & pdPWM_ENABLED; } /* Выключение LED */ void LEDOff() { pin_state &= ~pdIS_ON; if( pin_state & pdPWM_ENABLED ) { analogWrite( pin_number, 0 ); } else { digitalWrite( pin_number, LOW ); } } /* Включение LED */ void LEDOn() { pin_state |= pdIS_ON; if( pin_state & pdPWM_ENABLED ) { analogWrite( pin_number, pin_bright ); } else { digitalWrite( pin_number, HIGH ); } } /* Добавление яркости LED. Только для PWM, для остальных - игнорируется */ void addBright( uint8_t step ) { if( isPWMEnabled() ) { pin_bright += step; if( pin_bright > 255 ) { pin_bright = 255; } LEDOn(); } } /* Уменьшение яркости LED. Только для PWM, для остальных - игнорируется */ void subBright( uint8_t step ) { if( isPWMEnabled() ) { pin_bright -= step; if( pin_bright < 0 ) { pin_bright = 0; } LEDOn(); } } }; /* * Конфигурация пинов (LEDов) системы. 0 элемент не используется */ PinInfo pins[MAX_PINS] = { /* Не используется */ { 0, pdIS_OFF, 0 }, /* Далее реальные пины */ { 4, pdPWM_ENABLED, START_BRIGHT }, { 5, pdPWM_ENABLED, START_BRIGHT }, { 19, pdIS_OFF, 0 }, { 20, pdIS_OFF, 0 }, { 21, pdIS_OFF, 0 }, { 18, pdIS_OFF, 0 }, { 6, pdIS_OFF, 0 }, { 3, pdIS_OFF, 0 }, { 2, pdIS_OFF, 0 } }; /* * Погасить все светодиоды. Сбрасывает индекс последней нажатой кнопки */ void off_pins( void ) { for( uint8_t p = 1; p < MAX_PINS; p++ ) // Выключаем все светодиоды { pins[ p ].LEDOff(); } g_index = -1; } void setup() { INIT_SERIAL( 57600 ); // Инициализируем порт, скорость 57600. PRINTLN_DEBUG("Port Init"); // Выводим в порт сообщение. for( byte p = 1; p < MAX_PINS; p++ ) // Определяем пины светодиодов на вывод и моргаем для тестирования { pinMode( pins[ p ].pin_number, OUTPUT ); digitalWrite( pins[ p ].pin_number, HIGH ); delay(500); pins[ p ].LEDOff(); delay(500); } /* * Начальное значание индекса устанавливаем в -1 иначе будут глюки */ g_index = -1; /* * Включаем датчик на приём */ irrecv.enableIRIn(); } void loop() { /* * Ожидание кода с пульта. В это время мы ничего больше не делаем, только ожидаем сигнал (цикл ожидания организован в библиотеке) */ if(irrecv.decode(&results)) { /* Сохраняем полученный код, чтобы его не затер следующий код */ unsigned long l_value = results.value; /* И сразу разрешаем прием следующего кода */ irrecv.resume(); /* Если это не код повтора, сохраняем полученный код */ if( BTN_RETENTION != l_value ) { last_button = l_value; } /* Если это код повтора, обрабатываем его отдельно */ else { /* Повторяем предыдущую нажатую кнопку, только если это увеличение или уменьшение яркости */ if( BTN_VOL_UP == last_button || BTN_VOL_DOWN == last_button ) { l_value = last_button; } /* Иначе игнорируем */ else { return; } } /* Определяем, какая кнопка нажата и выполняем нужное действие */ switch (l_value) { case BTN_0: // Выключение ВСЕХ светодиодов PRINTLN_DEBUG("Button 0: OFF all LEDs"); off_pins(); break; #if MAX_PINS > 1 case BTN_1: // Включение/выключение LED1 (разрешен ШИМ) PRINT_DEBUG("Button 1: on/off LED on pin: "); PRINTLN_DEBUG( pins[ 1 ].pin_number ); check_button( 1 ); break; #endif #if MAX_PINS > 2 case BTN_2: // Включение/выключение LED2 (разрешен ШИМ) PRINT_DEBUG("Button 2: on/off LED on pin: "); PRINTLN_DEBUG( pins[ 2 ].pin_number ); check_button( 2 ); break; #endif #if MAX_PINS > 3 case BTN_3: // Вкл/выкл LED3 (без ШИМ) PRINT_DEBUG("Button 3: toggle pin: "); PRINTLN_DEBUG( pins[ 3 ].pin_number ); check_button( 3 ); break; #endif #if MAX_PINS > 4 case BTN_4: // Вкл/выкл LED4 (без ШИМ) PRINT_DEBUG("Button 4: toggle pin: "); PRINTLN_DEBUG( pins[ 4 ].pin_number ); check_button( 4 ); break; #endif #if MAX_PINS > 5 case BTN_5: // Вкл/выкл LED5 (без ШИМ) PRINT_DEBUG("Button 5: toggle pin: "); PRINTLN_DEBUG( pins[ 5 ].pin_number ); check_button( 5 ); break; #endif #if MAX_PINS > 6 case BTN_6: // Вкл/выкл LED6 (без ШИМ) PRINT_DEBUG("Button 6: toggle pin: "); PRINTLN_DEBUG( pins[ 6 ].pin_number ); check_button( 6 ); break; #endif #if MAX_PINS > 7 case BTN_7: // Вкл/выкл LED7 (без ШИМ) PRINT_DEBUG("Button 7: toggle pin: "); PRINTLN_DEBUG( pins[ 7 ].pin_number ); check_button( 7 ); break; #endif #if MAX_PINS > 8 case BTN_8: // Вкл/выкл LED8 (без ШИМ) PRINT_DEBUG("Button 8: toggle pin: "); PRINTLN_DEBUG( pins[ 8 ].pin_number ); check_button( 8 ); break; #endif #if MAX_PINS > 9 case BTN_9: // Вкл/выкл LED9 (без ШИМ) PRINT_DEBUG("Button 9: toggle pin: "); PRINTLN_DEBUG( pins[ 9 ].pin_number ); check_button( 9 ); break; #endif /* Эти кнопки не обрабатываются, можно их совсем отсюда убрать, но пока оставляем так */ case BTN_UP: case BTN_DOWN: case BTN_LEFT: case BTN_RIGHT: case BTN_POWER: case BTN_STOP: case BTN_EQ: case BTN_REPT: default: PRINT_DEBUG("Button ignored, code: "); PRINTLNHEX_DEBUG(l_value); break; case BTN_VOL_UP: PRINTLN_DEBUG("Volume Up"); brightness_control_up( g_index ); break; case BTN_VOL_DOWN: PRINTLN_DEBUG("Volume Donw"); brightness_control_down( g_index ); break; } } } /////////////////////Секция функций///////////////////////////////// /* * Функция обрабатывает кнопки, как PWM, так и обычные */ void check_button( int8_t index ) { if( index >= 0 ) { if( pins[ index ].isPWMEnabled() ) { /* Сохраняем индекс нажатой кнопки только PWM LEDов */ g_index = index; } /* * Если пин выключен, включаем его на сохраненной яркости */ if( pins[ index ].isOff() ) { /* Устанавливаем признак включения LED */ pins[ index ].LEDOn(); } /* * Если пин включен, выключаем его */ else { /* Выключаем пин */ pins[ index ].LEDOff(); /* Сбрасываем индекс последней нажатой кнопки */ g_index = -1; } } } /* * Увеличение яркости для пина с индексом index */ void brightness_control_up( int8_t index ) { if( index >= 0 ) { /* Увеличиваем яркость на определенный шаг и выводим на LED */ pins[ index ].addBright( BRIGHT_STEP ); } } void brightness_control_down( int8_t index ) { if( index >= 0 ) { /* Уменьшаем яркость на определенный шаг и выводим на LED */ pins[ index ].subBright( BRIGHT_STEP ); } }kiril22? обратитесь к уважаемому камраду kisoft, он перелопатил библиотеку IRremote, под atmega16, и теперь мой скетч занимает всего 8 с небольшим килобайт, а в нем задействовано 11 кнопок.
Спасибо! Попробую покопаться в вопросе оптимизации библиотек под конкретные задачи.
Я тут вчера тоже задумался над построением пульта. В интернете все примеры на TSOP22. А можно ли сделать это на ИК фототранзисторе(тот который в мышках)? Всеравно сигнал цифровой.
А если попробовать так? -
(по сути это некое подобие осцилографа)
//запись пока нажата кнопка while(digitalRead(StartButton)==1){ array[i]=digitalRead(2); time[i]=milis(); i++; delay(10); } .... //вывод массивов for(int k=0;k<i;i++) { Serial.Println(array[k]+':'+time[k]); }На выходе мы получим массив данных из которых можно построить график на компьютере с шагом 10 милисекунд. А затем можно выяснить какой длительности сигналы и просто эмулировать их и переслать на ИК светодиод.
*Хотел попробовать, но никак не могу найти фототранзистор, а разбирать мышь основываясь только на своей теории как-то нехочется.
Думаю, так работать не должно.
Вот здесь можно почитать про ИК приемники
http://www.myrobot.ru/wiki/index.php?n=Components.TSOP
Думаю, так работать не должно.
Вот здесь можно почитать про ИК приемники
http://www.myrobot.ru/wiki/index.php?n=Components.TSOP
Спасибо, интересная статья.
Всё отличие между транзистором и датчиком которую я увидел - это фильтрация сигналов, отличных от " 36, 38, 40 кГц". Я так понял - если датчик ловит "пачку" с кол-вом испульсов от 15 до 50 - он устанавливает соответствующее напряжение на Vo , а дальше всю работу делает софт - кодирует и декуодирует значения в более читабельные пакеты.
По моему предположению (если частоты считывания хватит), ардвинка должна ловить именно те самые пачки - то есть самый низкий уровень(физический уровень). А закодировать их через функцию не составит труда - Например массив для включения телевизора будет выглядеть так:
int TVOn[]={27,15,27,27,27}; - где элементы массива представляют колличство импульсов на частоте приемника
27 - некое значение представляющее собой логическую единицу.
15 - логический ноль.
Через вывод каждого элемента вводится задержка равная времени между пачками.
Итого на выходе мы получим значение 10111.
Так что по моему мнению все упирается только в частоту считывания сигнала.
Вот немного оптимизировал свой код, добавил комментарии для начинающих. Проверил на atmega8, прекрасно работает. Всем спасибо за участие и помощь!
Жирно конечно, на чистом Си у меня заняло 1350 байт.
Полностью согласен, что жирно. Однако, считаю это адекватной платой за удобство и низкий порог вхождения в программирование микроконтроллеров (в плане знаний). Где мне такой подход мешает, я начинаю применять "чистый Си". Жаль, что время на его изучение и практическое применение у меня сильно ограничено.
Поддержу пожалуй тему
Вот что мне удалось сделать на Atmega8 и Arduino
Это запись в память одной кнопик пульта в память и с дальнейшим управлением.
#include <IRremote.h> #include <EEPROM.h> #define BUTTON 12 int RECV_PIN = 11; int a=0; int val = 0; int state = 0; IRrecv irrecv(RECV_PIN); decode_results results; void setup(){ irrecv.enableIRIn(); DDRB = 0b00100100; } void loop() { val = digitalRead(BUTTON); delay(100); if (val == HIGH) { state = 1 - state; } if (state == 1) { for (int i = 0; i < 512; i++) EEPROM.write(i, 0); PORTB |= _BV(PC5); if (irrecv.decode(&results)) { EEPROM.write(0, results.value); irrecv.resume(); if (results.value != ' '){ PORTB &= ~_BV(PC5); state = 0; } } } else { uint8_t counter; counter = EEPROM.read(0); if (irrecv.decode(&results)) { uint8_t (results.value); delay(300); if (uint8_t(results.value) == counter) { //PORTB |= _BV(PC2); //delay(4000); //PORTB &= ~_BV(PC2); if (uint8_t(results.value) == counter) {a=a+1;} if (a==1){PORTB |= _BV(PC2);} else {PORTB &= ~_BV(PC2); a=0;} } { delay(50); } irrecv.resume(); } } }Кстати сейчас вполне недорогие Atmega168 ссыль
немного дороже 328 можно взять
http://www.aliexpress.com/item/10pcs-lot-Free-Shipping-ATmega328P-AU-ATM...
//---------------------------------------------------------------------------------------------------------------------- // TinyPCRemote // By Nathan Chantrell nathan.chantrell.net // Receives infra red codes and emulates a USB keyboard for remote control // // Licenced under the Creative Commons Attribution-ShareAlike 3.0 Unported (CC BY-SA 3.0) licence: // creativecommons.org/licenses/by-sa/3.0/ //---------------------------------------------------------------------------------------------------------------------- //#define F_CPU 9600000 #define IRpin_PIN PINB #define IRpin 0 #define MAXPULSE 5000 // max IR pulse length, default 5 milliseconds #define NUMPULSES 100 // max IR pulse pairs to sample #define RESOLUTION 1 // time between IR measurements uint16_t pulses[NUMPULSES][2]; // pair is high and low pulse uint8_t currentpulse = 0; // index for pulses we're storing #define led 1 void setup() { pinMode(0, INPUT); // Make sure IR pin is set as inpu pinMode(led, OUTPUT); digitalWrite(led, HIGH); delay(1000); digitalWrite(led, LOW); } void loop() { unsigned long irCode=listenForIR(); // Wait for an IR Code // Process the pulses to get our code for (int i = 0; i < 32; i++) { irCode=irCode<<1; if((pulses[i][0] * RESOLUTION)>0&&(pulses[i][0] * RESOLUTION)<500) { irCode|=0; } else { irCode|=1; } } // --------------------------------------------------------------------------------------- // Enter IR codes and keystrokes to send below, see keyboard_commands.txt for list of keys // --------------------------------------------------------------------------------------- if (irCode==3305615295) { // String example with trailing space, "hello " digitalWrite(led, HIGH); } else if (irCode==3317670975) { // String example with enter, "world <enter>" digitalWrite(led, LOW); } } // loop end // IR receive code int listenForIR() { currentpulse = 0; while (1) { unsigned int highpulse, lowpulse; // temporary storage timing highpulse = lowpulse = 0; // start out with no pulse length while (IRpin_PIN & _BV(IRpin)) { // got a high pulse highpulse++; delayMicroseconds(RESOLUTION); if (((highpulse >= MAXPULSE) && (currentpulse != 0))|| currentpulse == NUMPULSES) { return currentpulse; } } pulses[currentpulse][0] = highpulse; while (! (IRpin_PIN & _BV(IRpin))) { // got a low pulse lowpulse++; delayMicroseconds(RESOLUTION); if (((lowpulse >= MAXPULSE) && (currentpulse != 0))|| currentpulse == NUMPULSES) { return currentpulse; } } pulses[currentpulse][1] = lowpulse; currentpulse++; } }Только на тини13 почему-то не канает, код кнопки походу другой нежели как на ардуино.
Может когда-то будет желание то разберусь с этим...
поддержу тему. сделал управление открытием/закрытием экрана для домашнего кинотеатра с проектором на атмега8
пока только управление с пульта
хочу сделать еще "автоматически" пульт, который бедет слать коды IR при включении проектора автоматически. Хочу тоже сделать на мега8, но вот IRremote принципиально не компилируется для атмега8
знает ли кто решение?
все получилось, пролистал исходники библиотеки и обнаружил, что для мега8 надо использовать 9-й пин вместо 3-го