Sari la conținut
ELFORUM - Forumul electronistilor

HX711 si MikroC


Stefan

Postări Recomandate

Are cineva un exemplu de program in MikroC pentru citirea ADC-ului HX711? Am folosit biblioteca asta http://libstock.mikroe.com/projects/view/1568/hx711-library dar citesc valori aiurea (seamana cu ce trebuie dar nu "rasare"). Unele functii din biblioteca nu sunt convins ca functioneaza corect dau nu am intepes cum se folosesc si PDF-ul cu "Ajutor" are greseli. Cu ATmega328 (exemple arduino) am citit HX711 din prima, deci e exclusa o greseala hardware.Nu ma intrebati de ce vreau sa folosc MikroC.Multumesc.

Link spre comentariu
  • Răspunsuri 9
  • Creat
  • Ultimul Răspuns

Top autori în acest subiect

  • mars01

    5

  • Stefan

    3

  • cristi7521

    1

Salut,

 

Astept si eu placutele cu HX711 asa ca am portat un driver Arduino in mikroC pentru PIC16F (am preluat de aici: https://codebender.cc/library/HX711#HX711.cpp.

Nu l-am incercat, posteaza si tu un feedback aici daca ai timp sa il incerci.

 

Fisierul header HX711.h

#ifndef HX711_H#define HX711_H#define HIGH   1#define LOW    0#define OUTPUT 0#define INPUT  1typedef unsigned char uint8t;typedef signed char   int8t;typedef signed int    int16t;typedef unsigned int  uint16t;typedef unsigned long  uint32t;typedef signed long  int32t;extern sfr sbit SCK;extern sfr sbit SCK_dir;extern sfr sbit DOUT;extern sfr sbit DOUT_dir;// check if HX711 is ready// from the datasheet: 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.uint8t is_ready();// set the gain factor; takes effect only after a call to read()// channel A can be set for a 128 or 64 gain; channel B has a fixed 32 gain// depending on the parameter, the channel is also set to either A or Bvoid set_gain(uint8t gain);// waits for the chip to be ready and returns a readinguint32t read();// returns an average reading; times = how many times to readuint32t read_average(uint8t times);// returns (read_average() - OFFSET), that is the current value without the tare weight; times = how many readings to dofloat get_value(uint8t times );// returns get_value() divided by SCALE, that is the raw value divided by a value obtained via calibration// times = how many readings to dofloat get_units(uint8t times);// set the OFFSET value for tare weight; times = how many times to read the tare valuevoid tare(uint8t times);// set the SCALE value; this value is used to convert the raw data to "human readable" data (measure units)void set_scale(float scale);// set OFFSET, the value that's subtracted from the actual reading (tare weight)void set_offset(int32t offset);// puts the chip into power down modevoid power_down();// wakes up the chip after power down modevoid power_up();#endif /* HX711_H */

Fisierul sursa HX711.c

#include "HX711.h"uint8t GAIN;int32t OFFSET;float SCALE;uint8t is_ready() {   return DOUT == LOW;}void set_gain(uint8t 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;   }   SCK = LOW;   read();}uint32t read() {   uint8t i,j;   uint8t data_read[3];      // wait for the chip to become ready        while (is_ready() == 0);        // pulse the clock pin 24 times to read the data        for (j = 3; j--;) {            for (i = 8; i--;) {                SCK = HIGH;                  if (DOUT) {                    data_read[j] |= (1 << i);                  }                  else {                    data_read[j] &= ~(1 << i);                  }                SCK = LOW;        }   }  // set the channel and the gain factor for the next reading using the clock pin  for (i = 0; i < GAIN; i++) {    SCK = HIGH;    SCK = LOW;  }   data_read[2] ^= 0x80;   return ((uint32t) data_read[2] << 16) | ((uint32t) data_read[1] << 8) | (uint32t) data_read[0];}uint32t read_average(uint8t times) {   uint32t sum = 0;   uint8t i;   for (i = 0; i < times; i++) {      sum += read();   }   return sum / times;}float get_value(uint8t times) {   return read_average(times) - OFFSET;}float get_units(uint8t times) {   return get_value(times) / SCALE;}void tare(uint8t times) {   float sum = read_average(times);   set_offset(sum);}void set_scale(float scale) {   SCALE = scale;}void set_offset(int32t offset) {   OFFSET = offset;}void power_down() {   SCK = LOW;   SCK = HIGH;}void power_up() {   SCK = LOW;}

Atasat ai un proiect netestat cu un exemplu.

HX711.zip

Editat de mars01
Link spre comentariu

@mars01 Nu am respectivul microcontroller asa ca am recompilat pentru 16F887 cu LCD-ul la portul D.

La fiecare alimentare obtin cate o alta valoare si asa sta indiferent cat apas pe senzorii de greutate. Exemplu: 2513714176,  2066951522, 2228015744, 4133903104, 3053755136.

Daca am valoarea 3053755136 si scot comunicatia de la HX711 obtin 3062160640. Fara HX711 conectat la PIC se comporta asemanator.

 

Intre 16F887 si HX711 am 20cm de fir iar cele doua liniile SCK si DO nu sunt "trase" spre plus sau minus.

 

Legat de codul din CCS nu am incercat nimic.

 

De ce GAIN primeste valorile respective? Nu trebuia 25, 27, 26? :84

 

void set_gain(uint8t 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; } SCK = LOW; read();}

 

...

 

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

Link spre comentariu

Daca citim datasheet-ul (lucru care din lene nu l-am facut decat dupa ce am portat codul - daca o faceam inainte de portare probabil ca nici nu imi mai bateam capul sa caut pe net dupa un cod ci il faceam din start eu) o sa vedem ca lucrul cu acest cip este extrem de usor. Nu are registri, totul se face din timing-uri si numar de biti.

 

Cu alte cuvinte.

 

Primim cei 24 de biti care contin informatia, pe 24 pulsuri ale clock-ului (clock-ul este trimis de ucontroller). Daca dupa acesti 24 de biti (primiti pe 24 pulsuri clock) mai trimitem un puls clock atunci urmatoarea citire (cei 24 de biti) va fi cu un gain 128 (automat se selecteaza canalul A).

Daca dupa cele 24 de pulsuri clock (pentru a "extrage cei 24 de biti de informatie - pe pinul SDO) trimitem inca doua pulsuri de clock atunci urmatoarea citire se va face cu un gain 32 (se selecteaza automat canalul B).

Daca trimitem insa 3 pulsuri de clock suplimentare atunci urmatoarea citire se va face cu un gain 64 si se selecteaza automat canalul A.

 

Posted Image

Secventa:

SCK = HIGH;SCK = LOW;

Genereaza un puls de clock pe iesirea controlerului, un pin botezat in program SCK (in realitate este un pin fizic, putem sa alegem orice pin controller care se poate seta ca iesire digitala).

 

Daca pulsul de HIGH pe CLK dureaza mai mult de 60us atunci cipul intra in modul power down. Deci trebuie sa facem pulsurile de clock mai rapid de 60us ca sa nu punem cipul in power down. 

 

Ce mai trebuie stiut este ca informatia din cei 24 de biti este stocata in complement fata de 2 pentru a putea stoca valorile negative primite pe intrarea diferentiala.

 

 

In datasheet este un exemplu de driver minimal in C:

// atribuim anumiti pini unor variabile, cea de date, ADDO, si cea de clock, ADSKsbit ADDO = P1^5;  // se asociaza un pin controler variabilei ADDO - al 5-lea din portul 1 ?sbit ADSK = P0^0;  // se asociaza un pin controler variabilei ADSK - pinul 0 din portul 0 ?// functia de citire ADCunsigned long ReadCount(void){  unsigned long Count; // variabila care va contine informatia citita din ADC  unsigned char i;   // variabila contor pentru ciclul FOR  ADDO=1;   // se initializeaza variabila care contine informatia DATA cu 1 pentru a putea incepe procesul de shiftare cu un 1 logic pe bitul 0  ADSK=0; // clockul este LOW  Count=0; // informatia citita din ADC este la acest moment, nula  while(ADDO); // cat timp citim HIGH pe pinul asociat ADDO stai si asteapta LOW-ul care indica activitate ADC  for (i=0;i<24;i++){ // executam de 24 de ori continutul buclei     ADSK=1;  // facem pinul clock HIGH si astfel incepem un puls de clock    Count=Count<<1; // shiftam la stanga variabila Count care contine rezultatul     ADSK=0; // facem pinul clock LOW si astfel finalizam un puls clock - deci vor fi 24 de pulsuri clock    if(ADDO) Count++; // daca pe pinul de date asociat variabilei ADDO avem un HIGH atunci fa bitul 0 din rezultat HIGH - si va fi shiftat data viitoare la stanga  }  ADSK=1; // pinul clock HIGH - incepem un puls de clock  Count=Count^0x800000; // facem toggle la bitul cel mai semnificativ  ADSK=0; // pinul clock LOW - finalizam pulsul de clock si cum este un singur puls in final avem 24 + 1 = 25 pulsuri de clock deci un GAIN de 128.  return(Count); // returnam valoarea citita de ADC.} 
Editat de mars01
Link spre comentariu

Mda, asa se intampla cand doar portezi codul altuia. Functia read() este gresita, mai exact ofera datele in complementul lui doi. Practic ce iese din functie trebuie inversat bit cu bit si adunat cu 1.

Maine revin cu o biblioteca corectata.

Link spre comentariu

Poti folosi urmatoarea functie corectata. Diferenta este ca in program va trebui sa testezi valoarea  bitului 31 din rezultatul functiei pentru a afla:

- daca este 1 atunci rezultatul este unul negativ, asigura-te ca faci bitul acesta LOW inainte de a folosi rezultatul

- daca este 0 atunci rezultatul este unul pozitiv si il folosesti ca atare

 

Ceva de genul (programul postat mai sus in arhiva trebuie modificat):

enum semn {pozitiv;negativ;};res = read();if (res) {   res ^= 0x80000000;   semn = negativ;   // codul tau      ......   }else {   semn = pozitiv;   // codul tau} 

Si functia modificata:

uint32t read() {   uint8t i,j;   uint8t data_read[3];   uint32t result;   // wait for the chip to become ready        while (is_ready() == 0);        // pulse the clock pin 24 times to read the data        for (j = 3; j--;) {            for (i = 8; i--;) {                SCK = HIGH;                  if (DOUT) {                    data_read[j] |= (1 << i);                  }                  else {                    data_read[j] &= ~(1 << i);                  }                SCK = LOW;        }   }  // set the channel and the gain factor for the next reading using the clock pin  for (i = 0; i < GAIN; i++) {    SCK = HIGH;    SCK = LOW;  }  // if the reading is a negative one, bit23 is HIGH then,  if (data_read[2] & 0x80) {    // invert each bit in the result    data_read[2] = ~data_read[2];    data_read[1] = ~data_read[1];    data_read[0] = ~data_read[0];        // put everything into a LONG variable and add 1    result = (((uint32t) data_read[2] << 16) | ((uint32t) data_read[1] << 8) | ((uint32t) data_read[0])) + 1;        /* on bit 31 place a HIGH value so when you get in the main program this bit with  HIGH  value,    you'll know you have a negative value    Make sure that after you tested this bit, if HIGH you make this bit LOW so it will not be interpreted as a uint32 negative value    */    result |= 0x80000000;    return result;  }  else {    return ((uint32t) data_read[2] << 16) | ((uint32t) data_read[1] << 8) | (uint32t) data_read[0];  }}
Editat de mars01
Link spre comentariu
  • 4 luni mai târziu...
Vizitator NicolaPr

Hello everybody. Thank very much Mars01 for ported code. I took it as a basis for mikroC, but during the week the library reworked under my requirements and i found a few mistakes. The most serious error is incorrectly read RAW data from the HX711. After a few days spent in the shuffle, the solution to this problem was very trivial. I added a delay of one microsecond between the pulses. I think Arduino working more slowly than PIC16 so in the original library is not necessary. The second mistake is the use of unsigned variables while the HX711 outputs 24 bits of signed data +/-. I also tried to reduce memory consumption by replacing 32-bit to 16-bit and remove floating point. So, here is my library and photos. Thank you all for your help! Posted ImagePosted Imagehttp://homus.com.ua/hx711/HX711_NicolaPr.zip

http://homus.com.ua/hx711/schematic.jpg

http://homus.com.ua/hx711/IMG_4207_.JPG

Editat de NicolaPr
Link spre comentariu

Good job Nicola,

 

At the moment when I've ported the code I had no HX711 IC (or board) available so I could not test it. In the meantime I did receive the boards ordered from eBay but ... I kind of drifted toward other projects and did not take the time to actually test the ported code.

So thank you for doing this work and posting it here so others can benefit from it.

Editat de mars01
Link spre comentariu

Creează un cont sau autentifică-te pentru a adăuga comentariu

Trebuie să fi un membru pentru a putea lăsa un comentariu.

Creează un cont

Înregistrează-te pentru un nou cont în comunitatea nostră. Este simplu!

Înregistrează un nou cont

Autentificare

Ai deja un cont? Autentifică-te aici.

Autentifică-te acum



×
×
  • Creează nouă...

Informații Importante

Am plasat cookie-uri pe dispozitivul tău pentru a îmbunătății navigarea pe acest site. Poți modifica setările cookie, altfel considerăm că ești de acord să continui.Termeni de Utilizare si Ghidări