├── 4x20-LCD-panel.jpg
├── I2C_connector.jpg
├── LCD1.jpg
├── LCD2.jpg
├── LCDback.jpg
├── README.md
├── YwRobotLCD-CU-450.jpg
├── joystick.jpg
└── src
└── org
└── raiderrobotics
└── i2c.java
/4x20-LCD-panel.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/RaiderRobotics/FRC-LCD-Display/50269ff7c74fae049c91f410d71494c664e0f29e/4x20-LCD-panel.jpg
--------------------------------------------------------------------------------
/I2C_connector.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/RaiderRobotics/FRC-LCD-Display/50269ff7c74fae049c91f410d71494c664e0f29e/I2C_connector.jpg
--------------------------------------------------------------------------------
/LCD1.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/RaiderRobotics/FRC-LCD-Display/50269ff7c74fae049c91f410d71494c664e0f29e/LCD1.jpg
--------------------------------------------------------------------------------
/LCD2.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/RaiderRobotics/FRC-LCD-Display/50269ff7c74fae049c91f410d71494c664e0f29e/LCD2.jpg
--------------------------------------------------------------------------------
/LCDback.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/RaiderRobotics/FRC-LCD-Display/50269ff7c74fae049c91f410d71494c664e0f29e/LCDback.jpg
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # FRC-LCD-Display
2 |
3 | :large_blue_diamond: The source code here demonstrates how to set up a 4x20 LCD panel display with the Roborio (for FRC First Robotics Competition).
4 |
5 | All you have to do to use it is add the code that I've written, and then run the command `LCDwriteString(String s, int line);` where String s is the string to write to the display, and int line is line number (1-4).
6 |
7 | 
8 | 
9 | 
10 |
11 | -------------------
12 | ## First the hardware:
13 |
14 | :black_small_square: We're using a display like the one in the photo
15 |
16 | .
17 |
18 | 
19 |
20 | :black_small_square: Note that it comes with a backplate thing mounted on it. This backplate already has all of the connections between the LCD display and the I2C protocol.
21 |
22 | 
23 |
24 | :black_small_square: The connectors on the back of the LCD display do not match the connectors on the RoboRIO. The RoboRIO has the pins in a different order. Also note that the LCD display requires 5V, not the 3.3V on the RoboRIO I2C connector. We're just using 5V from a digital IO pin. You could also use the 5V from the Voltage Regulator Module.
25 |
26 |
27 |
28 |
29 | -------------------------------
30 |
31 | ## CODE
32 |
33 | ### Background information
34 |
35 | :boom: **WPI Documentation** The [WPI documenation](http://first.wpi.edu/FRC/roborio/stable/docs/java/classedu_1_1wpi_1_1first_1_1wpilibj_1_1I2C.html) is completely useless. The [source code](https://usfirst.collab.net/gerrit/gitweb?p=allwpilib.git;f=wpilibj/wpilibjava/src/main/java/edu/wpi/first/wpilibj/I2C.java;h=8476) is no help either.
36 |
37 | It's easy to make an I2C object: `lcdDisplay = new I2C(I2C.Port.kOnboard, 0x27);` The address of most LCD panels is 0x27. It's a lot harder to write to the display since the only thing that the documentation tells you is `boolean write (int registerAddress, int data)`. There is no explanation of what the register address should be, no examples of this being used anywhere. *(I finally figured it out, see below.)*
38 |
39 | :boom: LCD Panels are all driven by the [Hitachi HD44780 driver](http://www.waveshare.com/datasheet/LCD_en_PDF/HD44780.pdf). This page provides details, explains the display addressing, and lists the commands that are build in.
40 |
41 | :boom: There are some very useful code examples here:
42 |
43 | * LCD panel display documentation: http://www.microcontrollerboard.com/lcd.html
44 | * Using Java to access I2C devices with examples of LCD display: https://docs.oracle.com/javame/8.1/me-dev-guide/i2c.htm
45 | * This helped understand the hardware a bit. http://letsmakerobots.com/content/drive-standard-hd44780-lcd-using-pcf8574-and-i2c
46 |
47 | :boom: Finally, I realized that [my python code](https://github.com/salamander2/RaspberryPi/tree/master/programs/LCD) :snake: (which I got from someone else's Raspberry Pi repository) could be directly ported to Java. **It worked!!!**
48 |
49 | -----------------
50 |
51 | ### How the code works
52 |
53 | * It turns out that the register to write the I2C data is ALWAYS 0 (I'm talking about the WPI `I2C.write()` command). Why? This is either the I2C controller or the register on the I2C device. So it seems that the LCD display only has one (external facing) register.
54 | * However ... internally, there are TWO registers: a command register and a data/display register. The registers are INTERNAL and are selected by using the Rs bit or not.
55 | * Commands are always written 4 bits at a time. Why? This is because it's the way that everyone does it. (Originally it was so that you need fewer data lines connected to your display.)
56 | * Commands have to be "strobed" using the En bit for them to take effect.
57 | * Commands do not execute instantaneously, so you need a short delay between them.
58 | * There is a sequence of initialization commands that must be done to set up the display after it's been powered on before it can be used.
59 | * Many of the other commands (cursor movement, etc.) I have not tried.
60 |
61 |
--------------------------------------------------------------------------------
/YwRobotLCD-CU-450.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/RaiderRobotics/FRC-LCD-Display/50269ff7c74fae049c91f410d71494c664e0f29e/YwRobotLCD-CU-450.jpg
--------------------------------------------------------------------------------
/joystick.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/RaiderRobotics/FRC-LCD-Display/50269ff7c74fae049c91f410d71494c664e0f29e/joystick.jpg
--------------------------------------------------------------------------------
/src/org/raiderrobotics/i2c.java:
--------------------------------------------------------------------------------
1 | package org.raiderrobotics;
2 |
3 | import edu.wpi.first.wpilibj.*;
4 |
5 | /*
6 | * LCD display panel code written by Michael Harwood, FRC Team 5024. November 2015.
7 | * Please see https://github.com/RaiderRobotics/FRC-LCD-Display for source code repository and complete documentation.
8 | *
9 | * This java code is not originally mine.
10 | * It is based on my python code which in turn came from Paul Barber: https://github.com/paulbarber/raspi-gpio
11 | *
12 | * Feel free to copy it and modify it as desired
13 | */
14 |
15 | public class Robot extends IterativeRobot {
16 |
17 | /* **********************************************************
18 | * Constants for LCD Panel
19 | * ********************************************************/
20 | // LCD Commands
21 | private static final int LCD_CLEARDISPLAY = 0x01;
22 | private static final int LCD_RETURNHOME = 0x02;
23 | private static final int LCD_ENTRYMODESET = 0x04;
24 | private static final int LCD_DISPLAYCONTROL = 0x08;
25 | private static final int LCD_CURSORSHIFT = 0x10;
26 | private static final int LCD_FUNCTIONSET = 0x20;
27 | private static final int LCD_SETCGRAMADDR = 0x40;
28 | private static final int LCD_SETDDRAMADDR = 0x80;
29 |
30 | // Flags for display on/off control
31 | private static final int LCD_DISPLAYON = 0x04;
32 | private static final int LCD_DISPLAYOFF = 0x00;
33 | private static final int LCD_CURSORON = 0x02;
34 | private static final int LCD_CURSOROFF = 0x00;
35 | private static final int LCD_BLINKON = 0x01;
36 | private static final int LCD_BLINKOFF = 0x00;
37 |
38 | // Flags for display entry mode
39 | // private static final int LCD_ENTRYRIGHT = 0x00;
40 | private static final int LCD_ENTRYLEFT = 0x02;
41 | private static final int LCD_ENTRYSHIFTINCREMENT = 0x01;
42 | private static final int LCD_ENTRYSHIFTDECREMENT = 0x00;
43 |
44 | // Flags for display/cursor shift
45 | private static final int LCD_DISPLAYMOVE = 0x08;
46 | private static final int LCD_CURSORMOVE = 0x00;
47 | private static final int LCD_MOVERIGHT = 0x04;
48 | private static final int LCD_MOVELEFT = 0x00;
49 |
50 | // flags for function set
51 | private static final int LCD_8BITMODE = 0x10;
52 | private static final int LCD_4BITMODE = 0x00;
53 | private static final int LCD_2LINE = 0x08; //for 2 or 4 lines actually
54 | private static final int LCD_1LINE = 0x00;
55 | private static final int LCD_5x10DOTS = 0x04; //seldom used!!
56 | private static final int LCD_5x8DOTS = 0x00;
57 |
58 | // flags for backlight control
59 | private static final int LCD_BACKLIGHT = 0x08;
60 | private static final int LCD_NOBACKLIGHT = 0x00;
61 |
62 | //bitmasks for register control
63 | private static final int En = 0b00000100; // Enable bit
64 | private static final int Rw = 0b00000010; // Read/Write bit
65 | private static final int Rs = 0b00000001; // Register select bit
66 |
67 | /* *********************************************************************************
68 | * End of LCD constants
69 | * ********************************************************************************/
70 |
71 | final static double MAXSPEED = 0.50;
72 |
73 | // instance variables
74 | RobotDrive driveTrain;
75 | Joystick stick1;
76 | Talon talon1, talon2;
77 | I2C lcdDisplay;
78 |
79 | long startTime = 0;
80 |
81 | public void robotInit() {
82 | //first to run, only runs once
83 | talon1 = new Talon(1);
84 | talon2 = new Talon(2);
85 | driveTrain = new RobotDrive(talon1, talon2);
86 | stick1 = new Joystick(0);
87 | //invert motors
88 | driveTrain.setInvertedMotor(RobotDrive.MotorType.kFrontLeft, true);
89 | driveTrain.setInvertedMotor(RobotDrive.MotorType.kFrontRight, true);
90 | driveTrain.setInvertedMotor(RobotDrive.MotorType.kRearLeft, true);
91 | driveTrain.setInvertedMotor(RobotDrive.MotorType.kRearRight, true);
92 |
93 | initLCD();
94 | }
95 |
96 | /* ***************************************************************************
97 | * Methods for using LCD Display
98 | * **************************************************************************/
99 |
100 | void initLCD() {
101 | lcdDisplay = new I2C(I2C.Port.kOnboard, 0x27);
102 |
103 | LCDwriteCMD(0x03);
104 | LCDwriteCMD(0x03);
105 | LCDwriteCMD(0x03);
106 | LCDwriteCMD(0x02);
107 | //4 bit mode??? -- yes. Always. It's the default way of doing this for LCD displays
108 | LCDwriteCMD( LCD_FUNCTIONSET | LCD_2LINE | LCD_5x8DOTS | LCD_4BITMODE );
109 | LCDwriteCMD( LCD_DISPLAYCONTROL | LCD_DISPLAYON );
110 | LCDwriteCMD( LCD_CLEARDISPLAY );
111 | LCDwriteCMD( LCD_ENTRYMODESET | LCD_ENTRYLEFT );
112 | zsleep(10);
113 | }
114 |
115 | //write a sleep method to get rid of the try-catch stuff
116 | void zsleep(int t) {
117 | try { Thread.sleep(t);
118 | } catch(InterruptedException e) {}
119 | }
120 |
121 | //This is for writing commands, 4 bits at a time
122 | void LCDwriteCMD (int data) {
123 | LCD_rawWrite(data & 0xF0);
124 | LCD_rawWrite((data <<4 ) & 0xF0);
125 | }
126 |
127 | //This is for writing a character, 4 bits at a time
128 | void LCDwriteChar ( int data) {
129 | LCD_rawWrite( Rs | (data & 0xF0));
130 | LCD_rawWrite( Rs | ((data <<4 ) & 0xF0));
131 | }
132 |
133 | void LCD_rawWrite( int data) {
134 | lcdDisplay.write(0, data | LCD_BACKLIGHT );
135 | strobe(data);
136 | }
137 |
138 | void strobe(int data){
139 | // Syntax: lcdDisplay.write(reg,data);
140 | lcdDisplay.write(0, data | En | LCD_BACKLIGHT );
141 | zsleep(1);
142 | lcdDisplay.write(0, (data & ~En) | LCD_BACKLIGHT );
143 | zsleep(1);
144 | }
145 |
146 | //This is the "public" method. The one that is actually used by other code to write to the display.
147 | void LCDwriteString(String s, int line) {
148 | switch (line) {
149 | case 1: LCDwriteCMD(0x80); break;
150 | case 2: LCDwriteCMD(0xC0); break;
151 | case 3: LCDwriteCMD(0x94); break;
152 | case 4: LCDwriteCMD(0xD4); break;
153 | default: return; //invalid line number does nothing.
154 | }
155 |
156 | //limit to 20 chars/line so we don't have to worry about overflow messing up the display
157 | if (s.length() > 20) s = s.substring(0, 20);
158 |
159 | for (int i=0; i