Celle di carico con HX711

Disturbo perché uso celle di carico da 10 o 20 Kg. con amlificatore convertitore Analogico Digitale HX711.
Su Arduino nessun problema di lettura e taratura grazie alla libreria.
Mi chiedevo se nessuno le ha mai usate su ARM o su altre MPU e/o come ha fatto a sviluppare un codice, dato che il data sheet è un po' limitato...

Grazie in anticipo

steve-cr:
... Mi chiedevo se nessuno le ha mai usate su ARM o su altre MPU e/o come ha fatto a sviluppare un codice, dato che il data sheet è un po' limitato...

... mai fatto quindi NON posso aiutarti direttamemte, ma ... visto che hai la libreria per Arduino, non dovrebbe essere difficile capire come funziona :wink:

Guglielmo

Cosa non é chiaro in questa spiegazione?

Serial Interface
Pin PD_SCK and DOUT are used for data
retrieval, input selection, gain selection and power
down controls.
When output data is not ready for retrieval,
digital output pin DOUT is high. Serial clock
input PD_SCK should be low. When DOUT goes
to low, it indicates data is ready for retrieval. By
applying 25~27 positive clock pulses at the
PD_SCK pin, data is shifted out from the DOUT
output pin. Each PD_SCK pulse shifts out one bit,
starting with the MSB bit first, until all 24 bits are
shifted out. The 2h pulse at PD_SCK input will
pull DOUT pin back to high (Fig.2).
Input and gain selection is controlled by the
number of the input PD_SCK pulses (Table 3).
PD_SCK clock pulses should not be less than 25
or more than 27 within one conversion period, to
avoid causing serial communication error.

con i 24 Impulsi sul PD_SCK trasmetti il dato misurato. In aggiunta di questi con 1, 2o 3 impulsi selezioni l' amplificazione e l' entrata.
Ciao Uwe

E' il "dopo" i 24-27 impulsi che la cosa non viene spiegata, quindi non mi è chiara...
Il treno di impulsi che proviene da DATA cioè la lettura, come la interpreto?
E' una word? 8 bit? 16 bit?
Senza un oscilloscopio non lo vedo...

steve-cr:
E' il "dopo" i 24-27 impulsi che la cosa non viene spiegata, quindi non mi è chiara...

Ripeto, ma se apri la libreria (... che ho capito tu hai per Arduino) e guardi come fanno ?

Guglielmo

#include <Arduino.h>
#include <HX711.h>

#if ARDUINO_VERSION <= 106
    // "yield" is not implemented as noop in older Arduino Core releases, so let's define it.
    // See also: https://stackoverflow.com/questions/34497758/what-is-the-secret-of-the-arduino-yieldfunction/34498165#34498165
    void yield(void) {};
#endif

HX711::HX711(byte dout, byte pd_sck, byte gain) {
	begin(dout, pd_sck, gain);
}

HX711::HX711() {
}

HX711::~HX711() {
}

void HX711::begin(byte dout, byte pd_sck, byte gain) {
	PD_SCK = pd_sck;
	DOUT = dout;

	pinMode(PD_SCK, OUTPUT);
	pinMode(DOUT, INPUT);

	set_gain(gain);
}

bool HX711::is_ready() {
	return digitalRead(DOUT) == LOW;
}

void HX711::set_gain(byte gain) {
	switch (gain) {
		case 128:		// channel A, gain factor 128
			GAIN = 1;
			break;
		case 64:		// channel A, gain factor 64
			GAIN = 3;
			break;
		case 32:		// channel B, gain factor 32
			GAIN = 2;
			break;
	}

	digitalWrite(PD_SCK, LOW);
	read();
}

long HX711::read() {
	// wait for the chip to become ready
	while (!is_ready()) {
		// Will do nothing on Arduino but prevent resets of ESP8266 (Watchdog Issue)
		yield();
	}

	unsigned long value = 0;
	uint8_t data[3] = { 0 };
	uint8_t filler = 0x00;

	// pulse the clock pin 24 times to read the data
	data[2] = shiftIn(DOUT, PD_SCK, MSBFIRST);
	data[1] = shiftIn(DOUT, PD_SCK, MSBFIRST);
	data[0] = shiftIn(DOUT, PD_SCK, MSBFIRST);

	// set the channel and the gain factor for the next reading using the clock pin
	for (unsigned int i = 0; i < GAIN; i++) {
		digitalWrite(PD_SCK, HIGH);
		digitalWrite(PD_SCK, LOW);
	}

	// Replicate the most significant bit to pad out a 32-bit signed integer
	if (data[2] & 0x80) {
		filler = 0xFF;
	} else {
		filler = 0x00;
	}

	// Construct a 32-bit signed integer
	value = ( static_cast<unsigned long>(filler) << 24
			| static_cast<unsigned long>(data[2]) << 16
			| static_cast<unsigned long>(data[1]) << 8
			| static_cast<unsigned long>(data[0]) );

	return static_cast<long>(value);
}

long HX711::read_average(byte times) {
	long sum = 0;
	for (byte i = 0; i < times; i++) {
		sum += read();
		yield();
	}
	return sum / times;
}

double HX711::get_value(byte times) {
	return read_average(times) - OFFSET;
}

float HX711::get_units(byte times) {
	return get_value(times) / SCALE;
}

void HX711::tare(byte times) {
	double sum = read_average(times);
	set_offset(sum);
}

void HX711::set_scale(float scale) {
	SCALE = scale;
}

float HX711::get_scale() {
	return SCALE;
}

void HX711::set_offset(long offset) {
	OFFSET = offset;
}

long HX711::get_offset() {
	return OFFSET;
}

void HX711::power_down() {
	digitalWrite(PD_SCK, LOW);
	digitalWrite(PD_SCK, HIGH);
}

void HX711::power_up() {
	digitalWrite(PD_SCK, LOW);
}

Guglielmo, questa è la libreria, ma anche io ho i miei limiti… :confused:

long HX711::read() {
	// wait for the chip to become ready
	while (!is_ready()) {
		// Will do nothing on Arduino but prevent resets of ESP8266 (Watchdog Issue)
		yield();
	}

	unsigned long value = 0;
	uint8_t data[3] = { 0 };
	uint8_t filler = 0x00;

	// pulse the clock pin 24 times to read the data
	data[2] = shiftIn(DOUT, PD_SCK, MSBFIRST);
	data[1] = shiftIn(DOUT, PD_SCK, MSBFIRST);
	data[0] = shiftIn(DOUT, PD_SCK, MSBFIRST);

	// set the channel and the gain factor for the next reading using the clock pin
	for (unsigned int i = 0; i < GAIN; i++) {
		digitalWrite(PD_SCK, HIGH);
		digitalWrite(PD_SCK, LOW);
	}

	// Replicate the most significant bit to pad out a 32-bit signed integer
	if (data[2] & 0x80) {
		filler = 0xFF;
	} else {
		filler = 0x00;
	}

	// Construct a 32-bit signed integer
	value = ( static_cast<unsigned long>(filler) << 24
			| static_cast<unsigned long>(data[2]) << 16
			| static_cast<unsigned long>(data[1]) << 8
			| static_cast<unsigned long>(data[0]) );

	return static_cast<long>(value);
}

Ciao Uwe

Grazie Uwe, ma sono partito più terra terra.
E questo funziona !!!
Quindi lo stesso codice scritto più o meno uguale sul TPAC1007 (vedi su google) dovrebbe funzionare modulando opportunamente con qualche delay…

 int data = 0;
 String StringOne = "";


void setup() {
  
 pinMode(3, OUTPUT);
 pinMode(4, INPUT);
 digitalWrite (3,LOW);
 Serial.begin(9600);
  
}

void loop() {

if (digitalRead (4) == LOW) { 
for (int i=0; i <= 24; i++){
  
      digitalWrite (3,HIGH);
      data = digitalRead (4);
      //delay (1);
      digitalWrite (3,LOW);
      StringOne = String(StringOne + String(data));      
     }
     
 Serial.println (StringOne);
 StringOne = "";
 
 }
}

Adesso dovrei convertire la stringa in numero binario e da numero binario a numero decimale.....

Ma ce la posso fare....
Forse ! :o

Ti ripeto:

	// Replicate the most significant bit to pad out a 32-bit signed integer
	if (data[2] & 0x80) {
		filler = 0xFF;
	} else {
		filler = 0x00;
	}

	// Construct a 32-bit signed integer
	value = ( static_cast<unsigned long>(filler) << 24
			| static_cast<unsigned long>(data[2]) << 16
			| static_cast<unsigned long>(data[1]) << 8
			| static_cast<unsigned long>(data[0]) );

Ciao Uwe

Ti ringrazio Uwe ma ho visto che hai il dono della sintesi ...
La mia domanda è: il codice della libreria che ho postato, e che ho capito abbastanza, è un codice che può essere inserito in Atmel, ma se lo inserisco in un'altra MPU pensi che possa funzionare?
Perché, per esempio, le prime due righe #include mi sembra che abbiano poco senso dato che si riferiscono a Arduino, ma anche la successiva IF Arduino_Version...

Per la conversione l'ho capita poco, ma copio e incollo e va bene così.
Dal data sheet ho visto che i bit che escono partono dal MSB e arrivano al LSB quindi sono "in fila" anche se dal binario vedo che ad un certo punto della pressione sulla cella i primi 8 bit diventano di colpo tutti 1 mentre prima erano tutti 0 e la cosa è strana...

steve-cr:
La mia domanda è: il codice della libreria che ho postato, e che ho capito abbastanza, è un codice che può essere inserito in Atmel, ma se lo inserisco in un'altra MPU pensi che possa funzionare? ...

Ma ovviamente NO e non è neanche Atmel, è Arduino IDE dato che, se elimini il framework "Wiring", che ti mette a disposizione l'IDE ... ti scordi tutte le digitalWrite(), digitalRead() ecc. ecc.

Per portarlo su un'altra MCU occorre CAPIRE esattamente cosa fa e riscriverlo totalmente nell'ambiente di sviluppo dell'altra MCU e ... per farlo, occorre conoscere bene il linguaggio di programmazione sia di Arduino che, ovviamente, dell'altra MCU.

Su che MCU pensavi di farlo girare ?

Guglielmo

E' una ARM926JE, provvista di touch screen, un bel prodotto tutto italiano di una ditta torinese, la MECT, programmabile attraverso QTcreator.

Però, senza scomodare il C++, ho visto in Arduino, SENZA caricare la libreria, che dando i 24 impulsi ottengo i 24 bit e poi do il 25' impulso per dire che la prossima lettura la voglio sempre con gain a 128.

Quindi farò ancora così su quella CPU, dato che non esiste libreria.

Ora che ho letto meglio il data sheet la cosa è abbastanza semplice: quando i dati sono disponibili per la trasmissione sul pin DATA, questo passa a LOW e da quel momento inviando 24 impulsi sul pin PD_SCK ottengo come risposta sul pin DATA i 24 bit corrispondenti alla lettura. Poi termino inviando il 25esimo impulso per chiudere il pin DATA a HIGH fino a quando questo si riposizionerà su LOW per dirmi che è pronto alla prossima trasmissione.

Fondamentalmente non c'è bisogno di una libreria se non si vogliono cose particolari (quello che diciamo spesso qui dove, se possibile, si preferisce consigliare di non usare troppe librerie).

steve-cr:
Fondamentalmente non c'è bisogno di una libreria se non si vogliono cose particolari (quello che diciamo spesso qui dove, se possibile, si preferisce consigliare di non usare troppe librerie).

Cosa verissima nel ... 75% dei casi ! ... C'è un 25% di casi in cui il lavoro sarebbe talmente tanto che ... sarebbe come "reinventare la ruota", ma effettivamnete spessissimo, per le proprie esigenze ... conviene scriversi quelle poche istruzioni che servono senza scomodare librerie che, ovviamnete, fanno di tutto e di più :wink:

Guglielmo

Vabbé, non ci vuole un genio…

Adesso che l’ho capito, però :smiley: :smiley: :smiley:

Il data sheet parla chiaro, è che mi sono fatto “spaventare” dalle temporizzazioni, dai microsecondi, mentre sono temporizzazioni minime. Ma se leggo “con calma” funziona ugualmente (comunque entro i 50 ms).

Praticamente il pin DATA è HIGH e passa a LOW quando il treno di 24bit è pronto per la trasmissione dalla schedina HX711 ad Arduino.

Allora invio 24 impulsi sul pin SCK e ad ogni impulso la schedina risponde con un bit sul pin DATA (HIGH=1 e LOW=0) che metto in una stringa.

Termino con un ulteriore impulso (oppure due oppure tre) per comunicare alla schedina con che amplificazione voglio la prossima lettura.

FINITO.

int data = 0;
String StringOne = "";

void setup() {

  pinMode(3, OUTPUT);
  pinMode(4, INPUT);

  digitalWrite (3,LOW);
  Serial.begin(9600);

}

void loop() {

  if (digitalRead (4) == LOW) { //quando è LOW mando 24 impulsi su D3 per leggere 24 bit su D4
    for (int i=0; i <= 23; i++){

      digitalWrite (3,HIGH);
      data = digitalRead (4);
      digitalWrite (3,LOW);

      StringOne = String(StringOne + String(data));      
    }

    digitalWrite (3,HIGH);
    delay (21);
    digitalWrite (3,LOW);

    Serial.println (StringOne);

    StringOne = "";

  }
}

La stringa di 1 e 0 è perfetta e pronta per la conversione in decimale senza l’uso di librerie…

Qualche idea per convertire una stringa di 24 caratteri in un numero decimale?

Se ho capito bene, e la stringa (oggetto String, che non conosco bene) di 24 elementi contiene esclusivamente 0 e 1 si potrebbe fare un lavoro tipo

long StringdiBooltoLong ()
{
long numero=0;
for (byte i=0;i<24;i++)
{
numero=numero*2+stringa [i];//so che non è così che si fa con le String, ma non so come si legga l'iesimo punto
}
return (numero);
}

Perdonate la non indentazione e gli errori, ma lo ho scritto al volo. Certamente esiste un modo più diretto operando direttamente con i bit.

Comunque credo che il problema non sia questo (troppo facie se no), e quindi non ho capito qualcosa.
Sappi solo che se stai parlando di una stringa di 24 char che codificano cifre non esiste un tipo dati abbastanza grosso.

String
toInt()
Description

Converts a valid String to an integer. The input string should start with an integer number. If the string contains non-integer numbers, the function will stop performing the conversion.

però in questo modo devi spezzarla in più parti

oppure prima la converti in char array
string.toCharArray(buf, len)
e poi uno ad uno li leggi

Patrick, forse non hai capito bene che la stringa è di ZERO e UNO, quindi binario.
E mi serve la conversione in numero DECIMALE.

String to Int la riporta a numerico, ma sempre binario è !

Silente, ho capito cosa intendi, ma non è così semplice...

Ho trovato questo:

int binary2decimal(byte b)
{

 int dec = 0;
 int power = 1;
 byte mask;
 int weight;
 
 for (mask = 0x01; mask; mask <<= 1)
 {
   if (b & mask)
   {
     weight = 1;    
   }
   else
   {
     weight = 0;    
   }
   
   dec = dec + (power * weight);  
   power = power * 2;
   
}
 
 return dec;
}

… ma non ho la più pallida idea di come usarlo… !!!

La strada più semplice era quella di Silente … solo che occorre semplificare e velocizzare … :slight_smile:

String sNum = "101010101010101010101010"; // la tua stringa a 24 caratteri

void setup() {
   byte i = 0;
   unsigned long Num = 0;
   //
   Serial.begin(115200);
   //
   for (i = 0; i < 24; i++) {
      if (sNum.charAt(i) == '1') {
         Num |= (1ul << (23-i));
      }
   }
   Serial.print("La stringa binaria  ");
   Serial.print(sNum);
   Serial.print(" corrisponde a ");
   Serial.println(Num);
}

void loop() {
   // put your main code here, to run repeatedly:

}

… attenzione che il ‘ul’ dopo il numero 1 (ovvero 1ul) è obbligatorio per indicare che stiamo lavorando con gli unsigned long … altrimenti 1 lo prende come un intero a 16 bit e … difficilmente può farne lo shift a 24 bit :wink:

Guglielmo