управление лентой WS2811 через I2C

Тема в разделе "Arduino & Shields", создана пользователем TonyA, 15 июл 2019.

  1. TonyA

    TonyA Нуб

    Всем доброго дня!
    При выполнении проекта по управлению светодиодами, сервоприводами и светодиодной лентой путем считывания входящего сигнала с пульта р/у наткнулся на проблему.
    Описание схемы:
    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() {

    }
     
  2. b707

    b707 Гуру

    вы всю программу в прерывание засунули? включая управление Фастледом? - ну так что ж вы удивляетесь?

    Оставьте в прерывании только получение байта с I2C. а все остальное вынесите в ЛУП
    И еще почитайте в справочкике. какие переменные помечаются префиксом volatile и зачем это надо
     
    Последнее редактирование: 15 июл 2019
  3. parovoZZ

    parovoZZ Гуру

    I2C для передачи всего 2-х состояний? Не смешите.
     
  4. b707

    b707 Гуру

    ТС просто другого кода в инете не нашел. Видно же, что 100% копипаста без понимания сути
     
  5. TonyA

    TonyA Нуб

    Я не спорю, что не опытны программист или еще что, но:
    1. я сюда обратился за советом, а не за ухмылками.
    2. вам, как опытным программистам и сделавшим не один проект на ардуинках, наверное известно, что входящий сигнал от радиоприемника использует прерывания (interrupts) и так как он постоянно "прыгает", а код для обработки сигналов внушительный, то включить в него еще код по управлению светодиодной лентой, также использующей прерывания, хорошего результата не даст. Уже пройденный этап. Поэтому подключить вторую Микру только для управления светодиодной лентой - пока единственный выход, который был найден.
    3. про копи паст - даже комментировать не буду. суть написанного кода (после прочтения всех библиотек и работы с ними) прекрасно понятна, не буду спорить, что код изначально из туториалов, адаптированный и дописанный под нужды проекта.
    4. про volatile, спасибо, поправлю.
     
  6. b707

    b707 Гуру

    а я уверен, что именно сути этого кода вы не понимаете.
    Понимали бы - не вставили работу с лентой в прерывание. Volatile тут только верхушка айсберга.
    Перечитайте внимательно мой первый ответ. Там всего три строчки.
     
  7. TonyA

    TonyA Нуб

    Изначально работа с лентой была не в прерывании, а в лупе, а в прерывании только считка данных по I2C. И лента не выключалась также. В мониторе порта было видно, что updateRD, который приходит с мастера не передавался в loop. Когда писал данный пост параллельно набрасывал вариант скеча, в котором все убрал в событие и этот вариант опубликовал.
     
  8. b707

    b707 Гуру

    верните код обратно в ЛУП и добавьте к updateRD префик volatile. Если оставить ленту в прерывании - работать не будет, почему - вы сами верно изложили выше, когда обосновывали перенос кода ленты в отдельный контроллер
     
  9. TonyA

    TonyA Нуб

    Добавил 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
    }
     

    Вложения:

  10. b707

    b707 Гуру

    Во-первых, уберите вывод в Сериал из прерывания - Сериал в прерывании не работает.
    Во-вторых, нафига вы выключаете прерывания в ЛУП? какой в этом смысл?Уберите
    И в третьих, ваше условие <if(updateRDShared)> не является "проверкой изменения переменной". Оно лишнее

    а вообще - вы бы для начала хоть что-нибудь про прерывания почитали

    Добавка - и почитайте описание на хендлер Wire.onreceive() -вы его используете неверно

    (все еще будете утверждать, что понимаете смысл каждой строки? :) - да мне почти каждую вашу строчку исправлять приходится...
     
    Последнее редактирование: 16 июл 2019