Запись и чтение float во FRAM память "FM24C04B-G"

Otto
Offline
Зарегистрирован: 26.06.2016

Добрый день, подскажите пожалуйста как можно просто реализовать запись/чтение значений с плавающей запятой во внешнюю FRAM память "FM24C04B-G" с объемом памяти 4 kбит(512x8).

Использую удобную библиотеку с гитхаба: https://github.com/battosai30/FRAM

Она без проблем читает и пишет типы данных: byte, int, long.Но нет поддержки float,пробовал добавить по аналогии в библиотеку float, но это не заработало.

поделитесь пожалуйста примером с объяснением как можно сделать несложную функцию записи и чтения или ещё лучше дополнить эту библиотеку переменной float.

Выложу под спойлеры файлики из библиотеки:
FRAM.cpp

#include "FRAM.h"

FRAM::FRAM(byte Address) {

Wire.begin();
_i2cAddress= (0b101000 | Address)<<1;

}

FRAM::~FRAM() {

}

void FRAM::WriteByte(byte Page,byte Address,byte Data) {
 
  Wire.beginTransmission(_i2cAddress | (Page&1));
  Wire.write(Address);
  Wire.write(Data);
  Wire.endTransmission(); 
  
}


byte FRAM::ReadByte(byte Page,byte Address) {
 
  ReadBurst(Page,Address, 1);
     
  return Wire.read();
  
}

int FRAM::ReadInt(byte Page,byte Address) {

  ReadBurst(Page,Address, 2);
     
  return int(Wire.read()) | int(Wire.read())<<8;

}

void FRAM::WriteInt(byte Page, byte Address, int Data) {

byte Data_Array[2]={Data & 0xFF, (Data>>8) & 0xFF};

WriteBurst(Page, Address, Data_Array, 2);

}

long FRAM::ReadLong(byte Page,byte Address) {

  ReadBurst(Page,Address, 4);
     
  return long(Wire.read()) | long(Wire.read())<<8 | long(Wire.read())<<16 | long(Wire.read())<<24 ;

}

void FRAM::WriteLong(byte Page, byte Address, long Data) {

byte Data_Array[4]={Data & 0xFF, (Data>>8) & 0xFF, (Data>>16) & 0xFF, (Data>>24) & 0xFF};

WriteBurst(Page, Address, Data_Array, 4);

}

void FRAM::ReadBurst(byte Page, byte Address, int NumberOfByte) {

  Wire.beginTransmission(_i2cAddress | (Page&1));
  Wire.write(Address);
  Wire.endTransmission();  
  Wire.requestFrom(_i2cAddress | (Page&1), NumberOfByte);
  
 }
 
 void FRAM::WriteBurst(byte Page, byte Address, byte* Data, int NumberOfByte) {

  Wire.beginTransmission(_i2cAddress | (Page&1));
  Wire.write(Address);
  
  for(int i=0;i<NumberOfByte;i++) {
  Wire.write(Data[i]);
  }
  
  Wire.endTransmission(); 
  
 }
FRAM.h
/* 

This library is designed to drive FRAM memories model FM24C04B

Author : B@tto battomicro.wordpress.com

Compatible with Arduino and Energia

V1.0

 */


#ifndef FRAM_H
#define FRAM_H

#ifdef ARDUINO // Arduino
#if ARDUINO >= 100
#include <Arduino.h> // Arduino 1.0
#else
#include <WProgram.h> // Arduino 0022
#endif
#endif
 
#ifdef ENERGIA // Energia
#include <Energia.h>
#endif

#include <Wire.h>

class FRAM
{
	private:
	
	byte _i2cAddress;    
	void ReadBurst(byte Page,byte Address, int NumberOfByte);
	void WriteBurst(byte Page,byte Address, byte* Data, int NumberOfByte);
	
	public:
	
	FRAM(byte Adress);
	~FRAM();
	
	void WriteLong(byte Page, byte Address, long Data); 
	long ReadLong(byte Page,byte Address);
	void WriteInt(byte Page,byte Address, int Data); 
	int ReadInt(byte Page,byte Address);
	void WriteByte(byte Page,byte Address,byte Data);
	byte ReadByte(byte Page,byte Address);
};

#endif

И так же выложу пример из библиотеки:

// Example of using FRAM library

#include <FRAM.h>
#include <Wire.h>

FRAM fram(0b00); // i2c adress is determined by state of pins A2 and A1
                 // for example, if A2 = VCC and A1 = GND write : FRAM fram(0b10);
              
void setup() {
  
  Serial.begin(9600);
  fram.WriteByte(0,5,55);
  Serial.println(fram.ReadByte(0,5));
  
  fram.WriteInt(0,15,30000);
  Serial.println(fram.ReadInt(0,15));
  
  fram.WriteLong(0,20,-30000);
  Serial.println(fram.ReadLong(0,20));
  
}

void loop() {
  
}


 

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

Если просто, то примерно вот так:
 

float numberF = 123.321;
long numberL;

numberL = *((long*)&numberF);
FRAM.WriteLong(..., numberL);

И

float numberF;
long numberL;

numberL = FRAM.ReadLong(...);
numberF = *((float*)&numberL);

 

Otto
Offline
Зарегистрирован: 26.06.2016

sadman41 пишет:

Если просто, то примерно вот так:
 

float numberF = 123.321;
long numberL;

numberL = *((long*)&numberF);
FRAM.WriteLong(..., numberL);

И

float numberF;
long numberL;

numberL = FRAM.ReadLong(...);
numberF = *((float*)&numberL);

 

Спасибо, работает, вот только сохраняет и выводит не более 2-х знаков после запятой. Как можно сделать, что бы увеличить кол-во знаков после запятой, к примеру до 9.

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

Otto пишет:

Спасибо, работает, вот только сохраняет и выводит не более 2-х знаков после запятой.

все оно сохраняет, не выдумывайте.  А то, что у вас печатает только 2 знака - это потому что вы не прочитали описание функции print(), число выводимых знаков после запятой настраивается

Otto пишет:

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

9 слишком много, не хватит разрядности типа float.  Точнее, вывести на печать можно хоть 20 знаков. но после пятой позиции там будут идти случайные цифры. не имеющие отношения к реальности.

Рассчитывайте на точность примерно 5-6 знаков. Если 5 знаков мало - меняйте концепцию или МК. Тут нужен тип double вместо float, но на ардуино он не поддерживается.

Upper
Offline
Зарегистрирован: 23.06.2020
Пример
 
Serial.println(0.000000923456789,15); //gives 0.000000923456859
Serial.println(5.000000123456789,15); //gives 5.000000000000000
Serial.println(2.000000123456789,15); //gives 2.000000238418579
Otto
Offline
Зарегистрирован: 26.06.2016

Да, это моя ошибка была, совсем забыл, что print имеет дополнительные параметры. Спасибо!
Сейчас пытаюсь встроить данный код в эту библиотеку, только пока не очень получается.

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

Otto пишет:

Сейчас пытаюсь встроить данный код в эту библиотеку, только пока не очень получается.

что там встраивать, вам же готовую функцию дали

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

Проще взять готовые функции put/get из EEPROM - они для всего сразу работают, хоть float, хоть ещё чего

Otto
Offline
Зарегистрирован: 26.06.2016
Нашёл на гитхабе вот такую самопальнуюпростенькую библиотеку от автора B@tto.
Эта библиотека мне понравилась простатой, удобством и написана конкретно под данную FRAM - FM24C04B, но там не было реализована возможность записывать и читать тип данных float. Добавил такую возможность, так же спасибо за помощь sadman41.
Библиотека умеет писать/читать следующие типы данных: ByteIntegerLongFloat.
 
За одно немного изучал принцип для понимания как работает FRAM и её объёмами, страница.....
 
P.S. Библиотека не учитывает то, что было написано.
Это означает, что, например, если вы напишете длинное число на странице = 0, адрес = 20,  а после того, как вы напишете целое число на странице = 0 и адресе = 22, ваше длинное число будет повреждено, потому что вы перезаписали его последние два байта.
 
Выложу изменённый вариант, думаю кому нибудь, да пригодится.
ЕвгенийП
ЕвгенийП аватар
Offline
Зарегистрирован: 25.05.2015

Otto пишет:

Эта библиотека мне понравилась простатой

Самец попался. Бывает.