Jump to content
iT4iT.CLUB

Leaderboard


Popular Content

Showing content with the highest reputation on 03/09/2020 in all areas

  1. 1 point
    в теме про метеостанцию писал про датчик с передатчиком на NRF24L01 и возможность использования с метеостанцией простой код приемника на esp // https://aterlux.ru/article/nrf24l01p #include <Wire.h> #include <LiquidCrystal_I2C.h> LiquidCrystal_I2C lcd(0x3F,20,4); // set the LCD address to 0x27 for a 16 chars and 2 line, для 20x4 - 0x3F //#include <SPI.h> //#include "nRF24L01.h" #include "RF24.h" int32_t data[5]; RF24 radio(99, 15); // CE, CSN, 99 - это заглушка, чтобы освободить один пин, если передача не предполлагается то можно CE просто подтянуть резистором к питанию, иначе нужно указать вывод void setup(void) { lcd.init(); lcd.backlight(); radio.begin(); radio.setAutoAck(true); // radio.setAutoAck(true); включение и ли отклучение автоподтверждения radio.setChannel(100); radio.setDataRate (RF24_2MBPS); // скорость обмена RF24_2MBPS, RF24_1MBPS, RF24_250KBPS - максимальная чувствительность на 250 кбитс, NRF24L01 без плюса 250 не умеет radio.setPALevel (RF24_PA_MAX); // уровень мощности RF24_PA_MIN -18dBm, RF24_PA_LOW -12dBm, RF24_PA_HIGH -6dBM, RF24_PA_MAX 0dBm radio.openReadingPipe(1, 0xAABBCCDD11LL); radio.startListening(); } void loop(void) { if(radio.available()){ // Если в буфере имеются принятые данные, то получаем номер трубы, по которой они пришли, по ссылке на переменную pipe radio.read( &data, sizeof(data)); } // Читаем данные в массив data и указываем сколько байт читать lcd.setCursor(0,0); lcd.print("Temp "); lcd.print(float(data[3])/100, 2); lcd.print(" "); lcd.print((char)223); lcd.print("C"); lcd.setCursor(0,1); lcd.print("Battery "); lcd.print(float(data[0])/1000,3); lcd.print(" v"); lcd.setCursor(0,2); // на некоторых 4 строчных дисплеях в 3 и 4 строке ноль сдвинут на 4 символа вправо, поэтому нулевой символ это -4 lcd.print("Packet N "); lcd.print(data[1]); delay (100); } код передатчика // тема на форуме - http://forum.ixbt.com/topic.cgi?id=48:12460&r=lYjQSTixmu#2 // библиотека для датчика BME280 - https://github.com/sergeyastakhov/BME280 (чтобы не было конфликтов с другими библиотеками, желательно ее разместить в папке скетча) // потребление всего модуля в power save - 2.0 мкА(из них NRF24 - 0.9 мкА), 1.1 мкА - atmega168 // обязательно параллельно батарейке доп емкость около 2200мкф 6.3 в - падение при передаче 10 мВ, ток утечки конденсатора после подформовки менее 100 нА, - http://forum.ixbt.com/topic.cgi?id=48:11468:3073#3073 // измерение напряжение батарейки с помощью измерения питания atmega // еще можно питать атмегу напрямую от лития и измерять ее напряжение, а NRF и BME280 питается от стабилизатора 3.3 вольта с маленькой утечкой, например mcp1700-3302, ток утечки около 1.5 мкА // I2C преобразователь уровней не нужен, главное чтобы подтягивающие резисторы I2C питались от 3.3 вольт // проблема с вотчдогом - http://arduino.ru/forum/apparatnye-voprosy/ne-mogu-vylechit-vatchdog-na-goloi-atmege328r-s-vnutr-taktirovaniem-8-mgts #include <avr/wdt.h> #include <avr/sleep.h> //#include <avr/power.h> #include "RF24.h" RF24 radio(9, 10); // CE_PIN, CSN_PIN byte count = 0; // счетчик количества просыпаний int32_t data[5]; // на данный момент используется int32_t чтобы иметь возможность получить большие числа счетчика передач, для тестирования продолжительности работы от батарейки, // потом можно обычный int // data 0 - данные АЦП или пересчитанное напряжение питания c тремя знаками(в милливольтах, на стороне приемника переменная float деленная на 1000 // data 1 - счетчик отправленных пакетов, сбрасывается при снятии питания // data 2 - P атмсомферное в мм, можно умножить на 10 если нужны десятые, тогда на стороне приемника делить на 10 и float // data 3 - Т температура умноженное на 100 на стороне приемника float делить на 100 // data 4 - H влажность умноженная на 100 #include "BME280.h" // при таком написании компилятор ищет библиотеку в первую очередь в папке скетча using namespace BME280; class CustomI2CProtocol : public I2CProtocol { public: virtual void init() { I2CProtocol::init(); Wire.setClock(400000); // частота работы I2C, 400 кГц - максимум для BME280, уже чувствительна к качеству и длине линии } // реальная частота I2C зависит от регистра и строки в wire.cpp - TWBR = ((F_CPU / frequency) - 16) / 2 и при частоте 8 МГц она ниже, около 250 кГц // https://www.avrfreaks.net/forum/twi-clock-divider?name=PNphpBB2&file=viewtopic&t=79562 }; BME280Sensor bme280 = BME280Sensor(new CustomI2CProtocol()); //BME280Sensor bme280 = BME280Sensor(new I2CProtocol()) - I2C работает на частоте по умолчанию - 100 кГц ISR (TIMER2_OVF_vect) { // из прерывания по таймеру 2 нельзя выходить слишком быстро, поэтому инкрементирование переменной расположим здесь count++; } void setup() { MCUSR = 0; // необходимо при использовании вотчдога для сброса контроллера при зависании на выпонении кода wdt_disable(); // иначе при первом сбросе вотчдогом, будет установлено минимальное время вотчдога 0.15 с, и мк зависнет на этом цикле PORTC |= (1 << PC1); // включение светодиода, для индикации запуска мк delay(10); DDRB = 0b11000001; // настраиваем неиспользуемые выводы(и порты) на выход DDRC = 0b11111111; DDRD = 0b11111111; //clock_prescale_set(clock_div_2); // деление тактовой частоты для получения 4 МГц для работы atmega168 вплоть до 1.8 вольта bme280.init(false); bme280.setHumidityMode(Over_1); // установка режима измерения влажности, остальные при запуске измерения //bme280.setMode(Forced, Over_1, Over_1, Over_1); // Forced - однократный режим измрения, все оверсемплинги(T, P, Hum) = 1 PRR = (1<<PRTIM1) | (1<<PRUSART0); // отключаем неиспользуемую периферию, (1<<PRTIM2) - работает в асинхронном режиме // (1<<PRTIM0) - так не работает передача, видимо count использует этот таймер // (1<<PRSPI), (1<<PRTWI)- не отключаем, SPI - для NRF24 и TWI(по другому I2C) - для BME280 radio.begin(); radio.setAutoAck(true); // подтверждение приема, true - включено, false - отключено radio.setRetries (2, 1); // количество попыток передачи если включен режим автоподтверждения приема, первая цифра - задержка между передачами, 1 = 250 мкс, вторая - количество попыток передачи radio.setChannel(100); // номер канала, можно перед выбором просканировать эфир чтобы выяснить менее зашумленные каналы(использовать скетч scanner из библ. RF24) radio.setDataRate (RF24_2MBPS); // скорость обмена RF24_2MBPS, RF24_1MBPS, RF24_250KBPS - максимальная чувствительность на 250 кбитс radio.setPALevel (RF24_PA_MAX); // уровень мощности RF24_PA_MIN -18dBm, RF24_PA_LOW -12dBm, RF24_PA_HIGH -6dBM, RF24_PA_MAX 0dBm radio.openWritingPipe (0xAABBCCDD11LL); // уникальный номер передатчика, на приемнике должен быть такой же ADCSRA = 0; // отключаем АЦП ACSR |= (1<<ACD); // отключаем компаратор ADMUX = _BV(REFS0) | _BV(MUX3) | _BV(MUX2) | _BV(MUX1); // настраиваем АЦП на измерение собственного напряжения питания, опорное 1.1 вольт DIDR0 = 1; // отключаем цифровой вход выводов АЦП, он тоже немного потребляет ASSR |= (1<<AS2); // Асинхронный режим TCCR2A = (0<<WGM21)|(0<<WGM20); //режим normal TCCR2B = (1<<CS22)|(1<<CS21)|(1<<CS20); // clk/1024 TCNT2 = 0x00; // начальное значение таймера // OCR2A = 0x00; OCR2B = 0x00; TIMSK2 |= (1 << TOIE2); // разрешаем прерывание по переполнению Т2 SMCR = _BV(SM1) | _BV(SM0); // Power_Save, set_sleep_mode(SLEEP_MODE_PWR_SAVE), set_sleep_mode (SLEEP_MODE_PWR_DOWN) - выбор режима сна radio.powerDown(); PORTC &= ~_BV(PC1); // выключение светодиода } void loop() { if ( count >= 8 ) { // передавая один раз в 64 секунды = 8 radio_(); TCNT2 = 0x00; } while(ASSR&(1<<TCN2UB)){;} //wait to TCNT update!!! TCNT2 = 0x00; sleep_enable(); //SMCR |= _BV(SE); sleep_cpu (); } void radio_() { wdt_enable(WDTO_1S); radio.powerUp(); data[1]++; ADCSRA |= _BV(ADEN); // включаем АЦП Measurement measurement = bme280.readMeasurement(); // опрос датчика и расчет параметров data[2] = (measurement.getPressure32()*1000/133322); data[3] = (measurement.getTemperature()*100); data[4] = (measurement.getHumidity()*100); bme280.setMode(Forced, Over_1, Over_1); // запуск однократного измерения и установка оверсемплингов T, P, без влажности //bme280.setMode(Forced, Over_1, Over_1, Over_1); // запуск однократного измерения и установка оверсемплингов T, P, Hum ADCSRA |= _BV(ADSC); // запуск конверсии while (bit_is_set(ADCSRA,ADSC)); // измерение uint8_t low = ADCL; // сначала читаем ADCL - это расблокирует чтение ADCH uint8_t high = ADCH; int volt = (high<<8) | low; // данные АЦП data[0] = (1135494/volt); // 1135494 подобрано эксперементально и в общем случае равно 1100 милливольт опорное * 1024, но опорное не всегда 1100 мВ ADCSRA = 0; // отключаем АЦП // ******************************************** // код до этого места примерно 1700 мкс, убираем в файле RF24.cpp задержку delay(5) и добавляем перед отправкой данных // задержку в 2.3 мс, чтобы в сумме задежка получилась 4 мс, это минимальная задержка от команды powerUp() до write() // при которой стабильно работает большой модуль на RF24, smd модуль работает и при меньшей задержки, т.к. разные кварцы clock_prescale_set(clock_div_256); // на время задержки снижаем частоту контроллера до минимально возможной, для снижения энергопотребления delayMicroseconds(10); // на этой частоте для получения 2.3 миллисекунд нужно указать задержку в 256 раз меньше ~ 9 мкс // в этом режиме потребляет только atmega, которая работает на частоте 1/256 от номанальной clock_prescale_set(clock_div_1); // перед отправкой данных снова устанавливаем исходную частоту работы контроллера radio.write(&data, sizeof(data)); radio.powerDown(); count = 0; wdt_disable(); }
  2. 1 point
    Доброе время суток. Вот небольшой спойлер, но работы ведутся совсем не такими темпами как мне бы хотелось, банально из-за нехватки времени в связи с переездом в другой город и со всеми вытекающими из этого событиями. Я постарался сделать снимок экрана так, чтобы, присмотревшись к косвенным признакам, была возможность понять, что уже реализовано и, что используется в коде. Последние изменения были сделаны еще в конце лета 2019. @kamikozz Рад, что Вы с таким азартом отнеслись к этому проекту. Но, к сожалению, Вы упустили главную мысль - проект модульный и wifi.h один из модулей с малым количеством зависимостей, а если быть точным, то от него не зависят другие модули вообще. Вы вправе вообще удалить его или полностью переписать согласно необходимой логике работы. Главная идея wifi.h, это балансировка между режимами AP и STA. Нормальным считается, что контроллер подключен к домашней беспроводной сети, если этот пункт не выполнен, то контроллер переходит в режим AP и периодически пытается найти домашнюю сеть. В этом режиме мы получаем возможность его перенастроить т.к контроллер мог потерять домашнюю сеть из-за того, что у неё изменился SSID или контроллер переехал на другое место жительства. В Вашем случае работа данного модуля немного противоречит тому, что Вы хотите получить т.к в случае отсутствия связи с домашней точкой доступа контроллер будет пытаться её найти, а это возможно только при переводе контроллера в режим STA для сканирования эфира. В Вашем случае в этом нет необходимости, и можно пользоваться штатными средствами восстановления связи, предоставляемыми на аппаратном уровне т.к для установки новой точки доступа в качестве домашней, достаточно подключиться к точке поднимаемой контроллером в режиме AP+STA, ведь она доступна всегда. Но у меня вопрос, зачем Вам режим AP+STA? Возможно лучше и надежнее подключить второй контроллер к общей с первым точке доступа и просто перекидываться через HTTP API запросами? Почему я это спрашиваю - дело в том, что я упоминал, в том числе и в первом посте, что мы ограничены количеством обрабатываемых контроллером запросов и при некоторой нагрузке все может поломаться. Кстати, именно по этой причине много кода WEB интерфейса размазано по малому количеству файлов, в Index.htm валяется и css и java, а в css сохранены некоторые картинки. Динамическая подгрузка компонентов. Все это позволяет уложиться в минимальное, как я это видел, количество tcp соединений с контроллером т.к браузер загружает все компоненты страницы параллельно, а текущий web сервер не способен обрабатывать более одного соединения за раз, да и у контроллера попросту нет на это ресурсов. Обязательно помните об этом. Но вернемся к wifi.h. Если Вам ближе режим AP+STA место центрального маршрутизатора для обоих контроллеров, то просто удалите wifi.h и в основном файле добавьте необходимый режим. Убедитесь, что имеете доступ со стороны AP и STA. После этого можете начинать прикручивать сохраненные в config значения параметров для поднятия точки с нужным именем и для подключения к домашней точке доступа. @Neon @den48rus давайте разбираться с NRF. Под рукой, в текущий момент, её нет, но мы попробуем и пробежимся по основным моментам. На сколько я понимаю, подключается она по SPI, а это значит, что потребуется много портов. Следовательно, Вам придется освободить все порты, используемые под управление нагрузкой, но скорее всего еще что-то. На фото ниже видны 5 основных портов для передачи данных и один для прерывания. В данном проекте придется использовать прерывания т.к NRF может получить данные в момент когда будет происходить другая длительная операция, например загрузка web интерфейса. В таком случае данные будут потеряны. Прерывание поможет получать данные в тот момент когда, они пришли и это будет незаметно для остальных процессов. Бегло, я нашел информацию, что прерывание генерирует низкий уровень сигнала на порту IRQ. Отследить его можно с помощью attachInterrupt. В функции, которая будет вызвана при прерывании реализуйте логику чтения данных, как это делается в обычном случае. А теперь самое интересное. Например, в библиотеки RF24.h, которую, как мне кажется, используют многие, возможно использовать свой тип данных для передачи. Таким образом Вы можете объявить свою структуру, в которой можно определить что угодно. Допустим не просто пустые и безликие данные, а тип сенсора, показания с нескольких датчиков и, например, напряжение питания удаленного устройства. struct { byte type; float temperature; float humidity; float voltage; } nrf_data; nrf_data remote_sensor; Теперь важный момент. Переменная, которую мы будем использовать для хранения данных (в примере remote_sensor), должна быть объявлена в глобальном пространстве имен чтобы избежать проблем в дальнейшем, конечно, если у Вас нет иного механизма передачи данных между модулями проекта. После того как данные будут переданы, они будут сохранены в оперативной памяти микроконтроллера. Теперь их необходимо связать с сенсором, а это уже совсем не сложно. sensors.add(new knob_t(0, 100, ".01", "Влажность", "%"), "Humidity", [&](){ return remote_sensor.humidity; } ); Конечно, могут быть ситуации, когда в момент чтения переменной будет произведена попытка её перезаписи, но и это можно решить. В общем, у Вас все должно получиться. Но если будут вопросы, то обязательно пишите, и я постараюсь найти NFR24 и подготовить полноценный код для решения этой задачи.
  3. 1 point
    Файлы проекта обновлены. Добавлена поддержка последних, на момент публикации, версий Arduino IDE и модуля ESP8266. Добавлены небольшие исправления и доработки. При использовании, указанных в основном посте, версий программных компонентов Вы не получите вылет программы с критической ошибкой. Исправлена серьезная ошибка в медианном фильтре, кто использует проект обязательно обновите у себя объект medianFilter_t, он находится в tools.h В разделе загрузок, добавлена утилита для загрузки файлов web сервера во flash память. Также в описании к файлам, добавлена ссылка на скачивание готовой Arduino IDE со всеми библиотеками, утилитами, и последней версией проекта. Для работы модуля загрузки файлов во Flash может понадобится последняя версия Python https://www.python.org/downloads/
  4. 1 point
    заливал, но все равно не грузилось вэб содержимое, заработало только когда указал что флеш 4 мб, но попробую еще возможно ли не очень сложным способом добавить к метеостанции работу с NRF24L01+, чтобы радиомодуль принимал данные показаний датчиков и передавал их метеостанции интересует куда вставить код работы с NRF24 и как передать данные коду метеостанции, скетч работы с NRF24 в принципе есть, возможно нужно будет немного доработать
×
×
  • Create New...