tinygo.org/x/drivers@v0.27.1-0.20240509133757-7dbca2a54349/tm1637/tm1637.go (about)

     1  // Package tm1637 provides a driver for the TM1637 4-digit 7-segment LED display.
     2  //
     3  // Datasheet: https://www.mcielectronics.cl/website_MCI/static/documents/Datasheet_TM1637.pdf
     4  package tm1637
     5  
     6  import (
     7  	"machine"
     8  	"time"
     9  )
    10  
    11  // Device wraps the pins of the TM1637.
    12  type Device struct {
    13  	clk        machine.Pin
    14  	dio        machine.Pin
    15  	brightness uint8
    16  }
    17  
    18  // New creates a new TM1637 device.
    19  func New(clk machine.Pin, dio machine.Pin, brightness uint8) Device {
    20  	return Device{clk: clk, dio: dio, brightness: brightness}
    21  }
    22  
    23  // Configure sets up the pins.
    24  func (d *Device) Configure() {
    25  	pinMode(d.clk, false)
    26  	pinMode(d.dio, false)
    27  	d.clk.Low() // required for future pull-down
    28  	d.dio.Low() // required for future pull-down
    29  }
    30  
    31  // Brightness sets the brightness of the display (0-7).
    32  func (d *Device) Brightness(brightness uint8) {
    33  	if brightness > 7 {
    34  		brightness = 7
    35  	}
    36  	d.brightness = brightness
    37  	d.writeCmd()
    38  	d.writeDsp()
    39  }
    40  
    41  // ClearDisplay clears the display.
    42  func (d *Device) ClearDisplay() {
    43  	d.writeData([]byte{0, 0, 0, 0}, 0)
    44  }
    45  
    46  // DisplayText shows a text on the display.
    47  //
    48  // Only the first 4 letters in the array text would be shown.
    49  func (d *Device) DisplayText(text []byte) {
    50  	var sequences []byte
    51  	for i, t := range text {
    52  		if i > 3 {
    53  			break
    54  		}
    55  		sequences = append(sequences, encodeChr(t))
    56  	}
    57  	d.writeData(sequences, 0)
    58  }
    59  
    60  // DisplayChr shows a single character (A-Z, a-z)
    61  // on the display at position 0-3.
    62  func (d *Device) DisplayChr(chr byte, pos uint8) {
    63  	if pos > 3 {
    64  		pos = 3
    65  	}
    66  	d.writeData([]byte{encodeChr(chr)}, pos)
    67  }
    68  
    69  // DisplayNumber shows a number on the display.
    70  //
    71  // Only 4 rightmost digits of the number would be shown.
    72  //
    73  // For negative numbers, only -999 to -1 would be
    74  // shown with a negaive sign.
    75  func (d *Device) DisplayNumber(num int16) {
    76  	var sequences []byte
    77  	var start int16
    78  	if num < 0 {
    79  		sequences = append(sequences, segments[37])
    80  		num *= -1
    81  		start = 100
    82  		num %= 1000
    83  	} else {
    84  		start = 1000
    85  		num %= 10000
    86  	}
    87  	for i := start; i >= 1; i /= 10 {
    88  		if num >= i {
    89  			n := (num / int16(i)) % 10
    90  			sequences = append(sequences, segments[n])
    91  		} else {
    92  			if i == 1 && num == 0 {
    93  				sequences = append(sequences, segments[0])
    94  			} else {
    95  				sequences = append(sequences, 0)
    96  			}
    97  		}
    98  	}
    99  	d.writeData(sequences, 0)
   100  }
   101  
   102  // DisplayDigit shows a single-digit number (0-9)
   103  // at position 0-3.
   104  func (d *Device) DisplayDigit(digit uint8, pos uint8) {
   105  	digit %= 10
   106  	d.writeData([]byte{segments[digit]}, pos)
   107  }
   108  
   109  // DisplayClock allows you to display hour and minute numbers
   110  // together with the colon on/off.
   111  func (d *Device) DisplayClock(num1 uint8, num2 uint8, colon bool) {
   112  	var sequences []byte
   113  	num := []uint8{num1 % 100, num2 % 100}
   114  	for k := 0; k < 2; k++ {
   115  		for i := 10; i >= 1; i /= 10 {
   116  			n := (num[k] / uint8(i)) % 10
   117  			sequences = append(sequences, segments[n])
   118  		}
   119  	}
   120  	if colon {
   121  		sequences[1] |= 1 << 7
   122  	}
   123  	d.writeData(sequences, 0)
   124  }
   125  
   126  func encodeChr(c byte) byte {
   127  	r := rune(c)
   128  	switch {
   129  	case r == 32:
   130  		return segments[36] // space
   131  	case r == 42:
   132  		return segments[38] // star/degrees
   133  	case r == 45:
   134  		return segments[37] // dash
   135  	case r >= 65 && r <= 90:
   136  		return segments[r-55] // uppercase A-Z
   137  	case r >= 97 && r <= 122:
   138  		return segments[r-87] // lowercase a-z
   139  	case r >= 48 && r <= 57:
   140  		return segments[r-48] // 0-9
   141  	default:
   142  		return byte(0)
   143  	}
   144  }
   145  
   146  func delaytm() {
   147  	time.Sleep(time.Microsecond * time.Duration(TM1637_DELAY))
   148  }
   149  
   150  func pinMode(pin machine.Pin, mode bool) {
   151  	// TM1637 has internal pull-up resistors for both CLK and DIO pins.
   152  	// Set them to input mode will pull them high,
   153  	// and set them to output mode will pull them down
   154  	// (since we did so in the beginning.)
   155  	// The High()/Low() method don't work on some boards.
   156  	if mode {
   157  		pin.Configure(machine.PinConfig{Mode: machine.PinInput})
   158  	} else {
   159  		pin.Configure(machine.PinConfig{Mode: machine.PinOutput})
   160  	}
   161  }
   162  
   163  func (d *Device) start() {
   164  	pinMode(d.dio, false)
   165  	delaytm()
   166  	pinMode(d.clk, false)
   167  }
   168  
   169  func (d *Device) stop() {
   170  	pinMode(d.dio, false)
   171  	delaytm()
   172  	pinMode(d.clk, true)
   173  	delaytm()
   174  	pinMode(d.dio, true)
   175  }
   176  
   177  func (d *Device) writeByte(data uint8) {
   178  	for i := 0; i < 8; i++ {
   179  		pinMode(d.dio, data&(1<<i) > 0) // send bits from LSB to MSB
   180  		delaytm()
   181  		pinMode(d.clk, true)
   182  		delaytm()
   183  		pinMode(d.clk, false)
   184  		delaytm()
   185  	}
   186  	pinMode(d.clk, false)
   187  	delaytm()
   188  	pinMode(d.clk, true)
   189  	delaytm()
   190  	pinMode(d.clk, false)
   191  }
   192  
   193  func (d *Device) writeCmd() {
   194  	d.start()
   195  	d.writeByte(TM1637_CMD1)
   196  	d.stop()
   197  }
   198  
   199  func (d *Device) writeDsp() {
   200  	d.start()
   201  	d.writeByte(TM1637_CMD3 | TM1637_DSP_ON | d.brightness)
   202  	d.stop()
   203  }
   204  
   205  func (d *Device) writeData(segments []byte, position uint8) {
   206  	d.writeCmd()
   207  	d.start()
   208  	d.writeByte(TM1637_CMD2 | position)
   209  	for _, seg := range segments {
   210  		d.writeByte(seg)
   211  	}
   212  	d.stop()
   213  	d.writeDsp()
   214  }