Hitachi HD44780U Dot Matrix Liquid Crystal Display (#223)

Signed-off-by: Eugene Dzhurinsky <jdevelop@gmail.com>
pull/1/head
Eugene 8 years ago committed by M-A
parent 124fa6f98b
commit 1bd781af86

@ -4,6 +4,7 @@
# some cases, their employer may be the copyright holder. To see the full list
# of contributors, see the revision history in source control.
Cássio Botaro <cassiobotaro@gmail.com>
Fractal Industries, Inc
Google Inc.
Matt Aimonetti <mattaimonetti@gmail.com>
Max Ekman <max@looplab.se>

@ -0,0 +1,242 @@
// Copyright 2018 The Periph Authors. All rights reserved.
// Use of this source code is governed under the Apache License, Version 2.0
// that can be found in the LICENSE file.
// Package hd44780 controls the Hitachi LCD display chipset HD-44780
//
// Datasheet
//
// https://www.sparkfun.com/datasheets/LCD/HD44780.pdf
package hd44780
import (
"fmt"
"time"
"periph.io/x/periph/conn"
"periph.io/x/periph/conn/gpio"
)
// lineTwo offset for the second line in the LCD buffer.
const lineTwo = 0x40
// Dev is the 4-bit addressing device for HD-44780
type Dev struct {
// data pins
dataPins []gpio.PinOut
// register select pin
rsPin gpio.PinOut
// enable pin
enablePin gpio.PinOut
}
// New creates and initializes the LCD device
// data - references to data pins
// rs - rs pin
// e - strobe pin
func New(data []gpio.PinOut, rs, e gpio.PinOut) (*Dev, error) {
if len(data) != 4 {
return nil, fmt.Errorf("expected 4 data pins, passed %s", len(data))
}
dev := &Dev{
dataPins: data,
enablePin: e,
rsPin: rs,
}
if err := dev.Reset(); err != nil {
return nil, err
}
return dev, nil
}
// Reset resets the HC-44780 chipset, clears the screen buffer and moves cursor to the
// home of screen (line 0, column 0).
func (r *Dev) Reset() error {
if err := r.clearBits(); err != nil {
return err
}
delayMs(15)
if err := r.rsPin.Out(gpio.Low); err != nil {
return err
}
if err := r.enablePin.Out(gpio.Low); err != nil {
return err
}
if err := r.bulkSendData(resetSequence, r.write4Bits); err != nil {
return err
}
if err := r.bulkSendData(initSequence, r.writeInstruction); err != nil {
return err
}
return nil
}
func (r *Dev) String() string {
return "HD44870, 4 bit mode"
}
// Halt clears the LCD screen
func (r *Dev) Halt() error {
if err := r.writeInstruction(0x01); err != nil {
return err
}
delayMs(2)
return nil
}
// SetCursor positions the cursor
// line - screen line, 0-based
// column - column, 0-based
func (r *Dev) SetCursor(line uint8, column uint8) error {
if err := r.writeInstruction(0x80 | (line*lineTwo + column)); err != nil {
return err
}
return nil
}
// Print the data string
// data string to display
func (r *Dev) Print(data string) error {
for _, v := range []byte(data) {
if err := r.WriteChar(v); err != nil {
return err
}
}
return nil
}
// WriteChar writes a single byte (character) at the cursor position.
// data - character code
func (r *Dev) WriteChar(data uint8) error {
if err := r.sendData(); err != nil {
return err
}
if err := r.write4Bits(data >> 4); err != nil {
return err
}
if err := r.write4Bits(data); err != nil {
return err
}
delayUs(10)
return nil
}
// service methods
var resetSequence = [][]uint{
{0x03, 50}, // init 1-st cycle
{0x03, 10}, // init 2-nd cycle
{0x03, 10}, // init 3-rd cycle
{0x02, 10}, // init finish
}
var initSequence = [][]uint{
{0x14, 0}, // 4-bit mode, 2 lines, 5x7 chars high
{0x10, 0}, // disable display
{0x01, 2000}, // clear screen
{0x06, 0}, // cursor shift right, no display move
{0x0c, 0}, // enable display no cursor
{0x01, 2000}, // clear screen
{0x02, 2000}, // cursor home
}
func (r *Dev) bulkSendData(seq [][]uint, f func(_data uint8) error) error {
for _, v := range seq {
if err := f(uint8(v[0])); err != nil {
return err
}
if v[1] > 0 {
delayUs(v[1])
}
}
return nil
}
func (r *Dev) clearBits() error {
for _, v := range r.dataPins {
if err := v.Out(gpio.Low); err != nil {
return err
}
}
return nil
}
func (r *Dev) write4Bits(data uint8) error {
for i, v := range r.dataPins {
if data&(1<<uint(i)) > 0 {
if err := v.Out(gpio.High); err != nil {
return err
}
} else {
if err := v.Out(gpio.Low); err != nil {
return err
}
}
}
return r.strobe()
}
func (r *Dev) sendInstruction() error {
if err := r.rsPin.Out(gpio.Low); err != nil {
return err
}
if err := r.enablePin.Out(gpio.Low); err != nil {
return err
}
return nil
}
func (r *Dev) sendData() error {
if err := r.rsPin.Out(gpio.High); err != nil {
return err
}
if err := r.enablePin.Out(gpio.Low); err != nil {
return err
}
return nil
}
func (r *Dev) writeInstruction(data uint8) error {
if err := r.sendInstruction(); err != nil {
return err
}
// write high 4 bits
if err := r.write4Bits(data >> 4); err != nil {
return err
}
// write low bits
if err := r.write4Bits(data); err != nil {
return err
}
delayUs(50)
return nil
}
func (r *Dev) strobe() error {
if err := r.enablePin.Out(gpio.High); err != nil {
return err
}
delayUs(2)
if err := r.enablePin.Out(gpio.Low); err != nil {
return err
}
return nil
}
func delayUs(ms uint) {
time.Sleep(time.Duration(ms) * time.Microsecond)
}
func delayMs(ms int) {
time.Sleep(time.Duration(ms) * time.Millisecond)
}
var _ conn.Resource = &Dev{}
var _ fmt.Stringer = &Dev{}
Loading…
Cancel
Save