Quo Vadis ? Stories from a home laboratory

27Dec/1148

Hacking a weighing scale

HackingWeighingScale00

Last couple of weekends I mainly spent at home. This was ideal opportunity to do some home maintenance (cleaning :( ). Somewhere under the bed I found a weighing scale that my wife and I occasionally use. This is the simple digital weighing scale from Ikea - GRUNDTAL. During last months I stumbled upon couple of articles about automatic weight logging, so the outcome was obvious: the next home project - wireless logging weighing scale. Luckily I already had necessary tools and parts, so the next couple of days were fun.

IKEA GRUNDTAL Weghing scale

The idea was to connect the scale to Arduino Pro Mini, decode the readings from the scale, and send the weight wirelessly, using RFM12B radio module from HopeRF, to the central Homy system. There, the weight with the timestamp would be persisted into the database and published to Facebook wall.

The excellent starting point was project SdCardBathroomScale. Other useful resources were Hacking a digital bathroom scaleDigital Scale Strain Gauge Weight Sensor, ... I decided to use the simplest and the fastest approach - hooking to LCD signals, and decoding data sent to the display.

LCD display

Opening the scale was really simple; there are four screws to be unscrewed to access the inside of the scale. Then, six more screws to access the main circuit board of the scale. The nice surprise was that there were testing points for every pin going to LCD. I used these to solder "spy" cable. In addition to these, I soldered two more wires, one for GND and one for 5V, that would be used to power Arduino.

Soldering "spy" cable

After that I put the board back and fixed it with six screws. With that I finished hardware hacking part. Nice thing was that there was enough space left in the scale to put additional stuff like Arduino and wireless module.

"Spy" cable, 5V and GND

One important thing about the spy cable is to solder the wires in the same order as pins on the LCD; this will make things much easier later (I mixed up two wires, and was receiving some "crazy" numbers :( ) On the picture below, I marked the pins on the LCD as A, B, C, 1, 2, ..., 12.

Scale LCD pinout

The second step was to figure out how to decode the signals coming to LCD. Big help in understanding how this LCD works was a document describing LCD driver for  Z8 Encore!. After some probing, I came to the diagram that represents how LCD works in this scale and maps specific LED segment to the coresponding pin.

LCD display map

All the segments on the LCD are divided in 3 planes: A (green), B (yellow) and C (red) and 12 groups: 1, 2, ..., 12. All these (planes and groups) are mapped to specific pins, and by reading signal values, it would be possible to decode the value displayed on the scale using some simple acquisition algorithm and one multiple-output boolean function.

The third step was to connect the Arduino to the LCD and to connect the wireless module to the Arduino. After some soldering and testing all the connections, everything was ready for the next step.

Arduino pinout

Arduino Pro Mini, RFM12B module and weighing scale connected

The forth step was developing the program that will run on the Arduino. There were two important parts: decoding the LCD signals and optimizing the power consumption.

For the decoding part a combination of statistical methods and boolean function was used in order to have accurate readout of the display. For the power consumption part, interrupts and low power states were used. Minimizing the power consumption was necessary in order to maximize the life of 9V battery that was used to power the scale. I managed to go down with the consumption to 100μA.

This is the final program :

#include <JeeLib.h>
#include <SoftwareSerial.h>
#include <Streaming.h>
#include <avr/sleep.h>

#define DEBUG 0
#define THIS_NODE 15
#define DEST_NODE 13

#if DEBUG
	SoftwareSerial serial(0, 1);
#endif

int lcdA=0,lcdB=0,lcdC=0;

int pa,pb,pc;
bool lcd1,lcd2,lcd3,lcd4,lcd5,lcd6,lcd7,lcd8,lcd9,lcd10,lcd11,lcd12;

unsigned int SAn, SBn, SCn;
unsigned int SA[12], SB[12], SC[12];
bool A[12], B[12], C[12];

unsigned int _t;

int getDigit(int i, int j, int k)
{
	if ( A[i] &&  A[j] &&  true &&  B[i] && !B[j] &&  true &&  C[i] &&  C[j] &&  true) return 0;
	if ( A[i] && !A[j] &&  true &&  B[i] && !B[j] &&  true && !C[i] && !C[j] &&  true) return 1;
	if ( A[i] &&  A[j] &&  true && !B[i] &&  B[j] &&  true &&  C[i] &&  C[j] &&  true) return 2;
	if ( A[i] &&  A[j] &&  true &&  B[i] &&  B[j] && !B[k] &&  C[i] && !C[j] &&  true) return 3;
	if ( A[i] && !A[j] &&  true &&  B[i] &&  B[j] &&  true && !C[i] && !C[j] &&  true) return 4;
	if (!A[i] &&  A[j] &&  true &&  B[i] &&  B[j] &&  true &&  C[i] && !C[j] &&  true) return 5;
	if (!A[i] &&  A[j] &&  true &&  B[i] &&  B[j] &&  true &&  C[i] &&  C[j] &&  true) return 6;
	if ( A[i] &&  A[j] &&  true &&  B[i] && !B[j] &&  true && !C[i] && !C[j] &&  true) return 7;
	if ( A[i] &&  A[j] &&  true &&  B[i] &&  B[j] &&  true &&  C[i] &&  C[j] &&  true) return 8;
	if ( A[i] &&  A[j] &&  true &&  B[i] &&  B[j] &&  B[k] &&  C[i] && !C[j] &&  true) return 9;
	return 0;
}

void wakeUpNow()
{
}

void sleepNow()
{
	byte adcsraSave = ADCSRA;
	ADCSRA &= ~ bit(ADEN);
	byte prrSave = PRR;
	PRR &= 0xFF;

	attachInterrupt(1,wakeUpNow, CHANGE );

	set_sleep_mode(SLEEP_MODE_PWR_DOWN);
	sleep_enable();

	MCUCR = MCUCR | bit(BODSE) | bit(BODS);
	MCUCR = MCUCR & ~ bit(BODSE) | bit(BODS);

	sleep_cpu();
	sleep_disable();

	detachInterrupt(1);

	PRR = prrSave;
	ADCSRA = adcsraSave;

}

void setup() {
	#if DEBUG
		serial.begin(57600);
	#endif

	rf12_initialize(THIS_NODE, RF12_868MHZ);
	rf12_sleep(0);

	pinMode(3, INPUT);

	#if DEBUG
		serial << "Initialized..." << endl;
	#endif
}

void loop()
{
	#if DEBUG
		serial << "Going to sleep..."<< endl;
	#endif

	sleepNow();

	// waiting for display (interruption will continue from here)
	#if DEBUG
		serial << "Steped on the scale..." << endl;
	#endif

	// make sure that LCD is active
	_t = millis();
	while (lcdA<1023 && lcdB< 1023 && lcdC<1023 && (millis()-_t<10000))
	{
		lcdA = analogRead(A1);
		lcdB = analogRead(A2);
		lcdC = analogRead(A3);
	}

	// starts measuring
	#if DEBUG
		serial << "Measuring..." << endl;
	#endif
	SAn = SBn = SCn = 0;
	for (int i=0; i<8; i++)
	SA[i] = SB[i] = SC[i] = 0;
	int i=0;
	while (lcdA>0 || lcdB >0 || lcdC>0)
	{
		lcdA  = analogRead(A1);
		lcdB  = analogRead(A2);
		lcdC  = analogRead(A3);
		lcd1  = digitalRead(A4);
		lcd2  = digitalRead(A5);
		lcd3  = digitalRead(3);
		lcd4  = digitalRead(4);
		lcd5  = digitalRead(5);
		lcd6  = digitalRead(6);
		lcd7  = digitalRead(7);
		lcd8  = digitalRead(8);
		lcd9  = 0;
		lcd10 = digitalRead(9);
		lcd11 = digitalRead(A0);
		lcd12 = 0;

		// decode A, B and C signals to -1, 0, 1
		pa = 0;
		if (lcdA < 342) pa=-1; else if (lcdA > 683) pa=1;
		pb = 0;
		if (lcdB < 342) pb=-1; else if (lcdB > 683) pb=1;
		pc = 0;
		if (lcdC < 342) pc=-1; else if (lcdC > 683) pc=1;
		lcdA = pa; lcdB = pb; lcdC = pc;

		if (lcdA!=0 && lcdB==0 && lcdC==0 || lcdA==0 && lcdB!=0 && lcdC==0 || lcdA==0 && lcdB==0 && lcdC!=0)
		{
			if (lcdA==1 || lcdB==1 || lcdC==1)
			{
				lcd1 = 1-lcd1;
				lcd2 = 1-lcd2;
				lcd3 = 1-lcd3;
				lcd4 = 1-lcd4;
				lcd5 = 1-lcd5;
				lcd6 = 1-lcd6;
				lcd7 = 1-lcd7;
				lcd8 = 1-lcd8;
				lcd9 = 1-lcd9;
				lcd10 = 1-lcd10;
				lcd11 = 1-lcd11;
				lcd12 = 1-lcd12;
			}

			if (lcdA != 0)
			{
				SA[0] += lcd1;
				SA[1] += lcd2;
				SA[2] += lcd3;
				SA[3] += lcd4;
				SA[4] += lcd5;
				SA[5] += lcd6;
				SA[6] += lcd7;
				SA[7] += lcd8;
				SA[8] += lcd9;
				SA[9] += lcd10;
				SA[10] += lcd11;
				SA[11] += lcd12;
				SAn++;
			}
			if (lcdB != 0)
			{
				SB[0] += lcd1;
				SB[1] += lcd2;
				SB[2] += lcd3;
				SB[3] += lcd4;
				SB[4] += lcd5;
				SB[5] += lcd6;
				SB[6] += lcd7;
				SB[7] += lcd8;
				SB[8] += lcd9;
				SB[9] += lcd10;
				SB[10] += lcd11;
				SB[11] += lcd12;
				SBn++;
			}
			if (lcdC!=0)
			{
				SC[0] += lcd1;
				SC[1] += lcd2;
				SC[2] += lcd3;
				SC[3] += lcd4;
				SC[4] += lcd5;
				SC[5] += lcd6;
				SC[6] += lcd7;
				SC[7] += lcd8;
				SC[8] += lcd9;
				SC[9] += lcd10;
				SC[10] += lcd11;
				SC[11] += lcd12;
				SCn++;
			}

			i++;
		}

	}

	// measuring is done
	#if DEBUG
		serial << "Done..." << endl;
	#endif

	// finding the average of signals values during measuring period
	// not 100% correct, but the fastest way I could think of
	for (int i=0;i<12;i++)
	{
		A[i] = (1.0 * SA[i] / SAn >0.5);
		B[i] = (1.0 * SB[i] / SBn >0.5);
		C[i] = (1.0 * SC[i] / SCn >0.5);
	}

	// decoding
	float weight = 10.0*getDigit(6,7,8) + 1.0*getDigit(3,4,5) + 0.1*getDigit(0,1,2);

	/*
		#if DEBUG
		serial << "A ";
		for (int i=0;i		serial << " - ";
		serial << "B ";
		for (int i=0;i		serial << " - ";
		serial << "C ";
		for (int i=0;i		serial << " - ";
		#endif
	*/

	#if DEBUG
		serial << "Weight is " << weight << " kg" << endl;
	#endif
	if (weight > 5.0)
	{
		#if DEBUG
			serial << "Sending weight..." << endl;
		#endif

		rf12_sleep(-1);
		while (!rf12_canSend()) rf12_recvDone();
		rf12_sendStart(RF12_HDR_ACK | RF12_HDR_DST | DEST_NODE, &weight, sizeof(weight));
		rf12_sleep(0);

		#if DEBUG
			serial << "   ... sent!" << endl;
		#endif
	}
	else
	{
		#if DEBUG
			serial << "Sending skipped. Weight is below threshold value!" << endl;
		#endif
	}

	delay(200);
}

The last step was to collect the weight sent from the wireless enabled scale to the central Homy system. This information is persisted in database and posted to Facebook wall. This will not be described in this post, since it is similar to Facebook integration I have described in one of the previous posts.

Final look

And for the end, small video showing the whole functionality:

66,184 total views, 33 views today

Comments (48) Trackbacks (0)
  1. Did you know the Jeenode board ?
    It is an arduino compatible board with RFM12B integrated.

    • Sure… The central node of my home automation network is JeeNode, also some other attached devices (presence notification, irrigation control unit, …)

  2. Hi. I`m trying to follow this project but im having trouble getting a stable analogRead.
    -my LCD has 4 backplanes. im receiving around 0,215,430,645.
    -i already mapped the LCD by turning the segments on and off with digitalWrite.

    How can I translate this analogReads? whats ON and OFF? how can i get it stable?

    • Hello Bruno,

      As you could see in my code, I got 3 levels of signal (0-342, 342-683, 683-1000) that were coded as -1, 0, 1, and then depending on backplane signal (1, -1) encoded into 0 or 1.

      This might be totally different in your case.

      I would suggest you experiment with different polarity of backplane signal and different segment voltage levels to figure out coding in your case; I guess this is different with every LCD. Also, datasheet for LCD can help.

      Cheers.

  3. what is LCD part number?

  4. Hi Dušan,

    I am thinking on getting my hands on this project too .-).

    Can you please clarify if the Arduino pinout that you posted is complete?
    I think that there is no reference to pin number 9 on where it should be connected.

    Another question I have is that what kind of batteries does your weighting scale use?
    I ask because you refer two additional wires for 5v supply (for arduino and rfm12b) but in my case, my scale (also Grundtal) only uses two 1,5v AA batteries.

    Maybe I will need to change those two 1,5v batteries to a 9v battery and then add an LM7805 to limit the voltage…

    Your insights would be very helpful.
    Thanks

    • Hey Miguel,

      The pinout is correct. You can see also in code that pins 9 and 12 are not read. This I did on purpose, in order to save some pins since I had only 10 pins free on Arduino. You will be fine without this pin only in case you don’t have 9x kg (digits 3 and 9 will give the same readout), otherwise you would need to include it.

      My scale has 9V battery, so I didn’t have any problems with power source. Voltage regulator in your case would be an option.

  5. Hi Dušan,

    First of all, let me thank you for posting such great projects/hacks.
    Can I ask you what kind of device did you use to turn on/off those ceiling lamps? Did you dismantled the wall sockets you’ve shown in the pictures?

    Do you consider to allow access to the code of your applications?
    Once more, thanks for your projects.
    Best

  6. can you please give a pin diagram

  7. Hi Dušan,

    Finally I got it working! :-D
    I found that I had a hardware problem which caused the 7th bit to go high every time. I have posted the working sketch here: http://troels.leegaard.org/misc/grundtal20047/sketch.pde

    The sketch is for the Duemilanove as I’m still awaiting for a Mini Pro to arrive.
    Feel free to delete my previous posts as they’ll probably just confuse other visitors!

  8. Hi Dusan,

    I am now a bit closer to having it working. Right now I’m getting this output:


    Measuring...
    Done...
    A 000000000 - B 000000000 - C 000000000 - D 000000000
    Measuring...
    Done...
    A 000000000 - B 000011110 - C 000011110 - D 000011100
    Measuring...
    Done...
    A 000000000 - B 000000000 - C 000000000 - D 000000000
    Measuring...
    Done...
    A 000000000 - B 000000000 - C 000000000 - D 000000000
    Measuring...
    Done...
    A 000000000 - B 000000000 - C 000000000 - D 000000000
    Measuring...
    Done...
    A 000011111 - B 000000000 - C 000000000 - D 000000000

    It seems like the timing for when to start/stop counting is messed up, as the output should have been:
    A 000011111 – B 000011110 – C 000011110 – D 000011100

    Code can be found here: http://troels.leegaard.org/misc/scale.ino

    Do you think you can help me out on this?

    • I’m getting closer:


      A 000000000 - B 000000000 - C 000000000 - D 000000000
      A 000000000 - B 000000000 - C 000000000 - D 000000000
      A 000000000 - B 000000000 - C 000000000 - D 000000000
      A 000000000 - B 000000000 - C 000000000 - D 000000000
      A 000000000 - B 000000000 - C 000000000 - D 000000000
      A 000000000 - B 000000000 - C 000000000 - D 000000000
      A 001111100 - B 000000000 - C 000000000 - D 000000000
      A 001111100 - B 000000000 - C 000000000 - D 000000000
      A 000000000 - B 000000000 - C 000011110 - D 000000000
      A 000001010 - B 000000000 - C 000011110 - D 000000000
      A 000001010 - B 000000000 - C 000011110 - D 000000000
      A 000000000 - B 000000000 - C 000011110 - D 000000000
      A 000000000 - B 000000000 - C 000011110 - D 000000000
      A 000000000 - B 000000000 - C 000000000 - D 000000000
      A 000000000 - B 000000000 - C 000000000 - D 000000000
      A 000000000 - B 000001010 - C 000000000 - D 000000000
      A 000000000 - B 000001010 - C 000000000 - D 000000000
      A 000000000 - B 000000000 - C 000011110 - D 000000000
      A 000000000 - B 000001010 - C 000011110 - D 000000000
      A 000011111 - B 000001010 - C 000011110 - D 000000000
      A 000011111 - B 000001010 - C 000011110 - D 000000000
      A 000000000 - B 000000000 - C 000000000 - D 000011100
      A 000000000 - B 000000000 - C 000011110 - D 000011100
      A 000001010 - B 000001010 - C 000011110 - D 000011100
      A 000000000 - B 000000000 - C 000000000 - D 000000000
      A 000000000 - B 000000000 - C 000000000 - D 000000000
      A 000000000 - B 000000000 - C 000011110 - D 000000000
      A 000001010 - B 000000000 - C 000011110 - D 000000000
      A 000001010 - B 000000000 - C 000011110 - D 000000000

      Still aiming for the same result:
      A 000011111 – B 000011110 – C 000011110 – D 000011100

      But why is the result getting splitted?
      http://troels.leegaard.org/misc/closer.ino

      • Hi Dusan,

        Sorry for all the posts.. just made a little progress.. getting a lot more lines of output now, but the last outputted lines seems to be right every time now:


        A 000011110 - B 000001010 - C 000011110 - D 000011100
        A 000011110 - B 000001010 - C 000011110 - D 000011100
        A 000011110 - B 000001010 - C 000011110 - D 000011100
        A 000011110 - B 000001010 - C 000011110 - D 000011100
        A 000011110 - B 000001010 - C 000011110 - D 000011100

        • Hey…

          This already looks much better… Did you get any stable value afterall?

          • Hi Dusan,

            I’m now getting stable, but wrong, output (66.2kg):
            A 001111111 - B 001010010 - C 001111000 - D 001011000
            But unfortunately this should be:
            A 001111111 - B 001010110 - C 001111010 - D 001011000

            And this one (0.0kg):
            A 000011111 - B 000001110 - C 000011110 - D 000011000
            But this should be:
            A 000011111 - B 000001010 - C 000011110 - D 000011100

            I can’t figure out why this happens.. Code can be seen here: http://troels.leegaard.org/misc/better.ino

            Maybe if the averaged bits were calculated for only the last 10 or 100 values in array instead of the full array it would be more precise, but I cant figure out how to do that..

            Thanks for your time and interest! :-)

  9. Hi again,

    I got the Grundtal 20047 myself. As far as I can see Vince got mixed up the pin numbering. (Unless IKEA changed the display without changing the serial number)

    The pin arrangement I found is to be seen here: http://troels.leegaard.org/misc/grundtal20047.pdf

    I have made a small sketch (http://troels.leegaard.org/misc/unit.pde) which verifies the pin arrangement by checking backplane A and lcdpin 9 when outputting KG/LB/ST (can be changed on the back of the scale). In this case the backplanes are connected to analog inputs on the Arduino and lcdpin9 to a digital input. The backplane is low and the lcdpin high when the KG symbol is lid.

    I have been scratching my head getting further on, merging with your previous code – so any help will be much appreciated! :-)

  10. Hi Dusan,

    Did you and Vince ever solve the hacking of the 20047 model?

    I think I got the first part covered, but I have problems decoding the output..

    • Hello,

      I didn’t manage to follow Vince any further in his investigation. Maybe he can give some input here, in case he follows this discussion by any chance.

  11. Hey, I’m are doing a similar kind of project.
    I have been trying to understand your code, but have some problems with it..
    If you’re stil active here I’d have some questions :)

    Thanks
    Gard

    • Hi Gard,

      What is your project about? Feel free to drop any question.

      One part of the code (one handling decoding of LCD) is specific. Depending on LCD display this part needs to be changed (like in Vince’s case).

      • We are firstly trying to hook up a scale to an arduino. After that we’ll probably try to send the data online somewhere. We figured out the segments, here’s a link to the image: http://img13.imageshack.us/img13/5059/segmenttiwlevy.png
        I figured out the decoding part of the code, and I think your code would work for our display. We are still getting 0 weight, but we’ll keep debugging the code.
        We did make the program to print the values of ABC and first four segments, and we saw the backplanes go on and the required segments at the same time.

        Im not fully understand the part of the code with the if’s after decoding the 1,0,-1.
        the part with the SA[n],SB[n],SC[n].

        Thanks for your interest :)

        • The part with SA, SB, SC is all about trying to find the most common/frequent state of the segments from the moment LCD is turned on. Finding arithmetic median value gives correct weight in 99% of the cases.
          This is all because weight on LCD goes from 0 to target weight, and there is some flickering as well.

          Maybe this part could have been done in a much easier way, this was the first thing that came to my mind at that point :)

  12. Hi Dusan,

    dis you get an idea since I have put the last results ? Maybe you didn’t have time…I understand.

    Vince

  13. Hi Dusan,

    I went a little further in the code but now I’m stuck. I observed that the backplanes could take four different ranges, so four different states. So for lcdA, B, C, D, I do : if (lcdX == 0) px=-1; else if (lcdX >= 150 && lcdX = 350 && lcdX = 500) px=2;

    Now, for each measure of the same weight, I still have the following result (That’s a good news!): A 000111000 – B 001110100 – C 000000000 – D 000000000

    Now I have to understand how I can decode it, according to the lcd display map I drew http://www.arpege-studio.com/Grundtal/ and the Jata_Hogar_490 scale project.

    I already feel the headache arrived! If with these new elements, you have an idea to propose me.

    Thanks.
    Vince

    • Hi Vince,

      lcdX can take value 0 to 1024. Your if statement looks really strange.

      What is the weight you put on scale? What do you get in the console if you print out values for lcdA – lcdD, lcd1 – lcd9 in while loop?

      • Thanks for your quick answer Dusan.

        You’re right, bad copy/paste in my previous message for the lcdX, if statement.

        I put the sketch and the results you ask on my web server: http://www.arpege-studio.com/Grundtal/

        Vince

        • Try this:

          1) Swap A< ->C and B< ->D like this:

          lcdA = analogRead(A3);
          lcdB = analogRead(A4);
          lcdC = analogRead(A1);
          lcdD = analogRead(A2);

          2) Change decoding of A, B, C & D like :

          pa = 0;
          if (lcdA < 100) pa=1;
          pb = 0;
          if (lcdB < 100) pb=1;
          pc = 0;
          if (lcdC > 500) pc=1;
          pd = 0;
          if (lcdD > 500) pd=1;

          3) Extend the condition like this:

          if ((lcdA!=0 && lcdB==0 && lcdC==0 && lcdD==0 ||
          lcdA==0 && lcdB!=0 && lcdC==0 && lcdD==0 ||
          lcdA==0 && lcdB==0 && lcdC!=0 && lcdD==0 ||
          lcdA==0 && lcdB==0 && lcdC==0 && lcdD!=0) &&
          (lcd1!=0 || lcd2!=0 || lcd3!=0 || lcd4!=0 || lcd5!=0 || lcd6!=0 || lcd7!=0 || lcd8!=0 || lcd9!=0))

          4) lcd2 seems not to be conected, check the wire!

  14. Hi,
    In our case we have a 13 pin LCD, instead of the 15 pin shown above in your experiment. In this case, do we assign 3 pins for A,B,C, 1 for ground and the remaining 9 for the lcd displays? In this case it would mean we have three hex digits right? or is it possible to drive 4 lcd digits too?

    Thanks,
    Krishna

    • Hi Krishna,

      Are you using same scale (Grundtal)?

      In any case the LCD must be driven in a different way. No way I can tell what is the correct way to control the LCD in that case. I am afraid you need to figure it out by “playing” with LCD (as I did as well).

      Feel free to share your success once you have it figured out.

    • Hi Krishna,

      First of all, thanks for your tutorial Dusan !

      In fact I have the same problem that you. My scale is the Grundtal from IKEA but unfortunately I have only 13 pins on it.

      When the scale is On, I measure 1.44V between each lcd pins and GND. Don’t know if it’s usefull to know that.

      I have wired it like this: lcdA=>A1 / lcdB=>A2 / lcdC=>A3 / lcd1=>A4 / lcd2=>A5 / lcd3=>3 / lcd4=>4 / lcd5=>5 / lcd6=>6 / lcd7=>7 / lcd8=>8 / lcd9=>9 / lcd10=>A0

      Here is what I have in debug mode on the serial:
      A B C Weight is 0.00 kg
      Sending skipped. Weight is below threshold value!
      Going to sleep…
      Steped on the scale…
      Measuring…
      Done…

      Thanks for your help
      Vince

      • Hi Vince,

        From what you have described, it looks like either wiring or code is not working with your version of LCD.

        It is hard to say how that 13 pin display works. Try to find its serial number and some datasheet for it. Otherwise you would need to figure it out yourself.

        I found really good info on LCD decoding in http://code.google.com/p/casainho-projects/wiki/SdCardBathroomScale . Signals lcdA, lcdB and lcdC are backplane signals, and these guys are sync signals for the rest of the signals (lcd1-lcd?). You can not just measure DC voltage between 2 pins, you will not get usable value, and anyway the relevant voltage should be between backplane pin (lcdA, lcdB or lcdC) and segment pin (lcd1-lcd?).

        I suggest you guys use different approach, use 3V DC and apply it to lcdA (or lcdB, or lcdC) and other pins (lcd1-lcd?). In that way you would be able to figure out which pins are backplane and which are the segment pins. This is how I figured out what is each pin for.

        Good luck!

        • Hi Dusan,

          thanks for your explanations and the casainho-projects documentations. I followed your advice and found which pins are backplane and which are the segments pins. Here is the result: http://www.arpege-studio.com/Grundtal/

          Despite the code samples available, I fail to fit my case. I hope you can help me and that software’s part is a breeze for you!

          Regards.
          Vince

          • Hi Vince,

            This could be the code that works for your display:

            #include <JeeLib.h>
            #include <SoftwareSerial.h>
            #include <Streaming.h>
            #include <avr/sleep.h>
             
            #define DEBUG 0
            #define THIS_NODE 15
            #define DEST_NODE 13
             
            #if DEBUG
                SoftwareSerial serial(0, 1);
            #endif
             
            int lcdA=0,lcdB=0,lcdC=0,lcdD=0;
             
            int pa,pb,pc,pd;
            bool lcd1,lcd2,lcd3,lcd4,lcd5,lcd6,lcd7,lcd8,lcd9;
             
            unsigned int SAn, SBn, SCn, SDn;
            unsigned int SA[9], SB[9], SC[9], SD[9];
            bool A[9], B[9], C[9], D[9];
             
            unsigned int _t;
             
            int getDigit(int d)
            {
            	// d=0,1,2,3
            	// 
            	int i = 2*d+1;
            	int j = 2*d+2;
            	
                if ( A[i] &&  A[j] &&  B[i] && !B[j] &&  C[i] &&  C[j] &&  D[j]) return 0;
                if (!A[i] && !A[j] &&  B[i] && !B[j] &&  C[i] && !C[j] && !D[j]) return 1;
                if ( A[i] && !A[j] &&  B[i] &&  B[j] && !C[i] &&  C[j] &&  D[j]) return 2;
                if ( A[i] && !A[j] &&  B[i] &&  B[j] &&  C[i] && !C[j] &&  D[j]) return 3;
                if (!A[i] &&  A[j] &&  B[i] &&  B[j] &&  C[i] && !C[j] && !D[j]) return 4;
                if ( A[i] &&  A[j] && !B[i] &&  B[j] &&  C[i] && !C[j] &&  D[j]) return 5;
                if ( A[i] &&  A[j] && !B[i] &&  B[j] &&  C[i] &&  C[j] &&  D[j]) return 6;
                if ( A[i] && !A[j] &&  B[i] && !B[j] &&  C[i] && !C[j] && !D[j]) return 7;
                if ( A[i] &&  A[j] &&  B[i] &&  B[j] &&  C[i] &&  C[j] &&  D[j]) return 8;
                if ( A[i] &&  A[j] &&  B[i] &&  B[j] &&  C[i] && !C[j] &&  D[j]) return 9;
                return 0;
            }
             
            void wakeUpNow()
            {
            }
             
            void sleepNow()
            {
                byte adcsraSave = ADCSRA;
                ADCSRA &= ~ bit(ADEN);
                byte prrSave = PRR;
                PRR &= 0xFF;
             
                attachInterrupt(1,wakeUpNow, CHANGE );
             
                set_sleep_mode(SLEEP_MODE_PWR_DOWN);
                sleep_enable();
             
                MCUCR = MCUCR | bit(BODSE) | bit(BODS);
                MCUCR = MCUCR & ~ bit(BODSE) | bit(BODS);
             
                sleep_cpu();
                sleep_disable();
             
                detachInterrupt(1);
             
                PRR = prrSave;
                ADCSRA = adcsraSave;
             
            }
             
            void setup() {
                #if DEBUG
                    serial.begin(57600);
                #endif
             
                rf12_initialize(THIS_NODE, RF12_868MHZ);
                rf12_sleep(0);
             
                pinMode(3, INPUT);
             
                #if DEBUG
                    serial << "Initialized..." << endl;
                #endif
            }
             
            void loop()
            {
                #if DEBUG
                    serial << "Going to sleep..."<< endl;
                #endif
             
                sleepNow();
             
                // waiting for display (interruption will continue from here)
                #if DEBUG
                    serial << "Steped on the scale..." << endl;
                #endif
             
                // make sure that LCD is active
                _t = millis();
                while (lcdA<1023 && lcdB< 1023 && lcdC<1023 && lcdD<1023 &&(millis()-_t<10000))
                {
                    lcdA = analogRead(A1);
                    lcdB = analogRead(A2);
                    lcdC = analogRead(A3);
            		lcdD = analogRead(A4);
                }
             
                // starts measuring
                #if DEBUG
                    serial << "Measuring..." << endl;
                #endif
                SAn = SBn = SCn = SDn = 0;
                for (int i=0; i<9; i++)
            		SA[i] = SB[i] = SC[i] = SD[i] = 0;
                int i=0;
                while (lcdA>0 || lcdB >0 || lcdC>0 || lcdD>0)
                {
                    lcdA  = analogRead(A1);
                    lcdB  = analogRead(A2);
                    lcdC  = analogRead(A3);
            		lcdD  = analogRead(A4);
            		
                    lcd1  = digitalRead(A5);
                    lcd2  = digitalRead(A6);
                    lcd3  = digitalRead(3);
                    lcd4  = digitalRead(4);
                    lcd5  = digitalRead(5);
                    lcd6  = digitalRead(6);
                    lcd7  = digitalRead(7);
                    lcd8  = digitalRead(8);
                    lcd9  = digitalRead(9);
             
                    // decode A, B, C and D signals to -1, 0, 1
                    pa = 0;
                    if (lcdA < 342) pa=-1; else if (lcdA > 683) pa=1;
                    pb = 0;
                    if (lcdB < 342) pb=-1; else if (lcdB > 683) pb=1;
                    pc = 0;
                    if (lcdC < 342) pc=-1; else if (lcdC > 683) pc=1;
                    pd = 0;
                    if (lcdD < 342) pd=-1; else if (lcdD > 683) pd=1;
            		lcdA = pa; lcdB = pb; lcdC = pc; lcdD = pd;
             
                    if (lcdA!=0 && lcdB==0 && lcdC==0 && lcdD==0 || 
            			lcdA==0 && lcdB!=0 && lcdC==0 && lcdD==0 || 
            			lcdA==0 && lcdB==0 && lcdC!=0 && lcdD==0 || 
            			lcdA==0 && lcdB==0 && lcdC==0 && lcdD!=0)
                    {
                        if (lcdA==1 || lcdB==1 || lcdC==1 || lcdD==1)
                        {
                            lcd1 = 1-lcd1;
                            lcd2 = 1-lcd2;
                            lcd3 = 1-lcd3;
                            lcd4 = 1-lcd4;
                            lcd5 = 1-lcd5;
                            lcd6 = 1-lcd6;
                            lcd7 = 1-lcd7;
                            lcd8 = 1-lcd8;
                            lcd9 = 1-lcd9;
                        }
             
                        if (lcdA != 0)
                        {
                            SA[0] += lcd1;
                            SA[1] += lcd2;
                            SA[2] += lcd3;
                            SA[3] += lcd4;
                            SA[4] += lcd5;
                            SA[5] += lcd6;
                            SA[6] += lcd7;
                            SA[7] += lcd8;
                            SA[8] += lcd9;
                            SAn++;
                        }
                        if (lcdB != 0)
                        {
                            SB[0] += lcd1;
                            SB[1] += lcd2;
                            SB[2] += lcd3;
                            SB[3] += lcd4;
                            SB[4] += lcd5;
                            SB[5] += lcd6;
                            SB[6] += lcd7;
                            SB[7] += lcd8;
                            SB[8] += lcd9;
                            SBn++;
                        }
                        if (lcdC!=0)
                        {
                            SC[0] += lcd1;
                            SC[1] += lcd2;
                            SC[2] += lcd3;
                            SC[3] += lcd4;
                            SC[4] += lcd5;
                            SC[5] += lcd6;
                            SC[6] += lcd7;
                            SC[7] += lcd8;
                            SC[8] += lcd9;
                            SCn++;
                        }
                        if (lcdD!=0)
                        {
                            SD[0] += lcd1;
                            SD[1] += lcd2;
                            SD[2] += lcd3;
                            SD[3] += lcd4;
                            SD[4] += lcd5;
                            SD[5] += lcd6;
                            SD[6] += lcd7;
                            SD[7] += lcd8;
                            SD[8] += lcd9;
                            SDn++;
                        }			
             
                        i++;
                    }
             
                }
             
                // measuring is done
                #if DEBUG
                    serial << "Done..." << endl;
                #endif
             
                // finding the average of signals values during measuring period
                // not 100% correct, but the fastest way I could think of
                for (int i=0;i<9;i++)
                {
                    A[i] = (1.0 * SA[i] / SAn >0.5);
                    B[i] = (1.0 * SB[i] / SBn >0.5);
                    C[i] = (1.0 * SC[i] / SCn >0.5);
            		D[i] = (1.0 * SD[i] / SDn >0.5);
                }
             
             
            	#if DEBUG
            	serial << "A ";
            	for (int i=0;i<9;i++) serial << (A[i]?"1":"0");
            	serial << " - ";
            	serial << "B ";
            	for (int i=0;i<9;i++) serial << (B[i]?"1":"0");
            	serial << " - ";
            	serial << "C ";
            	for (int i=0;i<9;i++) serial << (C[i]?"1":"0");
            	serial << " - ";
            	serial << "D ";
            	for (int i=0;i<9;i++) serial << (D[i]?"1":"0");
            	serial << " - ";
            	#endif
              
                // decoding
                float weight = 100.0*getDigit(3) + 10.0*getDigit(2) + 1.0*getDigit(1) + 0.1*getDigit(0);
              
                #if DEBUG
                    serial << "Weight is " << weight << " kg" << endl;
                #endif
                if (weight > 5.0)
                {
                    #if DEBUG
                        serial << "Sending weight..." << endl;
                    #endif
             
                    rf12_sleep(-1);
                    while (!rf12_canSend()) rf12_recvDone();
                    rf12_sendStart(RF12_HDR_ACK | RF12_HDR_DST | DEST_NODE, &weight, sizeof(weight));
                    rf12_sleep(0);
             
                    #if DEBUG
                        serial << "   ... sent!" << endl;
                    #endif
                }
                else
                {
                    #if DEBUG
                        serial << "Sending skipped. Weight is below threshold value!" << endl;
                    #endif
                }
             
                delay(200);
            }
            

            Basically, additional variables for backplane signal D are added and getDigit function is adopted. In case of bad values, investigate about encoding/decoding 7 segment display; this could help about getDigit function.

            Hope this helped.

          • Hi Dusan,

            really appreciate your help! Unfortunately, it’s still doesn’t work. I’ve tried with d=0, d=1, d=2, d=3 and I always get the same result:
            A 000000000 – B 000000000 – C 000000000 – D 000000000 – Weight is 0.00 kg

            I have found another link that explain how to hack a weighing scale and this Jata Hogar scale got the same LCD (I’ve checked the 13 pins with my scope) than the new one they put in the Grundtal N° 20047. But the project isn’t written for the Arduino…too bad for me !
            http://code.google.com/p/casainho-projects/wiki/SdCardBathroomScale#Technical_details_–_Scale_Jata_Hogar_490

            If you don’t have time to explore this for me, could you just tell me what is the serial number of your Grundtal scale please ? I think it could be 20325: http://img.2ememain.be/f/normal/97732486_1-ikea-grundtal-personenweegschaal.jpg

            Thanks again.
            Vince

          • Hi,

            From what I can remmember, waveforms were more like for Scale Fagor BB-90. Algorithm in my code handles decoding that kind of waveforms. I suggest you deep little in the code and compare it with the one for your display. Let me know how it went.

            Scale serial is 20325, it lookes exactly like in that picture.

  15. Hi,

    great job, I am working on something similar, just using SI labs RF Dev kit.
    I tried your bathroom scale code for Arduino, but it doesn’t compile, I think it got somehow mangled when converted for web. Would you care to post the original source code somewhere?

    thanks.

  16. Ah should’ve looked around a little more closely on your blog before asking. This Homy thing is AWESOME! Great work, and thank you so much for sharing!!

  17. Quick question on this. What were you communicating with wirelessly outside of the scale? I assume the radio described can’t connect to a wifi network, so did you just build another arduino module with another RFM12B transmitter on it and hook that up to your computer for the Facebook posting part?

    Really cool project! I started researching this exact thing yesterday and I’m excited to build my own!


Leave a comment

No trackbacks yet.