raw_ht16k33 from William Beebe on Vimeo.
This is a bit more Go and Gobot-based sophisticated application. This application opens and writes using “raw” calls to Adafruit FeatherWing displays using the HT16K33 I2C display driver chip. It has the ability to check to make sure the device is really there, and you can pass more than one device address on the command line. To make the video, I executed “raw_ht16k33 0x70 0x71” and the application dutifully turned on every segment on the display at address 0x70, then 0x71.
package mainimport ("fmt""log""time""os""os/signal""strconv""syscall""gobot.io/x/gobot/drivers/i2c""gobot.io/x/gobot/platforms/raspi")const DEFAULT_ADDRESS int = 0x70// Commands to send the HT16K33//const (HT16K33_SYSTEM_SETUP byte = 0x20HT16K33_OSCILLATOR_ON byte = 0x01HT16K33_DISPLAY_SETUP byte = 0x80HT16K33_DISPLAY_ON byte = 0x01HT16K33_BLINK_OFF byte = 0x00HT16K33_BLINK_2HZ byte = 0x02HT16K33_BLINK_1HZ byte = 0x04HT16K33_BLINK_HALFHZ byte = 0x06HT16K33_CMD_BRIGHTNESS byte = 0xE0)var address = DEFAULT_ADDRESSvar device i2c.Connectionfunc initialize() (device i2c.Connection, err error) {adapter := raspi.NewAdaptor()adapter.Connect()bus := adapter.GetDefaultBus()// Check to see if the device actually is on the I2C buss.// If it is then use it, else return an error.//if device, err := adapter.GetConnection(address, bus) ; err == nil {if _, err := device.ReadByte() ; err == nil {fmt.Printf(" Using device 0x%x / %d on bus %d\n", address, address, bus)} else {return device, fmt.Errorf(" Could not find device 0x%x / %d", address, address)}}device, _ = adapter.GetConnection(address, bus)// Turn on chip's internal oscillator.device.WriteByte(HT16K33_SYSTEM_SETUP | HT16K33_OSCILLATOR_ON)// Turn on the display. YOU HAVE TO SEND THIS.device.WriteByte(HT16K33_DISPLAY_SETUP | HT16K33_DISPLAY_ON)// Set for maximum LED brightness.device.WriteByte(HT16K33_CMD_BRIGHTNESS | 0x0f)return device, nil}func lightAll() {// First four digits for Alphanumeric and 8x16 Matrix// FeatherWing Displays.//// The 'digit' address is the address/offset into the// HT16K33's internal eight byte array. Each bit// represents a segment or LED, each address a section// within an entire device//// Digit 0//device.WriteWordData(0, 0xFFFF)// Digit 1//device.WriteWordData(2, 0xFFFF)// Digit 2//device.WriteWordData(4, 0xFFFF)// Digit 3//device.WriteWordData(6, 0xFFFF)// Rest of the bytes for the// Adafruit 0.8" 8x16 LED Matrix FeatherWing Displaydevice.WriteWordData(8, 0xFFFF)device.WriteWordData(10, 0xFFFF)device.WriteWordData(12, 0xFFFF)device.WriteWordData(14, 0xFFFF)}func darkenAll() {// Turn off every segment on every digit.//var data []byte = make([]byte, 16)device.WriteBlockData(0, data)}func main() {// Hook the various system abort calls for us to use or ignore as we// see fit. In particular hook SIGINT, or CTRL+C for below.//signal_chan := make(chan os.Signal, 1)signal.Notify(signal_chan,syscall.SIGHUP,syscall.SIGINT,syscall.SIGTERM,syscall.SIGQUIT)// We can pass zero to many addresses on the command line.// For example, 'raw_ht16k33 0x70 0x71' will turn on both// displays, one after the other, if they are both attached.// If either one is not there or unreachable, the application// will abort.//var addresses []intfor _, arg := range os.Args[1:] {if newAddress, err := strconv.ParseInt(arg, 0, 32); err == nil {addresses = append(addresses, int(newAddress))} else {log.Fatal(err)}}// If nothing passed on the command line then use the default// address///if len(addresses) == 0 {addresses = append(addresses, DEFAULT_ADDRESS)}// We want to capture CTRL+C to first clear the display and then exit.// We don't want to leave the display lit on an abort.//go func() {for {signal := <-signal_chanswitch signal {case syscall.SIGINT:// CTRL+Cfmt.Println()darkenAll()device.Close()os.Exit(0)default:}}}()// Iterate over all the addresses passed on the command line (or not),// aborting if any of the devices are unreachable.//for _, addr := range addresses {address = int(addr)dev, err := initialize()if err != nil {log.Fatal(err)}device = devdarkenAll()lightAll()time.Sleep(2 * time.Second)darkenAll()device.Close()}}
This is also one of those little posts where I get to pull together a few other skills I’ve picked up along the way. The video was recorded with an Olympus E-M5 and mZuiko 17mm f/1.8 lens in manual focus mode. The video was quickly put together on my iPad Pro Mk 1, using iMovie, then pushed up to Vimeo where it’s linked above.