Easyelectronics.ru

Электроника для всех
Текущее время: 18 окт 2019, 20:05

Часовой пояс: UTC + 5 часов



JLCPCB – Прототипы печатных плат за $2/10pcs (Любой цвет!)
Крупнейший производитель печатных плат и прототипов. Более 600000 клиентов и свыше 10000 заказов в день!
Получите скидку на почтовую отправку при первом заказе в JLCPCB!

Начать новую тему Ответить на тему  [ Сообщений: 20 ] 
Автор Сообщение
 Заголовок сообщения: Как хранить адреса epprom для доступа к данным?
СообщениеДобавлено: 22 мар 2019, 07:29 
Только пришел
Аватара пользователя

Зарегистрирован: 22 мар 2019, 06:59
Сообщения: 22
Откуда: Н-Ноовгород
Здравствуйте, начинаю изучать c++ под Atmel Studio, решился сразу в качестве теста, сделать небольшой проектик, часы с термометром и хранение данных в температурах в внешней eeprom с годовым календарем.
Atmega8 + RTC DS3231 + 16x2 LCD + AT24C32
Так вот, я впал в ступор когда дело дошло до хранения данных, по задумке хотелось хранить 2 значения за каждый день, это средняя дневная и ночная температура.
Соответственно мне надо выделить по 2 адреса x 365 = 730 адресов.
И в каждый адрес я буду получается писать данные раз год.
А как мне узнать в каком конкретно адресе находятся например данные за определенный день?
Получается надо где-то составить какую то БД, в которой будет находится дата и адрес ячейки eeprom который ей соостветсвует. Не тупо же в лоб делать 365 переменных с адресами.
Чтобы потом при просмотре данных, можно было листать адреса и им назначались соответствующие даты.
Может есть какое -то оптимальное решение, вычислить и назначить по дате адрес в eeprom?

Гуглил, к сожалению ничего похожего не нашел, чтобы кто-то так делал.


Вернуться к началу
 Профиль  
 
 Заголовок сообщения: Re: Как хранить адреса epprom для доступа к данным?
СообщениеДобавлено: 22 мар 2019, 07:43 
Старожил
Аватара пользователя

Зарегистрирован: 28 дек 2011, 11:24
Сообщения: 4097
Откуда: г. Липецк
ZmeyA писал(а):
...А как мне узнать в каком конкретно адресе находятся например данные за определенный день?
Получается надо где-то составить какую то БД, в которой будет находится дата и адрес ячейки eeprom который ей соостветсвует. Не тупо же в лоб делать 365 переменных с адресами.
...

Можно и тупо, ничего сложного. Тут одна загвоздка, с февралем, надо определять високосный год. Тоже ничего сложного, код на Pascal, думаю переписать на С несложно.
Код:
function DaysInMonth(const Year: Word, Month: Byte): Byte;
const
  MonthDays: array[1..12] of Byte = (31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31);
begin
  Result := MonthDays(Month);
  if (Month <> 2) and not
    ((Year mod 400 = 0) or ((Year mod 4 = 0) and (Year mod 100 <> 0))) then Exit;
  Inc(Result);
end;

Можно написать похожую функцию, которая будет возвращать не кол-во дней в месяце, а кол-во дней в прошедших месяцах, и прибавить текущую дату. Получится номер дня с начала года.


Вернуться к началу
 Профиль  
 
 Заголовок сообщения: Re: Как хранить адреса epprom для доступа к данным?
СообщениеДобавлено: 22 мар 2019, 10:24 
Старожил

Зарегистрирован: 08 авг 2013, 09:43
Сообщения: 2284
Обычный кольцевой буфер. Плюс 1 ячейка хранит текущее положение указателя в буфере. В текущей позиции (назовем cur) хранятся значения за вчерашний день. Соотв. в cur-1 за позавчера и т.д. Если значение cur - x отрицательное - значит данные лежат за началом буфера, соотв. искать их надо по адресу buf_size + (cur - x). Ну или if (x > cur) buf = array[buf_size - (x - cur)]. Если в cur-x нули - значит данные за этот день еще не записаны.


Вернуться к началу
 Профиль  
 
 Заголовок сообщения: Re: Как хранить адреса epprom для доступа к данным?
СообщениеДобавлено: 22 мар 2019, 11:09 
Только пришел
Аватара пользователя

Зарегистрирован: 22 мар 2019, 06:59
Сообщения: 22
Откуда: Н-Ноовгород
NStorm
Я не об этом, я о том как на экране написать, что например ячейка 365 соответствует 31 декабря.
Пока что придумал забить в eeprom 2 года, один високосный, другой нет, т.к RTC постоянно выдает текущую дату, проверять по ней какой сейчас год, и листать/писать eeprom с соответствующих адресов.
Т.к памяти все равно много, зато ячейки будут больше жить.
А вот именно чтобы на экран потом вывести что ячейка соответствует именно такой то дате и придется либо во флэш сохранять таблицу номеров ячеек и дат к ней, или как то математически вычислять.
И еще косяк, если упаковать дату+мес, получается 9 бит, что уже не лезет в 1 байт для хранения.


Вернуться к началу
 Профиль  
 
 Заголовок сообщения: Re: Как хранить адреса epprom для доступа к данным?
СообщениеДобавлено: 22 мар 2019, 11:14 
Старожил
Аватара пользователя

Зарегистрирован: 17 апр 2010, 08:38
Сообщения: 4914
Откуда: Усинск, республика Коми
ZmeyA писал(а):
И еще косяк, если упаковать дату+мес, получается 9 бит, что уже не лезет в 1 байт для хранения.

В первой ячейке храните дату старта. Во второй - показания на дату старта. В третьей - показания на дату старта + 1 день и т.д. пока не кончится память. Соответственно, при считывании данных читаем дату старта из 1 ячейки и потом простым смещением читаем показания на нужную дату.

_________________
хаос это непознанный порядок


Вернуться к началу
 Профиль  
 
 Заголовок сообщения: Re: Как хранить адреса epprom для доступа к данным?
СообщениеДобавлено: 22 мар 2019, 11:49 
Только пришел
Аватара пользователя

Зарегистрирован: 22 мар 2019, 06:59
Сообщения: 22
Откуда: Н-Ноовгород
BigLeha
Что-то не соображу как это работает.
что за показания на дуту старта?


Вернуться к началу
 Профиль  
 
 Заголовок сообщения: Re: Как хранить адреса epprom для доступа к данным?
СообщениеДобавлено: 22 мар 2019, 12:31 
Старожил

Зарегистрирован: 08 авг 2013, 09:43
Сообщения: 2284
Ну вот сегодня 22 марта запустили девайс, записываете что 22.03.2019 - первый день старта. Вы мыслите критериями календаря. Надо переходить к критериям "минус Х дней от сегодня". Вам же в будущее заглядывать не нужно. Значит показания могут храниться только за прошлые даты. Вот запустили 22го. Где-то в EEPROM выделяете область начина от некоего DATA_START до DATA_START+365 по 2 байта каждая ячейка. В момент перехода на "завтра" пишете в DATA_START значения за сегодня. И также в отдельную ячейку записываете указатель, что следующее значение будет в DATA_START+1. Завтра аналогично в ячейку по этому указателю, скажем CUR (который станет равен DATA_START+1) будут записаны значения за завтра. Потом к примеру 30го марта вы хотите посмотреть показания за 22ое. У вас указатель показывает на DATA_START+8. Вы знаете, что сегодня 30ое, а вам нужны данные за 22ое - значит нужно прочитать данные из ячейки CUR-8. Смотрите чтобы CUR-X не стал меньше DATA_START. Если меньше, то как я уже выше писал.


Последний раз редактировалось NStorm 25 мар 2019, 09:13, всего редактировалось 1 раз.

Вернуться к началу
 Профиль  
 
 Заголовок сообщения: Re: Как хранить адреса epprom для доступа к данным?
СообщениеДобавлено: 22 мар 2019, 12:38 
Старожил
Аватара пользователя

Зарегистрирован: 17 апр 2010, 08:38
Сообщения: 4914
Откуда: Усинск, республика Коми
ZmeyA писал(а):
BigLeha
Что-то не соображу как это работает.
что за показания на дуту старта?

Организация памяти. Стартовая дата - 1 января
Ячейка - Показания
1 - 1 января (непосредственно дата старта)
2 - показания на 1 января (на дату старта)
3 - показания на 2 января
4 - показания на 3 января
5....
Чтобы получить показания, например, на 3 января, мы читаем из 1 ячейки дату старта (1 января) и вычисляем смещение между нужной датой (3 января) и датой старта (1 января). Получаем 2 дня. В итоге, чтобы получить значения на 3 января, нам необходимо прочитать ячейку памяти номер 4 (2+2).

Дата старта может быть любой. Она может занимать и 2, и 3 байта памяти - как получится. Главное - учесть это при вычислении адреса нужной ячейки.

_________________
хаос это непознанный порядок


Вернуться к началу
 Профиль  
 
 Заголовок сообщения: Re: Как хранить адреса epprom для доступа к данным?
СообщениеДобавлено: 22 мар 2019, 12:43 
Старожил

Зарегистрирован: 08 авг 2013, 09:43
Сообщения: 2284
Можно и не сохраняя дату старта в общем-то, как я написал. Просто при просмотре прошлых показаний если в ячейке за выбранную дату 0x00 или 0xFF, т.е. значение еще не записывалось туда - значит показаний за эту дату еще не была и она и так понятно что раньше даты старта значит.


Вернуться к началу
 Профиль  
 
 Заголовок сообщения: Re: Как хранить адреса epprom для доступа к данным?
СообщениеДобавлено: 22 мар 2019, 13:25 
Старожил

Зарегистрирован: 08 авг 2013, 09:43
Сообщения: 2284
EDIT: Блин много букв получилось. Короткая версия: на самом деле по большей части описание обычного кольцевого буфера. Его и используем как я сказал. Главная идея в том, чтобы отталкиваться не от календаря и дат, а от понятия СЕГОДНЯ - Х дней. Тогда поиск проходит элементарно, как любом кольцевом буфере.

Вот, к примеру для 7 дней:
Вложение:
Screenshot_20190322_104144.png
Screenshot_20190322_104144.png [ 9.78 Кб | Просмотров: 948 ]

Слева колонки - адреса ячеек. Для простоты считаем пока что ячейка по одному адресу вмещает все наши данные (т.е. два байта, умножить адрес на 2 не проблема в реальной задаче)ю DATA_START, т.е. откуда пишем показания - некая константа. Соотв. данные у нас размещены по адресам В первую пишем текущий указатель CUR. Все данные уже заполнены. На сегодня у нас указатель равен 0x5. Это значит, что показания за вчера хранятся в ячейке 0x5. Листаем данные назад, за сколько дней назад смотрим, пусть будет X. Т.е. за позавчера X = 1, за позапозавчера X = 2 и т.д. Просто алгоритм:
Код:
if (CUR - X >= DATA_START) {
  ADDR = CUR - X;
} else {
  ADDR = (DATA_START + 6) - (X - (CUR - DATA_START + 1));
}

Для позавчера X = 1: CUR - X = 5 - 1 = 4 и это равно DATA_START. Значит данные за позавчера хранятся в ячейке 0х4.
Для позапозавчера X = 2: CUR - X = 5 - 2 = 3 и это меньше DATA_START, значит по else данные хранятся в ячейке
(DATA_START + 6) - (X - (CUR - DATA_START + 1)) - подставляем 4 + 6 - (2 - (5 - 4 + 1)) = 10, т.е. данные за позапозавчера хранятся в ячейке 0x10.

DATA_START + 6 - это по сути адрес конца нашей таблицы, т.к. пишем за 7 дней, т.е. начальный адрес + еще 6 адресов.
При смене дня увеличиваем CUR, он становится 0x6, значит записываем в ячейку 0x6 данные за прошедший день. При переходе через DATA_START + 6 делаем CUR = DATA_START снова.
Так и пишем данные по кругу. Тут оперируем только понятиями текущий день и сколько дней назад от него. Т.к. мы знаем какое сегодня число, то и посчитать "дней назад от него" тоже всегда можем. Это рассчитываем уже только для вывода на экран пользователю, для поиска показаний это не нужно. Примеров для расчета календарных дней, вычислений дня месяца в таком-то году - полно в сети.


Вернуться к началу
 Профиль  
 
 Заголовок сообщения: Re: Как хранить адреса epprom для доступа к данным?
СообщениеДобавлено: 23 мар 2019, 05:16 
Только пришел
Аватара пользователя

Зарегистрирован: 22 мар 2019, 06:59
Сообщения: 22
Откуда: Н-Ноовгород
Ух, спасибо, не ожидал что так основательно разложите все по полочкам.
Самое интересное я ведь только пару дней назад читал статью о кольцевом буфере, но там для интерфейса было и как то не обратил на это внимание, что применимо и для этой задачи будет.
Но тут тоже как бы косяки еще имеются, допустим прибор выключится на N дней, тогда в чистом виде календаря уже хронология будет нарушена и данные за вчера, будут датой выключения прибора, правильно я понимаю?
И еще, а есть все же способы компактного хранения дат?
Уж очень хочется запихнуть например месяц и день в 8 бит, для хранения в 1 одной ячейки, вместо двух.
Не критично, но чисто для познавательности.


Вернуться к началу
 Профиль  
 
 Заголовок сообщения: Re: Как хранить адреса epprom для доступа к данным?
СообщениеДобавлено: 23 мар 2019, 07:06 
Заглядывает иногда

Зарегистрирован: 28 сен 2018, 00:25
Сообщения: 163
Про кольцевой буфер. Это все конечно хорошо, но если в лоб делать, то будет протираться до дыр ячейка в которую будет писаться позиция в буфере. Яб делал на двусвязном списке. Да, при старте придется пробежаться по всему списку в поисках текущей ячейки, зато все ячейки будут расходоваться равномерно.
Хотяяя... При записи раз в сутки можно этим вопросом вообще не заморачиваться.
Есть способ компактного хранения не только дат, но и даты со временем - Unix-time зовется. ;)
Или как вариант структуры с битовыми полями.


Вернуться к началу
 Профиль  
 
 Заголовок сообщения: Re: Как хранить адреса epprom для доступа к данным?
СообщениеДобавлено: 23 мар 2019, 08:19 
Старожил
Аватара пользователя

Зарегистрирован: 28 дек 2011, 11:24
Сообщения: 4097
Откуда: г. Липецк
ZmeyA писал(а):
...Уж очень хочется запихнуть например месяц и день в 8 бит, для хранения в 1 одной ячейки, вместо двух...

Никак не получится, день требует 5 бит (2^5=32), месяц 4 бита (2^4=16). 2^8=256 меньше кол-ва дней в году.


Вернуться к началу
 Профиль  
 
 Заголовок сообщения: Re: Как хранить адреса epprom для доступа к данным?
СообщениеДобавлено: 23 мар 2019, 08:41 
Старожил
Аватара пользователя

Зарегистрирован: 22 июл 2017, 11:48
Сообщения: 3646
А по-моему, всё не шибко сложно.
Адрес = 2 * [номер дня от 01.01.2019]
Преобразование календарной даты в номер дня делается суммированием числа дней в каждом месяце. Число дней в каждом месяце - табличное значение, как самый быстрый вариант.
num_days_of_month[12] = {31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31}; // обычный год
num_days_of_month_bis[12] = {31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31}; // високосный год
Сначала вычисляем, является ли год високосным или нет. Остаток от деления на 4, равен или не равен 0. И исходя из этого выбираем таблицу из представленных выше.
Далее в цикле от 0 до номера месяца - 1 суммируем значения числа дней из таблицы. И прибавляем число дней в текущем месяце.
В итоге мы получаем номер дня от начала года.
Сегодня 23.03.19.
19 % 4 != 0, год не високосный, нужна первая таблица.
Март, 3 месяц. Суммируем 3-1 значений таблицы: 31+28 = 59.
23 число, 59+23 = 82.
Номер дня = 82.
Умножаем на 2, поскольку два байта у нас хранится. Вот мы и получили адрес, 83*2 = 164.

Причем, мы можем использовать не только кольцевой буфер на 366 дней, но и расширить это кольцо до нескольких лет, просто приплюсовывая число дней в году (365 или 366).
Время жизни устройств составляет 7-10 лет, поэтому вы можете сохранять данные за последние 5 лет.

Цитата:
допустим прибор выключится на N дней, тогда в чистом виде календаря уже хронология будет нарушена и данные за вчера, будут датой выключения прибора, правильно я понимаю?

Чтобы не иметь этих проблем, нужно перед записью в еепром вычислять адрес точно так же по дате, по номеру дня. Иначе вы сильно усложните алгоритм поиска по произвольной дате


Вернуться к началу
 Профиль  
 
 Заголовок сообщения: Re: Как хранить адреса epprom для доступа к данным?
СообщениеДобавлено: 23 мар 2019, 11:34 
Старожил
Аватара пользователя

Зарегистрирован: 28 дек 2011, 11:24
Сообщения: 4097
Откуда: г. Липецк
BusMaster писал(а):
...Сначала вычисляем, является ли год високосным или нет. Остаток от деления на 4, равен или не равен 0. И исходя из этого выбираем таблицу из представленных выше...

Правильно, но не полно. Високосный год вычисляется немного сложнее. Выше я уже приводил правильную формулу, оригинал.


Вернуться к началу
 Профиль  
 
 Заголовок сообщения: Re: Как хранить адреса epprom для доступа к данным?
СообщениеДобавлено: 23 мар 2019, 11:38 
Старожил
Аватара пользователя

Зарегистрирован: 22 июл 2017, 11:48
Сообщения: 3646
:)))) Да, но вероятность того, что в обозримом будущем вы встретите это исключение из правила, крайне невероятна. Никто из существующих ныне на форуме людей не доживет до этого :))))) Так что на ближайшие 10-20 лет нам достаточно простого деления на 4.
Ближайшие високосные года - 2020, 24, 28, 32, 36. Дальше - не обязательно. А в 38 году вообще заканчивается unix-эпоха, и эта проблема посерьезнее для тех, кто использует 32-битный unix-time.


Вернуться к началу
 Профиль  
 
 Заголовок сообщения: Re: Как хранить адреса epprom для доступа к данным?
СообщениеДобавлено: 23 мар 2019, 12:51 
Заглядывает иногда

Зарегистрирован: 02 фев 2017, 00:22
Сообщения: 75
Почитайте про UNIX-time


Вернуться к началу
 Профиль  
 
 Заголовок сообщения: Re: Как хранить адреса epprom для доступа к данным?
СообщениеДобавлено: 23 мар 2019, 13:29 
Старожил
Аватара пользователя

Зарегистрирован: 22 июл 2017, 11:48
Сообщения: 3646
unix-time в чистом виде тут совершенно не нужен. Изначально из RTC берутся номера дня, месяца и года. И нужно получить всего лишь номер дня от начала года.
Обратное преобразование тоже по тому же принципу, только вместо сложения идет вычитание. Из числа дней от начала года вычитаются значения из таблички до тех пор, пока оставшееся число дней положительно. Индекс в табличке +1 покажет на текущий месяц, а прибавив к отрицательному результату число дней в текущем месяце, получим текущее число.
82 - 31 - 28 - 31 = -8, количество вычитаний = 3
-8 + 31 = 23.
23 марта.


Вернуться к началу
 Профиль  
 
 Заголовок сообщения: Re: Как хранить адреса epprom для доступа к данным?
СообщениеДобавлено: 23 мар 2019, 15:17 
Старожил

Зарегистрирован: 19 мар 2013, 19:37
Сообщения: 2622
Откуда: Санкт-Петербург
Для ленивых можно установить, что в месяце 32 дня. Тогда номер ячейки считается попросту - M*32+D (M считать от 0).


Вернуться к началу
 Профиль  
 
 Заголовок сообщения: Re: Как хранить адреса epprom для доступа к данным?
СообщениеДобавлено: 25 мар 2019, 10:52 
Только пришел
Аватара пользователя

Зарегистрирован: 22 мар 2019, 06:59
Сообщения: 22
Откуда: Н-Ноовгород
Спасибо, в принципе получилось довольно просто, всего пару функций:
Проверил в Visual Studio, считает нормально.
Код:
int year=2019, month, day;
int num_days_of_month[12] = { 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 }; // обычный год
int num_days_of_month_vis[12] = { 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 }; // високосный год

int count_days(int cday, int cmonth) {
   int *pTdays;
   if (year % 4 != 0) {
      pTdays = num_days_of_month;
   } else {
      pTdays = num_days_of_month_vis;
   }
   for (int i = 0; i < (cmonth - 1); i++) {
      cday += pTdays[i];
   }
   return cday;
}

int get_date(int countdays, int cyear) {
   int *pTdays;
   int cmonth=-1;
   if (cyear % 4 != 0) {
      pTdays = num_days_of_month;
   } else {
      pTdays = num_days_of_month_vis;
   }
   while (countdays > 0) {
      countdays -= pTdays[(++cmonth)];
   }
   return (countdays + pTdays[cmonth]);
}


Только при листании надо еще добавить проверки на прошлый год, високосный он или нет, а то получится что данные за прошлый год, если он был високосный на 1 ячейку памяти смещены.


Вернуться к началу
 Профиль  
 
Показать сообщения за:  Поле сортировки  
Начать новую тему Ответить на тему  [ Сообщений: 20 ] 

Часовой пояс: UTC + 5 часов


Кто сейчас на конференции

Сейчас этот форум просматривают: нет зарегистрированных пользователей


Вы не можете начинать темы
Вы не можете отвечать на сообщения
Вы не можете редактировать свои сообщения
Вы не можете удалять свои сообщения
Вы не можете добавлять вложения

Найти:
Перейти:  

Powered by phpBB © 2000, 2002, 2005, 2007 phpBB Group
Русская поддержка phpBB