Drive SC1602 and SC2004 with Raspberry Pi
As I program a driver of SC1602 with paying attention to readability, I even found a defective of SC1602.
As I told you already on the post, “A total beginner started to learn electronics with Raspberry Pi”, Nikkei Linux March 2013 was the beginning of using Raspberry Pi. This post became one of the biggest hit of my blog, and Google puts this post in the top 10 of search results using “Raspberry Pi” in Japanese. (As of September 22th, 2014)
I finished the story when I could turn an LED, but Nikkei’s article continues. Its next step is using an SC1602, a Liquid-crystal display. I have actually bought it with LED together. Because Nikkei’s article has a sample code, I could output some characters on the display. At that time, I couldn’t understand the instruction that came with SC1602 at all. I kept “decoding” the instruction little by little, and I could understand the whole stuff at last.
What is SC1602?
An SC1602 is a display which is used by machines. I searched what machines use SC1602.
Edy – Rakuten’s money card reader used at some stores in Japan
NEC’s reader at a convenience store
Ticketing machine at a parking lot
Definition of SC1602
I don’t know about the history of SC1602. I searched but couldn’t find very well. SC1602 would be a generic name of these displays and the method to control these displays.
An SC1602 might be a device which has a Hitachi HD44780-compatible controller. HD44780 is released in 1980s and since then many manufactures released compatible devices.
Most LCDs sold at stores have HD44780. In general, because those LCDs are compatible, they are controlled in the same way, but there are some differences on data sending time and voltage. If you doubt their behavior, check the datasheet that comes with your LCD. – マイコン徹底入門
There is an article about Hitachi HD44780 LCD controller on Wikipedia, but they don’t have an article written in Japanese even it is developed by Hitachi Japan.
The one I bought at Marutsu was made by TINSHARP and says “Sunlike SC1602 compatible.” Suppose SC1602 is compatible to Hitachi HD44780, Marutsu’s LCD is compatible of compatible.
There are some family devices and they can be classified by size such as 10×4, 16×1, 16×2,16×4, 20×2, 20×4, 40×2, and 40×4. As you can see, SC1602 may be named because the size is 16×2.
SC1602s I bought
I bought some SC1602s and one SC2004.
SC2004 (left) and SC1602 (right)
I soldered pins to the displays…
… to plug and unplug. This is the Raspberry wires.
I was first using female pins.
But I found that if I used female pins, I couldn’t solder when I create something.
Be careful! Vdd and GND are often assigned to pin number1 and 2, but it is sometimes opposite. If the Vdd and GND pins are connected to the other way, the LCD doesn’t work. Actually it might break. There may be various reasons for doing such a thing. This is regarded as a mystery.
Nikkei’s code
This is the beginning of Nikkei’s code.
GPIO_CLR = 0x1F <<7; // Clear GPIO10 7-10(DB4-7)and GPIO 11(RS) GPIO_CLR = 1 << 22; // GP10 22 (E: Enable Signal) = 0 usleep(1); GPIO_SET = 3 <<7; // Send 8bit connection config GP10 7-10 (DB4-7) // GP10 11(RS)=0 usleep(1); GPIO_SET = 1 << 22; // Enable Signal = 1 usleep(20); // Enough wait (20μs) GPIO_SET = 1 << 22; // Enable Signal = 0
Even I had knowledge of C, I was amazed. The comment says the first line clears the GPIOs, and the program shifts bits. The program prepares 1F in hexadecimal, shifts it by 7 bits, and writes it to the I/O address of GPIOs.
What does 1F in hexadecimal mean? Why do I need to shift 7 bits? What is I/O address of GPIO? I was at this level and kept investigating one by one.
GPIO_CLR was defined in gpio_setup.h.
#define GPIO_SET *(gpio+7) // sets bits which are 1 ignores bits which are 0
*(gpio+7) points address which is 7 units away from gpio. The gpio pointer is defined like this:
gpio = (volatile unsigned *)gpio_map;
This means the pointer is the same as gpio_map. Then what is gpio_map?
I kept investigating like this.
I found that this program is controlling BCM2835 directly with free use of bit orders I mentioned above.
1F means 11111 in binary. I get this by shifting 7 bits.
1111 1000 0000
The rightmost bit means GPIO0, and the second bit means GPIO1. Because I shifted bits by 7, GPIO7 to 11 are 1. Overwriting these bits to certain address where GPIO_CLR pointer clears those GPIOs.
This procedure lost my energy a lot. I could know how to drive SC1602, but is this the only way to drive?
Electronic DIY and programming
As I searched and read books, ALL people without exception called some libraries. Those libraries “manipulate” 0 and 1 freely. The ways to call those libraries are like these.
lcdwrite(0x23);
writeByte(b("00111000"));
We will forget what these source codes mean when we look later. And we can’t call writeByte or lcdwrite unless we know them. Additionally we could miss that b is actually a function like writeByte and lcdwrite.
Even if we can call functions, we need to look up for 00111000 and 0x23. If we look later, this means we are in need of making new functions or fixing problems. We would be in trouble every time we look later.
I’m from the computer field, which would make me believe that people who wrote those codes are in the electronic field and they are still there. They might program because they can’t avoid programming.
Source code and readability
I kept improving the source code, and it became like this.
#include "SC1602.cpp" int main (int argc, char *argv[]) { SC1602 *lcd; lcd = new SC1602; lcd << "Hello World!"; }
Only these few codes do from initializing the LCD to outputting a string. If we forget function names, eclipse helps us. We just need to type “lcd ->”. If you don’t know what I mean, read “Making Raspberry Pi program by cross-compiling C++ with Eclipse on CentOS”.
If you use SC2004, the code would be like this.
#include "SC1602.cpp" #include "SC2004.cpp" int main (int argc, char *argv[]) { SC1602 *lcd; lcd = new SC2004C; lcd << "Hello World!"; }
And the code of SC2004 is only this.
class SC2004 : public SC1602 { // SC2004-specific configuration SC2004 () { // Char number of 1 line DISPLAY_WIDTH = 20; // Char number shown in 1 line INTERNAL_DISPLAY_WIDTH = 20; // Lines DISPLAY_HEIGHT = 4; }; unsigned int setDDRAM (unsigned char x, unsigned char y) { unsigned char address = x; if (y == 0); // Do nothing else if (y == 1) address += 0x40; else if (y == 2) address += 0x14; else if (y == 3) address += 0x54; address |= FUNCTION_CODE_SET_DD_RAM_ADDRESS; SC1602::setDDRAM(address); return SUCCESS; }; };
SC2004 “extends” SC1602. Because the way to control is the same as SC1602, we should use SC1602 as is, and “override” only the difference. This is why Object-orientation is convenient.
On the other hand, SC1602 is made to be overridden.
protected: virtual unsigned int setDDRAM (unsigned char x, unsigned char y) { ... }
Code refactoring is necessary to override only the difference or to be overridden. This means if we are not interested in code refactoring, it is hard to make the original class (SC1602) to be overridden. I went back and forth between SC1602 and SC2004 when I refactor.
I couldn’t make codes like these at the first time. Object-orientation can be explained with a car and a motorcycle. These classes have common methods like “run”, “move speedometer”, and “refuel”. I could understand what they mean, but they could be just virtual example. The objects are just “data” on a computer, not physical “cars”. I haven’t dreamed that the Object-orientated language worked on physical devices like SC1602 and SC2004.
By the way, be careful that C++ is not always available on electronic DIY. I chose C++ because Microchip PIC32 series supports C++, and I took Object-orientation more than the cost and physical size of PIC32. Even I bought a Microchip PICKIT3, haven’t used it at all. The reason why I bought it is because I wanted to think what language can be ported from Raspberry Pi. I thought Microchip’s PIC was widely used in electronic DIY and it could be highly possible to use in the future.
SC1602 has a bug
The readable codes let me found malfunctioning on SC1602. I bought SC1602s at both Akizuki and Marutsu in Akihabara, and only Akizuki’s SC1602 seemed to have the malfunctioning.
The bug appears when the function code “left cursor shift” is called. When the cursor moves across the address 0x0 from right to left, SC1602 can’t handle DDRAM correctly.
Do you know what left cursor shift is? Strings can be displayed from right to left on SC1602, but you can invert the direction by calling the function code “5: Cursor / display Shift”. I have no idea when I need it. I guess the driver was made to handle letters that are written from right to left like Arabic.
Driver is a chip that controls the display. It might be soldered somewhere on the circuit board of SC1602. I called Sunlike Taiwan, and they said SC1602s sold at Akizuki have Sitronix ST7066U as driver. They also suggested choosing SPLC780D, but the problem is I can’t choose the driver. Kids can’t choose parents.
By the way, the Sunlike personnel said SC1602s sold at Marutsu have different drivers. This could be evidence of my investigation.
Another difference
Once SC1602 receive a function code, it needs time to execute the function. The time SC1602 needs is written in the specification. For example, “Clear Display” takes 1.5 milliseconds. The value may change like 1.52 or 1.64ms, but I don‘t know why. If Raspberry pi sends the next code without waiting, SC1602 ignores it. More precisely, SC1602 looks like ignoring.
I found that SC1602s’ response time is varying. Ones sold at Akizuki can respond in 0.5 milliseconds, and ones sold at Akizuki can respond in 0.4 milliseconds. In either case, nothing wrong happens if you wait 1.5 milliseconds.
No one writes code like “Do not wait for 1.5 milliseconds.” The problem is if we don’t know we need to do so, the program doesn’t wait for even 0.1 millisecond. This means we can never tell what causes problem unless we find it by chance. Additionally, if you output some debug string to the console, it takes more than 0.5 milliseconds, this could let the bug hide. I’ll explain this later.
Download
I published the program that I used for verification. This is an extension of the one I posted before, “Drive RHT03 with Raspberry Pi“.
Download Tango (Japanese Edition Only) – November 3 Edition
About options
Options change what the program does. Some options are required, and some are not. There is no particular order. Options are case sensitive. Options are considered only once in the order they are listed in the Option List below. Because demo10 loops, you need to press [Ctrl] and [c] when you finish.
Examples
./tango db4=4 db5=17 db6=27 db7=22 rw=10 rs=9 e=11
Initializes SC1602 in 4 bit mode. A blink cursor appears on SC1602.
./tango db4=4 db5=17 db6=27 db7=22 rw=10 rs=9 e=11 clear
Sends function code1 clear to SC1602. A blink cursor also appears on SC1602.
./tango db4=4 db5=17 db6=27 db7=22 rw=10 rs=9 e=11 write=ABCDEFG
Sends string ABCDEFG to SC1602.
./ tango db0=18 db1=23 db2=24 db3=25 db4=4 db5=17 db6=27 db7=22 rw=10 rs=9 e=11 info
Initializes SC1602 in 8 bit mode and shows configures in the console. A blink cursor appears on SC1602.
./ tango db4=4 db5=17 db6=27 db7=22 rw=10 rs=9 e=11 write=ABCDEFG && ./ tango db4=4 db5=17 db6=27 db7=22 rw=10 rs=9 e=11 noinit x=0 y=0 read=7
Sends string ABCDEFG to SC1602. If error code is 0, the cursor is move to address 0,0 (You can’t use home.) and then Raspberry Pi reads 1 char from SC1602 and outputs it in the console. Because this is done 7 times, the whole string will be output in the console.
If your LCD won’t work, just wire necessary ones.
SC1602 | Raspberry Pi |
DB0~DB3 | No wire |
DB4~DB7 | GPIOs you wish |
RW | GND |
RS | GPIO you wish |
E | GPIOs you wish |
VO | GND |
Options list
Options | behavior |
help | display usage and quits this program. All other options will be ignored. “usage” can be also instead. |
debug | output debug information. |
SC2004 | handle LCD as SC2004. (If not defined, SC1602 is drived) |
noadjust | omit the adjustment of cursor position after LCD moves the cursor. More details are written later. |
noinit | omit initialization. Noinit is supposed to be usesd with read. |
nosave | omit suspend. This affects to energy consumption, but not to function.More details are written later. |
db0=[2..31] | declare GPIO number to wire DB0. |
db1=[2..31] | declare GPIO number to wire DB1. (required with db0) |
db2=[2..31] | declare GPIO number to wire DB2. (required with db0) |
db3=[2..31] | declare GPIO number to wire DB3. (required with db0) |
db4=[2..31] | declare GPIO number to wire DB4. (required) |
db5=[2..31] | declare GPIO number to wire DB5. (required) |
db6=[2..31] | declare GPIO number to wire DB6. (required) |
db7=[2..31] | declar GPIO number to wire DB7. (required) |
rw=[2..31] | declare GPIO number to wire R/W. (required even when unwired.) |
rs=[2..31] | declare GPIO number to wire RS. (required) |
e=[2..31] | declares GPIO number to wire E. (required) |
info | shows configuration |
Function Code 1 and 2 | |
---|---|
clear=[0..1000000] | clear LCD. Cursor position and display position are also reset. You can declar the wait time. (The unit is microseconds, and default is 1520.) |
return | Cursor position and display position are reset. |
Function Code 3 Entry Mode | |
direction=[0,1] | declare direction to move cursor or display. 0:Left, 1:Right (default) |
shift=[0,1] | declares what to move. 0:Cursor (default), 1:DisplayIf display is declared, cursor doesn’t look moving, but its position (internal position called DDRAM) keeps changing. |
demo1 | demonstrate the Entry Mode. |
demo2 | demonstrate string output from right to left. |
Function Code 4 Display On/Off | |
display=[0,1] | Turns on/off the display. 0:off, 1:on (default) |
cursor=[0,1] | set the shape of the cursor. 0:None, 1:_ (default) |
blink=[0,1] | set how to blink the cursor. 0:always on, 1:Square and blink (default) |
demo3 | demonstrates Display On/Off |
Function Code 5 Cursor/display Shift | |
demo4 | demonstrates Cursor/display Shift |
demo5 | demonstrates string scrolling |
Function Code 6 Function Set | |
line=[0,1] | set line number. 0:1 line, 1:2 lines (default) |
font=[0,1] | set dot size of font. 0:5×8 (default), 1:5×11 |
demo6 | demonstrate both combinations. |
Function Code 7 Set CGRAM | |
char1 | set and displays smilly. |
char2 | set and displays bowling signs. |
char3 | set and displays battery signs. |
Function Code 8 Set DDRAM | |
x=[0..] | set horizontal position of cursor. |
y=[0..] | set vertical position of cursor. |
demo7 | demonstrate cursor movements. |
Function Code 9 Read Busy Flag/Address Counter | |
demo8 | demonstrate reading busy flag. |
demo9 | demonstrate reading address counter. |
Function Code 10 Write Data | |
write=ABC | display string “ABC”. |
demo10 | display strings that are typed. |
Function Code 11 Read Data | |
read=[0..] | read string at where the cursor is and displays the string. If number is defined, the same amount of characters are read. |
chardef | reads user char definitions and shows them. |
Verified components
I used the following devices.
- Raspberry Pi Model B
- OS 2014-01-07-wheezy-raspbian
- LCDs are shown below.
No | Vendor | Manufacture | Model | Lot No. | Vdd Pin No. | Backlight |
1 | RS Components | Powertip | PC1602-LRS-H | 921932019 | 2 | yes |
2 | Akizuki Denshi | Unknown | SC1602BS*B-XA-GB-K | 1006-005-109 | 1 | no |
3 | Akizuki Denshi | Unknown | SC2004CBWB-XA-GB-G | 1102-003-034 | 2 | yes outline character 20×04 |
4 | Marutsu | Linkman | TC1602E-06T | 134600012052 | 1 | yes |
Command to verify the left cursor malfunction
Use the command below to see how DDRAM changes.
./tango lcdbas db4=4 db5=17 db6=27 db7=22 rw=10 rs=9 e=11 noadjust direction=0 demo9
The console appears.
[0,0 (0000)]
This means [Cursor position x, Cursor position y (DDRAM Address)]
If your console is [0,0 (007F)], then your Pi couldn’t read the DDRAM Address. Make sureGPIO10 is wired to RS.
Type one key and press Enter. See what the address changes.
Correct Movement | Defective Movement |
[0,0 (0000)] | [0,0 (0000)] |
[39,1 (0067)] | [39,1 (007F)] |
[38,1 (0066)] | [38,1 (007E)] |
[37,1 (0065)] | [37,1 (007D)] |
[36,1 (0064)] | [36,1 (007C)] |
[35,1 (0063)] | [35,1 (007B)] |
[34,1 (0062)] | [34,1 (007A)] |
[33,1 (0061)] | [33,1 (0079)] |
[32,1 (0060)] | [32,1 (0078)] |
… | … |
[17,1 (0051)] | [17,1 (0069)] |
[16,1 (0050)] | [16,1 (0000)] |
[15,1 (004F)] | [15,1 (007F)] |
… | … |
These are what SC1602s look like after typing a to h.
Correct ResultDefective Result
Results
No | Vendor | Model | Result |
1 | RS Components | PC1602-LRS-H | defective |
2 | Akizuki Denshi | SC1602BS*B-XA-GB-K | defective |
3 | Akizuki Denshi | SC2004CBWB-XA-GB-G | defective |
4 | Marutsu | TC1602E-06T | fine |
Marutst’s SC1602 outputs only an ‘a’. This is because other characters are put at the addresses shown below. The gray part is out of display width, but can be displayed if you scroll.
On the other SC1602s, the cursor jumps to DDRAM addresses that don’t exist. But characters can be displayed at 0x00 to 0x07.
The cursor positions x and y are correct because the program counts. Once the position is determined, we can get the correct DDRAM address by using the matrix above. To avoid this malfunction, we can simply overwrite the DDRAM address.
Command to check the wait time of Clear Display
This command executes Clear Display and then prints “ABCDEFG”. But the wait time is shortened intentionally from 1520 microseconds to 500 microseconds.
./tango lcdbas db4=4 db5=17 db6=27 db7=22 rw=10 rs=9 e=11 clear=500 write=ABCDEFG
The result can be correct once a 10 times.
SC1602 misses the first character once a 10 times.
So, What happens another once a 10 times?
The string doesn’t make sense. But the string itself is always the same. This means if I get “ $4DTd”, I get “ $4DTd” again.
Verifying Energy Suspention
In addition, I verified the suspension effect.
Connect a multimeter between your Raspberry Pi and SC1602 in series.
Execute commands. They just display a string.
./tango lcdbas db4=4 db5=17 db6=27 db7=22 rw=10 rs=9 e=11 write=ABCDEFG
./tango lcdbas db4=4 db5=17 db6=27 db7=22 rw=10 rs=9 e=11 write=ABCDEFG nosave
If “nosave” is not used, GPIOs except E (DB, R/W, RS) are set to direction INPUT, voltage HIGH and pull UP. If “nosave” is used, GPIOs remain direction OUTPUT, voltage HIGH or LOW and pull UP or DOWN.
Results
No | Vendor | Model | Without suspention | With suspention | Reduced % |
1 | RS Components | PC1602-LRS-H | 0.92mA | 0.39mA | 58% |
2 | Akizuki Denshi | SC1602BS*B-XA-GB-K | 0.71mA | 0.26mA | 64% |
3 | Akizuki Denshi | SC2004CBWB-XA-GB-G | 31.46mA | 31.07mA | 1.1% |
4 | Marutsu | TC1602E-06T | 0.88mA | 0.43mA | 52% |
All the LCDs could reduce 0.5mA of current. Thus the energy consumption is cut to half. SC2004CBWB-XA-GB-G has the same result; however, because its current is originally high, there is no relative effect at all.
If you are interested in this post, check all posts of “Raspberry Pi and Electronics DIY ”. For example, I posted these articles.
- Drive RHT03 with Raspberry Pi
RHT03 is a hygrometer of MaxDetect. Today, I report how to control an RHT03 with a Raspberry Pi. It was great effort because I am - Drilling a Raspberry Pi case
I drilled my Raspberry Pi case to take GPIO pins out of case. I needed knowledge of DIY (Do it yourself) of both wood and metal. - Making Raspberry Pi program by cross-compiling C++ with Eclipse on CentOS
On the post written in the end of June, “A total beginner started to learn electronics with Raspberry Pi”, I wrote a shell script to turn on an LED ramp. Shell scripting is easy to start, but I thought using C language might increase possibility.
This post is also available in: Japanese
Leave a Reply