B4R Tutorial LCD Bar Graph

The attached project mimics this posting. Have added the basic functionality with inline C. It uses the rCore and rLiquidCrystal libraries.

Wiring diagram:
lcdbargraph_bb.png


Result:
20190601_164030.jpg



Sample code (change it to your licking):
B4X:
'LCD Display - LCD 1602
'See attached wiring diagram


#Region Project Attributes
    #AutoFlushLogs: True
    #CheckArrayBounds: True
    #StackBufferSize: 300
#End Region

Sub Process_Globals
    'These global variables will be declared once when the application starts.
    'Public variables can be accessed from all modules.
    Public Serial1 As Serial
    Dim lcd As LiquidCrystal
    Dim t As Timer
    Dim maxvalue As Byte = 100
    
End Sub

Private Sub AppStart
    Serial1.Initialize(115200)
    Log("AppStart")
    
    t.Initialize("t_Tick", 500)
    lcd.Initialize(8,255,9, Array As Byte(4,5,6,7))
    Delay(10)
    lcd.Begin(16, 2)
    lcd.Clear
    
    RunNative("createOne",Null)
    RunNative("createTwo",Null)
    RunNative("createThree",Null)
    RunNative("createFour",Null)
    RunNative("createFive",Null)
    
    lcd.SetCursor(0,0)
    
    lcd.Write("B4R - LCD Graph")
    Delay(3000)
    lcd.SetCursor(0,1)
    Delay(10)
    RunNative("writeCharAlarm", 0)
    
    t.Enabled = True

End Sub

Sub t_Tick
    
    Dim i As Byte = Rnd(0, maxvalue + 1)
    lcd.Clear
    lcd.SetCursor(0,0)
    lcd.Write("VALUE = ")
    lcd.SetCursor(8,0)
    lcd.Write(i)
    
    lcd.SetCursor(0,1)

    Dim full As Float = 16 * (i/maxvalue)
    Dim ff As Int = full
    
    Dim fraction As Int = Round(10 * (full - ff))
    fraction = Round((fraction * 5 / 10))
    
    For j = 1 To full
        RunNative("writeCharAlarm", 4)
    Next
    
    If fraction = 1 Then
        RunNative("writeCharAlarm", 0)
    Else if fraction = 2 Then
        RunNative("writeCharAlarm", 1)
    Else if fraction = 3 Then
        RunNative("writeCharAlarm", 2)
    Else if fraction = 4 Then
        RunNative("writeCharAlarm", 3)
            
    End If

End Sub

#if C                         

    Byte One[8] = {
    B10000,
    B10000,
    B10000,
    B10000,
    B10000,
    B10000,
    B10000,
    B10000
};

    byte Two[8] = {
    B11000,
    B11000,
    B11000,
    B11000,
    B11000,
    B11000,
    B11000,
    B11000
};

    Byte Three[8] = {
    B11100,
    B11100,
    B11100,
    B11100,
    B11100,
    B11100,
    B11100,
    B11100
};

    Byte Four[8] = {
    B11110,
    B11110,
    B11110,
    B11110,
    B11110,
    B11110,
    B11110,
    B11110
};

    Byte Five[8] = {
    B11111,
    B11111,
    B11111,
    B11111,
    B11111,
    B11111,
    B11111,
    B11111
};

    void createOne(B4R::Object* o) {
       b4r_main::_lcd->lc->createChar(0, One);
    }
    
    void createTwo(B4R::Object* o) {
       b4r_main::_lcd->lc->createChar(1, Two);
    }   
    
    void createThree(B4R::Object* o) {
       b4r_main::_lcd->lc->createChar(2, Three);
    }   
    
    void createFour(B4R::Object* o) {
       b4r_main::_lcd->lc->createChar(3, Four);
    }   
    
    void createFive(B4R::Object* o) {
       b4r_main::_lcd->lc->createChar(4, Five);
    }               

    void writeCharAlarm(B4R::Object* o) {
       b4r_main::_lcd->lc->write((Byte)o->toULong());
    }

#end if

There are most probably better ways to do this - but the lcd bar graph in the above/attached is working.
 

Attachments

  • b4rLiquidCrystalDisplay.zip
    1.5 KB · Views: 210

Johan Schoeman

Expert
Licensed User
Same wiring diagram as in post #1 above - it just takes away some of the unwanted flickering of the display while changing values. The below code will draw a bar graph in row 2 of the LCD display, starting at zero and going up to "maxvalue", and then down from maxvalue to zero (see comments added to the code) - actual value is displayed in Row 0 of the LCD display.

Change the value of "maxvalue" for a different "range"
B4X:
Sub Process_Globals
    'These global variables will be declared once when the application starts.
    'Public variables can be accessed from all modules.
    ....
    ....
    ....
    Dim maxvalue As Int = 100                        'set the maximum value to display
    ....
    ....
   
End Sub



B4X:
#Region Project Attributes
    #AutoFlushLogs: True
    #CheckArrayBounds: True
    #StackBufferSize: 300
#End Region

Sub Process_Globals
    'These global variables will be declared once when the application starts.
    'Public variables can be accessed from all modules.
    Public Serial1 As Serial
    Dim lcd As LiquidCrystal
    Dim t As Timer                                   'create a timer
    Dim maxvalue As Int = 100                        'set the maximum value to display
    Dim i As Byte
    Dim countupwards As Boolean = True               'are we counting up of down....
  
End Sub

Private Sub AppStart
    Serial1.Initialize(115200)
    Log("AppStart")
  
    t.Initialize("t_Tick", 200)                             'initialize the timer
    lcd.Initialize(8,255,9, Array As Byte(4,5,6,7))         'using pins 4, 5, 6, 7 for data, pin 8 = RS, pin 9 = Enable
    Delay(10)
    lcd.Begin(16, 2)                                        'set LCD display for 16 columns and 2 rows
    lcd.Clear
  
    RunNative("createOne",Null)                             'create the character that displays one column of 8 pixels (on LCD 1602 there are 16 * 5 = 80 columns)
    RunNative("createTwo",Null)                             'create the character that displays two columns of 8 pixels
    RunNative("createThree",Null)                           'create the character that displays three columns of 8 pixels
    RunNative("createFour",Null)                            'create the character that displays four columns of 8 pixels
    RunNative("createFive",Null)                            'create the character that displays five columns of 8 pixels
  
    lcd.SetCursor(0,0)                                      'set the cursor to column 0, row 0
  
    lcd.Write("B4R - LCD Graph")                            'display initial message
    Delay(1500)                                             'show initial message for 1.5 seconds
    lcd.Clear                                               'clear the display
    lcd.SetCursor(0,1)                                      'set the cursor to column 0, row 1
  
    t.Enabled = True                                        'enable the time

End Sub

Sub t_Tick
  
    lcd.SetCursor(0,0)                                      'set cursor to column 0, row 0
    lcd.Write("VALUE = ")                                   'display "VALUE = "
    For k = 8 To 15                                         'write a space (" ") to the remainder colums of row 0
        lcd.SetCursor(k,0)
        lcd.Write(" ")                                      'write the space
    Next
    lcd.SetCursor(8,0)                                      'set the cursor to column 8, row 0 (rows and coluns start at 0)
    lcd.Write(i)                                            'write the value of i to the LCD - it will display for eg  "VALUE = 73"
  
    lcd.SetCursor(0,1)                                      'put the cursor at column 0, row 1 (preparing for the bar graph)

    Log("i = ", i)
    Dim full As Float = 16 * (i/maxvalue)                   'calculate how many chars of 5x8 are needed to draw the bar graph (eg if maxvalue = 100, then if value to display = 73, then 16 * 73/100 is the number of "chars"on the LCD display to switch on")
    Dim ff As Int = full                                    'get the INT number of full 5x8 chars to switch on
    Log("ff = ", ff)

  
    Dim fraction As Int = Round(10 * (full - ff))           'calculate the fraction of a "char" that must be switched on
    fraction = Round((fraction * 5 / 10))                   'eg if calue to display = 73 and maxvalue = 100, 73/100 = 0.73 * 16 = 11 full chars and 0.68 of a char
    Log("fraction = ", fraction)                            '0.68 of a char  = 0.68 * 5 = 3.4 (then rounding 3.4 to the nearest int)
    Log(" ")
  
    lcd.SetCursor(0,1)                                      'first, fill the number of full chars with 5*8 all switched on
    For j = 0 To ff - 1
        RunNative("writeCharAlarm", 4)                      'write the nuber of full chars
    Next
  
    If fraction = 1 Then                                    'now write the fractions
        RunNative("writeCharAlarm", 0)                      'it can be 1 up to 4 rows of 8 (column) pixels - on a 16 * x display there 80 pixel columns
    Else if fraction = 2 Then
        RunNative("writeCharAlarm", 1)
    Else if fraction = 3 Then
        RunNative("writeCharAlarm", 2)
    Else if fraction = 4 Then
        RunNative("writeCharAlarm", 3)
    Else if fraction = 5 Then
        RunNative("writeCharAlarm", 4)
    Else if fraction = 0 Then
    End If

    Dim dummy As Int = 0                                   'want to determine where to clear the bar graph from without having to call lcd.Clear - it makes the display less flickering
    If fraction > 0 Then
        dummy = 1
    Else
        dummy = 0 
    End If

    Dim total_on As Int = ff + dummy                       'how many chars to clear in the bargraph after new bar graph has been written to the display

    For k = total_on To 15                                 'clear the excess "chars" in the bar graph
        If total_on < 16 Then
            lcd.SetCursor(k, 1)
            lcd.Write(" ") 
        End If
    Next
  
    If countupwards = True Then                         
        count_up                                           'count up from 0 to maxvalue and switch direction when getting to maxvalue - bar graph will follow suite
    Else
        count_down                                           'count down from maxvalue to 0 and switch direction when getting to maxvalue - bar graph will follow suite
    End If
  
  
End Sub

Sub count_up                                             'when counting up
  
    i = i + 1
    If i = maxvalue Then
        Delay(100)
        countupwards = Not(countupwards)                 'switch counting direction
    End If
  
End Sub

Sub count_down                                            'when counting down
  
    i = i - 1
    If i = 0 Then
        Delay(100)
        countupwards = Not(countupwards)                  'switch counting direction
    End If
  
End Sub


'the C code below creates the custom chars and displays them
#if C                       

    Byte One[8] = {
    B10000,
    B10000,
    B10000,
    B10000,
    B10000,
    B10000,
    B10000,
    B10000
};

    byte Two[8] = {
    B11000,
    B11000,
    B11000,
    B11000,
    B11000,
    B11000,
    B11000,
    B11000
};

    Byte Three[8] = {
    B11100,
    B11100,
    B11100,
    B11100,
    B11100,
    B11100,
    B11100,
    B11100
};

    Byte Four[8] = {
    B11110,
    B11110,
    B11110,
    B11110,
    B11110,
    B11110,
    B11110,
    B11110
};

    Byte Five[8] = {
    B11111,
    B11111,
    B11111,
    B11111,
    B11111,
    B11111,
    B11111,
    B11111
};

    //create ONE = one column ON (out of 80 columns on a 16*2 LCD display with 5 rows x 8 pixels per LCD char)
    void createOne(B4R::Object* o) {
       b4r_main::_lcd->lc->createChar(0, One);
    }
  
    //create TWO = two columns ON (out of 80 columns on a 16*2 LCD display with 5 rows x 8 pixels per LCD char)
    void createTwo(B4R::Object* o) {
       b4r_main::_lcd->lc->createChar(1, Two);
    } 
  
    //create THREE = three columns ON (out of 80 columns on a 16*2 LCD display with 5 rows x 8 pixels per LCD char) 
    void createThree(B4R::Object* o) {
       b4r_main::_lcd->lc->createChar(2, Three);
    } 
  
    //create FOUR = four columns ON (out of 80 columns on a 16*2 LCD display with 5 rows x 8 pixels per LCD char) 
    void createFour(B4R::Object* o) {
       b4r_main::_lcd->lc->createChar(3, Four);
    } 
  
    //create FIVE = five columns ON (out of 80 columns on a 16*2 LCD display with 5 rows x 8 pixels per LCD char) 
    void createFive(B4R::Object* o) {
       b4r_main::_lcd->lc->createChar(4, Five);
    }             

    //dispaly the char (0 to 4) that has been created and stored in the LCD Display
    void writeCharAlarm(B4R::Object* o) {
       b4r_main::_lcd->lc->write((Byte)o->toULong());
    }

#end if
 
Top