Запись и чтение EEPROM переменных типа float, unsigned long, long, unsigned int, int

maksim
Offline
Зарегистрирован: 12.02.2012

Функции чтения и записи EEPROM для разных типов переменных:

 float:

// чтение
float EEPROM_float_read(int addr) {    
  byte raw[4];
  for(byte i = 0; i < 4; i++) raw[i] = EEPROM.read(addr+i);
  float &num = (float&)raw;
  return num;
}

// запись
void EEPROM_float_write(int addr, float num) {
  byte raw[4];
  (float&)raw = num;
  for(byte i = 0; i < 4; i++) EEPROM.write(addr+i, raw[i]);
}

unsigned long:

// чтение
unsigned long EEPROM_ulong_read(int addr) {    
  byte raw[4];
  for(byte i = 0; i < 4; i++) raw[i] = EEPROM.read(addr+i);
  unsigned long &num = (unsigned long&)raw;
  return num;
}

// запись
void EEPROM_ulong_write(int addr, unsigned long num) {
  byte raw[4];
  (unsigned long&)raw = num;
  for(byte i = 0; i < 4; i++) EEPROM.write(addr+i, raw[i]);
}

long:

// чтение
long EEPROM_long_read(int addr) {    
  byte raw[4];
  for(byte i = 0; i < 4; i++) raw[i] = EEPROM.read(addr+i);
  long &num = (long&)raw;
  return num;
}

// запись
void EEPROM_long_write(int addr, long num) {
  byte raw[4];
  (long&)raw = num;
  for(byte i = 0; i < 4; i++) EEPROM.write(addr+i, raw[i]);
}

unsigned int:

// чтение
unsigned int EEPROM_uint_read(int addr) {    
  byte raw[2];
  for(byte i = 0; i < 2; i++) raw[i] = EEPROM.read(addr+i);
  unsigned int &num = (unsigned int&)raw;
  return num;
}
// запись
void EEPROM_uint_write(int addr, unsigned int num) {
  byte raw[2];
  (unsigned int&)raw = num;
  for(byte i = 0; i < 2; i++) EEPROM.write(addr+i, raw[i]);
}

int:

// чтение
int EEPROM_int_read(int addr) {    
  byte raw[2];
  for(byte i = 0; i < 2; i++) raw[i] = EEPROM.read(addr+i);
  int &num = (int&)raw;
  return num;
}

// запись
void EEPROM_int_write(int addr, int num) {
  byte raw[2];
  (int&)raw = num;
  for(byte i = 0; i < 2; i++) EEPROM.write(addr+i, raw[i]);
}

Пример использования:

#include <EEPROM.h>

void setup() 
{ 
  Serial.begin(9600);
  EEPROM_float_write(0, 1.2568);
  float a = EEPROM_float_read(0);
  Serial.println(a, 4);
}

void loop(){}


// чтение
float EEPROM_float_read(int addr) {    
  byte raw[4];
  for(byte i = 0; i < 4; i++) raw[i] = EEPROM.read(addr+i);
  float &num = (float&)raw;
  return num;
}

// запись
void EEPROM_float_write(int addr, float num) {
  byte raw[4];
  (float&)raw = num;
  for(byte i = 0; i < 4; i++) EEPROM.write(addr+i, raw[i]);
}

При работе с адресами необходимо помнить, что типы float, unsigned long и long занимают в памяти 4 байта, а типы unsigned int и int 2 байта. Пример записи и чтения трех переменных типа float и трех переменных типа int:

  EEPROM_float_write(0, 1.2345); // адрес 0 (+4 байта)
  EEPROM_float_write(4, 2.3456); // адрес 4 (+4 байта)
  EEPROM_float_write(8, 3.4567); // адрес 8 (+4 байта)
  // чтение
  float a = EEPROM_float_read(0);
  float b = EEPROM_float_read(4);
  float c = EEPROM_float_read(8);
  
  // запись
  EEPROM_int_write(12, 1000); // адрес 12 (+2 байта)
  EEPROM_int_write(14, 2000); // адрес 14 (+2 байта)
  EEPROM_int_write(16, 3000); // адрес 16 (+2 байта)
  // чтение
  int d = EEPROM_int_read(12);
  int e = EEPROM_int_read(14);
  int f = EEPROM_int_read(16);

 

sandr4
sandr4 аватар
Offline
Зарегистрирован: 11.02.2015

Большое спасибо maksim, думаю, многим поможет такая инфа. 

avton
avton аватар
Offline
Зарегистрирован: 11.05.2014

Огромный респект ! Все в одном месте. Спасибо!

vvadim
Offline
Зарегистрирован: 23.05.2012

Спасибо - полезная и нужная информация !

brokly
brokly аватар
Offline
Зарегистрирован: 08.02.2014

Я вас умоляю. В какую шапку? Конечно ТС систематизировал и разжевал, ему однозначно респект. Но если ленивый новичек сам до этого не дойдет, прочитав базовые статьи по работе с епромом и о размерах данных, то ему и смысла нет помогать. Все равно лентяи будут писать в пересекающиеся  блоки и затирать одну переменную другой, хоть ТС и рассказал об этом.

brokly
brokly аватар
Offline
Зарегистрирован: 08.02.2014

Согласен. Тема горячая :)

Araris
Offline
Зарегистрирован: 09.11.2012

Самая горячая тема здесь - тема дипломного/курсового проекта )))

brokly
brokly аватар
Offline
Зарегистрирован: 08.02.2014

А давайте ее вынесем в шапку ! :)

kisoft
kisoft аватар
Offline
Зарегистрирован: 13.11.2012

brokly пишет:

Я вас умоляю. В какую шапку? Конечно ТС систематизировал и разжевал, ему однозначно респект. Но если ленивый новичек сам до этого не дойдет, прочитав базовые статьи по работе с епромом и о размерах данных, то ему и смысла нет помогать. Все равно лентяи будут писать в пересекающиеся  блоки и затирать одну переменную другой, хоть ТС и рассказал об этом.

+100500

 

AS31979
Offline
Зарегистрирован: 22.12.2015

Может для того кто уже знает и понятно, если операции с разбивкой/склейкой примерно понятны, то пример использования с float/void мягко выражаясь не очень. Ну нет хорошо расписанных уроков на эту тему, во всех обучалках упор на использование переферии.

Неужели тяжело было в тексте примера вставить пару коментариев? Да и сам пример  использования неудачный.

Zen
Offline
Зарегистрирован: 10.12.2015

добрый вечер.

Столкнулся с проблемой записи переменной типа float в EEPROM  при помощи функции описанной пользователем maksim.  Запись положительных чисел проходит нормально, а вот при записи отрицательного числа с запятой, потом считывается не "0,0", а со знаком минус "-0,0". Причем при записи чисел -0,1, -0,2 проблем не возникает, а вот после записи -0,3, -0,4 и т.д....считать или записать в ячейку 0,0 без занка минус не получается:( помогите!!!:) 

yul-i-an
yul-i-an аватар
Offline
Зарегистрирован: 10.12.2012

Спасибо  maksim.

Хочу дополнить, если сохраняемое значение неотличается от сохраненного, то и сохранять его не стоит.

Я ввел проверку

// чтение
int EEPROM_int_read(int addr) {    
  byte raw[2];
  for(byte i = 0; i < 2; i++) raw[i] = EEPROM.read(addr+i);
  int &num = (int&)raw;
  return num;
}

// запись
void EEPROM_int_write(int addr, int num) {
  if (EEPROM_int_read(addr)!= num){//если сохраняемое отличается
    byte raw[2];
    (int&)raw = num;
    for(byte i = 0; i < 2; i++) EEPROM.write(addr+i, raw[i]);
  }
}

 

Stas0232
Offline
Зарегистрирован: 11.06.2016

Здравствуйте.

Если мы используем 4 байта вместо 1, то для пользователя удобнее чтобы это уже учитывалось в функции. Покажу на примере float. 

raw[i] = EEPROM.read((addr * 4)+i); // Внутри функций
EEPROM.write((addr * 4) + i, raw[i]); // Обратить внимание на (addr * 4) вместо addr 

И спокойно можно использовать EEPROM_float_write(int addr, float num) и EEPROM_float_read(int addr) в массиве, только помнить, что теперь количество возможных записей не 512, а 512/4.

Zen пишет:

добрый вечер.

Столкнулся с проблемой записи переменной типа float в EEPROM  при помощи функции описанной пользователем maksim.  Запись положительных чисел проходит нормально, а вот при записи отрицательного числа с запятой, потом считывается не "0,0", а со знаком минус "-0,0". Причем при записи чисел -0,1, -0,2 проблем не возникает, а вот после записи -0,3, -0,4 и т.д....считать или записать в ячейку 0,0 без занка минус не получается:( помогите!!!:) 

До конца не уверен, но возможно такое происходит из-за плавающей точки в float. Столкнулся с такой же проблемой при арифметических операциях с маленькими числами (меньше 1, т.е.  то, что идет после запятой). При этих самых арифметических действиях float-ы не складываются/отнимаются/перемножаются/делятся ровно тем числом, что вы прописываете. Бывает выскакивает где-то далеко (~0.000000000000000000000000213000022) какая-нибудь единица и вы отнимаете не ровно 0.1, а на самом деле чуть большее число (например 0.100000...001200). Т.е. той точностью, что у вас стоит(одна цифра после запятой) на самом деле float не ограничивается. Отсюда и вылазят -0.0 (а на самом деле например: -0.00000000000...000001002), просто вам не видны остальные цифры.
Выкрутиться можно каким-то макаром каждый раз зануляя хвост, мне было удобнее перевести float в int(переместил на 2 разряда вперед. Мне всего 2 цифры после запятой были нужны) и потом просто делить на 100, чтобы получить обратно float с 2-мя знаками после запятой.

Sikorskiy
Offline
Зарегистрирован: 25.04.2016

если я правильно помню

printf("%5.3d",x); покажет 5 знаков, и 3 после запятой, остальное отрежет

ЕвгенийП
ЕвгенийП аватар
Offline
Зарегистрирован: 25.05.2015

Sikorskiy пишет:

если я правильно помню

printf("%5.3d",x); покажет 5 знаков, и 3 после запятой, остальное отрежет

Боюсь, что неправильно помните. "d" - это про целые числа.

ЕвгенийП
ЕвгенийП аватар
Offline
Зарегистрирован: 25.05.2015

Коллеги, а вот кто-нибудь может мне объяснить, зачем всё это, когда в стандартной библиотеке EEPROM имеется универсальный функции EEPROM.put и EEPROM.get, которые благополучно запишут и прочитают любой тип данных, хоть структуру?

Joiner
Offline
Зарегистрирован: 04.09.2014

Приобрел недавно микросхемки памяти EEPROM на 512 килобит. Эту библиотеку можно будет использовать для записи во внешнюю память любого типа данных?

ЕвгенийП
ЕвгенийП аватар
Offline
Зарегистрирован: 25.05.2015

Я не знаю, чем Вы будете писать во внешний EEPROM, но эти две функции можно добавить в любую библиотеку, которая умее читать/писать байт. Посмотрите на них

   //Functionality to 'get' and 'put' objects to and from EEPROM.
    template< typename T > T &get( int idx, T &t ){
        EEPtr e = idx;
        uint8_t *ptr = (uint8_t*) &t;
        for( int count = sizeof(T) ; count ; --count, ++e )  *ptr++ = *e;
        return t;
    }
    
    template< typename T > const T &put( int idx, const T &t ){
        EEPtr e = idx;
        const uint8_t *ptr = (const uint8_t*) &t;
        for( int count = sizeof(T) ; count ; --count, ++e )  (*e).update( *ptr++ );
        return t;
    }

 

vvadim
Offline
Зарегистрирован: 23.05.2012

ЕвгенийП пишет:

Коллеги, а вот кто-нибудь может мне объяснить, зачем всё это, когда в стандартной библиотеке EEPROM имеется универсальный функции EEPROM.put и EEPROM.get, которые благополучно запишут и прочитают любой тип данных, хоть структуру?

а кто сидит на более ранних версиях IDE - тем по другому никак)))

ЕвгенийП
ЕвгенийП аватар
Offline
Зарегистрирован: 25.05.2015

vvadim пишет:

а кто сидит на более ранних версиях IDE - тем по другому никак)))

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

Joiner
Offline
Зарегистрирован: 04.09.2014

ЕвгенийП пишет:

Я не знаю, чем Вы будете писать во внешний EEPROM, .....................

Добавил тему в избранное, на будущее...когда займусь памятью

Pyotr
Offline
Зарегистрирован: 12.03.2014

Функции для записи и чтения из EEPROM любого типа данных. Стандартная библиотека не используется.
 

#include <avr/eeprom.h>
#define SIZE 11
word addrEeprom = 2;
//byte val = 111, outVal;
//word val = 22222,   outVal;
//unsigned long val = 3333333333, outVal;
//float val = 4444.44, outVal;
//byte val[SIZE] = {101,111,122,133,144}, outVal[SIZE];
int val[SIZE] = {-11111,11111,-22222,22222,-3333,3333},outVal[SIZE];
//word val[SIZE] = {11111,22222,33333,44444,55555}, outVal[SIZE];
//float val[SIZE]={1.1,2.2,3.3,4.4,5.5,6.6,7.7,8.9,9.9,123.45,66.78},outVal[SIZE];
//char val[SIZE] = "arduino.ru", outVal[SIZE];

void setup(){
  Serial.begin(9600);
  //Пишем в EEPROM значение val
  eepromWrite(addrEeprom, (byte*)(&val), sizeof(val));
  //Читаем
  eepromRead(addrEeprom, (byte*)(&outVal), sizeof(outVal));
  //функция пишет данные из EEPROM в переменную "outVal"
  
  Serial.println("outVal = ");
 // Serial.println(outVal);//для переменной byte, int, UL, float и char[]
  
  for(byte i=0; i<SIZE; i++){  //для массива
    Serial.println(outVal[i]);
  }
}
void loop(){}//здесь ничего нет

//-------------запись
void eepromWrite(unsigned int addr, byte *data, byte len){
  for(byte i = 0; i < len; i++){
    eeprom_write_byte(((unsigned char *)addr) + i, *(data + i));
  }
}
//--------------чтение
void eepromRead(unsigned int addr, byte *data, byte len){
  for(byte i = 0; i < len; i++){
    *(data + i) = eeprom_read_byte(((unsigned char *)addr) + i);
  }
}

 

llaabbss
Offline
Зарегистрирован: 28.12.2017

Всем доброго времени суток!

А может ли кто-то объяснить как работать с FRAM? Точно таким же образом или там есть свои фишки?
Если конкретно, то FRAM такая: FM24W256 (256-Kbit (32 K × 8) Serial (I2C) F-RAM).

Даташит есть здесь: ссылка

Как в нее записывать и считывать из нее, например, название SSID, пароль, как проектировать место для хранения каких типов данных?

Я в этом вопросе нуб, юзал только запись в EEPROM, но вопросов даже там много. Например, если я хочу сохранить в память название сети (SSID), то мне нужно отводить определенную область памяти для этого (32 байта для хранения возможных 32 символов). Название может быть и короче. Можно ли как-то динамически это менять?

Потом надо отводить место для хранения пароля к этой сети. 64 байта для хранения 64 символов. 

А как записывать строки произвольной длины и (самое главное) как их оттуда правильно считывать?

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

zoompe03
Offline
Зарегистрирован: 12.05.2018

Что делать, если пишет 'EEPROM_int_write' was not declared in this scope

 

Kakmyc
Offline
Зарегистрирован: 15.01.2018

Автору респект.
Готовые функции , без лишней шелухи,это хорошо.

Kakmyc
Offline
Зарегистрирован: 15.01.2018

zoompe03 пишет:

Что делать, если пишет 'EEPROM_int_write' was not declared in this scope

 

Функцию скопировать пробовал ?
Если есть ссылка на функцию, стало быть и функция должна быть.

b707
Offline
Зарегистрирован: 26.05.2017

Kakmyc пишет:
Автору респект. Готовые функции , без лишней шелухи,это хорошо.

вы немного опоздали с благодарностью - эти функции давно не нужны, в стандартном ардуино есть EEPROM.put() для любых типов данных

Ворота
Ворота аватар
Offline
Зарегистрирован: 10.01.2016

zoompe03 пишет:

Что делать, если пишет 'EEPROM_int_write' was not declared in this scope

Вешацца!

Baks
Baks аватар
Offline
Зарегистрирован: 11.01.2016

всем привет!

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

sadman41
Offline
Зарегистрирован: 19.10.2016

Читать можно пока не надоест.

ua6em
ua6em аватар
Offline
Зарегистрирован: 17.08.2016

ЕвгенийП пишет:

Коллеги, а вот кто-нибудь может мне объяснить, зачем всё это, когда в стандартной библиотеке EEPROM имеется универсальный функции EEPROM.put и EEPROM.get, которые благополучно запишут и прочитают любой тип данных, хоть структуру?

Интересная реплика!!!
Ситуация: имеем скетч радиолюбительского маяка, по сути это строка передаваемая азбукой Морзе, разбор строки позволяет выделить компоненты, а именно - позывной сигнал, координаты...и эти данные необходимо изменять оперативно, а не перепрошивкой нового скетча,  напрашивается передача данных в структуру по коммуникационному порту сохранение в EEPROM с последующим использованием, осталось только научиться это делать )))

/*
  Простой телеграфный маяк для экспериментов

  Исходный код:
  Written by Nicola Salsotto IN3GJH
  <a href="<a data-cke-saved-href="https://github.com/NicoVarg99" href="https://github.com/NicoVarg99" rel="nofollow">https://github.com/NicoVarg99</a>" title="<a data-cke-saved-href="https://github.com/NicoVarg99" href="https://github.com/NicoVarg99" rel="nofollow">https://github.com/NicoVarg99</a>" rel="nofollow"><a data-cke-saved-href="https://github.com/NicoVarg99" href="https://github.com/NicoVarg99" rel="nofollow">https://github.com/NicoVarg99</a></a>

  Модификация сделана: 
  UA6HJQ 18.11.2018 (добавлено управление радиостанцией)
  UA6EM 12/04/2019  (добавлен разбор символов нижнего регистра, проба работы с EEPROM)

  Интервал между передачей:
  10мин= 600000 (передача примерно 20 секунд)
  5мин = 300000
  3мин = 180000
  2мин = 120000
*/
#include <EEPROM.h></span>

struct MyBeacon {
  char call_sign[20];
  char loc[7];
};

#define SPEED (20)  //скорость в WPM
#define DOTLEN (1200/SPEED)
#define DASHLEN (3*(1200/SPEED))
#define PAUSE (180000)  //пауза между передачами маяка в милисекундах

int txPin=10;       //управление PTT
int ledPin=13;      //мигать встроенным светодиодом или подключить внешний на пин 13
int tonePin=5;      //выход звука
int toneFreq=800;   //Частота звука (выбирайте между 800 - 1500Гц)

char call[] = "UA6EM ua6EM ua6em BEACON LN14AE"; // текст передачи маяка

void sendMsg(char*);
void dash();
void dot();


void setup()
  {
    pinMode(ledPin, OUTPUT);
    pinMode(txPin, OUTPUT); 
    Serial.begin(9600);
  }


void loop()
  {
    digitalWrite(txPin, HIGH);
    delay(900);    //txdelay - задержка после нажатия PTT
  
    //  sendMsg("UA6HJQ UA6HJQ BEACON LN14AX"); //текст маяка/так было в оригинале
    
    sendMsg(call); //текст маяка - проба
    delay(20);
    digitalWrite(txPin, LOW);
    delay(PAUSE);
  }


void dash()
  {
    digitalWrite(ledPin, HIGH);
    tone(tonePin, toneFreq);
    delay(DASHLEN);
    digitalWrite(ledPin, LOW);
    noTone(tonePin);
    delay(DOTLEN);
  }


void dot()
  {
    digitalWrite(ledPin, HIGH) ;
    tone(tonePin, toneFreq);
    delay(DOTLEN);
    digitalWrite(ledPin, LOW);
    noTone(tonePin);
    delay(DOTLEN);
  }


void sendMsg(char *str)
{
  int i;

   delay(500);
 
  for(i=0;i<strlen(str);i++)
  {
    switch (str[i])
    {
    case 'A':
      dot();dash();break;
    case 'B':
      dash();dot();dot();dot();break;
    case 'C':
      dash();dot();dash();dot();break;
    case 'D':
      dash();dot();dot();break;
    case 'E':
      dot();break;
    case 'F':
      dot();dot();dash();dot();break;
    case 'G':
      dash();dash();dot();break;
    case 'H':
      dot();dot();dot();dot();break;
    case 'I':
      dot();dot();break;
    case 'J':
      dot();dash();dash();dash();break;
    case 'K':
      dash();dot();dash();break;
    case 'L':
      dot();dash();dot();dot();break;
    case 'M':
      dash();dash();break;
    case 'N':
      dash();dot();break;
    case 'O':
      dash();dash();dash();break;
    case 'P':
      dot();dash();dash();dot();break;
    case 'Q':
      dash();dash();dot();dash();break;
    case 'R':
      dot();dash();dot();break;
    case 'S':
      dot();dot();dot();break;
    case 'T':
      dash();break;
    case 'U':
      dot();dot();dash();break;
    case 'V':
      dot();dot();dot();dash();break;
    case 'W':
      dot();dash();dash();break;
    case 'X':
      dash();dot();dot();dash();break;
    case 'Y':
      dash();dot();dash();dash();break;
    case 'Z':
      dash();dash();dot();dot();break;
    //  *** и строчные ***
    case 'a':
      dot();dash();break;
    case 'b':
      dash();dot();dot();dot();break;
    case 'c':
      dash();dot();dash();dot();break;
    case 'd':
      dash();dot();dot();break;
    case 'e':
      dot();break;
    case 'f':
      dot();dot();dash();dot();break;
    case 'g':
      dash();dash();dot();break;
    case 'h':
      dot();dot();dot();dot();break;
    case 'i':
      dot();dot();break;
    case 'j':
      dot();dash();dash();dash();break;
    case 'k':
      dash();dot();dash();break;
    case 'l':
      dot();dash();dot();dot();break;
    case 'm':
      dash();dash();break;
    case 'n':
      dash();dot();break;
    case 'o':
      dash();dash();dash();break;
    case 'p':
      dot();dash();dash();dot();break;
    case 'q':
      dash();dash();dot();dash();break;
    case 'r':
      dot();dash();dot();break;
    case 's':
      dot();dot();dot();break;
    case 't':
      dash();break;
    case 'u':
      dot();dot();dash();break;
    case 'v':
      dot();dot();dot();dash();break;
    case 'w':
      dot();dash();dash();break;
    case 'x':
      dash();dot();dot();dash();break;
    case 'y':
      dash();dot();dash();dash();break;
    case 'z':
      dash();dash();dot();dot();break;
    case ' ':
      delay(DOTLEN*5);break;
    case '.':
      dot();dash();dot();dash();dot();dash();break;
    case ',':
      dash();dash();dot();dot();dash();dash();break;
    case ':':
      dash();dash();dash();dot();dot();break;
    case '?':
      dot();dot();dash();dash();dot();dot();break;
    case '\'':
      dot();dash();dash();dash();dash();dot();break;
    case '-':
      dash();dot();dot();dot();dot();dash();break;
    case '/':
      dash();dot();dot();dash();dot();break;
    case '(':
    case ')':
      dash();dot();dash();dash();dot();dash();break;
    case '\"':
      dot();dash();dot();dot();dash();dot();break;
    case '@':
      dot();dash();dash();dot();dash();dot();break;
    case '=':
      dash();dot();dot();dot();dash();break;
    case '0':
     dash();dash();dash();dash();dash();break;
    case '1':
     dot();dash();dash();dash();dash();break;
    case '2':
     dot();dot();dash();dash();dash();break;
    case '3':
     dot();dot();dot();dash();dash();break;
    case '4':
     dot();dot();dot();dot();dash();break;
    case '5':
     dot();dot();dot();dot();dot();break;
    case '6':
     dash();dot();dot();dot();dot();break;
    case '7':
     dash();dash();dot();dot();dot();break;
    case '8':
     dash();dash();dash();dot();dot();break;
    case '9':
     dash();dash();dash();dash();dot();break;

    }
    delay(2*DOTLEN);
  }

}

 

ЕвгенийП
ЕвгенийП аватар
Offline
Зарегистрирован: 25.05.2015

Не вижу в этом коде работы с eeprom, а потому не понимаю смысла поста. Можете пояснить, что имелось в виду?

b707
Offline
Зарегистрирован: 26.05.2017

ua6em пишет:

 напрашивается передача данных в структуру по коммуникационному порту сохранение в EEPROM с последующим использованием, осталось только научиться это делать )))

И как это противоречит реплике Евгения?

Чтобы научиться - надо сесть и научиться. Посмотрите готовые примеры к библиотеке ЕЕПРОМ, там все есть

 

ua6em
ua6em аватар
Offline
Зарегистрирован: 17.08.2016

ЕвгенийП пишет:

Не вижу в этом коде работы с eeprom, а потому не понимаю смысла поста. Можете пояснить, что имелось в виду?

всё очень просто, может подскажите как собрать строку из структуры, как заполнить структуру из EEPROM понятно, так же и как туда сохранить...
Строка это в моём случае переменная call[]

b707
Offline
Зарегистрирован: 26.05.2017

ua6em пишет:

всё очень просто, может подскажите как собрать строку из структуры

Строка это в моём случае переменная call[]

обьявляете строку call[] достаточного размера и потом strcpy() копируете в нее отдельные поля в нужные позиции

DetSimen
DetSimen аватар
Offline
Зарегистрирован: 25.01.2017

ua6em пишет:

всё очень просто, может подскажите как собрать строку из структуры, как заполнить структуру из EEPROM понятно, так же и как туда сохранить...

на самом деле, сериализация структур, особенно со строками - атнють нетривиальная задача... 

sadman41
Offline
Зарегистрирован: 19.10.2016

Да... это не студентов на собеседованиях валить - надо подумать слегонца ;)

ЕвгенийП
ЕвгенийП аватар
Offline
Зарегистрирован: 25.05.2015

ua6em пишет:

всё очень просто, может подскажите как собрать строку из структуры

А требования к таковой сборке можно определить? С примерами структуры и что должно получиться?

ua6em
ua6em аватар
Offline
Зарегистрирован: 17.08.2016

ЕвгенийП пишет:

ua6em пишет:

всё очень просто, может подскажите как собрать строку из структуры

А требования к таковой сборке можно определить? С примерами структуры и что должно получиться?

Есть функция
 

void sendMsg(char*);

Для работы функции сейчас использую такую строку:
 

char call[50] = "UA6EM ua6em BEACON QRA is LN14AE LN14AE"; // текст передачи маяка

В этой строке есть две переменные подстроки, это позывной сигнал - UA6EM и локатор размещения LN14AE их и думаю сохранять из монитора порта в память и оттуда забирать, споткнулся на типах данных )))
думал сделать так

struct MyBeacon {
  char call_sign[20];
  char loc[7];
};

 

sadman41
Offline
Зарегистрирован: 19.10.2016

snprintf(call, sizeof(call),"%s jdet vseh v punkte %s", MyBeacon.call_sign, MyBeacon.loc);

ua6em
ua6em аватар
Offline
Зарегистрирован: 17.08.2016

sadman41 пишет:

Да... это не студентов на собеседованиях валить - надо подумать слегонца ;)

Какие такие студенты, то были дипломированные специалисты )))

Насчет подумать, это да, сей предмет пока не входил в круг моих понятий

ua6em
ua6em аватар
Offline
Зарегистрирован: 17.08.2016

sadman41 пишет:

snprintf(call, sizeof(call),"%s jdet vseh v punkte %s", MyBeacon.call_sign, MyBeacon.loc);

там правила однако, два-три раза передается свой позывной с пробелами между, потом текст, потом два три раза локатор тоже с пробелами между, то-есть надо не просто собрать строку, но и чтобы она была char и этот char подсунуть функции )))

sadman41
Offline
Зарегистрирован: 19.10.2016

ua6em пишет:

там правила однако, два-три раза передается свой позывной с пробелами между, потом текст, потом....

И...? Мысль не закончена.

DetSimen
DetSimen аватар
Offline
Зарегистрирован: 25.01.2017

Если строки фиксированные, их можно и сразу в ROM пхать

ЕвгенийП
ЕвгенийП аватар
Offline
Зарегистрирован: 25.05.2015

А что Вы с этой строкой делать собираетесь? Только отправить, а потом выбросить? Или она ещё для чего-то нужна? По-другому: нужно получить такую строку, отправить и освободить память (надо будет, ещё раз получим), или сохранитьнужно?

И структура, кстати, она должна вечно жить или временно?

От ответов на эти вопросы зависит техника работы с памятью.

Если я правильно понял, что

1) серёдка всегда одинаковая, надо только в начало вставить n раз позывной, а в конец n раз "хвост"
2) строка после отправки нафиг не нужна и память можно освобождать.

То можно, например, вот так (если не усираться на параноидальной экономии времени выполнения)

struct MyBeacon {
  char call_sign[20];
  char loc[7];
};


//
//	Строка для отправки сформируется внутри,
//	а при выходе будет освобождена
//
void sendMsg(MyBeacon & mbStr) {
	static const char middle[] = "BEACON QRA is";	// серёдка сообщения
	static const int8_t sizeMiddle = strlen(middle);	// длина серёдки сообщения
	static const int8_t repeatCounter = 2;	// сколько раз повторять позывной и ... тот хвост
	//	
	// strSize - длина строки для отправки по sms, включая терминальный ноль.
	const int8_t strSize = sizeMiddle + (strlen(mbStr.call_sign) + strlen(mbStr.loc) + 2) * repeatCounter + 1;
	char str[strSize]; 
	//
	// Заполняем строку
	str[0] = '\0';
	for (int8_t i = 0; i < repeatCounter; i++) {
		strcat(str, mbStr.call_sign); 
		strcat(str, " "); 
	}
	strcat(str, middle); 
	for (int8_t i = 0; i < repeatCounter; i++) {
		strcat(str, " "); 
		strcat(str, mbStr.loc); 
	}
	//
	//	Теперь отправляем строку str как там надо
	//
	Serial.println(str);
}

void setup(void) {
	Serial.begin(115200);
	MyBeacon mb = {"UA6EM", "LN14AE"}; // структура для отправки 
	sendMsg(mb);
}

void loop(void){}

результат

UA6EM UA6EM BEACON QRA is LN14AE LN14AE

 

ua6em
ua6em аватар
Offline
Зарегистрирован: 17.08.2016

весь смысл сей бодяги, маяк надо инициализировать после определения координат развёртывания аппаратуры и определения каким позывным будем работать, то есть эти данные получить из серийного порта и записать в EEPROM, чтобы при отключении питания не надо было снова вносить корректные данные, при включении питания получаем строку из EEPROM её и подсовываем функции вывода маяка...
Строка должна быть актуальна всегда, вплоть до ввода новых значений...
Как-то так...
Можно конечно не парится а ставить на свой компьютер IDE и ей перешивать маяк всякий раз, когда это потребуется, но как-то не кошерно это

ЕвгенийП
ЕвгенийП аватар
Offline
Зарегистрирован: 25.05.2015

Вы говорите в терминах, которых я не понимаю.

То, что я написал подойдёт?

ua6em
ua6em аватар
Offline
Зарегистрирован: 17.08.2016

DetSimen пишет:

Если строки фиксированные, их можно и сразу в ROM пхать

нет, позывные разные по длине, тут обратное правило чем короче тем круче )))
 

ua6em
ua6em аватар
Offline
Зарегистрирован: 17.08.2016

ЕвгенийП пишет:

Вы говорите в терминах, которых я не понимаю.

То, что я написал подойдёт?

Да, только строку надо сохранить и сохранить в EEPROM, при включении оттуда забрать, срок жизни строки - до выключения питания, маяк работает круглосуточно, раз в три минуты передавая этот текст

Сейчас соберу весь скетч, попробую, реализация понятна

b707
Offline
Зарегистрирован: 26.05.2017

ua6em пишет:

весь смысл сей бодяги, маяк надо инициализировать после определения координат развёртывания аппаратуры и определения каким позывным будем работать, то есть эти данные получить из серийного порта и записать в EEPROM, чтобы при отключении питания не надо было снова вносить корректные данные, при включении питания получаем строку из EEPROM её и подсовываем функции вывода маяка...

звучит как ТЗ в разделе "Ищу исполнителя", уж простите. Не вижу ничего сложного, но удивлен, что активному участнику форума надо обьяснять очевидные вещи.

Делите задачу на отдельные части:

1. Прием позывного из Сериал

2. Запись позывного в ЕЕПРОМ

3. Извлечение позывного из ЕЕПРОМ

4. Формирование готовой строки из позывного, места положения и чего там еще

 

Задачки 1-3 по отдельности разобраны на форуме неоднократно. Задачу 4 только что расписали sadman и Евгений.

А уж скомпоновать из 4 задачек готовый код - это либо сами, либо в упомянутый раздел.

sadman41
Offline
Зарегистрирован: 19.10.2016

Я понимаю о чем речь, но не понимаю что тут непонятного в двух примерах. Наверное кто-то еще и с Сериала две строчки затрудняется получить...