• NP...

    But before going there, are you sure you want to burn cycles for the multiplexing? I'd reather spend another 3 x 39 cts and send the data all at once to the daisy chained 74HC595.

    With 4 x 73HC595, create a string (which handles all your divs and mods), take the ascii vals of the chars and point adjusted into a table with your bits for segments (as you already do with z[])... something like this (assuming positive integer):

    // ...mapping from digit(a char)>ascii>segIdx>segVal>display
    // ----------------------------------------­-----------------
    //                        ascii seg  segment    s v  display 
    // digit char ascii      & 0x0F idx  val bin    dec     char
    // ----- ---- ---------- ------ ---  ---------- ---  -------
    // 0 --- "0"  0b00110000 0b0000   0  0b00111111  63        0
    // 1 --- "1"  0b00110001 0b0001   1  0b00110000  91        1
    // 2 ...
    // ...
    // 9 --- "9"  0b00111001 0b1001   9  0b01111101 125        9
    //       ":"  0b00111010 0b1010  10  0b00000000   0    space
    //       ";"  0b00111011 0b1011  11  0b01001111  79        E 
    //       "<"  0b00111100 0b1100  12  0b01000010  66        r
    var segs = new Uint8Array([63, 91,..., 125,0,79,66]); // 13 elts -- 13 seg combins
    var displayInt = function(n)  {
      SPI1.send((((n > 9999) 
            ?  ";<<:" // map ;, < and : to segments for E, r and space (blank)
            : ("::::" + n).substr(-4) // map 0 to 9 to segments for 0..9 and : to space
          ).split("")).map(function(char){ return segs[char.charCodeAt(0) && 15]; })
        , B6);
    };
    

    You can go even further including:

    1. general conversion error: parseInt() NaN shows Err
    2. Overflow: shows ErrO
    3. Underrun: shows ErrU
    4. negative numbers (The negative sign "-" is a bit a trouble maker because it is not an adjacent ascii value and takes a digit away. Use ... : (((n<0) ? ":::=" : "::::") + Math.abs(n)).substr(-4) ... and map "=" (ascii 48 + 14) to 01000000 segments value.
    5. allow decimals to display... ;-) (do an or | 1 for the segments at the 1's).

    If you do not like array.map(), you can use array.reduce() or a simple loop over the 4 characters and stick the values into a predefined Uint8Array (with the loop you can even omit String.split("")).

    Using a predefined UInt8Array, you can even still keep the multiplexing and do some 'efficient' display. Your display may dim and with changing in brightness, show digits in different brightness, and - worst - get stuck on a digit when Espruino does some other non-interuptable thing and cannot handle the mux timer timely. Do not use the setInterval(), but more so the setTimeout(), to indicate that your muxing is not 'really' to a beat. For example something like this:

    var segs = new Uint8Array([63, 91,...,125,0,79,66]); // 13 elts -- 13 seg combins
    var digs = new Uint8Array([0,0,0,0]); // 4 elts -- 4 * 7-segment displays
    var ddx = -1; // -- will be 0..3 for digit index for all the 4 digits
    var den = 0b10000; // -- will be 0b1000, 0b0100, 0b0010, 0b0001 for 
        // digit enble for all the 4 7-seg displays w/ open collector / reverse
        // output with current limitting resistor... 
        // you may anyway need a driver the output pin and a current limiting
       // resistor on the the anodes give all the allowed brightness of 7 x 20 mA
      // per segment (57xx series) - see NOTE
    var displayInt = function(n){ // convers n into digs[]
      ("::::" + n).substr(-4).forEach(function(c,i){ // assuming n integer 0..9999
        digs[i] = c.charCodeAt(0) & 15;
    }); };
    var muxDsp = function(){
      digitalWrite([B10,B13,B14,B15],den = (den >>= 1) ? den : 8)
      SPI1.send(digs[++ddx % 4],B6);
      setTimeout(muxDsp,10); // frame rate of 25/s
    };
    

    You notice that the conversion form integer to the bit/segment patterns values in digs[] happens only once at every invocation of displayInt() and independent on the actual multiplexed displaying by muxDsp. Each digit is displayed one after the other in self-re-invocating muxDsp(). Something that Espruino is really cool in: ...being event driven.
    Note though, that a new value is displayed 'cleanly' only after 4 muxDSP() completed after completion of displayInt().

    NOTE: Driving for the common cathode can be done with simple NPN transistor or ULN2003. Instead of current limiting resistors on the anodes, you can use PWMs to drive the pull downs at the common cathode and choose a duty cycle that does not make the power consumption exceed the display segments limit - watch the inversion... :). Connecting the nss_pin (2nd argument of) SPI.send() - in your case B6 - inverted to _OE, you can save yourself pin(s) for other purposes. Any clearing/resetting etc is not needed since always 8 bits are sent per digit and after sending 4 * 8 bits, all 'funny' stuff if flushed - shifted - out anyway.

    My preferred HW would have 4 * 74HC595, a pwm pin connected to _OE, HDSP-5723 common cathodes grounded, and no SPI nss_pin used. A related SW for invocation with, for example,dsp(7,SPI1);, looked then like this:

    var dsp = (function() {
      var ss = new Uint8Array([63, 91,..., 125,0,79,66]), ds = new Uint8Array(4);
      return function(n,spi) { var s = (":::" + n).substr(-4);
        spi.send(ds.reduce(function(ds,d,i){ds[i­] = s.charCodeAt(i)  && 15; return ds; },ds)); }; 
    })();
    

    ...next thing is to make a module out of it using the typical connect()-pattern:

    Having a module, it makes sense to have brightness as a connect and runtime option. Useful additional connect options to consider are: leading 0, no leading 0, leading or trailing negative sign, etc. Extending the display for strings to map as many alphanumeric character as reasonably readable on 7-segment display will make it a versatile and useful - and may be a bit bloated - module).

    PS: code only partially tested... ;)

About

Avatar for allObjects @allObjects started