From f7dc106fc80be4bbc17b6ff6af7a4414662fb780 Mon Sep 17 00:00:00 2001 From: Alan Wang <44191076+alankrantas@users.noreply.github.com> Date: Sat, 1 Aug 2020 01:58:14 +0800 Subject: [PATCH] tm1637: add support for tm1637 7-segment LED --- Makefile | 4 +- examples/tm1637/main.go | 40 ++++++++ tm1637/registers.go | 16 +++ tm1637/tm1637.go | 215 ++++++++++++++++++++++++++++++++++++++++ 4 files changed, 274 insertions(+), 1 deletion(-) create mode 100644 examples/tm1637/main.go create mode 100644 tm1637/registers.go create mode 100644 tm1637/tm1637.go diff --git a/Makefile b/Makefile index aef0098..d529b35 100644 --- a/Makefile +++ b/Makefile @@ -119,6 +119,8 @@ smoke-test: @md5sum ./build/test.hex tinygo build -size short -o ./build/test.hex -target=circuitplay-bluefruit ./examples/tone @md5sum ./build/test.hex + tinygo build -size short -o ./build/test.hex -target=arduino-nano33 ./examples/tm1637/main.go + @md5sum ./build/test.hex tinygo build -size short -o ./build/test.hex -target=pyportal ./examples/touch/resistive/fourwire/main.go @md5sum ./build/test.hex tinygo build -size short -o ./build/test.hex -target=pyportal ./examples/touch/resistive/pyportal_touchpaint/main.go @@ -179,7 +181,7 @@ endif DRIVERS = $(wildcard */) NOTESTS = build examples flash semihosting pcd8544 shiftregister st7789 microphone mcp3008 gps microbitmatrix \ hcsr04 ssd1331 ws2812 thermistor apa102 easystepper ssd1351 ili9341 wifinina shifter hub75 \ - hd44780 buzzer ssd1306 espat l9110x st7735 bmi160 l293x dht keypad4x4 max72xx p1am tone + hd44780 buzzer ssd1306 espat l9110x st7735 bmi160 l293x dht keypad4x4 max72xx p1am tone tm1637 TESTS = $(filter-out $(addsuffix /%,$(NOTESTS)),$(DRIVERS)) unit-test: diff --git a/examples/tm1637/main.go b/examples/tm1637/main.go new file mode 100644 index 0000000..9a131a1 --- /dev/null +++ b/examples/tm1637/main.go @@ -0,0 +1,40 @@ +package main + +import ( + "machine" + "time" + + "tinygo.org/x/drivers/tm1637" +) + +func main() { + + tm := tm1637.New(machine.D2, machine.D3, 7) // clk, dio, brightness + tm.Configure() + + tm.ClearDisplay() + + tm.DisplayText([]byte("Tiny")) + time.Sleep(time.Millisecond * 1000) + + tm.ClearDisplay() + + tm.DisplayChr(byte('G'), 1) + tm.DisplayDigit(0, 2) // looks like O + time.Sleep(time.Millisecond * 1000) + + tm.DisplayClock(12, 59, true) + + for i := uint8(0); i < 8; i++ { + tm.Brightness(i) + time.Sleep(time.Millisecond * 200) + } + + i := int16(0) + for { + tm.DisplayNumber(i) + i++ + time.Sleep(time.Millisecond * 50) + } + +} diff --git a/tm1637/registers.go b/tm1637/registers.go new file mode 100644 index 0000000..96c2243 --- /dev/null +++ b/tm1637/registers.go @@ -0,0 +1,16 @@ +package tm1637 + +const ( + TM1637_CMD1 = 0x40 + TM1637_CMD2 = 0xC0 + TM1637_CMD3 = 0x80 + TM1637_DSP_ON = 0x08 + TM1637_DELAY = uint8(10) +) + +// 7-segment characters encoding for 0-9, A-Z, a-z, blank, dash, star +var segments []byte = []byte{ + 0x3F, 0x06, 0x5B, 0x4F, 0x66, 0x6D, 0x7D, 0x07, 0x7F, 0x6F, + 0x77, 0x7C, 0x39, 0x5E, 0x79, 0x71, 0x3D, 0x76, 0x06, 0x1E, + 0x76, 0x38, 0x55, 0x54, 0x3F, 0x73, 0x67, 0x50, 0x6D, 0x78, + 0x3E, 0x1C, 0x2A, 0x76, 0x6E, 0x5B, 0x00, 0x40, 0x63} diff --git a/tm1637/tm1637.go b/tm1637/tm1637.go new file mode 100644 index 0000000..cbaa6eb --- /dev/null +++ b/tm1637/tm1637.go @@ -0,0 +1,215 @@ +// Package tm1637 provides a driver for the TM1637 4-digit 7-segment LED display. +// +// Datasheet: https://www.mcielectronics.cl/website_MCI/static/documents/Datasheet_TM1637.pdf +// +package tm1637 + +import ( + "machine" + "time" +) + +// Device wraps the pins of the TM1637. +type Device struct { + clk machine.Pin + dio machine.Pin + brightness uint8 +} + +// New creates a new TM1637 device. +func New(clk machine.Pin, dio machine.Pin, brightness uint8) Device { + return Device{clk: clk, dio: dio, brightness: brightness} +} + +// Configure sets up the pins. +func (d *Device) Configure() { + pinMode(d.clk, false) + pinMode(d.dio, false) + d.clk.Low() // required for future pull-down + d.dio.Low() // required for future pull-down +} + +// Brightness sets the brightness of the display (0-7). +func (d *Device) Brightness(brightness uint8) { + if brightness > 7 { + brightness = 7 + } + d.brightness = brightness + d.writeCmd() + d.writeDsp() +} + +// ClearDisplay clears the display. +func (d *Device) ClearDisplay() { + d.writeData([]byte{0, 0, 0, 0}, 0) +} + +// DisplayText shows a text on the display. +// +// Only the first 4 letters in the array text would be shown. +func (d *Device) DisplayText(text []byte) { + var sequences []byte + for i, t := range text { + if i > 3 { + break + } + sequences = append(sequences, encodeChr(t)) + } + d.writeData(sequences, 0) +} + +// DisplayChr shows a single character (A-Z, a-z) +// on the display at position 0-3. +func (d *Device) DisplayChr(chr byte, pos uint8) { + if pos > 3 { + pos = 3 + } + d.writeData([]byte{encodeChr(chr)}, pos) +} + +// DisplayNumber shows a number on the display. +// +// Only 4 rightmost digits of the number would be shown. +// +// For negative numbers, only -999 to -1 would be +// shown with a negaive sign. +func (d *Device) DisplayNumber(num int16) { + var sequences []byte + var start int16 + if num < 0 { + sequences = append(sequences, segments[37]) + num *= -1 + start = 100 + num %= 1000 + } else { + start = 1000 + num %= 10000 + } + for i := start; i >= 1; i /= 10 { + if num >= i { + n := (num / int16(i)) % 10 + sequences = append(sequences, segments[n]) + } else { + if i == 1 && num == 0 { + sequences = append(sequences, segments[0]) + } else { + sequences = append(sequences, 0) + } + } + } + d.writeData(sequences, 0) +} + +// DisplayDigit shows a single-digit number (0-9) +// at position 0-3. +func (d *Device) DisplayDigit(digit uint8, pos uint8) { + digit %= 10 + d.writeData([]byte{segments[digit]}, pos) +} + +// DisplayClock allows you to display hour and minute numbers +// together with the colon on/off. +func (d *Device) DisplayClock(num1 uint8, num2 uint8, colon bool) { + var sequences []byte + num := []uint8{num1 % 100, num2 % 100} + for k := 0; k < 2; k++ { + for i := 10; i >= 1; i /= 10 { + n := (num[k] / uint8(i)) % 10 + sequences = append(sequences, segments[n]) + } + } + if colon { + sequences[1] |= 1 << 7 + } + d.writeData(sequences, 0) +} + +func encodeChr(c byte) byte { + r := rune(c) + switch { + case r == 32: + return segments[36] // space + case r == 42: + return segments[38] // star/degrees + case r == 45: + return segments[37] // dash + case r >= 65 && r <= 90: + return segments[r-55] // uppercase A-Z + case r >= 97 && r <= 122: + return segments[r-87] // lowercase a-z + case r >= 48 && r <= 57: + return segments[r-48] // 0-9 + default: + return byte(0) + } +} + +func delaytm() { + time.Sleep(time.Microsecond * time.Duration(TM1637_DELAY)) +} + +func pinMode(pin machine.Pin, mode bool) { + // TM1637 has internal pull-up resistors for both CLK and DIO pins. + // Set them to input mode will pull them high, + // and set them to output mode will pull them down + // (since we did so in the beginning.) + // The High()/Low() method don't work on some boards. + if mode { + pin.Configure(machine.PinConfig{Mode: machine.PinInput}) + } else { + pin.Configure(machine.PinConfig{Mode: machine.PinOutput}) + } +} + +func (d *Device) start() { + pinMode(d.dio, false) + delaytm() + pinMode(d.clk, false) +} + +func (d *Device) stop() { + pinMode(d.dio, false) + delaytm() + pinMode(d.clk, true) + delaytm() + pinMode(d.dio, true) +} + +func (d *Device) writeByte(data uint8) { + for i := 0; i < 8; i++ { + pinMode(d.dio, data&(1< 0) // send bits from LSB to MSB + delaytm() + pinMode(d.clk, true) + delaytm() + pinMode(d.clk, false) + delaytm() + } + pinMode(d.clk, false) + delaytm() + pinMode(d.clk, true) + delaytm() + pinMode(d.clk, false) +} + +func (d *Device) writeCmd() { + d.start() + d.writeByte(TM1637_CMD1) + d.stop() +} + +func (d *Device) writeDsp() { + d.start() + d.writeByte(TM1637_CMD3 | TM1637_DSP_ON | d.brightness) + d.stop() +} + +func (d *Device) writeData(segments []byte, position uint8) { + d.writeCmd() + d.start() + d.writeByte(TM1637_CMD2 | position) + for _, seg := range segments { + d.writeByte(seg) + } + d.stop() + d.writeDsp() +}