From 1bd781af8611f5095fe9c956895dd8a659b49ea3 Mon Sep 17 00:00:00 2001 From: Eugene Date: Sun, 25 Mar 2018 12:30:41 -0400 Subject: [PATCH] Hitachi HD44780U Dot Matrix Liquid Crystal Display (#223) Signed-off-by: Eugene Dzhurinsky --- AUTHORS | 1 + experimental/devices/hd44780/hd44780.go | 242 ++++++++++++++++++++++++ 2 files changed, 243 insertions(+) create mode 100644 experimental/devices/hd44780/hd44780.go diff --git a/AUTHORS b/AUTHORS index 34bcdca..5229ca8 100644 --- a/AUTHORS +++ b/AUTHORS @@ -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 +Fractal Industries, Inc Google Inc. Matt Aimonetti Max Ekman diff --git a/experimental/devices/hd44780/hd44780.go b/experimental/devices/hd44780/hd44780.go new file mode 100644 index 0000000..2ab39ab --- /dev/null +++ b/experimental/devices/hd44780/hd44780.go @@ -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< 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{}