Indicator bar.

Hi,

I am a noob in Arduino but learning wit tutorials and it is going slo..

The project what i am doing now is getting data from a caliber.
The caliber is showing the data on the screen, working.

Now comes a part that the most difficult for me as a noob.

I want a vertical bar with a center.
From the center i want a bar to go up and down.

Example:
if i get to a a number on the caliber like 2.10 that is the center on the bar.
if it goes lower then 2.10 i want the bar to move down and if the number is higher i want the bar to move up.

I don't know where to start.
Can you give me the right direction to make this

I am using:
Arduino Micro.
Oled display trough ic2

Greetings,
Sid

I want a vertical bar with a center.

Iron pipe? Drinking establishment? Chocolate?

You need some more detail here.

-jim lee

Which OLED?

What caliper?

Post your existing code.

A clear picture of what you want (hand drawn is fine) will help us understand your needs.

Explore what graphic library is available for that mysterious "Oled display trough ic2" and look at examples for drawing and erasing lines (or dots if it does not do lines)

Ok,

Caliper is a measurement devise. Link
The display is an : Monochroom 1.3" 128x64 Oled brand Stemma QT. Conected I2C.

Explanation:
In the attachment is a picture of the display in the display on the left side is an drawRect with a center line.
The center line percents result 2.10 mm.
From the center i want to have a bar from the center that gose up when de value is higher then 2.10.
and from the center down when the value is getting under the 2.10.

#include <SPI.h>
#include <Wire.h>
#include <Adafruit_GFX.h>
#include <Adafruit_SSD1306.h>

#define SCREEN_WIDTH 128 // OLED display width, in pixels
#define SCREEN_HEIGHT 64 // OLED display height, in pixels

#define CLOCK_PIN 12
#define DATA_PIN  11


// Declaration for an SSD1306 display connected to I2C (SDA, SCL pins)
#define OLED_RESET    4 // Reset pin # (or -1 if sharing Arduino reset pin)
Adafruit_SSD1306 display(SCREEN_WIDTH, SCREEN_HEIGHT, &Wire, OLED_RESET);

void setup() 
{
  pinMode(CLOCK_PIN, INPUT);
  pinMode(DATA_PIN, INPUT);

  Serial.begin(9600); 

  // SSD1306_SWITCHCAPVCC = generate display voltage from 3.3V internally
  if(!display.begin(SSD1306_SWITCHCAPVCC, 0x3D)) { // Address 0x3D for 128x64
    Serial.println(F("SSD1306 allocation failed"));
    for(;;); // Don't proceed, loop forever
  }

  // Show initial display buffer contents on the screen --
  // the library initializes this with an Adafruit splash screen.
  display.display();
  delay(2000); // Pause for 2 seconds

  // Clear the buffer
  display.clearDisplay();
  // Waithing for wire to turn.
  display.setTextColor(WHITE);
  display.setTextSize(1);
  display.setCursor(0,30);
  display.print("Wacht op aandrijving.");
  display.display();
  delay(1000);
  display.setTextColor(WHITE); 
}

char buf[20];
unsigned long tmpTime;
int sign;
int inches;
long value;
float result;
bool mm = true; //define mm to false if you want inces values

void loop()
{
  while(digitalRead(CLOCK_PIN)==LOW) {}
  tmpTime=micros();
  while(digitalRead(CLOCK_PIN)==HIGH) {}
  if((micros()-tmpTime)<500) return;
  readCaliper(); 
  buf[0]=' ';
  dtostrf(result,6,3,buf+1); strcat(buf," in ");  
  dtostrf(result*2.54,6,3,buf+1); strcat(buf," cm "); 

  if(mm)
  {
  Serial.print(result); Serial.println(" mm"); 
  display.clearDisplay();
  display.setTextSize(2);
  display.setCursor(20,0);
  display.print("Breedte");
  display.setTextSize(3);
  display.setCursor(15,25);
  display.print(result);
  display.print("");
  display.setCursor(90,32);
  display.setTextSize(2);
  display.print("mm");

    //Breedte max
  display.setTextSize(1);
  display.setCursor(13, 55);
  display.print("Min:2,08");
  display.setTextSize(1);
  display.setCursor(67, 55);
  display.print("Max:2,12");
  
  display.drawRect(0, 0, 5, 64, WHITE);// bar on the left
  display.drawLine(4, 32, 0, 32, WHITE);// bar on the left center line.
  
  display.display();
  delay(1000);
  }
}

void readCaliper()
{
  sign=1;
  value=0;
  inches=0;
  for(int i=0;i<24;i++) {
    while(digitalRead(CLOCK_PIN)==LOW) {}
    while(digitalRead(CLOCK_PIN)==HIGH) {}
    if(digitalRead(DATA_PIN)==HIGH) {
      if(i<20) value|=(1<<i);
      if(i==20) sign=-1;
      if(i==23) inches=1; 
    }
  }
  if(mm)
  {
    result=(value*sign)/100.0;
  }
  else
  {
  result=(value*sign)/(inches?2000.0:100.0); //We map the values for inches, define mm to false if you want inces values
  }
  
}

When the bar is at the top and bottom of the scale, what will the mm reading be?

That is, what's the scale? "2.10mm is the middle. The top is _.__mm and the bottom is _.__mm."

Are those the 2.08 and 2.12 values you show on the display or ...?

You can try this. Compiles, not tested.

To adjust the vertical scale, tweak this:

#define DELTA_BAR_RESULT    1.6f                                            //mm +/-deviation from MID value in upper and lower directions
#include <SPI.h>
#include <Wire.h>
#include <Adafruit_GFX.h>
#include <Adafruit_SSD1306.h>

#define SCREEN_WIDTH 128 // OLED display width, in pixels
#define SCREEN_HEIGHT 64 // OLED display height, in pixels

#define CLOCK_PIN 12
#define DATA_PIN  11

//bar defines
//these two values are an equal distance from 2.1
#define MID_BAR_RESULT      2.1f                                            //mm result for bar at center position
#define DELTA_BAR_RESULT    1.6f                                            //mm +/-deviation from MID value in upper and lower directions
#define MIN_BAR_RESULT      (MID_BAR_RESULT - DELTA_BAR_RESULT)             //mm min scale reading (bar at bottom of rectangle)
#define MAX_BAR_RESULT      (MID_BAR_RESULT + DELTA_BAR_RESULT)             //mm full scale reading (bar at top of rectangle)
//
#define MAX_BAR_Y           1                                               //pixel Y # for bar max reading
#define MIN_BAR_Y           63                                              //pixel Y # for bar min reading
#define BAR_Y_SPAN          (MIN_BAR_Y - MAX_BAR_Y)                         //pixel active Y span of rectangle
#define BAR_SCALE           ((MAX_BAR_RESULT-MIN_BAR_RESULT) / (float)BAR_Y_SPAN)   //mm/pixel scale term

char buf[20];
unsigned long tmpTime;
int sign;
int inches;
long value;
float result;
bool mm = true; //define mm to false if you want inces values
uint8_t newBarY;
uint8_t lastBarY = MIN_BAR_Y;

// Declaration for an SSD1306 display connected to I2C (SDA, SCL pins)
#define OLED_RESET    4 // Reset pin # (or -1 if sharing Arduino reset pin)
Adafruit_SSD1306 display(SCREEN_WIDTH, SCREEN_HEIGHT, &Wire, OLED_RESET);

void setup()
{
    pinMode(CLOCK_PIN, INPUT);
    pinMode(DATA_PIN, INPUT);
    
    Serial.begin(9600);
    
    // SSD1306_SWITCHCAPVCC = generate display voltage from 3.3V internally
    if(!display.begin(SSD1306_SWITCHCAPVCC, 0x3D)) 
    { // Address 0x3D for 128x64
        Serial.println(F("SSD1306 allocation failed"));
        for(;;); // Don't proceed, loop forever
    }
    
    // Show initial display buffer contents on the screen --
    // the library initializes this with an Adafruit splash screen.
    display.display();
    delay(2000); // Pause for 2 seconds
    
    // Clear the buffer
    display.clearDisplay();
    // Waithing for wire to turn.
    display.setTextColor(WHITE);
    display.setTextSize(1);
    display.setCursor(0,30);
    display.print("Wacht op aandrijving.");
    display.display();
    delay(1000);
    display.setTextColor(WHITE);
}

void loop()
{
    while(digitalRead(CLOCK_PIN)==LOW) 
    {}
    
    tmpTime=micros();
    while(digitalRead(CLOCK_PIN)==HIGH) 
    {}
    
    if((micros()-tmpTime)<500) 
        return;
        
    readCaliper();
    buf[0]=' ';
    dtostrf(result,6,3,buf+1); strcat(buf," in "); 
    dtostrf(result*2.54,6,3,buf+1); strcat(buf," cm ");

    //determine bar position
    //suppose 
    //  MIN_BAR_RESULT is 0.5mm
    //  MAX_BAR_RESULT is 3.7mm
    //
    //  MAX_BAR_Y = 1
    //  MIN_BAR_Y = 63
    //  BAR_Y_SPAN = 62
    //  BAY_SCALE = MAX_RESULT-MIN_RESULT / SPAN     (62pixels / 3.2mm == 19.375 pixels/mm)
    //
    //  suppose result = 2.1
    //      if result is higher than max or result is lower than min, bar sits at top/bottom of scale
    //      else
    //          barY = (uint8_t)((MIN_BAR_Y - (result - MIN_BAR_RESULT) * BAR_SCALE) + 0.5);        
    //              examples    result == 2.1mm: bary = 63 - (2.1 - 0.5) * 19.375 == 32.5000
    //                          result == 1.6mm: bary = 63 - (1.6 - 0.5) * 19.375 == 42.1875
    //                          result == 0.6mm: bary = 63 - (0.6 - 0.5) * 19.375 == 61.5625
    //                          result == 3.5mm: bary = 63 - (3.5 - 0.5) * 19.375 == 5.375
    //                          
    //          
    if( result <= MIN_BAR_RESULT )
        newBarY = MIN_BAR_Y;
    else if( result >= MAX_BAR_RESULT )
        newBarY = MAX_BAR_Y;
    else
        newBarY = (uint8_t)((MIN_BAR_Y - ((result - MIN_BAR_RESULT) * BAR_SCALE)) + 0.5);        

    if(mm)
    {
        Serial.print(result); Serial.println(" mm");
        display.clearDisplay();
        display.setTextSize(2);
        display.setCursor(20,0);
        display.print("Breedte");
        display.setTextSize(3);
        display.setCursor(15,25);
        display.print(result);
        display.print("");
        display.setCursor(90,32);
        display.setTextSize(2);
        display.print("mm");

        //Breedte max
        display.setTextSize(1);
        display.setCursor(13, 55);
        display.print("Min:2,08");
        display.setTextSize(1);
        display.setCursor(67, 55);
        display.print("Max:2,12");

        //if( newBarY != lastBarY ) //would be used when clearDisplay not used
        //{
            display.drawRect( 0, 0, 5, 64, WHITE );// bar on the left
            //display.drawLine( 4, lastBarY, 0, lastBarY, BLACK );//would be used when clearDisplay not used
            display.drawLine( 4, newBarY, 0, newBarY, WHITE );
            
            lastBarY = newBarY; //would be used when clearDisplay not used
            
        //}//if
        
        display.display();
        delay(1000);
        
    }//if
    
}//if

void readCaliper()
{
  sign=1;
  value=0;
  inches=0;
  for(int i=0;i<24;i++) {
    while(digitalRead(CLOCK_PIN)==LOW) {}
    while(digitalRead(CLOCK_PIN)==HIGH) {}
    if(digitalRead(DATA_PIN)==HIGH) {
      if(i<20) value|=(1<<i);
      if(i==20) sign=-1;
      if(i==23) inches=1;
    }
  }
  if(mm)
  {
    result=(value*sign)/100.0;
  }
  else
  {
  result=(value*sign)/(inches?2000.0:100.0); //We map the values for inches, define mm to false if you want inces values
  }
 
}

Blackfin,

Yes 2.10 is mm.
And yes min is 2.08mm and max is 2.12mm.

The script compiles fine and the drawRect is showing but there is no center line en there is no bar.
I am trying to look now why it is not working...

sidlord:
Blackfin,

Yes 2.10 is mm.
And yes min is 2.08mm and max is 2.12mm.

The script compiles fine and the drawRect is showing but there is no center line en there is no bar.
I am trying to look now why it is not working...

Try adding a serial print of newBarY just before drawing the bar. Maybe the math is wonky or the float to uint8_t casting went awry.

Ok,

Serial.println(newBarY); added.

Now in the serial monitor i see the number 63 at 0.00 on caliper and when i move the caliper to 2.50 it changes to 62 and when the caliper is set on 5.00 the number changes to 1.

sidlord:
Ok,

Serial.println(newBarY); added.

Now in the serial monitor i see the number 63 at 0.00 on caliper and when i move the caliper to 2.50 it changes to 62 and when the caliper is set on 5.00 the number changes to 1.

Hmm. That sounds right then. If you put the caliper to 2.1mm it should show 32 (ish).

It appears it should be drawing the line.

Maybe try using a different function to draw a simple horizontal line. Replace this line:

display.drawLine( 4, newBarY, 0, newBarY, WHITE );

with this one:

display.drawFastHLine( 0, newBarY, 5, WHITE );

and see if there’s any difference.

Double Check if buf is not too small and you overflow.

char buf[20];
...
    buf[0]=' ';                            
    dtostrf(result,6,3,buf+1);          
    strcat(buf," in "); 
    dtostrf(result*2.54,6,3,buf+1); 
    strcat(buf," cm ");

You not only need space for the data but also a trailing null char.. try setting buf to 50 chars just for the sake of it (I don't know how result can be since you state 6,3)

I see a line, but not correct

At 2.90 i see a line appearing at the bottom and 3.80 at i see a line appearing at top.
And at 2.10 nothing appears in the center.

Ok,

when i change this :

#define DELTA_BAR_RESULT    1.6f  //mm +/-deviation from MID value in upper and lower directions

To:

#define DELTA_BAR_RESULT    15.0f  //mm +/-deviation from MID value in upper and lower directions

I have response in the lower section in the bar, when i move the caliper from 0.0 to 16.0.
Above 16.0 the bar shoots to the top of the bar.

I don’t get what you do.

You said

The center line percents result 2.10 mm.
From the center i want to have a bar from the center that gose up when de value is higher then 2.10.
and from the center down when the value is getting under the 2.10.

And yes min is 2.08mm and max is 2.12mm.

and now you are discussing 2.90 and 3.80 and 16.0…

what’s the range of the bar?

I found a problem in my defines. I did the scaling def as mm/pixel and it should have been pixels/mm.

You can try changing this line:

#define BAR_SCALE           ((float)BAR_Y_SPAN/(MAX_BAR_RESULT-MIN_BAR_RESULT))   //pixel/mm scale term

and/or this ver of the code:

#include <SPI.h>
#include <Wire.h>
#include <Adafruit_GFX.h>
#include <Adafruit_SSD1306.h>

#define SCREEN_WIDTH 128 // OLED display width, in pixels
#define SCREEN_HEIGHT 64 // OLED display height, in pixels

#define CLOCK_PIN 12
#define DATA_PIN  11

//bar defines
//these two values are an equal distance from 2.1
#define MID_BAR_RESULT      2.1f                                            //mm result for bar at center position
#define DELTA_BAR_RESULT    1.6f                                            //mm +/-deviation from MID value in upper and lower directions
#define MIN_BAR_RESULT      (MID_BAR_RESULT - DELTA_BAR_RESULT)             //mm min scale reading (bar at bottom of rectangle)
#define MAX_BAR_RESULT      (MID_BAR_RESULT + DELTA_BAR_RESULT)             //mm full scale reading (bar at top of rectangle)
//
#define MAX_BAR_Y           1                                               //pixel Y # for bar max reading
#define MIN_BAR_Y           63                                              //pixel Y # for bar min reading
#define BAR_Y_SPAN          (MIN_BAR_Y - MAX_BAR_Y)                         //pixel active Y span of rectangle
#define BAR_SCALE           ((float)BAR_Y_SPAN/(MAX_BAR_RESULT-MIN_BAR_RESULT))   //pixel/mm scale term

char buf[20];
unsigned long tmpTime;
int sign;
int inches;
long value;
float result;
bool mm = true; //define mm to false if you want inces values
uint8_t newBarY;
uint8_t lastBarY = MIN_BAR_Y;

// Declaration for an SSD1306 display connected to I2C (SDA, SCL pins)
#define OLED_RESET    4 // Reset pin # (or -1 if sharing Arduino reset pin)
Adafruit_SSD1306 display(SCREEN_WIDTH, SCREEN_HEIGHT, &Wire, OLED_RESET);

void setup()
{
    pinMode(CLOCK_PIN, INPUT);
    pinMode(DATA_PIN, INPUT);
   
    Serial.begin(115200);
   
    // SSD1306_SWITCHCAPVCC = generate display voltage from 3.3V internally
    if(!display.begin(SSD1306_SWITCHCAPVCC, 0x3D))
    { // Address 0x3D for 128x64
        Serial.println(F("SSD1306 allocation failed"));
        for(;;); // Don't proceed, loop forever
    }
   
    // Show initial display buffer contents on the screen --
    // the library initializes this with an Adafruit splash screen.
    display.display();
    delay(2000); // Pause for 2 seconds
   
    // Clear the buffer
    display.clearDisplay();
    // Waithing for wire to turn.
    display.setTextColor(WHITE);
    display.setTextSize(1);
    display.setCursor(0,30);
    display.print("Wacht op aandrijving.");
    display.display();
    delay(1000);
    display.setTextColor(WHITE);
        
}

void loop()
{
    while(digitalRead(CLOCK_PIN)==LOW)
    {}
   
    tmpTime=micros();
    while(digitalRead(CLOCK_PIN)==HIGH)
    {}
   
    if((micros()-tmpTime)<500)
        return;
       
    readCaliper();
    buf[0]=' ';
    
    dtostrf(result,6,3,buf+1); strcat(buf," in ");
    dtostrf(result*2.54,6,3,buf+1); strcat(buf," cm ");

    //determine bar position
    //suppose
    //  MIN_BAR_RESULT is 0.5mm
    //  MAX_BAR_RESULT is 3.7mm
    //
    //  MAX_BAR_Y = 1
    //  MIN_BAR_Y = 63
    //  BAR_Y_SPAN = 62
    //  BAY_SCALE = MAX_RESULT-MIN_RESULT / SPAN     (62pixels / 3.2mm == 19.375 pixels/mm)
    //
    //  suppose result = 2.1
    //      if result is higher than max or result is lower than min, bar sits at top/bottom of scale
    //      else
    //          barY = (uint8_t)((MIN_BAR_Y - (result - MIN_BAR_RESULT) * BAR_SCALE) + 0.5);       
    //              examples    result == 2.1mm: bary = 63 - (2.1 - 0.5) * 19.375 == 32.5000
    //                          result == 1.6mm: bary = 63 - (1.6 - 0.5) * 19.375 == 42.1875
    //                          result == 0.6mm: bary = 63 - (0.6 - 0.5) * 19.375 == 61.5625
    //                          result == 3.5mm: bary = 63 - (3.5 - 0.5) * 19.375 == 5.375
    //                         
    //         
    if( result <= MIN_BAR_RESULT )
        newBarY = MIN_BAR_Y;
    else if( result >= MAX_BAR_RESULT )
        newBarY = MAX_BAR_Y;
    else
        newBarY = (uint8_t)((MIN_BAR_Y - ((result - MIN_BAR_RESULT) * BAR_SCALE)) + 0.5);       
    
    //Serial.print( "Measurement  \t" ); Serial.print(result); Serial.print( "\tY bar   \t" ); Serial.println( newBarY );
    
    if(mm)
    {
        Serial.print(result); Serial.println(" mm");
        display.clearDisplay();
        display.setTextSize(2);
        display.setCursor(20,0);
        display.print("Breedte");
        display.setTextSize(3);
        display.setCursor(15,25);
        display.print(result);
        display.print("");
        display.setCursor(90,32);
        display.setTextSize(2);
        display.print("mm");

        //Breedte max
        display.setTextSize(1);
        display.setCursor(13, 55);
        display.print("Min:2,08");
        display.setTextSize(1);
        display.setCursor(67, 55);
        display.print("Max:2,12");

        //if( newBarY != lastBarY ) //would be used when clearDisplay not used
        //{
            display.drawRect( 0, 0, 5, 64, WHITE );// bar on the left
            //display.drawLine( 4, lastBarY, 0, lastBarY, BLACK );//would be used when clearDisplay not used
            //display.drawLine( 4, newBarY, 0, newBarY, WHITE );
            
            display.drawFastHLine( 0, newBarY, 5, WHITE );
            
            lastBarY = newBarY; //would be used when clearDisplay not used
           
        //}//if
       
        display.display();
        delay(1000);
       
    }//if
   
}//if

void readCaliper()
{
  sign=1;
  value=0;
  inches=0;
  for(int i=0;i<24;i++) {
    while(digitalRead(CLOCK_PIN)==LOW) {}
    while(digitalRead(CLOCK_PIN)==HIGH) {}
    if(digitalRead(DATA_PIN)==HIGH) {
      if(i<20) value|=(1<<i);
      if(i==20) sign=-1;
      if(i==23) inches=1;
    }
  }
  if(mm)
  {
    result=(value*sign)/100.0;
  }
  else
  {
  result=(value*sign)/(inches?2000.0:100.0); //We map the values for inches, define mm to false if you want inces values
  }
 
}

J-M-L:
I don't get what you do.

You saidand now you are discussing 2.90 and 3.80 and 16.0...

what's the range of the bar?

Hi,
The range is still 2.08, 2.10 and 2.12.
But i was giving the information whats happening at some values.

as you overflow your range, you overflow your uint8_t as well.

add this function to your code

inline float fmap(float x, float in_min, float in_max, float out_min, float out_max)
{
  return (x - in_min) * (out_max - out_min) / (in_max - in_min) + out_min;
}

and when you have your reading R between 2.08 and 2.12 and you want to set the bar between 1 and 63 you do

barY = constrain(fmap(R, 2.08, 2.12, 1, 63), 1, 63); // to ensure it's within the bounds

then use barY to draw the bar

(constrain is not necessary if you can guarantee that R is between 2.08 and 2.12 always - if not the fmap() function is just a linear interpolation and will lead to numbers below 1 or above 63. Constrain makes sure you stay within the bounds)

For my code, just change this line:

#define DELTA_BAR_RESULT    0.02f                                           //mm +/-deviation from MID value in upper and lower directions

to give 2.1mm +/- 0.02mm

Blackfin,

Thanks this is exactly what i want!

The bar is now a line, how can i make it solid?