LCD.pm0000664000175000000120000001040014515043433010623 0ustar toddwheel# # http://www.toolz.com - software@toolz.com # # $Id: LCD.pm,v 1.13 2023/08/22 17:55:13 todd Exp $ # # Adapted from a Perl script posted by anita2R # on PerlMonks May 24, 2016 at 16:28 UTC # # Forget trying to make I2C to LCD work in 8-bit mode # $Id: LCD.pm,v 1.13 2023/08/22 17:55:13 todd Exp $ # use warnings; package RPi::I2C::LCD; our $VERSION = '1.13'; require Exporter; our @ISA = qw(Exporter); @EXPORT = qw(writeByte sendByte prntStr display lookup); use Time::HiRes; # LCD Address $DEVADDR = 0x27; # default address on i2c bus my $dataMode = 0x01; # Mode - send data my $cmdMode = 0x00; # Mode - send command my $blStatus = 0x08; # Backlight mask On=0x08 - Off=0x00 my $loMask = 0xF0; # Masks off low-order bits in byte my $sEN = 0x04; # 0000 0100 - mask to set enable bit my $cEN = 0x0B; # 0000 1011 - mask to clear enable bit & data %LINES = ( # DDRAM address for each line 1 => 0x80, 2 => 0xC0, 3 => 0x94, 4 => 0xD4 ); sub new { my ($class,%args) = @_; my $key; # defaults my %params = ( devaddr => $DEVADDR, busno => 1, # 0, 1 width => 16, rows => 2, backlight => 1, defwait => 0.0001, justify => 'center', version => "$VERSION", ); # default overrides foreach $key (keys %args) { $params{$key} = $args{$key}; } $params{bus} = RPi::I2C->new ($params{devaddr}); foreach $key (keys %params) { $self->{$key} = $params{$key}; } bless $self, $class; if (not $self->{backlight}) { $blStatus = 0; } &writeByte( $self, 0x30, $cmdMode ); # 8-bit &writeByte( $self, 0x30, $cmdMode ); &writeByte( $self, 0x20, $cmdMode ); # 4-bit # now in 4-bit mode # 4-bit, 1 lines, 5x7 pixel font if ($self->{rows} == 1) { &sendByte( $self, 0x20, $cmdMode ); } # 4-bit, 2 lines, 5x7 pixel font elsif ($self->{rows} == 2) { &sendByte( $self, 0x28, $cmdMode ); } sleep($self->{defwait}); $self->display('ON'); sleep($self->{defwait}); $self->display('CLEAR'); return $self; } # *************** Write Byte *************** # sub writeByte { my ($self,$byte) = @_; # # writes byte to i2c object (LCD) # Enable 'control port' toggled high-low # # write data with enable set $self->{bus}->write( $byte | $sEN ); sleep($self->{defwait}); # clear enable, clear data, keep backlight & mode $self->{bus}->write( $byte | $cEN ); sleep($self->{defwait}); } # # **************** Send byte *************** # sub sendByte { my ($self,$data,$mode) = @_; # splits data into high & low-order # puts each nibble into high-order bits # then adds mode & backlight status bits into low-order bits # # mask off 4 low-order bits & 'add' mode and backlight my $data_high = (( $data & $loMask ) | $mode | $blStatus ); # shift 4 low bits to high bits, mask-off low order bits # & 'add' mode and backlight my $data_low = ((( $data << 4 ) & $loMask ) | $mode | $blStatus ); # Send both nibbles of data to write routine &writeByte( $self,$data_high ); &writeByte( $self,$data_low ); sleep($self->{defwait}); } # # ************* Print a String ************* # sub prntStr { my ($self,$message,$line) = @_; my ($i); my $ddaddr = $LINES{$line}; # set DDRAM address &sendByte($self, $ddaddr, $cmdMode ); # iterate through message string my @str = split //,substr(justify($self->{justify},$self->{width},$message),0,$self->{width}); for ( $i = 0 ; $i < $self->{width} ; $i++ ) { # send bytes to be displayed (use character values) &sendByte( $self,ord( $str[$i] ), $dataMode ); } } sub display # OFF, ON, CLEAR { my ($self,$cmd) = @_; if ("$cmd" eq 'OFF') { $self->sendByte(0x08,$cmdMode); sleep($self->{defwait}); } elsif ("$cmd" eq 'ON') { $self->sendByte(0x0C,$cmdMode); sleep($self->{defwait}); } elsif ("$cmd" eq 'CLEAR') { $self->sendByte(0x01,$cmdMode); sleep(0.005); } } sub lookup { my ($self,$var) = @_; return $self->{$var}; } sub justify { my $mode = shift; my $width = shift; my $string = shift; my $more; if ("$mode" eq 'left') { return sprintf("%-*s",$width,$string); } elsif ("$mode" eq 'center') { my $pad = ' ' x (($width - length("$string")) / 2); if (length($string) % 2) { $more = ' ' } else { $more = ''; } return sprintf("%s%s%s%s","$pad","$string","$pad","$more"); } elsif ("$mode" eq 'right') { return sprintf("%*s",$width,$string); } } 1; README0000664000175000000120000000647114515046050010556 0ustar toddwheelNAME RPi::I2C::LCD - Interface vi I2C to the LCD1602 multi-line LCD display module SYNOPSIS use RPi::I2C::LCD # all option values have defaults my $device = RPi::I2C::LCD->new( 'devaddr' => , 'busno' => , 'width' => , 'rows' => , 'backlight' => , 'defwait' => , 'justify' => , 'version' => ); $device->writeByte($byte) $device->sendByte($data,$mode) $device->prntStr($message,$lineno) $device->display('OFF') $device->display('ON') $device->display('CLEAR') return $device->lookup(