Всем доброго дня! При выполнении проекта по управлению светодиодами, сервоприводами и светодиодной лентой путем считывания входящего сигнала с пульта р/у наткнулся на проблему. Описание схемы: 1. радиоприемник подключен к цифровому входу на Ардуино Уно (pin 9). Уно используется как мастер при считывании входящего сигнала с радиоприемника и в зависимости от сигнала управляет положением 10 сервомашинок, у некоторых сервомашинок есть логика движения по таймингу с использованием millis. 2. так как для считывания сигнала с радиоприемника используется ISR и библиотека <PinChangeInt.h>, то управление светодиодной лентой выведено на Ардуино Микро с передачей бита "1" = вкл или "2" - выкл с Мастер Ардуино Уно через I2C. 3. схема подключения 2-х ардуин: - 4 и 5 pin на Ардуино Уно подключены к 2 и 3 pin на Ардуино Микро - питание Ардуино Микро и Уно в 5В отдельные, подключена общая земля - к pin 2 и 3 на Микро подключены резисторы с питания на 1кОм 4. схема подключения светодиодной ленты (полностью в соответствии с описанием https://learn.adafruit.com/adafruit-neopixel-uberguide?view=all) - pin 6 подключен к DIN на ленте, на стороне Микры подключен резистор на 470Ом - так как у ленты отдельное питание на 12В, то подключен конденсатор на 1000Ф С кодом по считыванию сигнала с радиоприемника и управлением сервомашинками и светом проблем нет. Также с передачей битов "1" или "2" при необходимых условиях также проблем нет. Микра также получает входящий сигнал "1" или "2", но при этом ничего не происходит при обработке этих данных. Светодиодная лента зажигается и работает, но не выключается. Проблема очевидно в коде, но вот не могу до конца понять в каком направлении его дальше править... Код для Микры по управлению лентой Код (C++): // Wire Slave Receiver // include libraries #include <Wire.h> #include <FastLED.h> // define led and led output pins #define GEAR_LIGHTS_PIN 6 #define NUM_LEDS 14 #define BRIGHTNESS 255 #define LED_TYPE WS2811 #define COLOR_ORDER GRB CRGB leds[NUM_LEDS]; // define slave I2C address #define SLAVE_ADDR 9 // define variable for recieved data int currentRD = 0; int updateRD = 0; // variable for recieved data from I2C Master //variables to check the timing unsigned long previousMillis = 0; const long ledinterval = 5000; unsigned long ledMillis = 0; void setup() { delay(3000); pinMode(GEAR_LIGHTS_PIN, OUTPUT); FastLED.addLeds<LED_TYPE, GEAR_LIGHTS_PIN, COLOR_ORDER>(leds, NUM_LEDS).setCorrection( TypicalLEDStrip ); FastLED.setBrightness(BRIGHTNESS); Wire.begin(SLAVE_ADDR); // join i2c bus Wire.onReceive(receiveEvent); // register event Serial.begin(9600); // start serial for output } void receiveEvent() { updateRD = Wire.read(); // receive byte as an integer Serial.print("updateRD from Master: "); Serial.println(updateRD); // if updateRD from Master is not equial to updateRD in Slave if(currentRD != updateRD) { if(updateRD = 1) // turn led on { fill_solid(leds, NUM_LEDS, CRGB::White); FastLED.show(); ledMillis = millis(); currentRD = updateRD; } else if(updateRD = 2) // turn led off { fill_solid(leds, NUM_LEDS, CRGB::Black); FastLED.show(); currentRD = updateRD; } } Serial.println(currentRD); // print the variable for recieved data // turn led off if time exceeds ledinterval if(ledMillis - previousMillis > ledinterval) { fill_solid(leds, NUM_LEDS, CRGB::Black); FastLED.show(); previousMillis = ledMillis; } } Буду благодарен за помощь. void loop() { }
вы всю программу в прерывание засунули? включая управление Фастледом? - ну так что ж вы удивляетесь? Оставьте в прерывании только получение байта с I2C. а все остальное вынесите в ЛУП И еще почитайте в справочкике. какие переменные помечаются префиксом volatile и зачем это надо
Я не спорю, что не опытны программист или еще что, но: 1. я сюда обратился за советом, а не за ухмылками. 2. вам, как опытным программистам и сделавшим не один проект на ардуинках, наверное известно, что входящий сигнал от радиоприемника использует прерывания (interrupts) и так как он постоянно "прыгает", а код для обработки сигналов внушительный, то включить в него еще код по управлению светодиодной лентой, также использующей прерывания, хорошего результата не даст. Уже пройденный этап. Поэтому подключить вторую Микру только для управления светодиодной лентой - пока единственный выход, который был найден. 3. про копи паст - даже комментировать не буду. суть написанного кода (после прочтения всех библиотек и работы с ними) прекрасно понятна, не буду спорить, что код изначально из туториалов, адаптированный и дописанный под нужды проекта. 4. про volatile, спасибо, поправлю.
а я уверен, что именно сути этого кода вы не понимаете. Понимали бы - не вставили работу с лентой в прерывание. Volatile тут только верхушка айсберга. Перечитайте внимательно мой первый ответ. Там всего три строчки.
Изначально работа с лентой была не в прерывании, а в лупе, а в прерывании только считка данных по I2C. И лента не выключалась также. В мониторе порта было видно, что updateRD, который приходит с мастера не передавался в loop. Когда писал данный пост параллельно набрасывал вариант скеча, в котором все убрал в событие и этот вариант опубликовал.
верните код обратно в ЛУП и добавьте к updateRD префик volatile. Если оставить ленту в прерывании - работать не будет, почему - вы сами верно изложили выше, когда обосновывали перенос кода ленты в отдельный контроллер
Добавил volatile для переменной для получения сигнала по I2C, добавил статичную переменную для снятия локальной копии в loop, добавил interrupts. Не принимает значение локальной переменной все еще... Пробовал и с проверкой изменения состояния volatile переменной <if(updateRDShared)>, так и без этого условия. Код (C++): // Wire Slave Receiver // include libraries #include <Wire.h> #include <Adafruit_NeoPixel.h> // define led and led output pins #define GEAR_LIGHTS_PIN 6 #define NUM_LEDS 8 Adafruit_NeoPixel strip(NUM_LEDS, GEAR_LIGHTS_PIN, NEO_GRB + NEO_KHZ400); // define slave I2C address #define SLAVE_ADDR 9 // define variable for recieved data volatile int currentRD = 0; volatile int updateRDShared = 0; //variables to check the timing unsigned long previousMillis = 0; const long ledinterval = 5000; unsigned long ledMillis = 0; void setup() { delay(3000); pinMode(GEAR_LIGHTS_PIN, OUTPUT); strip.begin(); strip.show(); // Initialize all pixels to 'off' Wire.begin(SLAVE_ADDR); // join i2c bus Wire.onReceive(receiveEvent); // register event Serial.begin(9600); // start serial for output } void loop() { // create local variables to hold a local copies of the I2C inputs static int updateRD; if(updateRDShared) { noInterrupts(); // turn interrupts off quickly // take a local copy of I2C signal variable that was updated to use this in the rest of loop updateRD = updateRDShared; if (updateRD != currentRD) { if(updateRD = 1) // turn led on { strip.setBrightness(100); strip.setPixelColor(7, 255, 255, 255); strip.show(); ledMillis = millis(); currentRD = updateRD; } else // turn led off { strip.setBrightness(1); strip.setPixelColor(7, 0, 0, 0); strip.show(); currentRD = updateRD; } //Serial.print("currentRD - "); //Serial.println(currentRD); // print the variable for recieved data Serial.print("updateRD - "); Serial.println(updateRD); // print the variable for recieved data } // turn led off if time exceeds ledinterval if(ledMillis - previousMillis > ledinterval) { previousMillis = ledMillis; strip.setBrightness(1); strip.setPixelColor(7, 0, 0, 0); strip.show(); } interrupts(); // we have local copies of the inputs, so now turn interrupts back on } } // function that executes whenever data is received from master // this function is registered as an event, see setup() void receiveEvent() { updateRDShared = Wire.read(); // receive byte as an integer, variable for recieved data Serial.print("updateRD from Wire - "); Serial.println(updateRDShared); // print the variable for recieved data }
Во-первых, уберите вывод в Сериал из прерывания - Сериал в прерывании не работает. Во-вторых, нафига вы выключаете прерывания в ЛУП? какой в этом смысл?Уберите И в третьих, ваше условие <if(updateRDShared)> не является "проверкой изменения переменной". Оно лишнее а вообще - вы бы для начала хоть что-нибудь про прерывания почитали Добавка - и почитайте описание на хендлер Wire.onreceive() -вы его используете неверно (все еще будете утверждать, что понимаете смысл каждой строки? - да мне почти каждую вашу строчку исправлять приходится...