hybridgroup.gobot/drivers/gpio/hd44780_driver.go

411 lines
9.8 KiB
Go

package gpio
import (
"errors"
"gobot.io/x/gobot"
"time"
)
const (
HD44780_CLEARDISPLAY = 0x01
HD44780_RETURNHOME = 0x02
HD44780_ENTRYMODESET = 0x04
HD44780_DISPLAYCONTROL = 0x08
HD44780_CURSORSHIFT = 0x10
HD44780_FUNCTIONSET = 0x20
HD44780_SETCGRAMADDR = 0x40
HD44780_SETDDRAMADDR = 0x80
HD44780_ENTRYRIGHT = 0x00
HD44780_ENTRYLEFT = 0x02
HD44780_ENTRYSHIFTINCREMENT = 0x01
HD44780_ENTRYSHIFTDECREMENT = 0x00
HD44780_DISPLAYON = 0x04
HD44780_DISPLAYOFF = 0x00
HD44780_CURSORON = 0x02
HD44780_CURSOROFF = 0x00
HD44780_BLINKON = 0x01
HD44780_BLINKOFF = 0x00
HD44780_DISPLAYMOVE = 0x08
HD44780_CURSORMOVE = 0x00
HD44780_MOVERIGHT = 0x04
HD44780_MOVELEFT = 0x00
HD44780_1LINE = 0x00
HD44780_2LINE = 0x08
HD44780_5x8DOTS = 0x00
HD44780_5x10DOTS = 0x04
HD44780_4BITBUS = 0x00
HD44780_8BITBUS = 0x10
)
const (
HD44780_2NDLINEOFFSET = 0x40
)
// data bus mode
type HD44780BusMode int
const (
HD44780_4BITMODE HD44780BusMode = iota + 1
HD44780_8BITMODE
)
// databit pins
type HD44780DataPin struct {
D0 string // not used if 4bit mode
D1 string // not used if 4bit mode
D2 string // not used if 4bit mode
D3 string // not used if 4bit mode
D4 string
D5 string
D6 string
D7 string
}
// HD44780Driver is the gobot driver for the HD44780 LCD controller
// Datasheet: https://www.sparkfun.com/datasheets/LCD/HD44780.pdf
type HD44780Driver struct {
name string
cols int
rows int
rowOffsets [4]int
busMode HD44780BusMode
pinRS *DirectPinDriver
pinEN *DirectPinDriver
pinDataBits []*DirectPinDriver
displayCtrl int
displayFunc int
displayMode int
connection gobot.Connection
gobot.Commander
}
// NewHD44780Driver return a new HD44780Driver
// a: gobot.Conenction
// cols: lcd columns
// rows: lcd rows
// busMode: 4Bit or 8Bit
// pinRS: register select pin
// pinEN: clock enable pin
// pinDataBits: databit pins
func NewHD44780Driver(a gobot.Connection, cols int, rows int, busMode HD44780BusMode, pinRS string, pinEN string, pinDataBits HD44780DataPin) *HD44780Driver {
h := &HD44780Driver{
name: "HD44780Driver",
cols: cols,
rows: rows,
busMode: busMode,
pinRS: NewDirectPinDriver(a, pinRS),
pinEN: NewDirectPinDriver(a, pinEN),
connection: a,
Commander: gobot.NewCommander(),
}
if h.busMode == HD44780_4BITMODE {
h.pinDataBits = make([]*DirectPinDriver, 4)
h.pinDataBits[0] = NewDirectPinDriver(a, pinDataBits.D4)
h.pinDataBits[1] = NewDirectPinDriver(a, pinDataBits.D5)
h.pinDataBits[2] = NewDirectPinDriver(a, pinDataBits.D6)
h.pinDataBits[3] = NewDirectPinDriver(a, pinDataBits.D7)
} else {
h.pinDataBits = make([]*DirectPinDriver, 8)
h.pinDataBits[0] = NewDirectPinDriver(a, pinDataBits.D0)
h.pinDataBits[1] = NewDirectPinDriver(a, pinDataBits.D1)
h.pinDataBits[2] = NewDirectPinDriver(a, pinDataBits.D2)
h.pinDataBits[3] = NewDirectPinDriver(a, pinDataBits.D3)
h.pinDataBits[4] = NewDirectPinDriver(a, pinDataBits.D4)
h.pinDataBits[5] = NewDirectPinDriver(a, pinDataBits.D5)
h.pinDataBits[6] = NewDirectPinDriver(a, pinDataBits.D6)
h.pinDataBits[7] = NewDirectPinDriver(a, pinDataBits.D7)
}
h.rowOffsets[0] = 0x00
h.rowOffsets[1] = HD44780_2NDLINEOFFSET
h.rowOffsets[2] = 0x00 + cols
h.rowOffsets[3] = HD44780_2NDLINEOFFSET + cols
/* TODO : Add commands */
return h
}
// Halt implements the Driver interface
func (h *HD44780Driver) Halt() error { return nil }
// Name returns the HD44780Driver name
func (h *HD44780Driver) Name() string { return h.name }
// SetName sets the HD44780Driver name
func (h *HD44780Driver) SetName(n string) { h.name = n }
// Connecton returns the HD44780Driver Connection
func (h *HD44780Driver) Connection() gobot.Connection {
return h.connection
}
// Start initializes the HD44780 LCD controller
// refer to page 45/46 of hitachi HD44780 datasheet
func (h *HD44780Driver) Start() (err error) {
for _, bitPin := range h.pinDataBits {
if bitPin.Pin() == "" {
return errors.New("Initialization error")
}
}
time.Sleep(50 * time.Millisecond)
if h.busMode == HD44780_4BITMODE {
if err := h.writeBits(0x03); err != nil {
return err
}
time.Sleep(5 * time.Millisecond)
if err := h.writeBits(0x03); err != nil {
return err
}
time.Sleep(100 * time.Microsecond)
if err := h.writeBits(0x03); err != nil {
return err
}
time.Sleep(100 * time.Microsecond)
if err := h.writeBits(0x02); err != nil {
return err
}
} else {
if err := h.SendCommand(0x30); err != nil {
return err
}
time.Sleep(5 * time.Millisecond)
if err := h.SendCommand(0x30); err != nil {
return err
}
time.Sleep(100 * time.Microsecond)
if err := h.SendCommand(0x30); err != nil {
return err
}
}
time.Sleep(100 * time.Microsecond)
if h.busMode == HD44780_4BITMODE {
h.displayFunc |= HD44780_4BITBUS
} else {
h.displayFunc |= HD44780_8BITBUS
}
if h.rows > 1 {
h.displayFunc |= HD44780_2LINE
} else {
h.displayFunc |= HD44780_1LINE
}
h.displayFunc |= HD44780_5x8DOTS
h.displayCtrl = HD44780_DISPLAYON | HD44780_BLINKOFF | HD44780_CURSOROFF
h.displayMode = HD44780_ENTRYLEFT | HD44780_ENTRYSHIFTDECREMENT
if err := h.SendCommand(HD44780_DISPLAYCONTROL | h.displayCtrl); err != nil {
return err
}
if err := h.SendCommand(HD44780_FUNCTIONSET | h.displayFunc); err != nil {
return err
}
if err := h.SendCommand(HD44780_ENTRYMODESET | h.displayMode); err != nil {
return err
}
return h.Clear()
}
// Write output text to the display
func (h *HD44780Driver) Write(message string) (err error) {
col := 0
if (h.displayMode & HD44780_ENTRYLEFT) == 0 {
col = h.cols - 1
}
row := 0
for _, c := range message {
if c == '\n' {
row++
if err := h.SetCursor(col, row); err != nil {
return err
}
continue
}
if err := h.WriteChar(int(c)); err != nil {
return err
}
}
return nil
}
// Clear clear the display
func (h *HD44780Driver) Clear() (err error) {
if err := h.SendCommand(HD44780_CLEARDISPLAY); err != nil {
return err
}
time.Sleep(2 * time.Millisecond)
return nil
}
// Home return cursor to home
func (h *HD44780Driver) Home() (err error) {
if err := h.SendCommand(HD44780_RETURNHOME); err != nil {
return err
}
time.Sleep(2 * time.Millisecond)
return nil
}
// SetCursor move the cursor to the specified position
func (h *HD44780Driver) SetCursor(col int, row int) (err error) {
if col < 0 || row < 0 || col >= h.cols || row >= h.rows {
return errors.New("Invalid position value")
}
return h.SendCommand(HD44780_SETDDRAMADDR | col + h.rowOffsets[row])
}
// Display turn the display on and off
func (h *HD44780Driver) Display(on bool) (err error) {
if on {
h.displayCtrl |= HD44780_DISPLAYON
} else {
h.displayCtrl &= ^HD44780_DISPLAYON
}
return h.SendCommand(HD44780_DISPLAYCONTROL | h.displayCtrl)
}
// Cursor turn the cursor on and off
func (h *HD44780Driver) Cursor(on bool) (err error) {
if on {
h.displayCtrl |= HD44780_CURSORON
} else {
h.displayCtrl &= ^HD44780_CURSORON
}
return h.SendCommand(HD44780_DISPLAYCONTROL | h.displayCtrl)
}
// Blink turn the blink on and off
func (h *HD44780Driver) Blink(on bool) (err error) {
if on {
h.displayCtrl |= HD44780_BLINKON
} else {
h.displayCtrl &= ^HD44780_BLINKON
}
return h.SendCommand(HD44780_DISPLAYCONTROL | h.displayCtrl)
}
// ScrollLeft scroll text left
func (h *HD44780Driver) ScrollLeft() (err error) {
return h.SendCommand(HD44780_CURSORSHIFT | HD44780_DISPLAYMOVE | HD44780_MOVELEFT)
}
// ScrollRight scroll text right
func (h *HD44780Driver) ScrollRight() (err error) {
return h.SendCommand(HD44780_CURSORSHIFT | HD44780_DISPLAYMOVE | HD44780_MOVERIGHT)
}
// LeftToRight display text from left to right
func (h *HD44780Driver) LeftToRight() (err error) {
h.displayMode |= HD44780_ENTRYLEFT
return h.SendCommand(HD44780_ENTRYMODESET | h.displayMode)
}
// RightToLeft display text from right to left
func (h *HD44780Driver) RightToLeft() (err error) {
h.displayMode &= ^HD44780_ENTRYLEFT
return h.SendCommand(HD44780_ENTRYMODESET | h.displayMode)
}
// SendCommand send control command
func (h *HD44780Driver) SendCommand(data int) (err error) {
if err := h.pinRS.Off(); err != nil {
return err
}
if h.busMode == HD44780_4BITMODE {
if err := h.writeBits(data >> 4); err != nil {
return err
}
}
return h.writeBits(data)
}
// WriteChar output a character to the display
func (h *HD44780Driver) WriteChar(data int) (err error) {
if err := h.pinRS.On(); err != nil {
return err
}
if h.busMode == HD44780_4BITMODE {
if err := h.writeBits(data >> 4); err != nil {
return err
}
}
return h.writeBits(data)
}
// CreateChar create custom character
func (h *HD44780Driver) CreateChar(pos int, charMap [8]byte) (err error) {
if pos > 7 {
return errors.New("can't set a custom character at a position greater than 7")
}
if err := h.SendCommand(HD44780_SETCGRAMADDR | (pos << 3)); err != nil {
return err
}
for i := range charMap {
if err := h.WriteChar(int(charMap[i])); err != nil {
return err
}
}
return nil
}
// WriteBits output data to data-pins
func (h *HD44780Driver) writeBits(data int) (err error) {
for i, pin := range h.pinDataBits {
if ((data >> i) & 0x01) == 0x01 {
if err := pin.On(); err != nil {
return err
}
} else {
if err := pin.Off(); err != nil {
return err
}
}
}
return h.triggerPulse()
}
// triggerPulse trigger enable pulse
func (h *HD44780Driver) triggerPulse() (err error) {
if err := h.pinEN.Off(); err != nil {
return err
}
time.Sleep(1 * time.Microsecond)
if err := h.pinEN.On(); err != nil {
return err
}
time.Sleep(1 * time.Microsecond)
if err := h.pinEN.Off(); err != nil {
return err
}
time.Sleep(1 * time.Microsecond)
return nil
}