-
• #2
Hi! Looking good! :)
The easiest way for you to optimize is to cut down on white space. I think Espruino minimizes stuff slightly but if you don't optimize run-time you will optimize mental time and maybe even a few calories from having to scroll less ;)
Btw @Gordon, does Espruino support the ECMAScript 6 standard of the
0b1111
way of describing the value 15? Likewise for the octals with0o17
? -
• #3
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:
- general conversion error: parseInt() NaN shows Err
- Overflow: shows ErrO
- Underrun: shows ErrU
- 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
) to01000000
segments value. - allow decimals to display... ;-) (do an or
| 1
for the segments at the 1's).
If you do not like
array.map()
, you can usearray.reduce()
or a simple loop over the 4 characters and stick the values into a predefinedUint8Array
(with the loop you can even omitString.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 caseB6
- 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... ;)
- general conversion error: parseInt() NaN shows Err
-
• #4
nss_pin to OE won't do what you want. OE is active low, and nss_pin goes low, so that would only enable the outputs while you were putting data into them, instead of the other way around.
-
• #5
noticed that and updated to ...nss_pin inverted on _OE.. But thanks anyway.
-
• #6
Looks good!
does Espruino support the ECMAScript 6 standard of the 0b1111 way of describing the value 15?
Yes - so that could be a bit easier to read.
Also...
pinMode(B10, output);
isn't needed I think, but if it was, you'd need to define output as a string likepinMode(B10, 'output');
. Version 1v81 and later of Espruino will actually produce an error for your code when it comes out, because theoutput
variable isn't actually defined.- As @allObjects did with his code, you'll probably find that working with a 4 digit string simplifies things, even if you don't want to use
map
- which takes a bit of getting used to. - While less efficient than @allObjects' Uint8Array example, you could store all your digits directly in an object, which is a bit more readable and also allows you to handle stuff like spaces and alphanumeric characters if you wanted to:
{0:0b00111111, 1:0b00110000, ' ':0, '-':..., 'b':...}
. It means you'd then be able to display strings like"A -2"
if you wanted. - If I understand right, what you're doing with
digitalPulse
is actually really good - because it's running in an IRQ, regardless of what's going on in Espruino it'll always keep the LEDs lit for the same amount of time. Worst case is Espruino gets busy and the LEDs flicker off for a bit. I'd just wrap your 4 loop functions into 1, and I think using
setInterval
will be a bit neater:var digit = 0; var z = {0:0b00111111, 1:0b00110000, ' ':0, '-':..., 'b':...}; var text = "1234"; setInterval(function() { digit = (digit+1)&3; // digits 0..3 SPI1.send(z[text[digit]],B6); digitalPulse(outpins[digit],0,4); }, 5); // maybe make setInterval slightly bigger than digitalPulse, just in case
Hope that helps!
-
• #7
Hello friends,
thank you for you suggestions.
console.log("start"); //595 Pinput: /* 1 = 2 2 = 3 3 = 4 4 = 5 5 = 6 6 = 7 7 = 8 = Decimal Point/ DP 8 = GND 9 = carryover, to Next 595's SER/Pin 14 10 = SCL/CLR Rest, not used, flushing 32bit each time. 11 = Clock/SRCLK/SRCK, SPI1 SCK, Pin B3 12 = RCK/RCLK/LATCH/, SPI SS,Pin B6 via 10KOhm to Ground = Data Out 13 = Output Enable, GND 14 = Data/SER/SIN, SPI1 MOSI, Pin B5 15 = 1 16 = VCC 3,3V 330Ohm */ //SS Pin = B6 var sport = 0b00000001; var one = 48; // "00110000"; var two = 91; // "01011001"; var three = 121; // "01111001"; var four = 116; // "01110100"; var five = 109; // "01101101"; var six = 111; // "01101111"; var seven = 56; // "00111000"; var eight = 127; // "01111111"; var nine = 125; // "01111101"; var zero = 63; // "00111111"; var z = [zero,one,two,three,four,five,six,seven,eight,nine]; digitalWrite([B6,B7],0); // SS Pin to 0 digitalWrite([B7],1); SPI1.setup({ mosi:B5, sck:B3, baud:100000, order:'msb' }); //SPI Setup var out = 0; // current Segment var i = 0; // Value to Display var i1=0, i2=0, i3=0, i4=0; setInterval(function(){ i++; if (i>999)i=0; if (i>999){ i1 = Math.floor(i/1000); } else { i1 = 0; } if (i>99){ i2 = Math.floor(i/100) % 10; } else { i2 = 0; } if (i>9){ i3 = Math.floor(i/10) % 10; } else { i3 = 0; } i4 = i % 10; //SPI1.write(buf_off,B6); //flush only needed when not writing to all four segements SPI1.write([ z[i4], z[i3],z[i2],z[i1] ],B6); //SPI1.write([ sport, sport, sport ], B6); //to debug a segement },100);
I have chained three additional 74HC595 s. The problem with that solution is, that i have no clue how to bring all this wires to a PCB breadboard.
I think i will have to do it the multiplexing way to avoid all this new cables.
2 Attachments
-
• #8
Wow, that's great! A lot of wires there!!
-
• #9
The 'all-you-can-eat wire-buffet' hints the use of a dedicated peripheral display that includes the logic to receive by, for example I2c, SPI, etc. and do the multiplexing. ...if the display is not the only thing you want to show case (educationally).
Hi,
can someone review my code? i think that there must be a more efficient way to get this done.
2 Attachments