Вопросы по С/С++ (СИ)

Если ваш вопрос не влез ни в одну из вышеперечисленных тем, вам сюда.
Ответить
ARV
Ум, честь и совесть. И скромность.
Аватара пользователя
Сообщения: 18787
Зарегистрирован: Чт дек 28, 2006 08:19:56
Откуда: Новочеркасск

Сообщение ARV »

ПростоНуб писал(а):самое веселое начинается в юникоде
я так понимаю, в юникоде не надо умничать, а надо пользоваться библиотечными функциями/классами поддержки юникода, и веселье будет отменено.
если рассматривать человека снизу, покажется, что мозг у него глубоко в жопе
при взгляде на многих сверху ничего не меняется...

Мой уютный бложик... заходите!
Контактная информация:
Реклама
Собутыльник Кота
Аватара пользователя
Сообщения: 2723
Зарегистрирован: Пт сен 07, 2018 20:20:02
Откуда: деревня в Тульской губернии

Сообщение ПростоНуб »

ARV, когда оперативки гигабайт - так и делаю. А на МК тащить библиотеку поддержки UTF-16 - себе дороже. Только локали способны весь флеш занять. Аккуратно, ручками, только то, что надо или вообще самостоятельно. Не так уж часто приходится на МК по NTFS на флешке лазить или через ESP8266 SOAP/REST на UTF-16 парсить.
С UTF-8, как я уже писал выше, проще.
Реклама
Опытный кот
Сообщения: 768
Зарегистрирован: Вс янв 19, 2014 00:55:09

Сообщение MOHCTEP »

Братцы помогите разобраться с EEPROM и EEMEM-ами.
Железо - Мега 128, дисплей с тачем и остальная периферия. В EEPROM надо хранить разного рода настройки, кольцевой список данных, ну и сам указатель на текущую "ячейку" этих данных. Общение с EEPROM будет из разных си файлов проекта. Поэтому хотелось бы как-то оптимизировать, каталогизировать это дело. Начал с настроек тач панели.
Схимичил файлы "eeprom.h"

Код: Выделить всё

#ifndef EEPROM_H_
#define EEPROM_H_

#define EEPROM_TOUCH_ADDRESS	0

/*	Настройки тач панели дисплея	*/
float	touch_factor_x;
float	touch_factor_y;
int		touch_term_x;
int		touch_term_y;

#endif /* EEPROM_H_ */
и "eeprom.с"

Код: Выделить всё

#include <avr/eeprom.h>
#include "config.h"

/*	Настройки тач панели дисплея	*/
float EEMEM touch_factor_x;
float EEMEM touch_factor_y;
int EEMEM touch_term_x;
int EEMEM touch_term_y;/**/
Приинклюдил к файлу "touch.c". Так вот код

Код: Выделить всё

float factor_x, factor_y;
int term_x, term_y;
...
...
//uint16_t addr = EEPROM_TOUCH_ADDRESS;
	//factor_x = eeprom_read_float((float *) addr);
	//addr += sizeof(factor_x);
	//factor_y = eeprom_read_float((float *) addr);
	//addr += sizeof(factor_y);
	//term_x = eeprom_read_word((uint16_t *) addr);
	//addr += sizeof(term_x);
	//term_y = eeprom_read_word((uint16_t *) addr);

factor_x = eeprom_read_float((float *) &touch_factor_x);
	factor_y = eeprom_read_float((float *) &touch_factor_y);
	term_x = eeprom_read_word((uint16_t *) &touch_term_x);
	term_y = eeprom_read_word((uint16_t *) &touch_term_y);
	
	if(term_x == -1 && term_y == -1)	touch_calibrated = 0;
странно работает. Тач панель не отрабатывает нажатия. И стирание EEPROM, при прошивке, не дает никакого эффекта. Как будто калибровка корректная. Прежний вариант кода(закомментированный) с "абсолютной" адресацией работает отменно. Тач отрабатывает, как надо и стирание памяти запускает автоматическую калибровку. Не пойму, где ошибка?
ARV
Ум, честь и совесть. И скромность.
Аватара пользователя
Сообщения: 18787
Зарегистрирован: Чт дек 28, 2006 08:19:56
Откуда: Новочеркасск

Сообщение ARV »

я всегда все настройки собираю в структуру, потом эту структуру целиком пишу/читаю в/из EEPROM при помощи eeprom_read_block или eeprom_update_block.
если рассматривать человека снизу, покажется, что мозг у него глубоко в жопе
при взгляде на многих сверху ничего не меняется...

Мой уютный бложик... заходите!
Контактная информация:
Реклама
Эиком - электронные компоненты и радиодетали
Опытный кот
Сообщения: 768
Зарегистрирован: Вс янв 19, 2014 00:55:09

Сообщение MOHCTEP »

ARV, Проблема в том, что настройки потребуются "кусками" в непредсказуемые периоды времени. И обновляться тоже кусочно будут. Да еще и данные как-то надо писать/читать. Сначала массив данных будет расти до определенного предела, а потом старые данные будут затираться свежими по кругу. Получается, всю эту кучу надо будет перезаписывать, при малейшем изменении? Коли так, то буду признателен, если поделитесь примером кода применительным к ситуации. И "eeprom_update_block" обновит только изменившиеся данные или отрефрешит весь объем, занятый структурой?
Реклама
Поставщик валерьянки для Кота
Сообщения: 1978
Зарегистрирован: Ср июл 17, 2013 13:55:57

Сообщение NStorm »

eeprom_update_* сначало побайтово читают eeprom и если новые данные такие же - то не пишет, пропуская этот байт.

А у вас размер данных всегда динамический? Т.е. расти может до неопределенных размеров. Что будете делать, когда он помещаться перестанет? Лучше всё-таки имхо сразу установить максимальный размер и писать в EEPROM блоками по кольцу, вместе с настройками. Для уменьшения износа EEPROM настройки т.е. тоже лучше "двигать".
Реклама
ARV
Ум, честь и совесть. И скромность.
Аватара пользователя
Сообщения: 18787
Зарегистрирован: Чт дек 28, 2006 08:19:56
Откуда: Новочеркасск

Сообщение ARV »

MOHCTEP писал(а):настройки потребуются "кусками" в непредсказуемые периоды времени
после того, как все настройки считаны в ОЗУ в структуру config, вы в любой момент можете обращаться к её куску config.someone - в чем проблема?
MOHCTEP писал(а):обновляться тоже кусочно будут
на здоровье: в той же структуре обновляйте config.someone когда угодно и сколько угодно раз!
MOHCTEP писал(а):всю эту кучу надо будет перезаписывать, при малейшем изменении?
зачем?! только в критические моменты: при (перед) выключении питания или в моменты простоя (раз в 1...100 секунд, например). для чего после каждого чиха обновлять настройки?!
MOHCTEP писал(а):И "eeprom_update_block" обновит только изменившиеся данные
да, сверит все и обновит только те байты, которые изменились. потому она и update
если рассматривать человека снизу, покажется, что мозг у него глубоко в жопе
при взгляде на многих сверху ничего не меняется...

Мой уютный бложик... заходите!
Контактная информация:
Поставщик валерьянки для Кота
Сообщения: 1978
Зарегистрирован: Ср июл 17, 2013 13:55:57

Сообщение NStorm »

EEMEM не очень подходит для кольцевых буферов. Если уж делаете кольцевой, то делайте "абсолютную" адресацию, как и делали. Только действительно объедините все ваши значения в структуру и всё. Даже разного размера можно делать, только текущий размер тоже записывать в EEPROM надо будет. У меня с фиксированным размером по кольцевому буферу как-то так обычно настройки сохраняются/загружаются:
Спойлер

Код: Выделить всё

#define EEPROM_SIZE 512
#define EEPROM_ENTRY_SIZE (sizeof(settings_t) + sizeof(state_t))
#define EEPROM_ENTRIES (EEPROM_SIZE / EEPROM_ENTRY_SIZE)

typedef struct {
    uint32_t seq;
    // state_t goes here in actual EEPROM
    uint16_t crc;
} settings_t;

void load_settings() {
    uint8_t *ptr = 0; // byte pointer in EEPROM
    uint32_t cur_seq = 0;
    state_t state_buf;
    
    cli();

    while (queue_num < EEPROM_ENTRIES) {
        settings.seq = eeprom_read_dword((void *) ptr);
        if (settings.seq <= cur_seq || settings.seq == 0xFFFFFFFF) {
            settings.seq = cur_seq;
            break;
        }
        cur_seq = settings.seq;
        ptr += sizeof (settings.seq);
        eeprom_read_block(&state_buf, (void *) ptr, sizeof (state_buf));
        ptr += sizeof (state_buf);
        settings.crc = eeprom_read_word((void *) ptr);
        ptr += sizeof (settings.crc);

        if (settings.crc != crc16((void *) &state_buf, sizeof (state_buf))) {
            LOG("CRC incorrect\r\n");
            break;
        }
        // Since we are here, settings are valid, CRC are good
        state = state_buf;
        queue_num++;
    }
    sei();
}

void save_settings(eSaveMode savemode) {
    cli();

    settings.crc = crc16((void *) &state, sizeof (state)); // Calculate crc16 of state struct

    // Save data to EEPROM
    settings.seq++;
    if (queue_num >= EEPROM_ENTRIES) // Reset queue_num once we reach end of EEPROM
        queue_num = 0;
    uint8_t *ptr = (void *)(queue_num * EEPROM_ENTRY_SIZE); // Get location of next segment in EEPROM
    
    
    eeprom_write_dword((void *) ptr, settings.seq);
    ptr += sizeof (settings.seq);
    eeprom_update_block((void *)&state, (void *) ptr, sizeof (state));
    ptr += sizeof (state);
    eeprom_write_word((void *) ptr, settings.crc);

    sei();
}

Ну у меня тут небольшой костыль, две структуры. Т.к. настоящие "настройки" в структуре state, а структура settings - там лишь порядковый номер и CRC. Я тут обрезал, у меня еще кое что там было, не важно в данном случае. Смысл в том, что EEPROM по блокам по размеру обоих структур разбита и по кольцу пишется-читается с порядковым номером и CRC.
ARV
Ум, честь и совесть. И скромность.
Аватара пользователя
Сообщения: 18787
Зарегистрирован: Чт дек 28, 2006 08:19:56
Откуда: Новочеркасск

Сообщение ARV »

имхо, проблема "кольцевых буферов" в EEPROM для сохранения настроек надумана: настройки - это не та информация, которая обновляется часто. скажем, показания одометра обновляются часто, а настройки?! без малейших ухищрений ресурса в 100000 перезаписей должно хватить на 27 часов ежесекундных перезаписей! какие такие настройки можно так часто перезаписывать? а если настройки ведутся 1 раз в минуту, то ресурс исчерпается не раньше, чем через 70 суток. но я не могу себе представить и этой ситуации.
если рассматривать человека снизу, покажется, что мозг у него глубоко в жопе
при взгляде на многих сверху ничего не меняется...

Мой уютный бложик... заходите!
Контактная информация:
Поставщик валерьянки для Кота
Сообщения: 1978
Зарегистрирован: Ср июл 17, 2013 13:55:57

Сообщение NStorm »

ARV, ну в принципе да, если именно настройки, которые не часто сохраняются, то можно и без колец обойтись. ТС просто сам про кольц. буфер написал. А у меня там не совсем настройки, а состояния различные сохраняются, не раз в минуту, но может раз 10 за час меняться. Поэтому буфер сделал, чтобы хватило на годы.
Опытный кот
Сообщения: 768
Зарегистрирован: Вс янв 19, 2014 00:55:09

Сообщение MOHCTEP »

ARV, NStorm, спасибо!
Видимо я не совсем точно описал проблему.
Настройки - их одинаковая кучка, а значит и размер в памяти всегда одинаков, меняться будут только непосредственно значения, по необходимости.
Данные. Сначала, при самом первом включении, их просто еще нет. Со временем, они появляются тоже кучкой и пишутся в EEPROM, каждая следующая порция - за предыдущей. Это необходимо, для анализа их изменения и оперативного изменения тех самых настроек. Когда допустимый объем данных заполнен, следующая порция должна запомниться на месте устаревших данных. Вот тут-то, в области данных и нужен кольцевой буфер.
Ступор у меня в том, что разнообразие настроек довольно велико и они тоже разные: от 32 битных, до бит-полей, есть и структуры и массивы, возможны и строки. Вот как весь этот винегрет увязать в структуру и подружить ее с EEPROM?
Поставщик валерьянки для Кота
Сообщения: 1978
Зарегистрирован: Ср июл 17, 2013 13:55:57

Сообщение NStorm »

Ступор у меня в том, что разнообразие настроек довольно велико и они тоже разные: от 32 битных, до бит-полей, есть и структуры и массивы, возможны и строки. Вот как весь этот винегрет увязать в структуру и подружить ее с EEPROM?
Так в чем проблема? Делаете из них структуру и сохраняете, как выше писали. Структуры тоже вполне можно включать в структуры. Строки, если фиксированной максимальной длины - вообще без проблем.
ARV
Ум, честь и совесть. И скромность.
Аватара пользователя
Сообщения: 18787
Зарегистрирован: Чт дек 28, 2006 08:19:56
Откуда: Новочеркасск

Сообщение ARV »

MOHCTEP писал(а):для анализа их изменения и оперативного изменения тех самых настроек
micro-SD и FatFS от нашего японского коллеги по имени Чен решают любые проблемы, как с количеством записей, так и с анализом, так и со строками и всем прочим. файловый ввод-вывод - наше всё. для 128-й меги вообще не вопрос.
если рассматривать человека снизу, покажется, что мозг у него глубоко в жопе
при взгляде на многих сверху ничего не меняется...

Мой уютный бложик... заходите!
Контактная информация:
Опытный кот
Сообщения: 768
Зарегистрирован: Вс янв 19, 2014 00:55:09

Сообщение MOHCTEP »

Спасибо друзья! Вроде разобрался, благодаря вашей помощи.
Опытный кот
Сообщения: 768
Зарегистрирован: Вс янв 19, 2014 00:55:09

Сообщение MOHCTEP »

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

Код: Выделить всё

//float a = (float)((year / 19) - floor(year / 19)); // 0
	float a;
	//a = (float)(year / 19) - (uint8_t)(year / 19); // 0
	a = year / 19;
	num2dec(a * 1000,3);
	uart1_puts(digi_buffer);uart1_puts("\r\n"); // 106.000
	a = (float)(year / 19);
	num2dec(a * 1000,3);
	uart1_puts(digi_buffer);uart1_puts("\r\n");//106.000
2 Это, как бы, продолжение предыдущего разговора. Вот структура:

Код: Выделить всё

typedef struct{
	uint16_t time;	/* 2 bytes */
	uint32_t a;		/* 4 bytes */
	int16_t b[4];	/* 2 * 4 = 8 bytes */
	uint8_t c[4];	/* 1 * 4 = 4 bytes */
	/* total = 18 bytes */
}data_t;
Этими структурами постепенно заполняется ЕЕПРОМ (около 200 штучек). Теперь, мне со всех записей нужно прочесть в массив, допустим значения data_t.b[2] или все data_t.a. Вот как это правильно сделать и чтоб оперативка не сильно тратилась? В идеале бы только на массив нужных, в данное время, данных.
Поставщик валерьянки для Кота
Сообщения: 2089
Зарегистрирован: Вс июн 19, 2016 09:32:03

Сообщение Reflector »

Код: Выделить всё

float a;
a = year / 19.0f;  // или a = (float)year / 19;
А ты сначала целочисленно делишь а потом результат приводишь к float...
Опытный кот
Сообщения: 768
Зарегистрирован: Вс янв 19, 2014 00:55:09

Сообщение MOHCTEP »

Reflector, Спасибо! :beer: Так действительно работает!
А вариант

Код: Выделить всё

//a = (float)(year / 19)
У меня почему-то не работал правильно.
Поставщик валерьянки для Кота
Сообщения: 1978
Зарегистрирован: Ср июл 17, 2013 13:55:57

Сообщение NStorm »

Потому что опять же сначала целочисленное деление, а уже потом приведение результата к float. Из-за скобок.
Между

Код: Выделить всё

a = (float)(year / 19);
И

Код: Выделить всё

a = (float)year / 19;
Огромная разница. Во 2ом случае сначала year приводится к float, и потом делится на 19 уже как float.

Добавлено after 6 minutes 28 seconds:
[uquote="MOHCTEP",url="/forum/viewtopic.php?p=3885141#p3885141"]Этими структурами постепенно заполняется ЕЕПРОМ (около 200 штучек). Теперь, мне со всех записей нужно прочесть в массив, допустим значения data_t.b[2] или все data_t.a. Вот как это правильно сделать и чтоб оперативка не сильно тратилась? В идеале бы только на массив нужных, в данное время, данных.[/uquote]

Код: Выделить всё

uint32_t buf;
eeprom_read_block(&buf, sizeof(data_t) * NR_BLOCK + sizeof(data_t.time), sizeof(buf)); // Прочитать с блока NR_BLOCK (порядковый номер) значение .a
Ну т.е. банально вычисляем начало блока, плюс добавляем пропуск того, что идет до нужных данных, т.е. скипаем их. И читаем нужное кол-во байт. Если все блоки надо прочитать - ну проходимся по очереди NR_BLOCK от 1 до N.
Опытный кот
Сообщения: 768
Зарегистрирован: Вс янв 19, 2014 00:55:09

Сообщение MOHCTEP »

NStorm, Спасибо! С плавающим "флотом" вроде понял суть. А со структурами, вот как мне точно попасть на нужную переменную? Судя по вашему примеру, структура сохраняется в порядке объявления переменных?
И для чтения, к примеру, data_t.с[2] надо вот этакую конструкцию писать?

Код: Выделить всё

eeprom_read_block(&buf, sizeof(data_t) * NR_BLOCK + sizeof(data_t.time) + sizeof(data_t.a) + sizeof(data_t.b) + sizeof(data_t.c[0]) * 2, sizeof(buf));// Прочитать с блока NR_BLOCK (порядковый номер) значение .c[2]
Поставщик валерьянки для Кота
Сообщения: 1978
Зарегистрирован: Ср июл 17, 2013 13:55:57

Сообщение NStorm »

MOHCTEP, компилятор не меняет порядок в структуре. В каком порядке задали - в таком порядке оно будет в памяти. Т.е. да, "сохраняется в порядке объявления переменных". Единственный момент - как вы структуру в EEPROM писать будете. Если целиком структуру через eeprom_write_block(), то всё будет в таком порядке. Но если вручную как-то - то порядок уже от вас зависеть может.
В вашем примере - да, почти так. Только sizeof(data_t.b) надо еще на 4 умножить, т.к. там у вас массив в примере выше.
Ну и ес-но для удобства, чтобы не писать эту длинную фигню каждый раз, можно определить макрос. Вроде:

Код: Выделить всё

#define DATA_T_SZ sizeof(data_t)
#define DATA_T_C2_OFFSET sizeof(data_t.time) + sizeof(data_t.a) + sizeof(data_t.b) * 4 + sizeof(data_t.c[0]) * 2
...
eeprom_read_block(&buf, DATA_T_SZ * NR_BLOCK + DATA_T_C2_OFFSET, sizeof(buf));
Или написать небольшую функцию, которая будет считать нужны адрес каждый раз. Смотря как много разных элементов структуры вам так отдельно выцеплять надо. Функция будет такты отнимать на расчет адреса, макросы с фиксированными смещениями считаются на этапе компиляции, но будут занимать место во флэше.
Ответить

Вернуться в «Разные вопросы по МК»