Hilfe mit Analog Devices Waage CN0216

Hallo Gemeinde,

es geht um eine digitale Waage mit dem ADC CN0216 von Analog Devices.

Ich habe den converter angeschlossen und mein arduino mit dem Beispielcode vom hersteller
gefüttert und der Arduino liefert ordentliche Daten.

Mein Problem ist jetzt dass ich jedes mal den ADC kalibrieren muss wenn ich die Waage ausschalte,
und das ist für eine Waage ziemlich doof.

Ich wollte hier fragen ob es möglich wäre in die Bibliothek oder Sketch die Werte für die umrechnung einzutragen damit die Waage sofort los geht wenn man es einschaltet.

Hier den Code

/*
 CN0216_example.ino - Example code for CN0216 - Weighing Scale Module
 Created by Analog Devices Inc. - Circuits from the Lab, March 2015.
*/

#include <CN0216.h>
#include <SPI.h> 

// ADC mode register selections
const int CN0216_ADCMODE_UNBUF = 0x00;
const int CN0216_ADCMODE_BUF = 0x02;

// ADC filter register selections
const int CN0216_ADCRATE_9_5 = 7;
const int CN0216_ADCRATE_13_3 = 6; 
const int CN0216_ADCRATE_16_6 = 5; 
const int CN0216_ADCRATE_16_7 = 4; 
const int CN0216_ADCRATE_20 = 3; 
const int CN0216_ADCRATE_33_3 = 2; 
const int CN0216_ADCRATE_100 = 1; 
const int CN0216_ADCRATE_120 = 0; 

// SPI chip select 
const int CN0216_SS = 8;  //change the value if the CS pin assignment is different 

// Weigh Scale parameters
const int CAL_WT = 1000;  //value of calibration weight used, in grams

// Sketch variables
float fWeight = 0;
int long gewicht=0;

void setup() {
  // put your setup code here, to run once:
  CN0216.Configure(CN0216_ADCMODE_UNBUF,CN0216_ADCRATE_9_5,CN0216_SS);
  Serial.begin(9600);

  //Calibration for zero scale
  Serial.println("Zero calibration will start in 5 seconds, please remove weight from the sensor\n");
  delay(5000);
  Serial.println("Zero calibration in process please wait approximately 20 seconds\n");
  CN0216.Calibrate_zero();
  Serial.println("Zero calibration finished\n");
  delay(1000);
  
  //Full scale calibration routine
  Serial.println("Full scale calibration will start in 10 seconds, please place weight on sensor\n");
  delay(10000);
  Serial.println("Full scale calibration in process please wait approximately 20 seconds\n");
  CN0216.Calibrate_fullscale();
  Serial.println("Calibration finished\n");
  delay(1000);  
}

void loop() {
  fWeight = CN0216.Readweight(CAL_WT);
  gewicht= CN0216.Readdata();
  Serial.print(fWeight,2);  
  Serial.print("-----");
  Serial.println(gewicht); 
  delay(1000); 
}

Hier die CN0216.cpp

/*
  CN0216.cpp - Library for CN0216 Embedded World Demo- Weighing Scale Module
  Created by Analog Devices Inc. - Circuits from the Lab, January 2015.
  
  Always need to start with a write to the communications register of AD7791:
  Here is the normal operation of the part without using the data ready pin 
  Write: 
		Mode Register = 0x10
		Filter Register = 0x20
  Read:
		Status Register = 0x08
		Data Register = 0x38  
*/

#include "Arduino.h"
#include "CN0216.h"
#include "SPI.h"

CN0216class CN0216;

void CN0216class::Configure(byte ADCmode,byte ADCrate,byte CN0216_ss_pin)
{
  CN0216_ss_pin = ss_pin;
  
  pinMode(CN0216_ss_pin,OUTPUT);
  digitalWrite(CN0216_ss_pin,HIGH);
  SPI.begin();
  SPI.setBitOrder(MSBFIRST);          //  MSB to be sent first
  SPI.setDataMode(SPI_MODE3);         //  Set for clock rising edge
  SPI.setClockDivider(SPI_CLOCK_DIV4);    //  Set clock divider (optional)
  
  //resets the registers
  digitalWrite(CN0216_ss_pin,LOW);
  SPI.transfer(byte_full); //0xFF
  SPI.transfer(byte_full); //0xFF
  SPI.transfer(byte_full); //0xFF
  SPI.transfer(byte_full); //0xFF
  digitalWrite(CN0216_ss_pin,HIGH);
  delay(100);
  //configure the ADC filter register
  digitalWrite(CN0216_ss_pin,LOW);
  SPI.transfer(0x20);
  SPI.transfer(byte_zero | ADCrate);
  digitalWrite(CN0216_ss_pin,HIGH);
  delay(100);
  //configure the ADC mode register
  digitalWrite(CN0216_ss_pin,LOW);
  SPI.transfer(0x10);
  SPI.transfer(ADCmode);
  digitalWrite(CN0216_ss_pin,HIGH);
  }

long CN0216class::Readdata()
{

	//checks the status register if device is ready
	do
	{
		digitalWrite(ss_pin,LOW);
		SPI.transfer(0x08);
		cRDY = SPI.transfer(byte_zero); //0x00
		digitalWrite(ss_pin,HIGH);
		//delay(200);
	}while(cRDY != 0x0C); // meaning that the ADC has a new conversion
  
    // read 24 bits of data
	digitalWrite(ss_pin,LOW);
	SPI.transfer(0x38);
	u8_ADCDATA2 = SPI.transfer(byte_zero); //0x00
	u8_ADCDATA1 = SPI.transfer(byte_zero); //0x00
	u8_ADCDATA0 = SPI.transfer(byte_zero); //0x00
	digitalWrite(ss_pin,HIGH);
  
	lADCDATA = ((long)u8_ADCDATA2<<16) | ((long)u8_ADCDATA1<<8) | u8_ADCDATA0;
	
	return lADCDATA;
}

void CN0216class::Calibrate_zero()
{
  int x = 0;
  ulADCZEROSCALE = 0;

  for(x=0;x<100;x++)
  {
  ulADCZEROSCALE += CN0216.Readdata();
  delay(200);
  }
  fADCZEROSCALE = ulADCZEROSCALE/100.0;
}

void CN0216class::Calibrate_fullscale()
{
  int x=0;
  ulADCFULLSCALE = 0;

  for(x=0;x<100;x++)
  {
  ulADCFULLSCALE += CN0216.Readdata();
  delay(200);
  }
  fADCFULLSCALE = ulADCFULLSCALE/100.0;
}

float CN0216class::Readweight(int fcal_wt_input)
{
	float fweight = 0;
	float fcodetoweight = fcal_wt_input / (fADCFULLSCALE-fADCZEROSCALE);
	
	fweight = (CN0216.Readdata()-fADCZEROSCALE) * fcodetoweight; 
	
	return fweight;
}

Hier die CN0216.h

/*
  CN0216.h - Library for CN0216 Embedded World Demo- Weighing Scale Module
  Created by Analog Devices Inc. - Circuits from the Lab, January 2015.
*/
#ifndef CN0216_h
#define CN0216_h

#include "Arduino.h"
const byte byte_zero = 0x00;
const byte byte_full = 0xFF;
const float VREF = 5.0/16777216;

class CN0216class
{
	public:
		void Configure(byte ADCmode,byte ADCrate,byte CN0216_ss_pin);
		long Readdata();
		void Calibrate_zero();
		void Calibrate_fullscale();
		float Readweight(int fcal_wt_input);
	private:
		unsigned long ulADCZEROSCALE;
		unsigned long ulADCFULLSCALE;
		float fADCZEROSCALE;
		float fADCFULLSCALE;
		volatile byte cRDY;	
		byte u8_ADCDATA0;
	    byte u8_ADCDATA1;
	    byte u8_ADCDATA2;
	    long lADCDATA;
		byte ss_pin;
};

extern CN0216class CN0216;

#endif

Und hier die über Serial gelieferte Werte, erste zahl ist das Gewicht in Gramm un die zweite sind die entsprechenden "Rohdaten" vom ADC CN0216.Readdata();

Gramm-----Rohdaten
964.36-----8519486

1011.99 Gramm-----8495259
1016.52 Gramm-----8495235
980.74 Gramm-----8496796
1006.60 Gramm-----8495493
90.43 Gramm-----8538709
-25.37 Gramm-----8541911
-29.09 Gramm-----8541983
-16.09 Gramm-----8541227
-84.64 Gramm-----8546636
-276.30 Gramm-----8553175
-300.95 Gramm-----8554236
-301.06 Gramm-----8554086
-307.42 Gramm-----8554958
-361.72 Gramm-----8556820
-386.48 Gramm-----8557761
-383.94 Gramm-----8557970
-398.61 Gramm-----8558688
-393.79 Gramm-----8558368
-389.80 Gramm-----8555379
-8.27 Gramm-----8541102
441.97 Gramm-----8504278
3537.44 Gramm-----8374460
4456.74 Gramm-----8338613
4750.12 Gramm-----8333247
4821.02 Gramm-----8323978
5136.42 Gramm-----8312362
4214.02 Gramm-----8372743
1068.52 Gramm-----8488284
4962.66 Gramm-----8304521
6100.89 Gramm-----8266286
6285.44 Gramm-----8258142
6699.23 Gramm-----8237282
7080.31 Gramm-----8221347
7476.90 Gramm-----8204823
7621.61 Gramm-----8197450
7615.41 Gramm-----8204869
7566.35 Gramm-----8199302
3809.81 Gramm-----8425888
-6.09 Gramm-----8541072
-12.71 Gramm-----8540955
7.02 Gramm-----8540222
9.96 Gramm-----8540259
8.05 Gramm-----8540307
9.76 Gramm-----8540237
11.75 Gramm-----8540150
11.52 Gramm-----8540145
13.17 Gramm-----8540102
11.19 Gramm-----8540165
11.06 Gramm-----8540183

Wenn ich die Kalibrierungsroutinen unterbinde wird nur das hier ausgegeben:

inf Gramm-----8544291
inf Gramm-----8544289
inf Gramm-----8540255
inf Gramm-----8539166
inf Gramm-----8527118
inf Gramm-----8540154
inf Gramm-----8540107
inf Gramm-----8540102
inf Gramm-----8540126
inf Gramm-----8540277
inf Gramm-----8540149
inf Gramm-----8540132
inf Gramm-----8540243
inf Gramm-----8540167
inf Gramm-----8540302
inf Gramm-----8540271
inf Gramm-----8540386
inf Gramm-----8540297
inf Gramm-----8540299
inf Gramm-----8540345
inf Gramm-----8540329
inf Gramm-----8540319
inf Gramm-----8540380
inf Gramm-----8540305
inf Gramm-----8540334
inf Gramm-----8540452
inf Gramm-----8540398
inf Gramm-----8540426
inf Gramm-----8540440
inf Gramm-----8540406

Hätte vielleicht jemand einen Tipp wie ich das am besten umsetze?
Ich wäre euch sehr dankbar.

Wünsche euch einen schönen Abend.

Du kannst die Kalibrationsdaten ins EEPROM des Arduino schreiben und bei jedem Einschalten herausholen.
Grüße Uwe

Hallo Uwe,
vielen Dank.
Also, mein problem ist wie ich an die Daten komme.
Am ende der cpp Datei steht die Formel zur Berechnung des Gewichts:

fweight = (CN0216.Readdata()-fADCZEROSCALE) * fcodetoweight;

"CN0216.Readdata" kann ich über serial ausgeben aber "fADCZEROSCALE" und "fcodetoweight" nicht.
Gibt es da eine möglichkeit die Daten nach eine Kalibrierung auszulesen?

"CN0216.Readdata" kann ich über serial ausgeben aber "fADCZEROSCALE" und "fcodetoweight" nicht.

Für fADCZEROSCALE gibt es zwei Optionen. Das einfachste ist du machst die Variable public. Sauberer ist aber du fügst Getter und Setter Methoden für den Zugriff hinzu

Wozu du fcodetoweight brauchst ist mir nicht ganz klar. Aber an der Wert kannst du kommen wenn du noch eine Referenz oder einen Zeiger als Parameter zur Methode hinzufügst. Dann kann man eine Variable als Parameter übergeben und eine Änderung daran ist nach außen sichtbar.
Ein Zeiger hat hier den Vorteil, dass man auch NULL übergeben kann wenn man den Wert nicht möchte. Man muss dann aber in der Methode für dem Zugriff auf NULL abfragen!

Hallo Serenifly,
danke dir.
Das mit public machen habe ich schon gestern versucht aber leider ohne Erfolg.

	public:
		void Configure(byte ADCmode,byte ADCrate,byte CN0216_ss_pin);
		long Readdata();
		void Calibrate_zero();
		void Calibrate_fullscale();
		float Readweight
                float fADCZEROSCALE

Wäre das so richtig?
Danke

Für fADCZEROSCALE ja. Readweight() musst du natürlich als Methode lassen! Das ist keine Variable

An fcodetoweight kommst du so:

Im Header, das ändern:

float Readweight(int fcal_wt_input);

in:

float Readweight(int fcal_wt_input, float* fctw);

Und die .cpp Datei so:

float CN0216class::Readweight(int fcal_wt_input, float* fctw)
{
 float fweight = 0;
 float fcodetoweight = fcal_wt_input / (fADCFULLSCALE-fADCZEROSCALE);

 if (fctw != NULL)
   *fctw = fcodetoweight
 
 fweight = (CN0216.Readdata()-fADCZEROSCALE) * fcodetoweight;
 
 return fweight;
}

Dann kannst du das machen:

float fcodetoweight;
Readweight(CAL_WT, &fcodetoweight);

Oder NULL übergeben wenn du den Wert nicht auslesen willst

Und sauberer ist es du lässt fADCZEROSCALE private, aber fügst das in den Header unter public ein:

void SetScale(float scale);
float GetScale();

Und das in die .cpp Datei:

void CN0216class::SetScale(float scale)
{
   fADCZEROSCALE = scale;
}

float CN0216class::GetScale()
{
   return fADCZEROSCALE;
}

Das ist der übliche Weg um auf private Variablen zuzugreifen

Ok, herzlichen Dank.
Ich werde heute Abend versuchen und hier berichten ob es funktioniert hat.
Wünsche euch allen einen schönen Tag.
LG

Serenifly:
Wozu du fcodetoweight brauchst ist mir nicht ganz klar.

Für eine Kalibration braucht es Offset und Slope (Steigung) um die gelesenen ADC Werte in ein Gewicht umzurechnen.
Grüße Uwe

Ja, aber das wird ja so berechnet:
fcal_wt_input / (fADCFULLSCALE-fADCZEROSCALE

Wobei fcal_wt_input als Parameter übergeben wird. Vom Aufbau der Klasse her wäre es vernünftiger die zwei SCALE Variablen zu setzen und den Rest wie vorher berechnen zu lassen

Hallo zusammen,
wie geplant wollte ich gestern eure Lösungsansätze ausprobieren, hats aber leider nicht geklappt!

Die CN0216 Platine liefert überhaupt keine daten mehr.
Noch vorgestern hat einwandfrei funktioniert und gestern als ich es einsgeschaltet habe, blieb bei der Kalibrierungsroutine hängen und sonnst hat sich nichts mehr getan.
Es hat aber sich absolut nichts geändert, Sketch war immer noch drin, Wägezelle ist angeschlossen geblieben, habe nur die Stromversorgung unterbrochen, sonnst nichts.
Wenn ich die Stromversorgung einschalte kommt nur

"Zero calibration will start in 5 seconds, please remove weight from the sensor"

Kurz später:

"Zero calibration in process please wait approximately 20 seconds"

Und dann bleibt so, echt seltsam. Der ADC scheint tot zu sein :frowning:

Habe auch ohne Kalibrierungsroutine probiert aber liefert auch keine Daten.

Analog Devices hat eine Evaluation Software für windows, werde damit versuchen aber muss zuerst noch installieren.

Falls der ADC tot sein soll muss ich ein anderer bestellen, im Moment überlege ich mir ein HX711 zu holen, was meint Ihr dazu? Gibts auch andere Module wo ADC und Verstärker zusammen gelötet sind?
Für meine Zwecke reicht eine Auflösung von 50 Gramm völlig aus, und meine Wägezelle ist eine Tedea 1250 für 200 Kg, könnte das funktionieren?

LG