Skip to main content

3642BS Embedded Driver

banner

Makes displaying stuff on the 3642BS easy. The 3642BS is a 4 digit, 7 segment display with a common anode configuration. Since it shares the segment pins between all the digits, they have to be time-division multiplexed. This has to be done really fast for persistance of vision to fill in the gaps, so the speed of the library matters.

For now, the library includes these functions:

  • .clear(), Which pulls down all the common anodes, essentially turning off the display.
  • .custom(), Which takes an array with 4 8-bit unsigned integers (each corresponding to a digit) where every bit corresponds to a segment on the digits.
  • .number(), Which prints an integer from -1999 to 9999 on the display. It basically translates the number you feed it to the [u8; 4] the .custom() function requires and calls it.
  • .hex() Which does the same thing as the previous one, but it prints a number from -0x1FFF to 0xFFFF
  • .time() Which does the same as .numbers() but it also blinks the two dots every second

.custom() Allows you to print anything you want to the display, and it does so by using bit arithmetic:

// Constants with the bit corresponding to the segment turned on
pub const SEG_A: u8 = 0b01000000;
pub const SEG_B: u8 = 0b00100000;
pub const SEG_C: u8 = 0b00010000;
...

if segments & SEG_A == SEG_A {
    self.seg_a.set_low()?;
} else {
    self.seg_a.set_high()?;
}

if segments & SEG_B == SEG_B {
    self.seg_b.set_low()?;
} else {
    self.seg_b.set_high()?;
}
...

The arithmetic is quite simple, what it does first is an and operation. An and operation will ony result in the bits both variables share. So for example if segments is the binary number 11001100, an and operation with the value 01100110 would look like this:

1 1 0 0 1 1 0 0
& & & & & & & &
0 1 1 0 0 1 1 0
= = = = = = = =
0 1 0 0 0 1 0 0

The resulting value being 01000100. If this is done with a variable like SEG_A, the resulting value will only have a 1 in it if segments had the bit corresponding to the A segment turned on. To determine if it should turn on the segment or not, it just checks if the result of the and operation is the same as the segment we’re checking for. These two operations can be done really fast by any processor, since the silicon in them is explicitly designed to do them. This contributes significantly to the speed of the library, but it also makes it too fast.

In order for the display to show a coherent output, the pins on the microcontroller and the LEDs on the display need to have time to turn on and off. For that reason, after .custom() is done executing, there is a 1 millisecond delay:

self.delay.delay_ms(1);

Making your own custom characters is easy, you just need to do a bitwise or operation with the segments that should turn on:

                                                            //   ===A===
// Make your own custom characters:                         //  ‖       ‖
let letter_c = SEG_A | SEG_F | SEG_E | SEG_D;               //  F       B
let letter_o = SEG_G | SEG_E | SEG_C | SEG_D;               //  ‖       ‖
let letter_l = SEG_F | SEG_E | SEG_D;                       //   ===G===
let text_cool = [letter_c, letter_o, letter_o, letter_l];   //  ‖       ‖
                                                            //  E       C
display.custom(text_cool).unwrap()                          //  ‖       ‖
                                                            //   ===D===

The crate has been published on Crates.io, and the documentation is available at Docs.rs. It is compatible with any HAL based on the generic embedded_hal and with embassy.

Check out the project on gitlab: https://gitlab.com/slusheea/sevseg-3642bs