Monday, November 12, 2012

The Morrow Progress

The CBR box is mostly assembled, and I've been coding up the behavior.  As is my wont, I've been thinking about the programming process.

But here's a pic:







Why is the pic so blurry?  Explanation and more boring text-ty stuff below the fold.  Plus more pics of me soldering things.





So the evolving program went through four not-particularly-discrete steps:

Proof-of-Concept Tests

Functional Tests

Framework

Details


The first started way back, when I attempted to light the vacuum fluorescent display.  This was the major questionable element; I knew I could write software for any display I could get working, and the rest was simple familiar stuff (read buttons, light LEDs).

Getting the VFD to light was the major thing I did on breadboard.  I also proofed the capacitance sensor and tried out a simple tone generation.



Functional tests is, roughly, testing the actual hardware.  For this, I was writing sketches; short bits of code that were only designed to turn on or otherwise test whatever component I was looking at.  I'd done a previous wire harness test (brushing a 5v supply lead against each of the LED wires), but I also had to hook up everything to the final board and check to see if I'd assigned it to the right pin.

The major part of this was getting the entire VFD working as a unit and writing text to it.  Another time-consuming element was calibrating the resistor ladder, and I suspect the same calibration cycle will be necessary for the capacitance sensor; I'm working with only the faceplate now, with the wires leading to the body still unconnected.



The framework was the code that allowed the box to go into various states on command (aka the selector switch and test button), and run through various programmed behaviors.  The primary difficulty is that the VFD requires constant refreshes.  Also, the VFD code is not that efficient; it consumes something like a 400th of a second for every single write I make to it.

So all of the code needs to be based on counters; number of cycles elapsed since last event.  Fortunately the ATmega's outputs are latching, AND it has several internal timers meaning PWM and tone writes are essentially latching as well.

An added complexity is that I want it to react transparently (aka with no delay, and no "garbage" left on the displays) when the mode is changed.  The most efficient framework seemed to be using loop() (the Arduino equivalent of C's "main()") as a function host.  On each cycle through loop() it tests the selector switch and branches to a function() defining the appropriate behavior.

The difficulty is of course this happens hundreds of times a second, meaning no part of this loop can include initialization.  I'm up against that issue right now with the "Test" function, as currently the write to the display happens at the top of the function.  Which is incompatible with the test sequence.  I'm split now whether to do yet another if...else... branch to test before writing to display, or moving the initial state (aka display) to within a unique switch...case... call within the selector switch test function.



The point of no return (sort of): hot-gluing the VFD into the faceplate and soldering all the connecting wires.

 
I also pulled the speaker out of the body and used my Dremel to cut away more of the excess casting in there.  One downside; it is now significantly lighter as well.  But at least now I can cram the circuit board and battery in without risking my wires every time.

And here's a test assembly:


You might wonder why it is a little blurry.  That's my thumb you see there!  I didn't want to re-code the newly finished test button function just for a picture, so I had to push the shutter, then quickly reach into the frame and tap the test button.  It took a good dozen tries; the lights pulse twice for about a quarter of a second.

The longer part of the test() state is that after about eight seconds, it displays "Self Test" (or, rather, "SLF tESt") then a series of labels with rapidly changing numbers.  I finally got around to writing a simple function that turns numeric data into a String object of char values (which is then referenced via an index of the ASCII value of the characters to a lookup table written in binary, which tells the VFD which segments to light up!)

(I wanted to, after reading about the coding on the original "Sliders" Timer, do a similar scroll-by of various inside-joke words, but it didn't inspire me enough to write a character scrolling routine for the display.)

(Oh; the empty hole is where the power switch goes after that's been soldered between the battery and circuit board.  The speaker is also still on alligator clips, and is going to have to stay that way until all the software is written; it shares a pin with MOSI and interferes with writing new code to flash memory.)

Oh, and I meant to wire that LED to a PWM port so I could run it at a low, dark level and look like a period 2-5 ma red LED (instead of the 10-20 ma I've got).  But I ran out of PWM pins that were convenient to get to.


Now on to coding the meaty part; the simulated alarm. 

(Here's what it looks like in darker conditions -- wobbling back and forth from my lunge for the test button.)




Okay...I really have to explain my stupid-sounding VFD code.

In the body of the program, all I have to do is type out an 8-character string using capital letters, numbers, and a limited punctuation set:

wordBuffer = "PLTONIUM"
wordBuffer = "2500_PPM"

(Actually, my "space bar" character is "@.")

When I call the write_word() function, two loops parse the String one character at a time.   They then send each character to a lookup table.  The lookup table is a display of which of the eight segments of that digit are lit; 11110111 means all seven segments are lit but the decimal point is dark.  I worked out the table on graph paper to match the pin order in which I had connected to the driver chip.

For each digit, I clock eight times into the driver chip (a latching shift register) with the data pin pulsed HIGH on just the digit selected, then another eight times with the data pin HIGH for each matching position in the binary value from the lookup table.  Then a couple more times to bring it up to an even 20 (the width of the shift register).  I do this eight times...which is why the total routine consumes a good 400th of a second of CPU time.

At the end of each digit I pulse the blanking pin and hold for a few dozen microseconds in order to clean up the display.  At my current refresh time, the flickering is invisible unless you move the display rapidly.



The Medkit is going to have three display behaviors at best.  Off, blink randomly, and turn everything on.  And I'm going to leave off the VFD and just stick a blue LED or EL panel behind the display.

No comments:

Post a Comment