Multi Function Shield


Some multi-digit displays come with the TM1638 to control the multiplex drive of the segments. For the multi function shield offered by different Chinese companies you have to install an ISR to handle all the segments.

This examples shows how to calculate and display π on a multi function shield (without using any raspberries)
You will find the display functions a second file at the end.

/*
 * http://www.cut-the-knot.org/Curriculum/Algorithms/FastSpigotForPi.shtml
 */
#include "Timer2.h"

void setup() {
  Serial.begin(9600);
  Serial.println(F(__FILE__));
  setupTimer2();
  const long a = 10000;
  const long aa5 = a / 5 * a;;
  const word c_ = 868; // (875; ohne display)
  int c = c_;
  boolean first = true;
  long b = c;
  word e = 0;
  word f[c_];
  word g;
  long h = 0;
  c = c - 14;
  while ( c > 0) {
    b--;
    long d;
    while (b != 0) {
      if (first) d = b * h + aa5; else d = b * h + a * f[b];
      g = b * 2 - 1;
      h = d / g;
      f[b] = d - h * g;
      b--;
    }
    b = c;
    c = c - 14;
    word i = e + d / a;
    if (i < 1000) Serial.print(F("0"));
    if (i <  100) Serial.print(F("0"));
    if (i <   10) Serial.print(F("0"));
    Serial.print(i);
    Serial.print(F(" "));
    display(i,4);
    for (byte i = 0; i < 4; i++) {
      shift();
      delay(1000);
    }
    first = false;
    e = d % a;
  }
  Serial.println(F("\nDone."));
  display("done");
}

void loop() {}

And this is the Timer2.h file to control the segments:

// forward references
void dispCharAt(char c, byte pos);
void display(char * t);

// Display:
const byte latchPin = 4;
const byte clockPin = 7;
const byte dataPin  = 8;

static inline void latchPinH() {
  bitSet(PORTD, 4);
}
static inline void latchPinL() {
  bitClear(PORTD, 4);
}
static inline void clockPinH() {
  bitSet(PORTD, 7);
}
static inline void clockPinL() {
  bitClear(PORTD, 7);
}
static inline void dataPinH() {
  bitSet(PORTB, 0);
}
static inline void dataPinL() {
  bitClear(PORTB, 0);
}

void myShiftOut(byte data) {
#ifdef HS420361K
  /*
   * for HS420361K exchange cathodes and anodes:
   * */
  data = 255 - data;
#endif  
  latchPinL();
  clockPinL();
  for (byte i = 0; i <= 7; i++) {
    if (data & B10000000) dataPinH(); else dataPinL();
    clockPinH();
    clockPinL();
    data = data << 1;
  }
  latchPinH();
}

byte commaPos = 1; // Positionen: 0, 1, 2, 3

// "Zeichengenerator"
const byte PROGMEM charGen[] = {
  0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, //  0 - 15
  0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 16 - 31
  ~0, // space
  0,
  ~B00100010, // "
  0, 0, 0, 0,
  ~B00000010, // '
  ~B00111001, // (
  ~B00001111, // )
  0, 0, 0,
  ~B01000000, // -
  0, 0, // 32 - 47
  /*76543210
    .gfedcba    */
  ~B00111111, //  B11000000, // 0
  ~B00000110, //  B11111001, // 1
  ~B01011011, //  B10100100, // 2
  ~B01001111, //  B10110000, // 3
  ~B01100110, //  B10011001, // 4
  ~B01101101, //  B10010010, // 5
  ~B01111101, //  B10000010, // 6
  ~B00000111, //  B11111000, // 7
  ~B01111111, //  B10000000, // 8
  ~B01101111, //  B10010000, // 9
  0, 0, 0,
  ~B01001000, // =
  0, 0, 0,
  ~B01110111, // A
  ~B01111100, // b
  ~B00111001, // C
  ~B01011110, // d
  ~B01111001, // E
  ~B01110001, // F
  ~B00111101, // G
  ~B01110110, // H
  ~B00000110, // I = eins
  ~B00001110, // J
  ~B00000000, // (K)
  ~B00111000, // L
  ~B00000000, // (M)
  ~B01010100, // N
  ~B00111111, // O = null
  ~B01110011, // P
  ~B00000000, // (Q)
  ~B01010000, // r
  ~B01101101, // S
  ~B01111000, // t
  ~B00111110, // U
  ~B00011100, // v
  ~B00000000, // (W)
  ~B00000000, // (X)
  ~B01101110, // Y
  ~B01011011, // Z = zwei
  ~B00111001, // [
  ~B00110110, // ll (doppel-L) 0x5C
  ~B00001111, // ]
  ~B00100011, // f-a-b
  ~B00011100, // c-d-e
  0,
  ~B01110111, // A
  ~B01111100, // b
  ~B01011000, // c
  ~B01011110, // d
  ~B01111001, // E
  ~B01110001, // F
  ~B00111101, // G
  ~B01110100, // h
  ~B00000110, // I
  ~B00001110, // J
  ~B00000000, // (K)
  ~B00111000, // L
  ~B00000000, // (M)
  ~B01010100, // n
  ~B01011100, // o
  ~B01110011, // P
  ~B00000000, // (Q)
  ~B01010000, // r
  ~B01101101, // S
  ~B01111000, // t
  ~B00011100, // u
  ~B00011100, // v
  ~B00000000, // (W)
  ~B00000000, // (X)
  ~B01101110, // Y
  ~B01011011, // Z
  0
};
const byte komma = ~B10000000;
// das "Video-RAM"
char VRAM[8] = "        ";

// display TEXT (4 chars)
void display(char * t) {
  // "AAAA"
  memcpy(VRAM, t, 4);
  commaPos = 4;
}

// display NUMBER:
void display(int i, byte comma) {
  // "9999"
  byte d = i % 10;
  VRAM[7] = '0' + d; i = i / 10; d = i % 10;
  VRAM[6] = '0' + d; i = i / 10; d = i % 10;
  VRAM[5] = '0' + d; i = i / 10;
  VRAM[4] = '0' + i;
  commaPos = comma;
}

void shift() {
  for (byte i = 0; i < 8; i++) VRAM[i] = VRAM[i+1];
}

// ========== TIMER2 ===========

void setupTimer2() {
  pinMode(latchPin, OUTPUT);
  pinMode(clockPin, OUTPUT);
  pinMode(dataPin, OUTPUT);
  TCCR2B = 5; 
  TIMSK2 = 1;
}

ISR(TIMER2_OVF_vect) {
  static byte stelle;
  byte b = VRAM[stelle];
  dispCharAt(b, stelle);
  if (++stelle > 3) stelle = 0;  // naechste Stelle
}

void dispCharAt(char c, byte pos) {
  byte d = pgm_read_byte_near(charGen + c);
  if (pos == commaPos) d = d & komma;
  myShiftOut(d);                 // schicke Ziffer
  myShiftOut(1 << pos);          // schicke Position
}




contact: nji(at)gmx.de