LCD character displays typically include some RAM where custom characters can be stored.
Here is a short Perl script that allows custom characters to be written to the character generator RAM (CGRAM). Two parameters are used, one is the number of the custom character (0 to 7) and the other is a string of 8 hex characters that represent the character.
An example call is: sudo ./lcd_i2c_cg.pl --charAddr 0 --charStr '00,00,0E,11,11,0F,01,0E'. This creates a custom lower case 'g' which descends into the cursor line, and IMHO looks better than the standard 'g' used on my lcd !
Each of the 8 bytes for each custom character consist of 5 bits (3 high-order bits all zero). These are the 5 of the 5x8 character width or columns and the 8 bytes are the 8 rows. This site shows how the hex bytes are constructed http://www.circuitvalley.com/2012/02/lcd-custom-character-hd44780-16x2.html. There are, no doubt, many others.
This script is based on my previous script for an i2c-connected lcd. The initialization routine has been changed slightly to correct some logic errors in the enable high/low masking, and to remove some unintended obfuscation (The write byte calls in the initialization sequence had additional variables that were not used).
If this script is called without a '--charStr' parameter, the 8 existing custom characters are displayed.
As part of developing my display script for the i2c-attached lcd, I wanted a swap line function. Being able to read the existing data from the lcd display made this easier to achieve. This led to the conclusion that the Raspberry Pi's i2c bus can safely read from an attached i2c device operating at 5 volts. Results are consistent and have been working, at this stage, for around three weeks.
I hope to post the new display script shortly. It includes multiple user functions from the simple swap line to more complicated message display formats. Custom characters are included - displayable using escape sequences in the text
If you use this script, remember to put your username and group name into the two variables $user and $group (lines 38 & 39). This is for the script to fall back to regular user permissions as soon as the i2c object has been created.
#!/usr/bin/perl # # lcd_i2c_cg.pl # Version 1.00 # June 2016 # anita2R # # A script to create custom characters for # an lcd character display # Eight 5x8 pixel characters are possible # # Call this script with two parameters: # --charAddr # --charStr # The address is a single value in the range 0 to 7 # The character string is 8 hex bytes (comma delimited) # Example # for a lower case 'g' that descends into the cursor row: # sudo ./lcd_i2c_cg.pl --charAddr 0 --charStr 00,00,0E,11,11,0F,01,0E # use HiPi::BCM2835::I2C qw( :all ); use HiPi::Utils; use Getopt::Long; # use strict; # # get the command line parameters my ($cstrParam, $caddrParam); GetOptions( 'charStr=s' => \$cstrParam, 'charAddr=i' => \$caddrParam ); # #setup bus number, speed and i2c 'backpack' address. my $i2cBus = BB_I2C_PERI_1; # bus #1 on vers 2. my $i2cSpeed = BB_I2C_CLOCK_100_KHZ; # fastest reliable on RPi my $i2cAddr = 0x3f; # SainSmart i2c lcd at 0x3f # setup regular user & group id's - for permission drop-back my $user = '<YourUserName>'; my $group = '<YourGroupName>'; # setup values specific to the 2 row 16 character SainSmart i2c LCD my $dWidth = 16; # Displayed characters per line my $mWidth = 40; # Memory size per line my $dataMode = 0x09; # Mode - send data with backlight on my $cmdbMode = 0x08; # Mode - send command with backlight on my $line1 = 0x80; # Address command for the 1st line my $line2 = 0xC0; # Address command for the 2nd line my $loMask = 0xF0; # Masks off low-order bits in byte my $setEn = 0x04; # 0000 0100 mask: set enable bit my $clrEn = 0x0B; # 0000 1011 mask: clear enable bit/data # hold/wait times are in the code but do not seem to be required # perhaps the delay inherent in 12c serial # to parallel conversion is sufficient my $enHold = 0; # hold enable high (microseconds) my $wait = 0; # wait before next write (microseconds) # ****************************************** # # ***************** Setup ****************** # # # create an i2c device object my $objI2c = HiPi::BCM2835::I2C->new( peripheral => $i2cBus, address => $i2cAddr ); HiPi::Utils::drop_permissions_name( $user, $group ); $objI2c->set_baudrate( $i2cSpeed ); # # Initialize &init; # # ****************************************** # # ************** Main Program ************** # # # If a character byte string is present create the character # else just display the custom characters if( $cstrParam ) { # Set character generator RAM address to the # start of required custom character (0x00 to 0x07) &sendByte( &cgConv( $caddrParam ), $cmdbMode ); # Read 8 bytes from character string parameter # and write to CGRAM my @newChar = split( /,/, $cstrParam ); foreach( @newChar ) { &sendByte( hex $_, $dataMode ); } } # On line 1, display the 8 possible custom characters &sendByte( $line1, $cmdbMode ); for( my $n = 0; $n < 8; $n++ ) { &sendByte( $n, $dataMode ); &sendByte( 0x20, $dataMode ); } exit 0; # # # ****************************************** # # ************** Subroutines *************** # # # *************** Initialize *************** # sub init { # 8-bit write (Control bits not LCD data in lower nibble) &writeByte ( 0x38 ); # 0011 xxxx Sets 8-bit mode &writeByte ( 0x38 ); # repeat in case LCD was in # 4-bit mode/out of sync &writeByte ( 0x38 ); # & 4-bit mode needs # next byte to action cmd. &writeByte ( 0x28 ); # 0010 xxxx Sets 4-bit mode # now in 4-bit mode - both nibbles of data sent to LCD &sendByte ( 0x28, $cmdbMode ); # 0010 1000 - 2 lines, small chars &sendByte ( 0x0C, $cmdbMode ); # 0000 1100 Display On, no cursor &sendByte ( 0x01, $cmdbMode ); # 0000 0001 Clear display } # # *************** Write Byte *************** # sub writeByte { my $byte = $_[0]; # # writes byte to i2c object (LCD) # 'Enable' toggled high-low to latch byte # # write data with enable high $objI2c->bus_write( $byte | $setEn ); $objI2c->delayMicroseconds( $enHold ); # clear enable - keep backlight and mode bits $objI2c->bus_write( $byte & $clrEn ); $objI2c->delayMicroseconds( $wait ); } # # **************** Send byte *************** # sub sendByte { my $data = $_[0]; my $mode = $_[1]; # # splits data into high & low-order # puts each nibble into high-order bits # then adds mode bits into low-order bits # mode can be with or without backlight (cmdbMode/cmdxMode) # or dataMode (always with backlight) # # mask off 4 low-order bits & 'add' mode my $data_high = (( $data & $loMask ) | $mode ); # shift 4 low bits to high bits, # mask-off low order bits & 'add' mode my $data_low = ((( $data << 4 ) & $loMask ) | $mode ); # Send both nibbles of data to write routine &writeByte( $data_high ); &writeByte( $data_low ); } # # ***** CG Character Number to Command ***** # sub cgConv { my $cgAdd = $_[0]; # convert character number to address command value # bit 6 high for CG RAM addresses # Character data starts every 8 bytes $cgAdd = ( ($cgAdd *8) | 0x40); #0x40 = 0100 0000 return( $cgAdd ); } # ****************************************** #
|
---|
Replies are listed 'Best First'. | |
---|---|
Re: i2c lcd Custom Characters
by toolic (Bishop) on Jun 10, 2016 at 18:42 UTC | |
by anita2R (Scribe) on Jun 10, 2016 at 18:58 UTC | |
Re: i2c lcd Custom Characters
by jmlynesjr (Deacon) on Jun 10, 2016 at 19:06 UTC | |
by anita2R (Scribe) on Jun 10, 2016 at 19:52 UTC | |
by jmlynesjr (Deacon) on Jun 11, 2016 at 19:09 UTC | |
by anita2R (Scribe) on Jun 11, 2016 at 20:01 UTC | |
by jmlynesjr (Deacon) on Jun 12, 2016 at 20:30 UTC |