• Система автоматизации с открытым исходным кодом на базе 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. Более того, при передергивании провода функция не срабатывает как надо. В смысле время вообще перестало считываться. Возможно помимо косяков в библиотеке, есть еще и косяки в самом модуле. Ну и ладно. Я не настолько хорошо разбираюсь пока в программировании и схемотехники, чтобы этот вопрос решить. Так что остаюсь пока на "костылях".
 
Сверху Снизу