• Уважаемые посетители сайта esp8266.ru!
    Мы отказались от размещения рекламы на страницах форума для большего комфорта пользователей.
    Вы можете оказать посильную поддержку администрации форума. Данные средства пойдут на оплату услуг облачных провайдеров для сайта esp8266.ru
  • Система автоматизации с открытым исходным кодом на базе esp8266/esp32 микроконтроллеров и приложения IoT Manager. Наша группа в Telegram

Умный дом для чайника

Alexey N

Member
А на луа этой проблемы с удержанием SDA не было бы? Это же не зависит от языка вообще.
 

Сергей_Ф

Moderator
Команда форума
@Alexey N вполне возможно, что не было бы проблемы. Это зависит от библиотеки, а на Lua реализация OneWire вполне может работать корректно с DS3231. А может и нет. У Вас есть возможность проверить.
 

nikolz

Well-known member
А на луа этой проблемы с удержанием SDA не было бы? Это же не зависит от языка вообще.
Зависит не от языка а от библиотек и от возможности правильно и просто написать обработку событий.
---------------------------------------
Вот для примера моя основная программа от марта 2015
--------------------------------
pds=1;pam=2; scl=4; oss=0;T0=0;TM=0; adT={}
gpio.mode(pam, gpio_OUTPUT); gpio.write(pam, gpio.HIGH)
--DS18B20--AM2302--BMP180(SCL,SDA=SCL+1)
local ae={{96,209,111,6,0,0,149},{199,186,111,6,0,0,45}}
------1--2--3--4-5--6-7--8-9-10-11-12-13-14-
TD={3,0,0,0,2,0,0,4,0,0, 0,0,1, 0};
ssid,pwd="axxx","k8Txxx"; port=9991
dofile("nk_start.lc") -- dofile=603200
gpio.mode(3,gpio.INPUT)
---------------------
function cb()
T0=T0+1; --номер датчика
dofile(DS18b20.lua');
T0=T0+3; --номер датчика
dofile('get_tp.lc'); dofile('norm.lc'); --BMP180
m=6 -- номер позиции в таблице результатов для данного датчика
dofile('AM2302.lc');
m=14 -- номер позиции в таблице результатов для данного датчика
TD[m]=adc.read(0); -- АЦП
cu:connect(9992,"192.168.0.108"); -- a udp client
cu:send(T0..';4;'..table.concat(TD,";")..';'..node.heap())--..",T1="..T1)
end
tmr.alarm(1,2000,1,cb)
------------------------------
Она каждые две секунды опрашивает датчики и отправляет данные по UDP
Добавление нового датчика делается путем dofile соответствующего файла
Таким образом, сначала отлаживается интерфейс работы модуля по WIFI
Потом добавляются любые датчики и в любом количестве
В данном проекте было три DS18B20 один AM2302 и один BMP180
----------------------------------
Датчики не влияют друг на друга и можно добавлять убавлять и отлаживать каждый отдельно и все вместе.
Полагаю, что понятно? Сравните со своей основной программой на дурине.
 
Последнее редактирование:

Alexey N

Member
Хм. Выглядит сильно короче. Но сильно непонятнее. Ардуиновский С я как-то уже понимаю что делает. А нет ли какого-то учебника или ресурса по ЛУА именно для ЕСП и для чайников? Я пытался что-то искать, но натыкался в основном на использование луа для моддинга игр.
 

nikolz

Well-known member
Хм. Выглядит сильно короче. Но сильно непонятнее. Ардуиновский С я как-то уже понимаю что делает. А нет ли какого-то учебника или ресурса по ЛУА именно для ЕСП и для чайников? Я пытался что-то искать, но натыкался в основном на использование луа для моддинга игр.
Луа отличается от дурины тем, что дурина лишь в дурине, а луа встроена не только в eSP и игры но и в кучу микроконтроллеров для управления пром линиями.
Вообще-то луа делали как встраиваемый язык в пром приборы. Это потом вдруг его стали в страивать в игры.
На нем можно даже писать торговых роботов для бирж.
Поэтому изучите луа как язык, а потом на основе описания ESP луа
NodeMCU Documentation
пишите программы для ESP.
Вот здесь eLua - eluaproject
Можете изучить то, что встроено в луа и какие еще процессоры поддерживают ELua.
--------------------------
Если надо будет очень быстро изучайте СИ.
А если уж совсем быстро -то ассемблер
 

Сергей_Ф

Moderator
Команда форума
@Alexey N кстати, А какой библиотекой RTC Вы пользовались? Я в только менеджере нашел 4 штуки. Вполне возможно, что при использовании другой(их) библиотек проблемы и не было.
 

Alexey N

Member
@Сергей_Ф, я давал ссылку на библиотеку, но она видимо затерялась в потоке GitHub - adafruit/RTClib: A fork of Jeelab's fantastic RTC library И на странице библиотеки есть примечание, что для ESP8266 она подходит. Что меня и подкупило. Хотя я пробовал менять библиотеки. И из стандартного пакета примеров тоже брал. Безрезультатно. Я так понимаю, если бы я нашел работающую библиотеку, в ней было бы уже реализовано то же самое, что в тех ссылках, которые я нашел? Тогда мне больше нравится иметь в коде свои строчки. Я хотя бы знаю, что они делают и что происходит.
 
Последнее редактирование:

=AK=

New member
А нет ли какого-то учебника или ресурса по ЛУА именно для ЕСП и для чайников? Я пытался что-то искать, но натыкался в основном на использование луа для моддинга игр.
Не слушайте вредных советов, держитесь подальше от Lua. Это маргинальный язык, каких сейчас расплодилось тысячи, случайно появившийся в ESP8266 благодаря какому-то румынскому энтузиасту. Во встроенных системах никакого будущего у него нет. Вы сделали правильный выбор, знания С и Ардуино вам пригодятся не только с ESP8266, но и с другими платформами.
 

=AK=

New member
@Сергей_Ф, я давал ссылку на библиотеку, но она видимо затерялась в потоке GitHub - adafruit/RTClib: A fork of Jeelab's fantastic RTC library
Невооруженным глазом видны ошибки в библиотеке. Функци RTC_DS3231::now() и RTC_DS3231::readSqwPinMode() не посылают завершающий I2C STOP (т.е Wire.endTransmission() в конце обмена), из-за чего шина остается в подвешенном состоянии.
 

Сергей_Ф

Moderator
Команда форума
@=AK= посмотрите, пожалуйста, Rtc/src at master · Makuna/Rtc · GitHub
Если не ошибаюсь, там все на месте.
Во всяком случае, при записи. На счет чтения, не уверен.
Сразу вопрос, завершать передачу разве должен не источник данных?
 
Последнее редактирование:

=AK=

New member
Если не ошибаюсь, там все на месте.
Там тоже есть места, где шина остается брошенной после чтения в неопределенном состоянии, без STOP.

Сразу вопрос, завершать передачу разве должен не источник данных?
Завершать любую транзакцию должен тот же, кто ее начал, т.е. мастер. Безотносительно к тому, читает он данные или пишет.
 

Alexey N

Member
Как я понимаю, вместо того, чтобы использовать костыли типа многократного изменения состояния пина, можно просто добавить Wire.endTransmission() в конец функции, перед return? Или в код скетча после вызова now().
 

=AK=

New member
Угу. Только причем тут "костыли"? Библиотеки написаны чайниками. Кое-как работают только в случае, когда на I2C шине находится всего один чип.
 

Сергей_Ф

Moderator
Команда форума
Угу. Только причем тут "костыли"? Библиотеки написаны чайниками. Кое-как работают только в случае, когда на I2C шине находится всего один чип.
Костыли - это Hanging I2C on DUE, SDA Low SCL High permanent.

А есть библиотека для RTC написанная не чайником? И достаточно ли в библиотеках от "чайников" прописать
Wire.endTransmission() в конец функции, перед return? .
 

=AK=

New member
И достаточно ли в библиотеках от "чайников" прописать
Если там нет каких-то боковых эффектов, то должно быть достаточно. Это вообще-то альфа и омега I2C - любую транзакцию начинать со СТАРТ, а заканчивать СТОП.

Фокус в том, что в операциях чтения используется два СТАРТ-а подряд, т.е. СТАРТ без СТОПа для чипа выглядит вполне легально. Тем более что во многих бит-банг реализациях функций I2C сам СТАРТ фактически начинается со СТОПа. То есть, если на шине не пассивное состояние (SCL=hi, SDA=hi), то сначала выдается СТОП, и только потом СТАРТ. Если на шине уже есть пассивное состояние, то этот СТОП перед СТАРТом осциллографом не увидишь.

Поэтому незаконченная транзакция не завешивает сам чип, а завешивает только шину. Очевидно, либа работает именно на этом эффекте. Какие-то транзакции завершаются СТОПом, какие-то нет. Когда чип на шине один, это будет работать.
 
Последнее редактирование:

Сергей_Ф

Moderator
Команда форума
@=AK= а не получится так, что мы пошлем СТОП до окончания приема данных от RTC? Мы же не отслеживаем окончание приема. Только в этом могут быть подводные камни.
И Вы не ответили, есть ли правильные либы для rtc, на С. Не обязательно, под Wire. Не знаете?
 

=AK=

New member
а не получится так, что мы пошлем СТОП до окончания приема данных от RTC? Мы же не отслеживаем окончание приема. Только в этом могут быть подводные камни.
Заставил себя посмотреть, как устроена ардуиновская I2C либа Wire, на основе которой делаются специализированные либы под конкретные чипы. Она сделана не бит-бангом, а сидит на I2C железяке.

При записи в девайс последовательность такая:
Wire.beginTransmission();
Wire.write();
Wire.write();
...
Wire.endTransmission();

Чтение как известно является комбинированной операцией. Сперва идет запись, как выше. Затем должна идти такая последовательность:
Wire.requestFrom();
while(Wire.available())
{
Wire.read();
}
Вся фишка в команде Wire.requestFrom(). Очевидно она заряжает конечный автомат, который управляет I2C железякой. В параметрах указывается из какого устройства надо читать, количество байт, которые надо прочесть, и, опционально, надо ли посылать СТОП по завершению чтения.

Насколько я вижу, упомянутые выше либы используют Wire некорректно:
- При запросе чтения N байт не указывают, что чтение надо завершить СТОПом
- Читают байты командой Wire.read() не проверяя, имеется ли запрошенный байт в наличии или нет
Удивительно, что это вообще хоть как-то работает.

И Вы не ответили, есть ли правильные либы для rtc, на С. Не обязательно, под Wire. Не знаете?
Я ардуиновскими либами для I2C вообще никогда не пользовался, впервые их вижу.
 

Alexey N

Member
Вот функция now() из той библиотеки, которой я пользуюсь. Красным выделил строчку Wire.endTransmission(), которую я добавил. Снова получил все вышеописанные симптомы. Так что проблема действительно более глубоко зарыта.


DateTime RTC_DS3231::now() {
Wire.beginTransmission(DS3231_ADDRESS);
Wire._I2C_WRITE((byte)0);
Wire.endTransmission();

Wire.requestFrom(DS3231_ADDRESS, 7);
uint8_t ss = bcd2bin(Wire._I2C_READ() & 0x7F);
uint8_t mm = bcd2bin(Wire._I2C_READ());
uint8_t hh = bcd2bin(Wire._I2C_READ());
Wire._I2C_READ();
uint8_t d = bcd2bin(Wire._I2C_READ());
uint8_t m = bcd2bin(Wire._I2C_READ());
uint16_t y = bcd2bin(Wire._I2C_READ()) + 2000;

Wire.endTransmission();

return DateTime (y, m, d, hh, mm, ss);
}
 

=AK=

New member
Код:
DateTime RTC_DS3231::now()
{
   Wire.beginTransmission(DS3231_ADDRESS);
   Wire._I2C_WRITE((byte)0);
   Wire.endTransmission();

   Wire.requestFrom(DS3231_ADDRESS, 7, true); // читать 7 байт, завершить СТОПом
   while(7 > Wire.available())  // пока все 7 байт не прочитаны
   {
      delay(0); // ждем-с
   }
   uint8_t ss = bcd2bin(Wire._I2C_READ() & 0x7F);
   uint8_t mm = bcd2bin(Wire._I2C_READ());
   uint8_t hh = bcd2bin(Wire._I2C_READ());
   Wire._I2C_READ();
   uint8_t d = bcd2bin(Wire._I2C_READ());
   uint8_t m = bcd2bin(Wire._I2C_READ());
   uint16_t y = bcd2bin(Wire._I2C_READ()) + 2000;

   return DateTime (y, m, d, hh, mm, ss);
}
Как-то так...
 

Alexey N

Member
Неа, на работает. Все также держит SDA. Более того, при передергивании провода функция не срабатывает как надо. В смысле время вообще перестало считываться. Возможно помимо косяков в библиотеке, есть еще и косяки в самом модуле. Ну и ладно. Я не настолько хорошо разбираюсь пока в программировании и схемотехники, чтобы этот вопрос решить. Так что остаюсь пока на "костылях".
 
Сверху Снизу