#!/usr/bin/perl ... use HiPi::Utils; use HiPi::Device::I2C; ... use strict; use warnings; # ********************************************************** # # *** User entered values required before running script *** # # ********************************************************** # # Setup regular user & group id's for permission drop-back my $user = ''; my $group = ''; # LCD backpack's serial to parallel i2c device address & i2c bus my $i2cAddr = 0x3F; # SainSmart's backpack address my $i2cDev = '/dev/i2c-3'; # alternate i2c bus - SDA on gpio 22/SCL on gpio 23 ... # ********************************************************** # # **************** Setup i2c & lcd constants *************** # # ********************************************************** # # setup values specific to the 2 row 16 character SainSmart i2c LCD my $D_WIDTH = 16; # Displayed characters per line my $M_WIDTH = 40; # Memory size per line my $DATA_MODE = 0x09; # Mode - send data my $CMD_BMODE = 0x08; # Mode - send command with backlight on my $CMD_XMODE = 0x00; # Mode - send command with backlight off my $LINE_1 = 0x80; # Address command for the 1st line my $LINE_2 = 0xC0; # Address command for the 2nd line my $BL_STATUS = 0x08; # Backlight mask On=0x08 - Off=0x00 my $LO_MASK = 0xF0; # Masks off low-order bits in byte my $SET_EN = 0x04; # 0000 0100 - mask to set enable bit my $CLR_EN = 0x0B; # 0000 1011 - mask to clear enable bit & data my $DISP_CLR = 0x01; # Clears display & home's cursor my $CUR_HOME = 0x02; # Home the cursor my $DISP_OFF = 0x08; # Display off my $DISP_ON = 0x0C; # Display on my $MOVE_L = 0x18; # Move display Left my $MOVE_R = 0x1C; # Move display Right ... # hold/wait times (microseconds) are in the script but do not # seem to be required, perhaps the delay inherent in 12c serial # to parallel conversion is sufficient my $EN_HOLD = 0; # hold enable high my $WAIT_WR = 0; # wait before next write my $WAIT_CMD = 0; # wait after sending instruction ... # ********************************************************** # # **** create i2C object as root then drop permissions ***** # # ********************************************************** # my $objI2c = HiPi::Device::I2C->new( devicename => $i2cDev, address => $i2cAddr, busmode => 'i2c' ); HiPi::Utils::drop_permissions_name( $user, $group ) ... # *********************** Write Byte *********************** # sub writeByte { my $byte = $_[0]; # writes byte to i2c object (LCD) # 'Enable' toggled high-low to latch byte # timed to avoid i2c bus contention with readI2cAmpsTB.pl # only write at 'safe' time -> 1, 2 or 3 seconds after each 5 seconds (0,5,10 etc.) my $wait = 1; while( $wait ) { my ($yr, $mo, $dy, $hr, $mi, $se) = Today_and_Now(); my $secAfter = $se - ( int( $se /5 ) *5 ); if( $secAfter == 1 || $secAfter == 2 || $secAfter == 3 ) { # write data with enable high $objI2c->bus_write( $byte | $SET_EN ); $objI2c->delayMicroseconds( $EN_HOLD ); # clear enable - keep backlight and mode bits $objI2c->bus_write( $byte & $CLR_EN ); $objI2c->delayMicroseconds( $WAIT_WR ); # end while loop $wait = 0; } else { # wait select(undef,undef,undef, .1); } } return(); # *********************** Read Bytes *********************** # sub readBytes { my ($line, $posn, $readN) = @_; # reads bytes from i2c object (LCD) at address set by write command # 'Enable' control port toggled high-low # i2c_read command must have bits to be read set high # LCD controller increments address after each read # set RAM address to start position - wait for command to complete sendByte( $line + $posn -1, $CMD_BMODE ); $objI2c->delay( $WAIT_WR ); my (@dataH, @dataL); my $dataStr; for( my $n = 0; $n < $readN; $n++ ) { # wait for transfer of RAM data to data register $objI2c->delayMicroseconds( $WAIT_WR ); # only write at 'safe' time -> 1, 2 or 3 seconds after each 5 seconds (0,5,10 etc.) my $wait = 1; while( $wait ) { my ($yr, $mo, $dy, $hr, $mi, $se) = Today_and_Now(); my $secAfter = $se - ( int( $se /5 ) *5 ); if( $secAfter == 1 || $secAfter == 2 || $secAfter == 3 ) { # read MSB # enable high $objI2c->bus_write( 0xFF ); # data bits all high & BL=1, EN=1, RW=1, RS=1 $objI2c->delayMicroseconds( $WAIT_WR ); # read the data - 1 byte # in 4-bit mode this will be the MSB of the data byte @dataH = $objI2c->i2c_read( 1 ); # set enable low $objI2c->bus_write( 0x0B ); #(0000 1011); #BL=1, EN=0, RW=1, RS=1 $objI2c->delayMicroseconds( $WAIT_WR ); # read LSB # enable high $objI2c->bus_write( 0xFF ); # data bits all high & BL=1, EN=1, RW=1, RS=1 # read the data - 1 byte # in 4-bit mode this will be the LSB of the data byte @dataL = $objI2c->i2c_read( 1 ); # set enable low $objI2c->bus_write( 0x0B ); # BL=1, EN=0, RW=1, RS=1 $objI2c->delayMicroseconds( $WAIT_WR ); # put the high nibbles from each read into one byte & add to data string $dataStr = $dataStr . chr(( $dataH[0] & 0xF0 ) | ( $dataL[0] >> 4 & 0x0F )); # end while loop $wait = 0; } else { # wait select( undef, undef, undef, .1 ); } } } return( $dataStr ); }