IRremote не реагирует после нескольких нажатий
- Войдите на сайт для отправки комментариев
Сб, 30/11/2019 - 04:16
Здравствуйте!
Написал код для управления светодиодной лентой с пульта. Столкнулся с проблемой, после нескольких нажатий на пульте ардуина перестает реагировать на команды с пульта. Добавил кнопку, она работает без проблем, меняет еффекты, но даже после нажатий на кнопку на пульт не реагирует. Подскажите в чем может быть ошибка?
#include "IRremote.h" #include <WS2812FX.h> #include <EEPROM.h> #define IR_RECV_PIN 4 #define LED_PIN 13 #define LED_COUNT 180 #define BUTTON 2 IRrecv irrecv(IR_RECV_PIN); decode_results results; WS2812FX ws2812fx = WS2812FX(LED_COUNT, LED_PIN, NEO_GRB + NEO_KHZ800); byte ledMode = 1; int ledColor = 0; void setup() { EEPROM.get(0,ledMode); ws2812fx.init(); ws2812fx.setBrightness(30); ws2812fx.setSpeed(1000); ws2812fx.setColor(0xFFFFFF); ws2812fx.setMode(ledMode); ws2812fx.start(); irrecv.enableIRIn(); pinMode(2,INPUT_PULLUP); attachInterrupt (digitalPinToInterrupt (BUTTON), btnChangeEffect, CHANGE); } void loop() { if (irrecv.decode(&results)) { switch (results.value) { case 0xFFA25D: //---------------------------------------- Key 1 break; case 0xFF629D: //---------------------------------------- Key 2 break; case 0xFFE21D: //---------------------------------------- Key 3 break; case 0xFF22DD: //---------------------------------------- Key 4 break; case 0xFF02FD: //---------------------------------------- Key 5 break; case 0xFFC23D: //---------------------------------------- Key 6 break; case 0xFFE01F: //---------------------------------------- Key 7 Speed - if (ws2812fx.getSpeed() <= 0) {ws2812fx.setSpeed(1);} else {ws2812fx.setSpeed(ws2812fx.getSpeed() * 0.8);} break; case 0xFFA857: //---------------------------------------- Key 8 break; case 0xFF906F: //---------------------------------------- Key 9 Speed + if (ws2812fx.getSpeed() >= 54600) {ws2812fx.setSpeed(65535);} else {ws2812fx.setSpeed(ws2812fx.getSpeed() * 1.2);} break; case 0xFF9867: //---------------------------------------- Key 0 break; case 0xFF6897: //---------------------------------------- Key * Brightness - if (ws2812fx.getBrightness() <= 25) {ws2812fx.setBrightness(1);} else {ws2812fx.decreaseBrightness(25);} break; case 0xFFB04F: //---------------------------------------- Key # Brightness + if (ws2812fx.getBrightness() >= 230) {ws2812fx.setBrightness(255);} else {ws2812fx.increaseBrightness(25);} break; case 0xFF18E7: //---------------------------------------- Key Up Color + ledColor += 10; if (ledColor > 768) {ledColor = 0;} changeColor(ledColor); break; case 0xFF4AB5: //---------------------------------------- Key Down Color - ledColor -= 10; if (ledColor <= 10) {ledColor = 768;} changeColor(ledColor); break; case 0xFF10EF: //---------------------------------------- Key Left Prev effect ledMode--; if (ledMode < 1) {ledMode = 55;} EEPROM.put(0, ledMode); ws2812fx.setMode(ledMode); break; case 0xFF5AA5: //---------------------------------------- Key Right Next effect ledMode++; if (ledMode > 55) {ledMode = 1;} EEPROM.put(0, ledMode); ws2812fx.setMode(ledMode); break; case 0xFF38C7: //---------------------------------------- Key Ok break; } irrecv.resume(); // Receive the next value } ws2812fx.service(); } void btnChangeEffect() { if (digitalRead (BUTTON) == HIGH) { ledMode++; if(ledMode>55) {ledMode=1;} EEPROM.put(0, ledMode); ws2812fx.setMode(ledMode); // asm volatile (" jmp 0"); } } void changeColor(int color) { uint8_t redIntensity; uint8_t greenIntensity; uint8_t blueIntensity; if (color > 0 && color < 768) { if (color <= 255) { redIntensity = 255 - color; greenIntensity = color; blueIntensity = 0; } else if (color <= 511) { redIntensity = 0; greenIntensity = 255 - (color - 256); blueIntensity = (color - 256); } else { redIntensity = (color - 512); greenIntensity = 0; blueIntensity = 255 - (color - 512); } } else { redIntensity = 255; greenIntensity = 255; blueIntensity = 255; } ws2812fx.setColor(redIntensity, greenIntensity, blueIntensity); }
А где default?
http://arduino.ru/Reference/SwitchCase
Ошибка, скорее всего, в неправильном алгоритме. Например, функция на строке 96 слишком часто вызывается.
Давайте, я Вам расскажу несколько общих соображений, которые, возможно и не имеют отношения к Вашему конкретному случаю, но, на мой взгляд, небесполезны.
Вы используете вместе библиотеки IRremore и Adafruit_NeoPixel, которые очень плохо дружат между собой. Не то, чтобы их невозможно заставить работать вместе, но это не всегда просто и часто – глюкаво. Дело в том, что обе заточены на точные тайминги. Посмотрите, что делается в самом начале функции Adafruit_NeoPixel::show(void). Одна из первых строк там - noInterrupts(); и далее идёт достаточно длительный отрезок работы с запрещёнными прерываниями (длительность пропорциональна длине ленты). Всё это время IRremore будет тщетно ожидать прерывания, на которое он заточен и это запросто может нарушить его работу.
Я бы на Вашем месте не дожимал этот код, а … ну не знаю, например, вынес бы работу с IR на самостоятельный контроллер (на тиньку типа) и сообщал бы основному контроллеру о готовых командах по мере их прихода. Ну, или наоборот, вынес бы обслуживание ленты на отдельный контроллер. В общем, я бы их разнёс. Adafruit_NeoPixel (особенно при длинных лентах) – огромная нагрузка на контроллер.
я когда споткнулся на конфликте IRremote с другими библиотеками, использующими тот же таймер, что и IRremote - залил IRremote в атмегу8(самое доступное, что у меня под рукой было) и передавал код с м8 на основной контроллер по сериалу.
эту архитектуру повторил ещё один форумчанин - сделал контроллер кондиционера. всё очень стабильно работало.
но... если вспомнить, что сериал в дуино занят для заливки и отладки, то фиг его знает - как извращаться.
Если пользователь светоинсталляции не пчела, то достаточно просто реже выводить на ленту. Тогда резко снижается вероятность наступления любой широкораспространенной "светодиодной" библиотекой на хвост Irremote.
Спасибо всем за ответы. Попробую выводить реже, если не поможет придумаю что то другое.
А где default?
http://arduino.ru/Reference/SwitchCase
насколько я знаю то default не обязателен
в описании к библиотеке в примерах она постоянно в лупе
https://github.com/kitesurfer1404/WS2812FX/blob/master/extras/WS2812FX%20Users%20Guide.md
У меня скетч сейчас занимает почти всю память в nano и не могу добавить Serial чтоб в мониторе порта посмотреть что происходит. Попробую убрать библиотеку IRemote и Bluetooth модуль HC-06 вместо пульта добавить, но не уверен хватит ли места . Подскажите возможно есть альтернатива Serial менее прожорливая?
Нашел вот такую штуку https://github.com/AlexGyver/GyverCore
там указано Добавлен очень быстрый и лёгкий uart (аналог классу Serial)
Но почитав здесь отзывы по поводу AlexGyver, боюсь чтобы не сделать еще хуже))
в описании к библиотеке в примерах она постоянно в лупе
На то он и пример, чтобы просто показать общий принцип. В этом примере вообще ничего кроме функций библиотеки не дёргается в лупе.