sweep from William Beebe on Vimeo.
This is a test of the Adafruit 0.8″ Red Matrix FeatherWing (https://www.adafruit.com/product/3155) that’s also driven by the HT16K33 I2C display driver kit. In this example, I’ve gotten a bit fancier, if for no other reason than to create a more interesting display test. The application, sweep, does just that; it sweeps a triangle wave across the display five times, testing each LED in both arrays. The code follows.
package mainimport ("fmt""time""os""os/signal""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 con i2c.Connectionfunc initialize() i2c.Connection {adapter := raspi.NewAdaptor()adapter.Connect()bus := adapter.GetDefaultBus()fmt.Printf("bus %d\n", bus)con, _ = adapter.GetConnection(DEFAULT_ADDRESS, bus)// Turn on chip's internal oscillator.con.WriteByte(HT16K33_SYSTEM_SETUP | HT16K33_OSCILLATOR_ON)// Turn on the display. YOU HAVE TO SEND THIS.con.WriteByte(HT16K33_DISPLAY_SETUP | HT16K33_DISPLAY_ON)// Set for maximum LED brightness.con.WriteByte(HT16K33_CMD_BRIGHTNESS | 0x0f)return con}// A very simple test for the Adafruit 0.8" 8x16 LED Matrix// FeatherWing Display.// "Bounces" a row of lit LEDs from top to bottom and back to the top, left to right,// leaving a single straight line of lit LEDs across the top of the display.//func lightAll() {block := make([]byte, 16)upDirection := make([]bool, 16)altIndex := []int{0,2,4,6,8,10,12,14,1,3,5,7,9,11,13,15}for i := range block {block[i] = 0x80}for i := 0 ; i < 2 * len(block) ; i++ {con.WriteBlockData(0, block)if i > 0 {time.Sleep(25 * time.Millisecond)}for j := i ; j >= 0 ; j-- {if j < len(block) && block[altIndex[j]] > 1 && ! upDirection[altIndex[j]] {block[altIndex[j]] >>= 1} else if j < len(block) && block[altIndex[j]] == 1 {upDirection[altIndex[j]] = true}if j < len(block) && block[altIndex[j]] < 0x80 && upDirection[altIndex[j]] {block[altIndex[j]] <<= 1}}}}// Just turns every lit LED off.//func darkenAll() {// Turn off every bit on the displays.//block := make([]byte, 16)con.WriteBlockData(0, block)}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)con := initialize()// 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()con.Close()os.Exit(0)default:}}}()darkenAll()for i := 0 ; i < 6 ; i++ {lightAll()}time.Sleep(30 * time.Millisecond)darkenAll()con.Close()}
The interesting part is function lightAll, starting at line 68. That’s what’s doing all the fancy management of the bit bouncing, or sweeping.