Настраиваемое ядро для Arduino

Тема в разделе "Глядите, что я сделал", создана пользователем DIYMan, 20 дек 2017.

  1. DIYMan

    DIYMan Guest

    Поиск на шине - самая объёмная часть кода в 1-Wire ;) Можете глянуть. Если поиск не юзать - объём кода будет меньше, но мне поиск нужен, т.к. вся фишка - это горячая замена датчиков DS18B20 с сохранением их индексов в системе - то, чего нет практически нигде в самописных скетчах, а у меня - реализовано, можете сами проверить: добавить два датчика DS18B20 в конфиг, загрузить конфиг, дождаться, когда с этих датчиков пойдут показания, потом отцепить один, дождаться, пока с него не будет показаний, потом - прицепить третий, с совершенно новым адресом: он встанет на место отсоединённого. Без плясок с бубном из-за особенностей поиска адресов на шине 1-Wire - такого функционала не получить, т.к. порядок выдачи адресов - недетерминирован ;)

    И да - ещё я скромный :D

    З.Ы. Код инициализации I2C оптимизировал, в следующей обнове будет. Щас думаю, как внедрить BMP180 - там под него надо свою структуру представления данных, думаю, шоб не ошибиться и чего не донепредусмотреть :)
     
  2. DIYMan

    DIYMan Guest

    Так, по BMP180, что надо из настроек в конфиге:

    1. Выбор шины I2C - первая или вторая;
    2. Указание нормального давления для своего местоположения - для корректировки высоты над уровнем моря;
    3. Указание вида измерений - в паскалях или мм. рт. ст.

    Что по данным в хранилище:

    1. Температура;
    2. Давление;
    3. Высота над уровнем моря.

    Ничего не забыл?
     
  3. alex_rnd61

    alex_rnd61 Нерд

    Высота квартиры от уровня земли :) Кроме давления в мм. рт. ст. и температуры в градусах другими не пользовался, хотя для экстремалов высота наверное будет важна. Тут ещё столкнулся с тем, что нужно запрашивать текущие настройки датчика. У меня слейвы выдают "сырые" данные, а мастер делает с ними что хочет, но для некоторых датчиков , чтобы получить результат, нужно знать их настройки. Но это уже "на любителя".
     
  4. DIYMan

    DIYMan Guest

    Ну в принципе в классы датчиков мона дописать методы нужные. Все датчики наследуются от CoreSensor - можно получить из списка датчиков датчик и привести к нужному потомку ;)
     
  5. alex_rnd61

    alex_rnd61 Нерд

    Щас главное I2C добить и начать боевые испытания датчиков. Я уже и дуню DUE подтянул и ... о что откопал, совсем про неё забыл: Leonardo GPRS/GSM IOT с SIM800C на борту. :oops:
     
  6. DIYMan

    DIYMan Guest

    Так а чего там добивать-то? Оно и без мелкой оптимизации работает: у мну щас висят BMP180, DS3231, BH1750, Si7021 - все на I2C, все работают ;)
     
  7. alex_rnd61

    alex_rnd61 Нерд

    Ну я как раз про мелкую оптимизацию. В каком модуле лучше инициализировать I2C?
     
  8. DIYMan

    DIYMan Guest

    Да не мешает это жить никому :) Впрочем, я обновил на гитхабе, и с части датчиков убрал инициализацию Wire.begin - теперь всё разруливается при вызове getWireInterface автоматически. Исключение - Si7021 - там в коде класса HTU21D ещё осталось, позже займусь.
     
  9. DIYMan

    DIYMan Guest

    С праздником всех!

    Провёл небольшой рефакторинг в плане оптимизации и приведения много где чего к однозначным размерностям типов данных (вместо int - int16_t и т.п.). Заодно добавил поддержку BMP085/BMP180. Вот как сейчас у мну выглядят показания (залито на Mega2560, всё на длинных сопливых макетных проводах):

    screen.png

    Вот как выглядят датчики конфига:

    screen2.png

    А вот так - добавление датчика BMP180, как видно - там можно указывать и единицы измерения для давления, и нормальное давление местоположения датчика:

    screen3.png

    Сурово, чо :D Теперь надо насчёт HX711 подумать, а то часто просят - шоб весы, шобы вешаться :)
     
  10. DIYMan

    DIYMan Guest

    Сделал для RS-485 отсыл любых данных, не отключая логики работы ядра, т.е. обмена информацией хранилищ. При этом остаётся возможность полностью выключить логику ядра, чтобы получить минимальную обвязку для работы с RS-485. Отсыл пользовательских данных инициируется в любой момент мастером, и выглядит так:

    Код (C++):
        byte* data = ....;
        uint16_t dataLength = ...;
        Stream* writeStream = RS485.beginUserPacket(dataLength);
        if(writeStream)
        {
          writeStream->write(data,dataLength);
          RS485.endUserPacket();
        }
    При этом на слейв приходит событие, в котором он могёт послать эхо мастеру (мастер после отсыла пользовательских данных уже ждёт автоматически):

    Код (C++):
    void ON_RS485_DATA_RECEIVED(Stream* stream, uint16_t dataToRead)
    {
      DBG(F("USER DATA ON RS-485, LENGTH="));
      DBGLN(dataToRead);

      // просто пишем эти данные в Serial
      uint16_t readed = 0;
      while(readed < dataToRead)
      {
        while(stream->available())
        {
          Serial.write(stream->read());
          readed++;
        }
      }

      // вычитали данные, отправляем назад любые данные к мастеру, какие хочется
      String pingBack = F("Ping back from RS-485 slave!");
      // отсылаем данные мастеру, пусть делает с ними что хочет.
      // Тут мы ожидаем, что после окончания передачи мастер переключится на приём, и будет ждать от нас ответа.
      RS485.echo((uint8_t*) pingBack.c_str(),pingBack.length());
    }
    Префикс пользовательского пакета посылается как "0x0D 0x0D 0x0D 0x0D ДлинаДанныхВДвухБайтах 0x0A 0x0A 0x0A 0x0A" (т.е. максимальная длина одного пакета пользовательских данных - 65535 байт, думаю, достаточно ;)). После этого слейв сигнализирует о событии, и надо вычитать остальные данные внутри события.

    Проверил в терминалке, закрепив в конфигураторе Serial за RS-485 и ручками сэмулировав пакет - работает, зараза, плюётся эхом после получения пакета.

    Что получаем по итогу? Во-первых, уже есть обмен данными хранилища из коробки, т.е. данные со всех слейвов попадут к мастеру - и это хорошо ;) Во-вторых, в зависимости от логики конкретного проекта - всегда можно пообщаться со слейвами своим форматом пакетов - и с этим не вопрос теперь ;) Из оверхэда - только 10 байт при отсыле пользовательского пакета от мастера, и всё - не такая большая плата за универсальность, считаю.

    @alex_rnd61 - надеюсь, порадовал такой новостью ;) В скетче есть пример, оставил там, чтобы самому не забыть :) Эх, доку бы к этому делу начать писать, но всё не до сук :D:D:D
     
    Последнее редактирование модератором: 23 фев 2018
    alex_rnd61 нравится это.
  11. alex_rnd61

    alex_rnd61 Нерд

    С праздником! Ничего себе "подарочек". Боюсь что родня меня сегодня и ещё недельку не увидит. :)
     
  12. DIYMan

    DIYMan Guest

    И вас также с праздником! Не, не мучайте себя - лучше отдохните ;) А то всё равно не факт, что я всё написал без ошибок, и вы потонете в тестировании - кому это надо? Пусть пока отлежится чуть, потом будет видно. Праздник - оно святое ;)
     
  13. DIYMan

    DIYMan Guest

    Обновил, добавил поддержку датчика освещённости MAX44009 - по случаю оказалось, что он у мну есть :)
     
  14. DIYMan

    DIYMan Guest

    Обновил, добавил поддержку УЗ-датчика HC-SR04, в связи с этим появилась новая единица хранения - расстояние в мм (с учётом сотых долей, ессно). В дальнейшем можно будет и другие датчики расстояния добавить в систему, т.к. тип данных - уже готов.

    Подключил датчик, показывает:

    screen.png

    А то всё руки не доходили до этих двухглазок :) Теперь есть поддержка в ядре, удобно.

    З.Ы. Кстати, чтобы самому не забыть - вот так можно обновлять показания любого датчика в хранилище, минуя настроенное время интервала обновлений (это актуально для того же датчика расстояния):
    Код (C++):
    CoreSensor* hcSr04 = Core.Sensors()->get(F("distance")); // distance - имя датчика в конфиге

    if(hcSr04) // если датчик с таким именем есть в конфиге
        Core.pushToStorage(hcSr04); // помещаем данные с него в хранилище
    Т.е. буквально три строчки, и никакой мороки - обновляй когда хошь ;)
     
  15. alex_rnd61

    alex_rnd61 Нерд

    Что то подсказывает, что надо на 644 переезжать. :)
     
  16. DIYMan

    DIYMan Guest

    Давно пора :) А ещё лучше - 2560, ибо уже из коробки протестировано под этим делом, а как будет с 644 - сходу не скажу - есть много тонких мест с директивами условной компиляции ;) (например, сейчас не соображу, как менять делитель SPI на Due, поэтому медленный режим для термопары под Due просто не поддерживается).
     
  17. alex_rnd61

    alex_rnd61 Нерд

    2560 мне паять уже тяжело, да и куда такой монстр. А вот серия 164/324/644/1284 куда интереснее под датчики. Сначала лучше отладить всё на AVR, а потом на другие переползать.
     
    DIYMan нравится это.
  18. DIYMan

    DIYMan Guest

    Вот почему ребята-авторы Wiring сделали SPI.setClockDivider() - но не сделали SPI.getClockDivider()? Вот конкретный юзкейс: мне надо на время чтения какого-либо устройства на SPI поменять делитель, после чтения - возвратить тот, который был. Под AVR всё просто:
    Код (C++):
    uint8_t oldSPCR = SPCR; // сохраняем регистр настроек SPI
    SPCR |= 3; // делитель на 128, хай ползает медленно

    // ... тут что-то делаем

    SPCR = oldSPCR; // восстанавливаем прежний делитель
    Под SAM3X8E - дичь какая-то, пока продерёшься, как оно там настраивается - уже лоб расшиб :) А вот тупо юзать SPI.setClockDivider, без восстановления прежнего состояния - мне религия не позволяет :(
     
  19. alex_rnd61

    alex_rnd61 Нерд

    Похоже эти ребята сами иногда не понимают что творят. Но можно читать из регистра, напрямую. И там для каждого сигнала выборки должен быть свой делитель, чтобы работать с разными по скорости устройствами.
     
    Последнее редактирование: 24 фев 2018
    DIYMan нравится это.
  20. DIYMan

    DIYMan Guest

    Да, пришлось покопаться, чтобы вытащить текущий делитель и при этом учитывать настройки библиотеки поддержки Arduino Due. Короче, получилось так:

    Код (C++):
     SPI.begin();
    SPI.setClockDivider(SPI_CLOCK_DIV32);

    uint8_t spiChannel = BOARD_PIN_TO_SPI_CHANNEL(SPI_INTERFACE_ID);
    uint32_t csr = SPI_INTERFACE->SPI_CSR[spiChannel];
    Serial.println(csr);
    Serial.println((csr & SPI_CSR_SCBR_Msk) >> 8); // !!!!!
    Serial.println(SPI_CLOCK_DIV32);
    В строке, выделенной восклицательными знаками - тот же самый делитель, что устанавливается во второй и печатается в последней. Т.е. получить я его могу, ну и установить - тоже. Щас буду править ядро, чтобы ввести поддержку медленного режима для термопары под Due ;)
     
    Последнее редактирование модератором: 24 фев 2018