Demonstration
This is a simple project that shows how to control LCD16x2 via I2C interface, using PHPoC. It provides a web-based controller for LCD 16x2: just input any sentence, and it will be displayed on LCD after you finish typing.
Hardware components
PHPoC Blue × 1
LCD 16x2 (HD44780U) with I2C interface × 1
Schematics
Connect pin GND, VCC, and SDA and SCL of LCD16x2 to GND, PWR5V, SDA and SCL of PHPoC, respectively.
How it works
PHPoC Blue connects with LCD16x2 via I2C interface.
PHPoC Blue and Web browser exchange data via WebSocket connection, in which PHPoC Blue acts as a WebSocket server. After receiving text data from WS client, it will control LCD 16x2 to display those texts.
Source Code
Source code includes:
init.php : It's run when system boots and specifies which file is run next
PHP Code:
<?php
system("php task0.php");
?>
task0.php: This file contains server side code. It processes the data sent from the client and controls what to display on LCD16x2.
PHP Code:
<?php
if(_SERVER("REQUEST_METHOD"))
exit; // avoid php execution via http request
include_once "/lib/sn_tcp_ws.php";
include_once "lcd1602_i2c.php";
ws_setup(0, "lcd", "text.phpoc");
i2c_setup(0, LCD_ADDRESS);
$rbuf ="";
begin();
back_light();
set_cursor(1,0);
lcd_print("PHPoC with LCD");
while (ws_state(0) != TCP_CONNECTED)
{
sleep(1);
scroll_display_left();
sleep(1);
scroll_display_right();
sleep(1);
scroll_display_right();
sleep(1);
scroll_display_left();
}
while(1)
{
if(ws_state(0) == TCP_CONNECTED)
{
$rlen = ws_read(0, $rbuf);
if($rlen)
{
clear();
home();
for ($i=0;$i<$rlen;$i++)
{
lcd_print($rbuf[$i]);
if ($i==15)
{
set_cursor(0,1);
}
}
}
}
}
?>
index.php: This is client side code. When you input any sentence, the Web client (Web browser) will send it to Web server (PHPoC Blue) via WebSocket connection.
PHP Code:
<!DOCTYPE html>
<html>
<head>
<title>PHPoC - LCD 1602</title>
<meta name="viewport" content="width=device-width, initial-scale=0.7, maximum-scale=0.7">
<style>
body { text-align: center; font-size: 15pt; font-family: Arial, Helvetica, sans-serif;}
h1 { font-weight: bold; font-size: 25pt; }
h2 { font-weight: bold; font-size: 15pt; }
button { font-weight: bold; font-size: 15pt; }
textarea { width:500px; height:100px; padding:20px; font-family:courier; font-size:50px; background-color: #ccff66;overflow:hidden;word-wrap:break-word;}
</style>
<script>
var ws = null;
var last_sent = null;
var timer = null;
function init()
{
var lcd_display = document.getElementById("wc_text");
lcd_display.addEventListener("keydown", key_down);
}
function connect_onclick()
{
if(ws == null)
{
var ws_host_addr = "<?echo _SERVER("HTTP_HOST")?>";
ws = new WebSocket("ws://" + ws_host_addr + "/lcd", "text.phpoc");
document.getElementById("ws_state").innerHTML = "CONNECTING";
ws.onopen = ws_onopen;
ws.onclose = ws_onclose;
ws.onmessage = ws_onmessage;
}
else
ws.close();
}
function ws_onopen()
{
document.getElementById("ws_state").innerHTML = "<font color='blue'>CONNECTED</font>";
document.getElementById("bt_connect").innerHTML = "DISCONNECT";
}
function key_down()
{
clearTimeout(timer);
timer = setTimeout(send_to_lcd, 2000);
}
function ws_onclose()
{
document.getElementById("ws_state").innerHTML = "<font color='gray'>NOT CONNECTED</font>";
document.getElementById("bt_connect").innerHTML = "START";
ws.onopen = null;
ws.onclose = null;
ws.onmessage = null;
ws = null;
}
function ws_onmessage(e_msg)
{
e_msg = e_msg || window.event;
alert("msg : " + e_msg.data);
}
function send_to_lcd()
{
var val = document.getElementById("wc_text").value;
if(ws != null)
{
if (val != last_sent)
{
last_sent = val;
ws.send(val);
}
}
}
window.onload = init;
</script>
</head>
<body>
<center>
<p>
<h1>PHPoC - LCD 1602</h1>
</p>
<h2>
<p>
<textarea id="wc_text" class="input" type="text" cols="20" rows="2" maxlength="32" font="Courier" ></textarea><br>
</p>
<p>
WebSocket : <span id="ws_state">null</span>
</p>
<button id="bt_connect" type="button" onclick="connect_onclick();">START</button>
</h2>
</center>
</body>
</html>
lcd1602_i2c.php : LCD16x2 library with I2C interface for PHPoC.
PHP Code:
<?php
include_once "/lib/sd_340.php";
// Device I2C Adrress
define ("LCD_ADDRESS", 0x3F);
// LCD commands
define ("LCD_CLEARDISPLAY", 0x01);
define ("LCD_RETURNHOME", 0x02);
define ("LCD_ENTRYMODESET", 0x04);
define ("LCD_DISPLAY_CONTROL", 0x08);
define ("LCD_CURSORSHIFT", 0x10);
define ("LCD_FUNCTIONSET", 0x20);
define ("LCD_SETCGRAMADDR", 0x40);
define ("LCD_SETDDRAMADDR", 0x80);
// Flags for display entry mode
define ("LCD_ENTRYRIGHT", 0x00);
define ("LCD_ENTRYLEFT", 0x02);
define ("LCD_ENTRYSHIFTINCREMENT", 0x01);
define ("LCD_ENTRYSHIFTDECREMENT", 0x00);
// Flags for display on/off control
define ("LCD_DISPLAYON", 0x04);
define ("LCD_DISPLAYOFF", 0x00);
define ("LCD_CURSORON", 0x02);
define ("LCD_CURSOROFF", 0x00);
define ("LCD_BLINKON", 0x01);
define ("LCD_BLINKOFF", 0x00);
// Flags for display/cursor shift
define ("LCD_DISPLAYMOVE", 0x08);
define ("LCD_CURSORMOVE", 0x00);
define ("LCD_MOVERIGHT", 0x04);
define ("LCD_MOVELEFT", 0x00);
// Flags for function set
define ("LCD_8BITMODE", 0x10);
define ("LCD_4BITMODE", 0x00);
define ("LCD_2LINE", 0x08);
define ("LCD_1LINE", 0x00);
define ("LCD_5x10DOTS", 0x04);
define ("LCD_5x8DOTS", 0x00);
define ("LCD_BACKLIGHT", 0x08);
define ("LCD_NOBACKLIGHT", 0x00);
// Bit control
define ("EN", 0x04); //Enable bit
define ("RS", 0x01); //Register select
$display_control = 0;
$display_function = 0;
$backlight_val = 0;
$display_mode = 0;
function expander_write($data)
{
global $backlight_val;
i2c_write(0, ($data | $backlight_val) , 1);
}
function pulse_enable($data)
{
expander_write($data | EN);
usleep(1);
expander_write($data & (~EN));
usleep(50);
}
function write_nibble($data)
{
expander_write($data);
pulse_enable($data);
}
function send_data($value, $mode)
{
$high_nib= $value&0xf0;
$low_nib=($value<<4)&0xf0;
write_nibble(($high_nib)|$mode);
write_nibble(($low_nib)|$mode);
}
function command($cmd)
{
send_data($cmd, 0);
}
function display()
{
global $display_control;
$display_control |= LCD_DISPLAYON;
command(LCD_DISPLAY_CONTROL | $display_control);
}
function clear()
{
command(LCD_CLEARDISPLAY);
usleep(2000);
}
function home()
{
command(LCD_RETURNHOME);
usleep(2000);
}
function back_light() {
global $backlight_val;
$backlight_val = LCD_BACKLIGHT;
expander_write(0);
}
function no_back_light() {
global $backlight_val;
$backlight_val = LCD_NOBACKLIGHT;
expander_write(0);
}
function print_ascii($data)
{
send_data($data, RS);
}
function lcd_print($str) {
$len = strlen($str);
for ($i=0; $i < $len; $i++)
{
$cur_char = bin2int($str, $i, 1);
print_ascii($cur_char);
}
}
function scroll_display_left() {
command(LCD_CURSORSHIFT | LCD_DISPLAYMOVE | LCD_MOVELEFT);
}
function scroll_display_right() {
command(LCD_CURSORSHIFT | LCD_DISPLAYMOVE | LCD_MOVERIGHT);
}
function set_cursor($col, $row){
$row_offsets = array(0x00, 0x40);
if (($row==0)||($row==1))
{
command(LCD_SETDDRAMADDR | ($col + $row_offsets[$row]));
}
else
{
echo "Please select row value again";
return;
}
}
function begin()
{
global $display_control, $backlight_val, $display_mode;
$display_function = LCD_4BITMODE | LCD_2LINE | LCD_5x8DOTS;
// Wait for more than 40ms after Vcc rises to 2.7V
usleep(50000);
// Turn backlight off
$backlight_val = LCD_NOBACKLIGHT;
expander_write($backlight_val);
usleep(1000);
write_nibble(0x03 << 4);
// Wait for more than 4.1ms
usleep(4500);
write_nibble(0x03 << 4);
// Wait for more than 4.1ms
usleep(4500);
write_nibble(0x03 << 4);
// Wait for more than 100us
usleep(150);
// Set to 4-bit interface
write_nibble(0x02 << 4);
// Set number of lines, font size
command(LCD_FUNCTIONSET | $display_function);
// Turn the display on with no cursor or blinking default
$display_control = LCD_DISPLAYON | LCD_CURSOROFF | LCD_BLINKOFF;
display();
// Clear LCD
clear();
// Initialize to default text direction
$display_mode = LCD_ENTRYLEFT | LCD_ENTRYSHIFTDECREMENT;
// Set the entry mode
command(LCD_ENTRYMODESET | $display_mode);
home();
}
?>