Beefy Boxes and Bandwidth Generously Provided by pair Networks
Do you know where your variables are?
 
PerlMonks  

Re: i2c attached LCD Character Display for a Raspberry Pi

by jmlynesjr (Hermit)
on May 25, 2016 at 20:48 UTC ( #1164139=note: print w/replies, xml ) Need Help??


in reply to i2c attached LCD Character Display for a Raspberry Pi

anita2R Nice Work!

I plan to look at your code in detail to learn something new about the RPI. I have used the chipKIT UNO32 with a Sparkfun I2C backpack.

How does the 4/8 bit mode stuff come into play over an I2C backpack interface? I thought 4/8 bit mode related to using a 4 or 8 bit parallel interface. This should be handled by the backpack processor.

I think RPI users could be a source of new Perl users. More posts like yours might help this along.

Update: After reading your code it appears that the SainSmart LCD you are using has a much lower level interface than the Sparkfun unit that I used. The Sparkfun backpack hides all of the bit manipulation from the user.

James

There's never enough time to do it right, but always enough time to do it over...

  • Comment on Re: i2c attached LCD Character Display for a Raspberry Pi

Replies are listed 'Best First'.
Re^2: i2c attached LCD Character Display for a Raspberry Pi
by anita2R (Beadle) on May 26, 2016 at 14:31 UTC

    I wasn't aware that the SparkFun module provided more than just serial to parallel conversion.

    The SainSmart backpack is a simple (and cheap) device. I just looked, their 2 x 16 LCD with i2c backpack is under $10 US. There are other similar backpacks out there that you can wire up yourself to an LCD display which are now really cheap. The disadvantage is that the information on using them is poor.

    While trying to get mine working I read numerous posts from people who could not get theirs to work. In the end I went back to basics, and worked out how the backpacks work and how the LCD 4-bit mode works, and then avoided the high level libraries. Simple i2c communication using the HiPi::BCM2835::I2C was all that was needed. The module is described as: The HiPi::BCM2835::I2C module provides direct access to the Broadcom I2C Serial peripheral.

    After that it came down to understanding the commands and the way the parallel side of the i2c backpack was connected to the LCD.

    I will write up some more detailed notes on the 8-bit/4-bit issue and initialization and post it later

    I have a Perl script that collects data from an spi bus-attached ADC that monitors some voltages. I should tidy up the script and post that as well

      anita2R

      I went back and looked at my chipKIT code. Turns out my Sparkfun LCD is a SPI interface. My SF 4 digit LED display uses I2C. In either case neither required any bit twiddling. Their backpack has an on-board PIC that abstracts out the HD44780 handling. Ease of use and no soldering comes at a higher price(double) than you have with the SainSmart product.

      Update:I read through the HiPi docs last night. Good stuff! The developer, Mark Dootson, has done much work on wxPerl and I believe that wxPerl will run on the RPI, if you need to do any GUI work.

      For Example:

      // SerLCDTest.pde - Serial Interface Version for use with the chipKIT +UNO // // This display uses the HD44780 LCD controller and a PIC16F688 serial + interface // // Test file for the Sparkfun Serial LCD used with the chipKIT UNO // Uses UART1(pin 40 TX) so UART0/USB can be used for debug message +s // Combined header and library files for initial testing of the dis +play. // Hope to split into a library after testing. // // James M. Lynes, Jr. // Last Modified: December 24,2012 // // This code is public domain, but you buy me a beer(or Dr. Pepper) // if you use this and we meet some day(Beerware License). // // Constant Definitions // // Display Commands // #define COMMAND 0xFE // Command Code #define CLEARDISP 0x01 // Clear the display #define CURSORHOME 0x02 // Send the cursor home #define CURSORRIGHT 0x14 // Move the cursor right one pos +ition #define CURSORLEFT 0x10 // Move cursor left one position #define SCROLLRIGHT 0x1C // Scroll the display right #define SCROLLLEFT 0x18 // Scroll the display left #define DISPLAYON 0x0C // Turn the display on #define DISPLAYOFF 0x08 // Turn the display off #define UCURSORON 0x0E // Turn underline cursor on #define UCURSOROFF 0x0C // Turn underline cursor off #define BOXCURSORON 0x0D // Turn box cursor on #define BOXCURSOROFF 0x0C // Turn box cursor off #define LINE1 0x80 // Row 1 COl 1 Address #define LINE2 0xC0 // Row 2 COl 1 Address #define RESET 0x12 // Reset code, send at 9600 baud i +mmediately after POR // // Configuration Commands // #define CONFIG 0x7C // Configuration Code #define B2400 0x0B // Set 2400 baud #define B4800 0x0C // Set 4800 baud #define B9600 0x0D // Set 9600 baud #define B144K 0x0E // Set 14400 baud #define B192K 0x0F // Set 19200 baud #define B384K 0x10 // Set 38400 baud #define SAVESPLASH 0x0A // Save a new splash message #define TOGGLESPLASH 0x09 // Toggle splash screen on and +off #define BACKLIGHTOFF 0x80 // Turn the backlight off #define BACKLIGHTMED 0x8F // Turn the backlight to 50% #define BACKLIGHTHIGH 0x9D // Turn the backlight to 100% // // Misc Defines // #define LCDTYPE 0x03 // Type 2 line x 16 characters #define LCDDelay 0x10 // General delay timer #define LCDDelay2 0x200 // Scroll timer // // Function Protypes // void LCDClear(); // Clear the display void LCDSelectLineOne(); // Position cursor to the beginning + of line 1 void LCDSelectLineTwo(); // Position cursor to the beginning + of Line 2 void LCDGoTo(int position); // Position cursor to a specific + character 0-15, 16-31 void LCDBacklightOn(); // Turn the backlight on void LCDBacklightOff(); // Turn the backlight off void LCDCursorHome(); // Position cursor to home void LCDCursorRight(); // Set cursor to move left to rght void LCDCursorLeft(); // Set cursor to move right to left void LCDScrollRight(); // Scroll the display right void LCDScrollLeft(); // Scroll the dispaly left void LCDDisplayOn(); // Turn the display on void LCDDisplayOff(); // Turn the display off void LCDUCursorOn(); // Turn the underline cursor on void LCDUCursorOff(); // Turn the underline cursor off void LCDBoxCursorOn(); // Turn the box cursor on void LCDBoxCursorOff(); // Turn the box cousor off void LCDBlackStart(); // Restart from an unknown state void LCDSaveSplash(char*, char*); // Save a new spash display void LCDToggleSplash(); // Toggle the splash display on/off/ +on void LCDSetBrightness(int); // Set the screen brightness 128 +-157(0x80-0x9D) void LCDSetBaud(int); // Set a new baud rate // // Test Function Prototypes // void tstwrite(); // Write out two lines of text void tstmoves(); // Try some cursor moves void tstscroll(); // Try some scrolling void tstbrightness(); // Cycle the backlight high to off // // Main Program // void setup() { delay(3000); // Time to allow the splash screen to disp +lay Serial.begin(9600); // Start serial communications for debu +g messages Serial.println("Initialized UNO Serial/USB Port"); Serial1.begin(9600); // Initialize the UART1 hardware Serial.println("Initialized UNO UART1"); LCDClear(); // Reset the LED display, cursor to positio +n 1 Serial.println("Cleared the LCD Display"); LCDSetBrightness(BACKLIGHTHIGH);// Set display to max brightness } void loop() { Serial.println("Mainloop"); Serial.println("Writes"); tstwrite(); delay(2000); Serial.println("Moves"); tstmoves(); delay(10000); Serial.println("Scrolls"); tstscroll(); delay(2000); // Serial.println("Brightness"); // tstbrightness(); // delay(2000); } // Test Subroutines void tstwrite() { LCDClear(); LCDSelectLineOne(); Serial1.print("Merry Christmas"); LCDSelectLineTwo(); Serial1.print(" to my Sweetie "); } void tstmoves() { LCDClear(); LCDSelectLineOne(); Serial1.print("789ABCDEF6543210"); LCDSelectLineTwo(); LCDGoTo(24); Serial1.print("@"); LCDCursorRight(); LCDCursorRight(); Serial1.print("#"); LCDCursorHome(); Serial1.print("$"); LCDCursorHome(); LCDCursorLeft(); // LCDCursorLeft(); Serial1.print("%"); } void tstscroll() { LCDClear(); LCDSelectLineOne(); Serial1.print("0123456789ABCDEF"); delay(LCDDelay); for(int i=1 ; i<9; i++){ LCDScrollLeft(); } for(int i=1 ; i<9; i++){ LCDScrollRight(); } } void tstbrightness() { tstwrite(); LCDSetBrightness(BACKLIGHTHIGH); LCDSetBrightness(BACKLIGHTMED); LCDSetBrightness(BACKLIGHTOFF); } // Library Subroutines void LCDClear() { Serial1.write(COMMAND); Serial1.write(CLEARDISP); // Clear the display delay(LCDDelay); } void LCDSelectLineOne() { Serial1.write(COMMAND); Serial1.write(LINE1); // Select line 1 delay(LCDDelay); } void LCDSelectLineTwo() { Serial1.write(COMMAND); Serial1.write(LINE2); // Select line 2 delay(LCDDelay); } void LCDGoTo(int position) { if(position < 16) // Go to specific position 0-31 { Serial1.write(COMMAND); Serial1.write(position + 128); } else if(position < 32) { Serial1.write(COMMAND); Serial1.write(position + 48 + 128); } else { LCDGoTo(0); } delay(LCDDelay); } void LCDBacklightOn() { Serial1.write(CONFIG); Serial1.write(BACKLIGHTHIGH); // Turn the backlight on delay(LCDDelay); } void LCDBacklightOff() { Serial1.write(CONFIG); Serial1.write(BACKLIGHTOFF); // Turn the backlight off delay(LCDDelay); } void LCDCursorHome() { Serial1.write(COMMAND); Serial1.write(CURSORHOME); // Position the cursor to home delay(LCDDelay); } void LCDCursorRight() { Serial1.write(COMMAND); Serial1.write(CURSORRIGHT); // Move cursor right one positi +on delay(LCDDelay); } void LCDCursorLeft() { Serial1.write(COMMAND); Serial1.write(CURSORLEFT); // Move cursor left one position delay(LCDDelay); } void LCDScrollRight() { Serial1.write(COMMAND); Serial1.write(SCROLLRIGHT); // Scroll the display right one + position delay(LCDDelay2); } void LCDScrollLeft() { Serial1.write(COMMAND); Serial1.write(SCROLLLEFT); // Scroll the display left one p +osition delay(LCDDelay2); } void LCDDisplayOn() { Serial1.write(COMMAND); Serial1.write(DISPLAYON); // Turn the display on delay(LCDDelay); } void LCDDisplayOff() { Serial1.write(COMMAND); Serial1.write(DISPLAYOFF); // Turn the display off delay(LCDDelay); } void LCDUCursorOn() { Serial1.write(COMMAND); Serial1.write(UCURSORON); // Turn the underline cursor on delay(LCDDelay); } void LCDUCursorOff() { Serial1.write(COMMAND); Serial1.write(UCURSOROFF); // Turn the underline cursor off delay(LCDDelay); } void LCDBoxCursorOn() { Serial1.write(COMMAND); Serial1.write(BOXCURSORON); // Turn the box cursor on delay(LCDDelay); } void LCDBoxCursorOff() { Serial1.write(COMMAND); Serial1.write(BOXCURSOROFF); // Turn the box cursor off delay(LCDDelay); } void LCDBlackStart() { Serial1.write(RESET); // Restart from unknown condition delay(LCDDelay); } void LCDSaveSplash(char *l1, char *l2) { LCDSelectLineOne(); // Replace the splash screen Serial1.print(l1); LCDSelectLineTwo(); Serial1.print(l2); Serial1.write(CONFIG); Serial1.write(SAVESPLASH); delay(LCDDelay); } void LCDToggleSplash() { Serial1.write(CONFIG); // Toggle the splash screen on/o +ff/on Serial1.write(TOGGLESPLASH); delay(LCDDelay); } void LCDSetBrightness(int level) { Serial1.write(CONFIG); // Change the brightness level Serial1.write(level); delay(LCDDelay); } void LCDSetBaud(int rate) { Serial1.write(CONFIG); // Change the baud rate Serial1.write(rate); delay(LCDDelay); }

      James

      There's never enough time to do it right, but always enough time to do it over...

        This code uses the HiPi module which seemed to me to require I load the whole GUI (I am using minibian) so I converted a Python demo program to Perl as an illustration of how to use the SMBus module to write to an I2C LCD (16x2). Here is the code:

        #!/usr/bin/perl # Example program which writes to the I2C LCD at address 0x3f. This w +as # a direct port of the program published by Matt Hawkins on the site # www.raspberrypi-spy.co.uk. Port performed by Steve Stock. # use strict; use warnings; use Time::HiRes ('usleep'); use Device::SMBus; my $I2C_ADDR=0x3f; my $DEVICE_PATH = '/dev/i2c-1'; my $dev = Device::SMBus->new(I2CBusDevicePath => $DEVICE_PATH, I2CDeviceAddress => $I2C_ADDR); my $LCD_WIDTH = 16; my $LCD_CHR=1; my $LCD_CMD=0; my $FILL_CHAR=" "; my $LCD_LINE_1=0x80; my $LCD_LINE_2=0xc0; my $LCD_LINE_3=0x94; my $LCD_LINE_4=0xd4; my $LCD_BACKLIGHT=0x08; my $LCD_BACKLIGHT_OFF=0x00; my $ENABLE=0b00000100; my $E_PULSE=500; my $E_DELAY=500; sub lcd_toggle_enable { my ($bits)=@_; usleep($E_PULSE); my $rc = $dev->writeByteData(0x00,$bits | $ENABLE); $rc = $dev->writeByteData(0x00,$bits & ~$ENABLE); } sub lcd_byte { my ($bits,$mode) = @_; my $bits_high=0;my $bits_low=0; $bits_high = $mode | ($bits & 0xf0) | $LCD_BACKLIGHT; $bits_low = $mode | (($bits << 4) & 0xf0) | $LCD_BACKLIGHT; my $rc = $dev->writeByteData(0x00,$bits_high); lcd_toggle_enable($bits_high); $rc = $dev->writeByteData(0x00,$bits_low); lcd_toggle_enable($bits_low); usleep($E_PULSE); } sub lcd_init { lcd_byte(0x33,$LCD_CMD); lcd_byte(0x32,$LCD_CMD); lcd_byte(0x06,$LCD_CMD); lcd_byte(0x0c,$LCD_CMD); lcd_byte(0x28,$LCD_CMD); lcd_byte(0x01,$LCD_CMD); usleep($E_PULSE); } sub lcd_string { my ($message, $line) = @_; lcd_byte($line, $LCD_CMD); for (0..$LCD_WIDTH) {$message=$message.$FILL_CHAR}; for (my $i=0;$i<($LCD_WIDTH);$i++) {lcd_byte(ord(substr($message,$i, +1)),$LCD_CHR);} } # MAIN while (1==1) { lcd_init(); lcd_string("RPiSpy <",$LCD_LINE_1); lcd_string("I2C LCD <",$LCD_LINE_2); sleep(5); lcd_string("> RPiSpy",$LCD_LINE_1); lcd_string("> I2C LCD",$LCD_LINE_2); sleep(5); }

Log In?
Username:
Password:

What's my password?
Create A New User
Node Status?
node history
Node Type: note [id://1164139]
help
Chatterbox?
and all is quiet...

How do I use this? | Other CB clients
Other Users?
Others wandering the Monastery: (6)
As of 2018-06-17 23:43 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?
    Should cpanminus be part of the standard Perl release?



    Results (107 votes). Check out past polls.

    Notices?