Go Down

Topic: MAX7219 As Bar-Graph (Read 325 times) previous topic - next topic

LEDMaestro101

May 16, 2019, 05:30 pm Last Edit: May 16, 2019, 05:35 pm by LEDMaestro101
OK, First post so I apologise in advance if I haven't put this question in the correct section!

I'm back programming arduinos after about 5 years being out of it. I'm trying to create a temperature display using a Nano, DS1621 and MAX7219 and the LedControl library.

I have a "working" code but I want to know how to condense it as it is obscenely convoluted!! So much so that I have exceeded the maximum characters for the forum!

My code is made up of a couple of examples with some of my own code throw in for the display. I know this can be simplified but neither my days spent trying nor googling seem to have produced anything.

I can easily control the LED's but I cant seem to "map" the DS1621 values to the Max7219, no matter what I try, the max always outputs the raw data from the DS1621 as binary (Obviously I suppose). I can't seem to get it to display the read temperature (tC) as the corresponding amount of LED's, 25 led's lit for 25°C read for example.

every other similar type of project outputs the temp as numbers on a display, I'm trying to output like a bar graph across 50 LED's, something I haven't come across in my searches, hence my landing here to ask for help lol. I hope I have explained this well enough. If not then please let me know and I'll add more explanation. TIA


The convoluted, part 1:

Code: [Select]
if ( tC == 0){
    for (int i=0; i<8; i++){
  lc.setRow(0,i,zero[i]);
  }
}
  else;
 
  if ( tC == 1){
    for (int i=0; i<8; i++){
  lc.setRow(0,i,one[i]);
  }
}


The convoluted, part 2:

Code: [Select]
byte zero[8]=     {B10000000,B00000000,B00000000,B00000000,B00000000,B00000000,B00000000,B00000000};
byte one[8]=      {B11000000,B00000000,B00000000,B00000000,B00000000,B00000000,B00000000,B00000000};

PaulRB

Code: [Select]
  else;
I think that is a mistake - the semicolon ends the "else" part, so that the following "if" becomes a completely separate "if" to the previous "if". It is not an "else if" as you intended.  This isn't really what you were asking for help about, but it may make the code slightly slower to execute, and I thought I should let you know.

LEDMaestro101

yeah I realised after I uploaded that the else; statements are very much redundant. Thanks for pointing it out though!

PaulRB

#3
May 16, 2019, 06:01 pm Last Edit: May 16, 2019, 06:04 pm by PaulRB
try something like this:
Code: [Select]

  byte row = tC >> 3;
  byte rowBits = (1 << (tC & 7)) - 1;

  for (int i=0; i<8; i++) {
    if (tC < row)
      lc.setRow(0, i, 0b11111111);
    else if (tC > row)
      lc.setRow(0, i, 0b00000000);
    else
      lc.setRow(0, i, rowBits);
  }




LEDMaestro101

Hummm, doesn't seem to be outputting anything to the display now. I notice you're using bit shifting, that was my first go to method to try and map the raw data from the sensor to the MAX display but I had no luck :(

PaulRB

It was slightly wrong. Try:
Code: [Select]

  byte rowBits = (1 << ((tC & 7) + 1)) - 1;


However... even that first version should have output something.

Need to see your full code now. Should be much, much shorter than before and able to post with code tags.

LEDMaestro101

Hi, Thanks for the update. Still not displaying anything but that might be down to me putting the code in the wrong place. I do have the "byte zero[8]=…" going up to 50 but omitted them for the sake of being able to post the code here.

As I previously stated, the temperature reading part of the code was from another post on this fine forum (can't remember who exactly) so all I'm trying to do is display one dot on the display for each x°C read into tC.

Code: [Select]
#include <Wire.h>
#include <binary.h>
#include <LedControl.h>

// SDA pin is Analog4
// SCL pin is Analog5
// DS1621 has A2, A1, and A0 pins connected to GND


// device ID and address

#define DEV_TYPE   0x90 >> 1                    // shift required by wire.h
#define DEV_ADDR   0x00                         // DS1621 address is 0
#define SLAVE_ID   DEV_TYPE | DEV_ADDR

// DS1621 Registers & Commands

#define RD_TEMP    0xAA                         // read temperature register
#define ACCESS_TH  0xA1                         // access high temperature register
#define ACCESS_TL  0xA2                         // access low temperature register
#define ACCESS_CFG 0xAC                         // access configuration register
#define RD_CNTR    0xA8                         // read counter register
#define RD_SLOPE   0xA9                         // read slope register
#define START_CNV  0xEE                         // start temperature conversion
#define STOP_CNV   0X22                         // stop temperature conversion

// DS1621 configuration bits

#define DONE       B10000000                    // conversion is done
#define THF        B01000000                    // high temp flag
#define TLF        B00100000                    // low temp flag
#define NVB        B00010000                    // non-volatile memory is busy
#define POL        B00000010                    // output polarity (1 = high, 0 = low)
#define ONE_SHOT   B00000001                    // 1 = one conversion; 0 = continuous conversion

LedControl lc=LedControl(11,13,10,1);

byte zero[8]=     {B10000000,B00000000,B00000000,B00000000,B00000000,B00000000,B00000000,B00000000};
byte one[8]=      {B11000000,B00000000,B00000000,B00000000,B00000000,B00000000,B00000000,B00000000};
byte two[8]=      {B11100000,B00000000,B00000000,B00000000,B00000000,B00000000,B00000000,B00000000};
byte three[8]=    {B11100000,B00000000,B00000000,B00000000,B00000000,B00000000,B00000000,B00000000};
byte four[8]=     {B11110000,B00000000,B00000000,B00000000,B00000000,B00000000,B00000000,B00000000};
byte five[8]=     {B11111000,B00000000,B00000000,B00000000,B00000000,B00000000,B00000000,B00000000};
byte six[8]=      {B11111100,B00000000,B00000000,B00000000,B00000000,B00000000,B00000000,B00000000};
byte seven[8]=    {B11111110,B00000000,B00000000,B00000000,B00000000,B00000000,B00000000,B00000000};
byte eight[8]=    {B11111111,B00000000,B00000000,B00000000,B00000000,B00000000,B00000000,B00000000};
byte nine[8]=     {B11111111,B10000000,B00000000,B00000000,B00000000,B00000000,B00000000,B00000000};
byte ten[8]=      {B11111111,B11000000,B00000000,B00000000,B00000000,B00000000,B00000000,B00000000};
byte eleven[8]=   {B11111111,B11100000,B00000000,B00000000,B00000000,B00000000,B00000000,B00000000};


void setup()
{
 Wire.begin();                                 // connect I2C
 startConversion(false);                       // stop if presently set to continuous
 setConfig(POL | ONE_SHOT);                    // Tout = active high; 1-shot mode
 setThresh(ACCESS_TH, 51);                     // high temp threshold = 80F
 setThresh(ACCESS_TL, 0);                     // low temp threshold = 75F

 Serial.begin(9600);
 delay(5);
 Serial.println("DS1621 Demo");

 int tHthresh = getTemp(ACCESS_TH);
 Serial.print("High threshold = ");
 Serial.println(tHthresh);

 int tLthresh = getTemp(ACCESS_TL);
 Serial.print("Low threshold = ");
 Serial.println(tLthresh);

  lc.shutdown(0,false);                   // turn off power saving, enables display
  lc.setIntensity(0,12);                  // sets brightness (0~15 possible values)
  lc.clearDisplay(0);                     // clear screen
}


void loop()
{
 int tC, tFrac;

 tC = getHrTemp();                             // read high-resolution temperature

 if (tC < 0) {
   tC = -tC;                                   // fix for integer division
   Serial.print("-");                          // indicate negative
 }
 
 tFrac = tC % 100;                             // extract fractional part
 tC /= 100;                                    // extract whole part

 Serial.print(tC);
 Serial.print(".");
 if (tFrac < 10)
   Serial.print("0");
 Serial.println(tFrac);

  byte row = tC >> 3;
  byte rowBits = (1 << ((tC & 7) + 1)) - 1;

  for (int i=0; i<8; i++) {
    if (tC < row)
      lc.setRow(0, i, 0b11111111);
    else if (tC > row)
      lc.setRow(0, i, 0b00000000);
    else
      lc.setRow(0, i, rowBits);
  }
}


// Set configuration register

void setConfig(byte cfg)
{
 Wire.beginTransmission(SLAVE_ID);
 Wire.write(ACCESS_CFG);
 Wire.write(cfg);
 Wire.endTransmission();
 delay(15);                                    // allow EE write time to finish
}


// Read a DS1621 register

byte getReg(byte reg)
{
 Wire.beginTransmission(SLAVE_ID);
 Wire.write(reg);                               // set register to read
 Wire.endTransmission();
 Wire.requestFrom(SLAVE_ID, 1);
 byte regVal = Wire.read();
 return regVal;
}


// Sets temperature threshold
// -- whole degrees C only
// -- works only with ACCESS_TL and ACCESS_TH

void setThresh(byte reg, int tC)
{
 if (reg == ACCESS_TL || reg == ACCESS_TH) {
   Wire.beginTransmission(SLAVE_ID);
   Wire.write(reg);                             // select temperature reg
   Wire.write(byte(tC));                        // set threshold
   Wire.write(0);                               // clear fractional bit
   Wire.endTransmission();
   delay(15);
 }
}


// Start/Stop DS1621 temperature conversion

void startConversion(boolean start)
{
 Wire.beginTransmission(SLAVE_ID);
 if (start == true)
   Wire.write(START_CNV);
 else
   Wire.write(STOP_CNV);
 Wire.endTransmission();
}


// Reads temperature or threshold
// -- whole degrees C only
// -- works only with RD_TEMP, ACCESS_TL, and ACCESS_TH

int getTemp(byte reg)
{
 int tC;

 if (reg == RD_TEMP || reg == ACCESS_TL || reg == ACCESS_TH) {
   byte tVal = getReg(reg);
   if (tVal >= B10000000) {                    // negative?
     tC = 0xFF00 | tVal;                       // extend sign bits
   }
   else {
     tC = tVal;
   }
   return tC;                                  // return threshold
 }
 return 0;                                     // bad reg, return 0
}


// Read high resolution temperature
// -- returns temperature in 1/100ths degrees
// -- DS1620 must be in 1-shot mode

int getHrTemp()
{
 startConversion(true);                        // initiate conversion
 byte cfg = 0;
 while (cfg < DONE) {                          // let it finish
   cfg = getReg(ACCESS_CFG);
 }

 int tHR = getTemp(RD_TEMP);                   // get whole degrees reading
 byte cRem = getReg(RD_CNTR);                  // get counts remaining
 byte slope = getReg(RD_SLOPE);                // get counts per degree

 if (tHR >= 0)
   tHR = (tHR * 100 - 25) + ((slope - cRem) * 100 / slope);
 else {
   tHR = -tHR;
   tHR = (25 - tHR * 100) + ((slope - cRem) * 100 / slope);
 }
 return tHR;
}

LEDMaestro101

 is there a way of comparing current and previous data values and then increment or decrement the display accordingly? or am I going waaay off the beaten path and looking for a more complex solution than needed?

dougp

is there a way of comparing current and previous data values and then increment or decrement the display accordingly?
Sure.  Compare currentVal to previousVal, if different do something, like update display.  When done updating copy currentVal to previousVal to be ready for the next change.
Everything we call real is made of things that cannot be regarded as real.  If quantum mechanics hasn't profoundly shocked you, you haven't understood it yet. - Niels Bohr

No private consultations undertaken!

PaulRB

#9
May 17, 2019, 05:12 pm Last Edit: May 17, 2019, 05:20 pm by PaulRB
I do have the "byte zero[8]=…" going up to 50 but omitted them for the sake of being able to post the code here.
You don't need that array any more, it is no longer used.

I made another mistake, a stupid one. Change it like this:
Code: [Select]

  for (int i=0; i<8; i++) {
    if (i < row)
      lc.setRow(0, i, 0b11111111);
    else if (i > row)
      lc.setRow(0, i, 0b00000000);
    else
      lc.setRow(0, i, rowBits);
  }

LEDMaestro101

that is PERFECT!! had to make a very minor alteration to
Code: [Select]
  byte row = tC >> 3;
  byte rowBits = (1 << ((tC & 7))) - 1;
to remove the +1 after the "tC & 7" part as it was effectively adding a digit to the actual temp (e.g. it was reading 27°C but displaying 28 LED's.

if you don't mind, could you explain that bit of code to me? Obviously you're bit shifting tC and then (I assume) shifting out the tens value to be able to display units in "rowBits"? is this correct?
Just want to try and relearn as much as I can.

Thanks again for all your help with this, so so happy!!!!!

PaulRB

#11
May 17, 2019, 05:56 pm Last Edit: May 18, 2019, 05:50 am by PaulRB
Let's say tC is 28

Code: [Select]
tC >> 3
means bit-shift tC right by 3 bits and is equivalent to tC / 8 which is 28 / 8 = 3.
(In C language, division between integers gives an integer result, the remainder is lost.)

So "row" gets set to 3.

Code: [Select]
tC & 7
means bit-wise AND tC with 7 or 0b00000111. This is equivalent to tC % 8 which is 28 % 8 = 4

Code: [Select]
1 << 4
means shift 1 by 4 bits to the left, which is equivalent to 2^4 which is 16.

16 - 1 is 15 which is 0b00001111.

So "rowBits" gets set to 0b00001111.

Then the for-loop sets rows 0, 1 and 2 to 0b11111111, row 3 to 0b00001111 and rows 4, 5, 6 and 7 to 0b00000000.

Does that help?





LEDMaestro101

That helps immensely! Thank you for taking the time to explain, it's all so clear now!

I had such a block while writing that I couldn't quite get my head around how bit shifting worked, no matter how many times I read the reference pages (lol) but your explanation is so simple, thank you so much!

Go Up