Сканирование 1-Wire и сохранение в EEPROM
- Войдите на сайт для отправки комментариев
Коллеги,
на ATMega 168pa реализован модуль, который работает с датчиками ds18b20 - измеряет температуру, и отдает их по протоколу Modbus RTU. Прошивка сделана так, что позволяет подключать новые датчики на шине 1-wire и сохранение их адресов в EEPROM. Для обнаружения датчиков используется функция scan
, приведенная в тексте, она вызывается по команде, передаваемой по modbus.
Проблема в том, что при сканировании, если на шине находится более 2-х датчиков (например, 4), в EEPROM записываются не все адреса, а только 2 и еще небольшой огрызок. При этом при сканировании обнаруживаются все датчики (4 штуки). Поведение функции устойчивое, для записи всех 4-х датчиков приходится выполнять два последовательных цикла сканирования.
Как думаете, почему не удается записать сразу 4 адреса?
Функция сканирования во вложении приведена с минимальными упрощениями:
#include <OneWire.h> #include <EEPROM.h> #define SENSOR_PIN_1 9 #define ADDR_E_SEN_qty_1 5 #define ADDR_E_sensAddress 10 // максимальное количество датчиков на одной линии const uint8_t MAX_SENSORS_QTY = 5; typedef uint8_t DeviceAddress[8]; DeviceAddress sensAddress[MAX_SENSORS_QTY]; OneWire oneWire(SENSOR_PIN_1); void setup() { // инициализация } void loop() { // измерение температур // обработка запросов modbus // сканирование датчиков на шине 1-wire } // функция сканирования датчиков QneWire void scan() { uint8_t newQty = 0; DeviceAddress newSensors[MAX_SENSORS_QTY]; bool exists[MAX_SENSORS_QTY] = {false}; // сканирование шины и отбор новых датчиков while (newQty < MAX_SENSORS_QTY && oneWire.search(newSensors[newQty])) { // проверить контрольную сумму if (OneWire::crc8(newSensors[newQty], 7) == newSensors[newQty][7]) { // проверка наличия найденного датчика в существующем массиве bool found = false; for(uint8_t j=0; j<MAX_SENSORS_QTY; j++) { if(compareAddr(newSensors[newQty], sensAddress[j])) { exists[j] = true; found = true; } } if(!found) newQty++; } } // новые датчики рассовываем по списку рабочих датчиков в свободные ячейки for (uint8_t i=0; i<newQty; i++) { for (uint8_t j=0; j<MAX_SENSORS_QTY; j++) { if(!exists[j]) { copyAddr(newSensors[i], sensAddress[j]); exists[j] = true; break; } } } // обнуляем адреса несуществующих датчиков и подсчитываем общее кол-во uint8_t qty = 0; for (uint8_t i=0; i<MAX_SENSORS_QTY; i++) { if(!exists[i]) { setZeroAddr(sensAddress[i]); } else { qty++; } } // записываем в EEPROM EEPROM.update(ADDR_E_SEN_qty_1, qty); EEPROM.put(ADDR_E_sensAddress, sensAddress); } //--------------------------------------------------------------------------- // сравнить адреса bool compareAddr(DeviceAddress sens1, DeviceAddress sens2) { for(uint8_t i = 0; i < 8; i++) { if(sens1[i] != sens2[i]) return false; } return true; } //--------------------------------------------------------------------------- // скопировать адрес void copyAddr(DeviceAddress from, DeviceAddress to) { for(uint8_t i = 0; i < 8; i++) { to[i] = from[i]; } } //--------------------------------------------------------------------------- // обнулить адрес void setZeroAddr(DeviceAddress sens) { for(uint8_t i = 0; i < 8; i++) { sens[i] = 0; } } //---------------------------------------------------------------------------
Проблема в том, что при сканировании, если на шине находится более 2-х датчиков (например, 4), в EEPROM записываются не все адреса, а только 2 и еще небольшой огрызок. При этом при сканировании обнаруживаются все датчики (4 штуки). Поведение функции устойчивое, для записи всех 4-х датчиков приходится выполнять два последовательных цикла сканирования.
А что если выдать обнаруженные адреса на терминал? Они все выдаются или 2 и огрызок?
Не вникал, но здесь инициализирован только первый элемент массива, из пяти. Так задумано?
Не вникал, но здесь инициализирован только первый элемент массива, из пяти. Так задумано?
Нет. Так инициализируются ВСЕ элементы одним значением. Правда, '=' тут лишнее, надо
Да, наврал я, инициализируются, все. Первый - заданным значением, остальные - нулями. В данном случае, значение с этими нулями удачно совпадает.
инициализируются, все. Первый - заданным значением, остальные - нулями.
это если '=' стоит. если не стоит, мемсетом инициализатор размазывается по всему массиву. :)
Upd. Опять я неправ, разобрался, инициализируется, как ты и говоришь, только первое значение, остальные - конструктором по умолчанию для заданного типа.
А что если выдать обнаруженные адреса на терминал? Они все выдаются или 2 и огрызок?
Правильный вопрос )) Выдается 2 и огрызок. Правда, я читаю эти адреса из регистров модбас, но туда необъяснимым образом заносятся только те, которые записываются в EEPROM.
При этом количество найденных адресов (
qty
) пишется правильное - 4. И это я объяснить не могу((это если '=' стоит. если не стоит, мемсетом инициализатор размазывается по всему массиву. :)
Upd. Опять я неправ, разобрался, инициализируется, как ты и говоришь, только первое значение, остальные - конструктором по умолчанию для заданного типа.
Чтобы все заинитились одинаково, нужно, по-моему, запятую ставить в курлы: array[4] = {false,}
Нет, всё равно инитица только первый, я проверил. :)
Я вообще всегда думал, инитятся только элементы которые указаны, а остальные остаются как есть, с мусором.
Оказывается, мусор остаётся только если массив (локальный!) совсем не инициализировать. Если инициализирован хотя бы один элемент, остальные инициализируются значением по умолчанию.
Ну, буду знать, если не забуду. :)
ЗЫ: А без "=" я вообще не знал, и раньше не пользовался. И компилятор мой, которым проверял, тоже такого не понимает - наверно старенький он, что ли..
Попробуйте в 30 строке поставить oneWire.reset_search();
Попробуйте в 30 строке поставить oneWire.reset_search();
Увы, не помогло. И reset() тоже.
Кстати, что касается вашего предыдущего вопроса (про вывод обнаруженных адресов): если не записывать обнаруженные адреса в EEPROM, а просто их передавать в регистрах modbus, то они туда попадают все четыре. Как запись в память связана с ОЗУ, ума не приложу ((
Но ведь 2 датчика обнаруживает и записывает правильно. Что за...
Не забываем reset_search()
Я уже отвечал - не влияет.
Вот что интересно. Если в программе пытаешься записать все 4 адреса:
то в память пишутся 2,5 адреса. И при этом в sensAddress те же 2,5 адреса!
А если закомментировать EEPROM.put, или намеренно сделать ошибку, например, EEPROM.update - то в sensAddress все 4 адреса. В обоих случаях qty пишется правильно - 4.
Как EEPROM влияет на ОЗУ, не понимаю. Кстати, сводного ОЗУ - 163 байта.
И еще добавлю - пробовал разные способы записи: eeprom_write_block, записывать по байтам - все едино.
а при чем тут регистры Модбас? - в коде в заглавном сообщении никакого Модбас нет. Или вы, как многие новички - выложили в форум один код, а запускаете другой?
Давайте работать именно с тем кодом. что в первом сообщении. Вставьте именно в этот код вывод найденных адресов в сериал - где-то примерно в 43 строке. А после 45 еще добавте диагностику типа "Найден новый адрес" или "Найденный адрес уже есть в массиве"
И выкладывайте результваты сюда
Кстати, сводного ОЗУ - 163 байта.
как вы это определили? - по диагностике при компиляции скетча?
тогда почти наверняка причина в нехватке памяти. Вывод при компиляции показывает расход памяти только на глобальные переменные, - и они уже занимают 84% ОЗУ. А у вас еще куча локальных. в том числе массивы
попробуйте для начала уменьшить MAX_SENSORS_QTY, например, до 4. Если после этого в ЕЕПРОМ запишется не 2.5 адреса. а скажем три - все будет ясно. дело в памяти
а при чем тут регистры Модбас? - в коде в заглавном сообщении никакого Модбас нет. Или вы, как многие новички - выложили в форум один код, а запускаете другой?
Давайте работать именно с тем кодом. что в первом сообщении. Вставьте именно в этот код вывод найденных адресов в сериал - где-то примерно в 43 строке. А после 45 еще добавьте диагностику типа "Найден новый адрес" или "Найденный адрес уже есть в массиве"
И выкладывайте результаты сюда
На плате, где установлена atmega, Serial используется под modbus, поэтому всю отладку я веду через запросы к регистрам. Железо уже разобрали и готовят увезти на объект. Как только соберем новый стенд, сделаю минимальный пример, выложу.
На плате, где установлена atmega, Serial используется под modbus, поэтому всю отладку я веду через запросы к регистрам. Железо уже разобрали и готовят увезти на объект. Как только соберем новый стенд, сделаю минимальный пример, выложу.
не майтесь фигней. Запустите код из заголовка на обычной Уно или нано.
железо увозят на обьект, а программа не работает? Интересно. вы всегда так делаете - сначала собираете готовое жедезо, а только потом начинаете писать и тестировать код? :)
как вы это определили? - по диагностике при компиляции скетча?
https://alexgyver.ru/lessons/code-optimisation/
тогда почти наверняка причина в нехватке памяти. Вывод при компиляции показывает расход памяти только на глобальные переменные, - и они уже занимают 84% ОЗУ. А у вас еще куча локальных. в том числе массивы
84% флеша, а его можно забивать под завязку. Использование динамической памяти при компиляции показывает 825 байт, что при 1 кб ОЗУ микросхемы примерно соответствует показаниям memoryFree().
попробуйте для начала уменьшить MAX_SENSORS_QTY, например, до 4. Если после этого в ЕЕПРОМ запишется не 2.5 адреса. а скажем три - все будет ясно. дело в памяти
Попробую, спасибо.
железо увозят на обьект, а программа не работает? Интересно. вы всегда так делаете - сначала собираете готовое железо, а только потом начинаете писать и тестировать код? :)
Нет ;) Я занимаюсь серверной частью, которая общается с этими платами по modbus, а модули разрабатывали другие. Как только выяснилась такая проблема, мне пришлось подключиться ((
не майтесь фигней. Запустите код из заголовка на обычной Уно или нано.
Вот по причине, которую я написал выше, я не все понял. Уно- это отладочная плата такая? %))