Nano 33 BLE - Timer for counter

Hello everyone,

I have read the datasheet for the nRF52840.
Unfortunately, that didn't make me any smarter.
I get along better with Atmel's datasheets.

I have the problem that I do not understand the registers for the timers.
I would like to measure an incoming rectangular signal where I only measure the low pass. It comes from a flow meter.
Unfortunately, I don't know now whether I can do it with an interrupt counter or just count a timer.

And millis () seems a bit harder to me. Do you have any ideas?

I have experience with Atmel, the Atmega32A and Interrups, Registers, through another project.
But I don't know whether the measurement is correct, i.e. more of a hardware problem, or whether the Arduino's measurement is wrong.
The square wave signal is currently being made available by an Atmega32A for testing purposes and sent to the Arduino.

Atmega32A-Code:

//Takt
	#define F_CPU 16000000UL	//16 MHz

//Libraries
	#include <avr/io.h>			//AVR device-specific IO definitions
	#include <avr/interrupt.h> //Interrupt
	//#include  <util/delay.h>
	

//Funktionen deklarieren
#pragma region
	void Timer_init (void);
	void Eingang (void);
	void Taster (void);
	void Signal (void);
#pragma endregion


//Shortcuts
	#define Minus_On 0 //Shortcut für Low-Pin an
	#define Minus_Off 1 //Shortcut für Low-Pin aus
	#define On 1 //Shortcut für Pin an
	#define Off 0 //Shortcut für Pin aus


//Pin-Beschreibung
#pragma region
	#define Taster_Durchfluss_Mehr				PC7
	#define Taster_Durchfluss_Weniger			PC6
	#define Taster_Geschwindigkeit_Mehr			PC5
	#define Taster_Geschwindigkeit_Weniger		PC4
	#define Signal_Durchfluss					PB0
	#define Signal_Geschwindigkeit				PB1
	#define Signal_Taster						PA0
#pragma endregion

//Variablen
#pragma region
	//Festgelegte Werte
		//Impulse Durchflussmesser
			#define Wert_Zeit_Impulse_Durchflussmesser_Max							 381
			#define Wert_Zeit_Impulse_Durchflussmesser_Min							   7
			#define Wert_Zeit_Impulse_Durchflussmesser_An							  50
			
		//Impulse Geschwindigkeit
			#define Wert_Zeit_Impulse_Geschwindigkeit_Max							3852		//1070 & km/h > ms/mm
			#define Wert_Zeit_Impulse_Geschwindigkeit_Min							  35		//1070 & km/h > ms/mm
		
		//Taster
			#define Wert_Zeit_Taster_Durchfluss_Mehr_An								 100
			#define Wert_Zeit_Taster_Durchfluss_Mehr_Aus							 500
			#define Wert_Zeit_Taster_Durchfluss_Weniger_An							 100
			#define Wert_Zeit_Taster_Durchfluss_Weniger_Aus							 500
	
	//Zwischenspeicher
		//Impulse Durchflussmesser
			volatile uint16_t Zeit_Impulse_Durchflussmesser_Soll = Wert_Zeit_Impulse_Durchflussmesser_Min;
			volatile uint16_t Zeit_Impulse_Durchflussmesser_Ist = 0;
		
		//Impulse Geschwindigkeit
			volatile uint16_t Zeit_Impulse_Geschwindigkeit_Soll = Wert_Zeit_Impulse_Geschwindigkeit_Max;
			volatile uint16_t Zeit_Impulse_Geschwindigkeit_Ist = 0;
			
		//Taster
			volatile uint8_t Zeit_Taster_Durchfluss_Mehr_An;
			volatile uint16_t Zeit_Taster_Durchfluss_Mehr_Aus = Wert_Zeit_Taster_Durchfluss_Mehr_Aus;
			volatile uint8_t Zeit_Taster_Durchfluss_Weniger_An;
			volatile uint16_t Zeit_Taster_Durchfluss_Weniger_Aus = Wert_Zeit_Taster_Durchfluss_Weniger_Aus;
			volatile uint8_t Eingang_Taster_Durchfluss_Mehr;
			volatile uint8_t Eingang_Taster_Durchfluss_Weniger;
		
		//Timer-Einstellung in Timer2 vornehmen
			//volatile uint8_t Zeit_100 = 0;										//Variable für 100er-Timer
#pragma endregion



int main(void)
{
	//Pins deklarieren
		//Pins als EIngang / Ausgang 
			DDRA = 0b00000001;				//
			DDRB = 0b00000011;				//
			//DDRC = 0b00000000;			//
			//DDRD = 0b00000000;			//
		
		//Pins als Low (Reagiert bei Spannung) / High (Reagiert bei Masse)
			//PORTA = 0b00001111;			//
			PORTB = 0b00000000;			//
			PORTC = 0b11110000;			//
			//PORTD = 0000000000;			//
	
		//Timer 0, 1, 2
			Timer_init();
			
		//Global Interrupts aktivieren
			sei();
	
	
	while (1)
	{
		Eingang();
		Taster();
		Signal();
	}
}


void Signal(void)
{
	if (Zeit_Impulse_Durchflussmesser_Ist >= Zeit_Impulse_Durchflussmesser_Soll)
	{
		PORTB |= (1 << Signal_Durchfluss);		// 5V
			
		if (Zeit_Impulse_Durchflussmesser_Ist >= (Zeit_Impulse_Durchflussmesser_Soll + Wert_Zeit_Impulse_Durchflussmesser_An) )
		{
			Zeit_Impulse_Durchflussmesser_Ist = 0;	
		}
	}
	else
	{
		PORTB &= ~(1 << Signal_Durchfluss);		// 0V
	}
}


void Eingang (void)
{
	if (!(PINC & (1 << Taster_Durchfluss_Mehr)))	//Eingang Taster Taster_Durchfluss_Mehr
	{
		Eingang_Taster_Durchfluss_Mehr = On;
	}
	else
	{
		Eingang_Taster_Durchfluss_Mehr = Off;
	}
	
	if (!(PINC & (1 << Taster_Durchfluss_Weniger)))	//Eingang Taster Taster_Durchfluss_Weniger
	{
		Eingang_Taster_Durchfluss_Weniger = On;
	}
	else
	{
		Eingang_Taster_Durchfluss_Weniger = Off;
	}
	
	if (Zeit_Taster_Durchfluss_Mehr_An >= Wert_Zeit_Taster_Durchfluss_Mehr_An)
	{
		PORTA |= (1 << Signal_Taster);		// 5V
	}
	
	if (Zeit_Taster_Durchfluss_Weniger_An >= Wert_Zeit_Taster_Durchfluss_Weniger_An)
	{
		PORTA |= (1 << Signal_Taster);		// 5V
	}
	
	if ( (Zeit_Taster_Durchfluss_Mehr_Aus >= Wert_Zeit_Taster_Durchfluss_Mehr_Aus) & (Zeit_Taster_Durchfluss_Weniger_Aus >= Wert_Zeit_Taster_Durchfluss_Weniger_Aus) )
	{
		PORTA &= ~(1 << Signal_Taster);		//0V
	}
}


void Taster (void)
{	
	if ( (Zeit_Taster_Durchfluss_Mehr_An >= Wert_Zeit_Taster_Durchfluss_Mehr_An) & (Zeit_Taster_Durchfluss_Mehr_Aus >= Wert_Zeit_Taster_Durchfluss_Mehr_Aus) )
	{
		if (Zeit_Impulse_Durchflussmesser_Soll <= Wert_Zeit_Impulse_Durchflussmesser_Min)
		{
			Zeit_Impulse_Durchflussmesser_Soll = Wert_Zeit_Impulse_Durchflussmesser_Max;
		}
		else
		{
			Zeit_Impulse_Durchflussmesser_Soll--;
		}
		
		Zeit_Taster_Durchfluss_Mehr_An = 0;
	}
	
	if ( (Zeit_Taster_Durchfluss_Weniger_An >= Wert_Zeit_Taster_Durchfluss_Weniger_An) & (Zeit_Taster_Durchfluss_Weniger_Aus >= Wert_Zeit_Taster_Durchfluss_Weniger_Aus) )
	{
		if (Zeit_Impulse_Durchflussmesser_Soll >= Wert_Zeit_Impulse_Durchflussmesser_Max)
		{
			Zeit_Impulse_Durchflussmesser_Soll = Wert_Zeit_Impulse_Durchflussmesser_Min;
		}
		else
		{
			Zeit_Impulse_Durchflussmesser_Soll++;
		}
		
		Zeit_Taster_Durchfluss_Weniger_An = 0;
	}
}


void Timer_init (void)
{
	//Timer 1 konfigurieren
		TCCR1B |= (1<<WGM12);						// CTC Modus
		TCCR1B |= (1<<CS11) | (1<<CS10);			// Prescaler 64
		OCR1A = 250-1;
	
	//Compare Interrupt erlauben
		TIMSK |= (1<<OCIE1A);
}



ISR (TIMER1_COMPA_vect)
{
	//Jede Millisekunde
		Zeit_Impulse_Durchflussmesser_Ist++;
		Zeit_Impulse_Geschwindigkeit_Ist++;
		
		//Taster
		if (Eingang_Taster_Durchfluss_Mehr == On)
		{
			Zeit_Taster_Durchfluss_Mehr_An++;
			Zeit_Taster_Durchfluss_Mehr_Aus = 0;
		}
		else if ( (Eingang_Taster_Durchfluss_Mehr == Off) & (Zeit_Taster_Durchfluss_Mehr_Aus < Wert_Zeit_Taster_Durchfluss_Mehr_Aus) )
		{
			Zeit_Taster_Durchfluss_Mehr_Aus++;
		}
		
		if (Eingang_Taster_Durchfluss_Weniger == On)
		{
			Zeit_Taster_Durchfluss_Weniger_An++;
			Zeit_Taster_Durchfluss_Weniger_Aus = 0;
		}
		else if ( (Eingang_Taster_Durchfluss_Weniger == Off) & (Zeit_Taster_Durchfluss_Weniger_Aus < Wert_Zeit_Taster_Durchfluss_Weniger_Aus) )
		{
			Zeit_Taster_Durchfluss_Weniger_Aus++;
		}
}

Arduino-Code:

//Declare Pins für RGB-LED
#define RGB_LED_RED 22
#define RGB_LED_GREEN 23
#define RGB_LED_BLUE 24

const byte Pin_Button = 7; 
const byte Pin_Signal_Verbrauch = 2;

int State_Button = 0;
int State_Signal_Verbrauch = 0;

int Zeit_Signal_Verbrauch = 0;
int Zeit_Signal_Geschwindigkeit = 0;

float Geschwindigkeit = 0;
float Wert_Verbauch;

unsigned long Zeit_Aktuell_1;
unsigned long Zeit_Zuletzt_1;




void setup()  // Start of setup
{
  Serial.begin(9600);
  
  // initialize the pushbutton pin as an input:
  pinMode(Pin_Button, INPUT);
  pinMode(Pin_Signal_Verbrauch, INPUT);


  attachInterrupt(digitalPinToInterrupt(Pin_Signal_Verbrauch), Verbrauch, CHANGE);  
}  // End of setup







void loop()  // Start of loop
{
  Zeit_Aktuell_1 = millis();

  if (Zeit_Signal_Geschwindigkeit > 0)
  {
    Geschwindigkeit = 1.00/Zeit_Signal_Geschwindigkeit*1070.00*3.60;
  }
  
  if (State_Signal_Verbrauch == HIGH)
  {
    //Zeit_Signal_Verbrauch = (Zeit_Aktuell_1 - Zeit_Zuletzt_1);

    if (Zeit_Signal_Geschwindigkeit > 0)
    {
      Wert_Verbauch = 1.00/Zeit_Signal_Verbrauch*3600000.00/105.00/Geschwindigkeit;
    }
    else
    {
      Wert_Verbauch = 1.00/Zeit_Signal_Verbrauch*36000.00/105.00;
    }
    
    Zeit_Zuletzt_1 = Zeit_Aktuell_1;
  }
  else if ( (Zeit_Aktuell_1 - Zeit_Zuletzt_1) >= 500)
  {
    Wert_Verbauch = 0;
  }
  
  
  
  //State_Signal_Verbrauch = digitalRead(Pin_Signal_Verbrauch);

  if (State_Signal_Verbrauch == LOW)
  {
    // turn LED on:
    digitalWrite(RGB_LED_BLUE, HIGH);
    //Serial.println("Signal an");
    //Serial.println(Zeit_Signal_Verbrauch);
  }
  else
  {
    // turn LED off:
    digitalWrite(RGB_LED_BLUE, LOW);
    //Serial.println("Signal aus");
  }

  
  State_Button = digitalRead(Pin_Button);

  if (State_Button == LOW)
  {
    // turn LED on:
    digitalWrite(RGB_LED_RED, LOW);

    //Zeit_Signal_Geschwindigkeit = 38; //100km/h
    Zeit_Signal_Geschwindigkeit = 77; // 50km/h
  }
  else
  {
    // turn LED off:
    digitalWrite(RGB_LED_RED, HIGH);

    Zeit_Signal_Geschwindigkeit = 0;
  }
}  // End of loop



void Verbrauch (void)
{
  State_Signal_Verbrauch = !State_Signal_Verbrauch;

  if (State_Signal_Verbrauch == HIGH)
  {
    Zeit_Signal_Verbrauch = (Zeit_Aktuell_1 - Zeit_Zuletzt_1);
  }
  else
  {
    Zeit_Zuletzt_1 = Zeit_Aktuell_1;
  }
}

Before looking at the issue, may I suggest a few things.

  • When you post an example, reduce it to the bare minimum to show your issue. e.g., remove all TFT code, remove all dead code. This will allow others to play with your code and make suggestions. Most user likely do not have the same TFT as you have.

  • Program using two languages not three. Your English seems fine.

  • Spend more time picking variable and function names. Variable1 2 3 are not good variable names.

  • Use the Arduino variable naming conventions camelCase staring with lower case for variables and functions, CAPITAL_WITH_UNDERSCORE for constant values

Now to your issue. Can you provide some more information about the signal ( frequency, duty cycle including the range ) you are trying to capture and what resolution and update rate do you need? I am assuming the signal is digital and at the right voltage level.

1 Like

I have 3 languages because I speak German by birth. But since I am also looking for help from the English area, I have posted it here.

The Arduino code was momentarily for testing purposes. But I also changed this for you. :slight_smile:

Oh. The variable rule is new for me. Thank you. I'll try to change that.

The frequency is generated by the ATmega32A. It is determined by

#define Wert_Zeit_Impulse_Durchflußmesser_Max 381
#define Wert_Zeit_Impulse_Durchflußmesser_Min 7
#define Wert_Zeit_Impulse_Durchflußmesser_An 50

"Min" & "Max" is for low and "An" for high time.
To test it, I try to change the low time with two buttons.

Taster_Durchfluss_Mehr				PC7
Taster_Durchfluss_Weniger			PC6

The signal is digital and 5V and is brought to 3V via a voltage divider.

It is just a recommendation. Write your code so it is easy to understand for other programmers. After not looking at your code for two months, you are one of the others. :slight_smile: C/C++ is based on English. I am not a native English speaker.

I am a bit confused about the sensor signal. The ATmega is just for simulating a real flow sensor, right?

I understood you have a LOW interval that changes but the HIGH interval stays fixed. That seems weird. I do not want to reverse engineer your ATmega code and start with a wrong premise because I made a mistake.

What does the flow sensor signal look like?

I am asking because, the Arduino Nano 33 BLE is an expensive piece of hardware for the amount of code you have so far. Do you want to use BLE or anything else this chip has to offer? Because then the basic principle of your current code will not work.

A few more things I noted about your code.

  • I am not sure the following code is safe to use. Make Zeit_Signal_Verbrauch an unsigned long.
Zeit_Signal_Verbrauch = (Zeit_Aktuell_1 - Zeit_Zuletzt_1);
  • When you miss an interrupt, your code will break because it will start measuring the HIGH phase of your signal.

  • I would recommend giving interrupt handlers a special name. That will make it immediately clear for somebody reading the code. Some use ISR and the Common Microcontroller Software Interface Standard (CMSIS) from ARM recommends suffix _Handler in the name.

Good question! If you are not going to using BLE there are way better choices for your board. I suspect that a basic nano clone would be fine.
Why have you chosen the nano 33 BLE?

I don't think that you have answered these questions you were previously asked?

Can you provide some more information about the signal ( frequency, duty cycle including the range ) you are trying to capture and what resolution and update rate do you need?

I'll try it in my later codes :slight_smile:

ATmega is for simulating, right. This is the Flowmeter:
https://www.conrad.de/
Datasheet Flowmeter
The Flowmeter generates 10,500 pulses per liter.
At max. (0.8l/min): 7.14 ms/Pulse
At min. (0.015l/min): 380.95ms/Pulse

I also could missunderstand my informations

My inital idea was to load the skretch via Bluetooth. But after buying and more investigation i realized, that is not possible with the 33 BLE. But in the Future, i want to change settings via app an transfer data to another Arduino. - The problem to not have an EEPROM is my next step to solve.

I'll try.

I hope could clear the confusion :smiley:

To determine flow rate, you can time the period between hall sensor pulses with a very simple interrupt routine.

//attachInterrupt(digitalPinToInterrupt(Pin_Signal_Verbrauch), Verbrauch, CHANGE);  
attachInterrupt(digitalPinToInterrupt(Pin_Signal_Verbrauch), Verbrauch, RISING);

The ISR is

void Verbrauch()
{
 pulseInterval = (micros() - time_last); 
 time_last = micros();
}

The problem to not have an EEPROM is my next step to solve.

For the non volatile storage Nano 33 BLE you can use Key Value pairs with KVStore.h.

The NVS on the Nano 33 BLE is somewhat complex, and may be another reason to not use the platform.

This will give you a good resolution when the flow rate is low. As the pulses get shorter the resolution will get lower because the timer get more inaccurate.

For higher flow rate you can inverse the measurement and just count pulses. Simply increment a counter in the ISR. In your main loop you would then read the counter variable in a regular interval and get the frequency. Here you get the inverse issue when the flow rate gets very low you get lower resolution.

In any case, if you want to use BLE later you should look into using the hardware timer. You will have the same two options.

It works perfectly. Thank you. Micro is the better idea.

I can't find the library to include KVStore in the Arduino IDE or Atmel Studio.
I prefer to work with Atmel Studio :wink:
Did anyone have a link. I couldn't find anything usefull at MbedOS.

It's ok for me. It doesn't need to be 1000% right. :slight_smile:

I've read the datasheet of the nRF52840, but can't find usefull infos about the timer registers and the ISR. Or I don't understand the datasheet.
The Atmel-datasheets are more userfriendly in my eyes.
Did you have infos what Timer I have, need for BLE and can use for other tastks?
I would love to use the ISR for counting micro and not use mirco().

Thanks for your help :slight_smile:

Did you have infos what Timer I have, need for BLE and can use for other tastks?
I would love to use the ISR for counting micro and not use mirco().

Regarding Timers and the Nano33 BLE there are two libraries you can use. Both are available through the library manager.

NRF52_MBED_TimerInterrupt
by Khoi Hoang v1.2.1

TimerInterrupt_Generic
by Khoi Hoang v1.7.0

I can't find the library to include KVStore in the Arduino IDE or Atmel Studio.
I prefer to work with Atmel Studio :wink:
Did anyone have a link. I couldn't find anything usefull at MbedOS.

Here is a simplified example of KV store. There is no library that I am aware of.

//https://os.mbed.com/docs/mbed-os/v6.12/apis/kvstore.html
//KVStore. TDBStore - Default implementation of the KVStore API. It provides static wear-leveling and quick access for when you have a small number of KV pairs.
//https://os.mbed.com/docs/mbed-os/v6.12/apis/data-architecture.html

#include "KVStore.h"
#include "kvstore_global_api.h"

void setup() {
  Serial.begin(115200);
  while (!Serial);
  Serial.println("--- Mbed OS KVStore Simplified example--- ");

  /* Start By Resetting the KV Storage */
  Serial.println("kv_reset");
  kv_reset("/kv/");//comment out when retreiving saved data
  Serial.println();

  const char* const Key1 = "store_cString";
  const char* const Key2 = "store_longArray";
  const char* const Key3 = "store_Struct";

  /* Set First Key/Value pair*/ 
  const char* const cStringToStore = "Hello World/Goodnight Moon";//const pointer to constant string
  Serial.print("kv_set key: ");
  Serial.println(Key1);
  kv_set(Key1, cStringToStore, strlen(cStringToStore), 0); //0 for flags?

  /* Read the KV Pair you've just set */
  char Key1Out[strlen(cStringToStore) + 1] = "";
  memset(Key1Out, '\0', strlen(cStringToStore) + 1); //clear and null terminate
  kv_get(Key1, Key1Out, strlen(cStringToStore) + 1 , 0);
  Serial.print("kv_get key: ");
  Serial.println(Key1);
  Serial.print("kv_get key Value: ");
  Serial.println(Key1Out);
  Serial.println();

  /* Set Second Key/Value pair*/
  uint32_t km[3];
  km[0] = 123456789;
  km[1] = 234567891;
  km[2] = 345678912;

  Serial.print("kv_set key: ");
  Serial.println(Key2);
  kv_set(Key2, (uint8_t*)&km, sizeof(km), 0);

  /* Read the KV Pair you've just set */
  uint32_t kmOut[3];
  kmOut[0] = 0;
  kmOut[1] = 0;
  kmOut[2] = 0;

  Serial.print("kv_get key: ");
  Serial.println(Key2);
  kv_get(Key2, (byte*)&kmOut, sizeof(kmOut), 0);

  Serial.print("kv_get key Value: ");
  for (byte i = 0; i < 3; i++)
  {
    Serial.print(kmOut[i]);
    if (i != 2)
      Serial.print(',');
  }
  Serial.println();
  Serial.println();

  /* Set Third Key/Value pair*/
  typedef struct {
    unsigned long timeStamp;
    float accel;
    char pres[4];
  } structData;


  structData dataSaved;
  structData dataRetreived;

  dataSaved.timeStamp = 445566;
  dataSaved.accel = 1.23;
  strcpy(dataSaved.pres, "789");

  dataRetreived.timeStamp = 0;
  dataRetreived.accel = 0;
  strcpy(dataRetreived.pres, "---");
  
  Serial.print("kv_set key: ");
  Serial.println(Key3);
  kv_set(Key3, (uint8_t*)&dataSaved, sizeof(dataSaved), 0);

  Serial.print("kv_get key: ");
  Serial.println(Key3);
  kv_get(Key3, (byte*)&dataRetreived, sizeof(dataRetreived), 0);

  Serial.print("kv_get key Value: ");
  Serial.print(dataRetreived.timeStamp);
  Serial.print(',');
  Serial.print(dataRetreived.accel);
  Serial.print(',');
  Serial.print(dataRetreived.pres);
  Serial.println();

  /* Finally, reset will format kvstore and remove All Keys (including write-once keys) */
  //Serial.println("kv_reset");
  //kv_reset("/kv/");
}
void loop() {}

It's to simple for me. I don't understand how to store and get my Values.
I think it's a declaration like the Atmel-EEPROM. But how can I fix the savepoint.
This is to hard for me to translate :smiley:

kv_set() and kv_get()

Please explain exactly what in the example you don't follow? I made it somewhat more complex to store multi byte values at a given key.

What data do you want to store?

For example i want to store
#define WHEEL_CIRCUMFERENCE 1070
#define TANK_CAPACITY_MAX 6000

float Total_Consumption_Hour;
float Total_Consumption_Distance;

This values later have to send and save if they change via BLE.

This was my first idea:

unsigned int KV_STORE_TANK_CAPACITY_MAX = 2
unsigned int Tank_Capacity_Max;

kv_set(KV_STORE_TANK_CAPACITY_MAX, Tank_Capacity_Max, sizeof(Tank_Capacity_Max), 0);

But it's not what the programm want and I not understand :smiley:

But it's not what the programm want and I not understand

The syntax for set is (const char *key, const void *buffer, size_t size, uint32_t create_flags)

KVStore is using the concept of Key/Value pairs, and not a storage address. All the internal address management is taken care of by the KVStore application.

The Key needs to be a character array name. I think the name is limited to 16 bytes. In your case, the Key might be "TankCapMax".

The stored value might be unsigned 16 bit integer maxAmount. It needs to be broken into bytes for storage and retreival.

//https://os.mbed.com/docs/mbed-os/v6.12/apis/kvstore.html
//KVStore. TDBStore - Default implementation of the KVStore API. It provides static wear-leveling and quick access for when you have a small number of KV pairs.
//https://os.mbed.com/docs/mbed-os/v6.12/apis/data-architecture.html

#include "KVStore.h"
#include "kvstore_global_api.h"

void setup() {
  Serial.begin(115200);
  while (!Serial);
  Serial.println("--- Mbed OS KVStore Simplified example--- ");

  /* Start By Resetting the KV Storage */
  Serial.println("kv_reset");
  kv_reset("/kv/");//comment out when retreiving saved data
  Serial.println();

  uint16_t maxAmountStored = 1234;
  uint16_t maxAmountReadBack = 0;
  
  kv_set("TankCapMax", (uint8_t*)&maxAmountStored, sizeof(maxAmountStored), 0);
  kv_get("TankCapMax", (uint8_t*)&maxAmountReadBack, sizeof(maxAmountReadBack), 0);
  Serial.print("max amount =  ");
  Serial.println(maxAmountReadBack);
  /* Finally, reset will format kvstore and remove All Keys (including write-once keys) */
  //Serial.println("kv_reset");
  //kv_reset("/kv/");
}
void loop() {}
1 Like

Perfectly answered! Thank you. It works flawless :slight_smile:

Now I have a Value-problem, i don't understand:
In my case "State_Display" is always 1 although Total_Fuel (5500) is above RESERVE_WARNUNG_1 (1000). What is the problem?

#define PIN_SIGNAL_CONSUMPTION			   2
#define TANK_CAPACITY_MAX			    5500
#define TIME_CONSUMPTION_MAX	     2000000	//2sec * 1000ms * 1000µs
#define RESERVE_WARNUNG_1			    1000
#define TIME_TOTAL_UPDATE				 250
float Value_Consumption_Hour;
float Value_Consumption_Tank;
float Total_Consumption_Tank;
float Total_Fuel;
unsigned char State_Display = 0;
unsigned long Time_Signal_Consumption_Handler = 0; 
unsigned long Time_Last_Consumption;
unsigned long Time_Total_Last;

void Consumption(void);

void setup()  // Start of setup
{
	// initialize the pushbutton pin as an input:
	pinMode(PIN_SIGNAL_CONSUMPTION, INPUT);

	attachInterrupt(digitalPinToInterrupt(PIN_SIGNAL_CONSUMPTION), Consumption, RISING);
}

void loop()  // Start of loop
{
	//Values
		//Consumption
			if ( (micros() - Time_Last_Consumption) >= TIME_CONSUMPTION_MAX)
			{
				Value_Consumption_Hour = 0;
			}
			else
			{
				Value_Consumption_Hour = 36000000.0/Time_Signal_Consumption_Handler/105.0;
			}
			
		//Total
			//Consumption
				if ( (Value_Consumption_Hour > 0) & ( (millis() - Time_Total_Last) >= TIME_TOTAL_UPDATE) )		//Save Values every 250ms
				{
					Value_Consumption_Tank = 250000.000000/Time_Signal_Consumption_Handler/105.000000;			//1,000,000 divided by 4 (every 1/4s (250ms))
					Total_Consumption_Tank += Value_Consumption_Tank;
					
					Time_Total_Last = millis();
				}
		//Tank capacity
			Total_Fuel = TANK_CAPACITY_MAX - Total_Consumption_Tank;
			
			
	//Display
		if (Total_Fuel <= RESERVE_WARNUNG_1 && State_Display == 0);
		{
			State_Display = 1;
		}
}  // End of loop

void Consumption (void)
{
	Time_Signal_Consumption_Handler = (micros() - Time_Last_Consumption);
	Time_Last_Consumption = micros();
}

In my case "State_Display" is always 1

You have an ; at the end of the conditional test. Oops :wink:

//if (Total_Fuel <= RESERVE_WARNUNG_1 && State_Display == 0);
if (Total_Fuel <= RESERVE_WARNUNG_1 && State_Display == 0)
1 Like

Oh :smiley: What a fail. Thank you. :sweat_smile: