Saturday, December 29, 2012

Electric Imp Tweeting Cat Door

Objective:
  • Using the Electric Imp,  create a rig to 'tweet' whenever activity is sensed on a cat door.
  • Create a real time graph of the activity here.
For those not interested in the build details, Kelso helped with this short video of @OurCatDoor in action:
-----
We have two cats (Zena and Kelso) that were eager to get online.  When they are not helping out in the labs (example pic) they like to walk through a cat door and relax on the screened in sun porch where they can enjoy food, drink, and take a bathroom break.

Tweeting cat doors are nothing new to The Net.  However, when I saw the Electric Imp I thought it could be a different way to tackle the problem and learn a few things along the way.  Let's take you through the process.

To start you are going to need an Electric Imp and an "April" Imp Breakout Board.  Oh, and a cat or two...



The Electric Imp is a pretty cool piece of kit.  It looks like a SD Card, but it is really a Cortex-M3 processor with WiFi on board.  Damn!  An onboard mini USB connector is used only to power the device; not for data.
-----
The Electric Imp is useless until you get it established with a wireless network.  As mentioned above, the USB is not used for data.  So how do you program it?  With light from the screen of an app that is run on your iPhone or Android.  You enter your WiFi SSID (and security paswords if needed) and the app sends "flashes" to the screen that are picked up by the Imp to program it.  The process works surprisingly well.
----
The physical I/O for the project is pretty straight forward.  All that is needed is a magnetic reed switch to sense if the cat door flap has opened.  A blue LED is used as a visual clue for ON/OFF and switch detection.  After deciding how to map the Imp's GPIO for the project, the schematic is embarrassingly simple:
-----
After soldering headers to the April breakout board a connector was repurposed making the connection setup clean and simple.
-----
The real challenge is in the software and the cross platform integration (Imp to WhiskeyTangoHotel.com webserver to Sen.se to Twitter) and that process was not trivial, but I'll take you through that as well.
-----
Now that you have the Imp all wired up and connected to a WiFi network, how do you program it?  Remember again that the USB is just for power.  The Imp is programmed in Squirrel through your browser (I used Chrome) from the Electric Imp website.  To me, Squirrel has a "C" type feel to it.  You work through a screen called "The Planner" to code up your project behind "nodes".  These "nodes" can be connected with "noodles" for flow control.  Here is the Imp planner screenshot of my finished project.  Note that you can't see the source code here as it is embedded under the "blue node".  I'll show my source code below later.
-----
In The Planner above, the Imp runs the code under the BLUE box and passes output to the GREEN box.  The code in the BLUE box has the Imp doing a few basic things:  1) turn on a blue LED to let everyone know the Imp is powered and 2) monitoring a magnetic reed switch on the cat door.  If the cat door is opened the reed switch opens contact.  The Imp will 'see' the switch change and 3) blink the blue LED off to provide a visual confirmation and 4) pass the text string to be "tweeted" to the green box.

So what's in the green box?  When the green box is called a PHP script is executed on the WhiskeyTangoHotel.com webserver.  From this point, we leave the Electric Imp world and enter the Sen.se world.  
-----
Sen.se is one cool place.  Their goal is to assist in internet connectivity of personal devices.  They have widgets, tools, applications, channels and a few other things that I barely understand. One of the widgets found there helps with broadcasting to Twitter.  So, the PHP script in the green box above passes the string the cat wanted to "tweet" to the Sen.se Twitter app and the final result is achieved; a cat walking through a door unknowingly Tweeting a message to the world.  

Presto!  Even without opposable thumbs, the ability to type, speak English, read, or boot a computer our cats are online. 
-----
A few closing comments... I found the current Electric Imp user community to be pretty small. That said, the project wouldn't have come off without help from Electric Imp forums.  Most notable are "brendandawes" and "Hugo" who were my two main enablers.  Hugo is actually the CEO/Co-Founder of Electric Imp and I was pretty impressed that he is so involved.  Also,  I do wonder how the project would have gone with a near cost equivalent Raspberry PI.  I never really got comfortable with the fact that all my Electric Imp code was not stored locally.  I also wish there were more examples on the web to build a knowledge base from.   But, the Electric Imp package is crazy small and tight with low power draw so that is a huge plus.  In all I can't complain, the project works great and taught me a lot.  I don't have any experience with the Raspberry PI anyway, so any judgement will have to wait. 
-----
If you are still with us, here is some source code for your reading pleasure:
-----
Code Under the "Blue" Box Electric Imp Planner

/*
Tweeting Cat Door
Dec 2012
www.WhiskeyTangoHotel.Com

Read switch on PIN7 and GND
    Normally Open or Normally Closed can be adjusted in swEvent function
Blue LED PIN9 to V3V is ON if the code in running
    Blinks off for 0.5 secs when door switch dectected
*/

hardware.pin9.write(0); // LED ON, active LOW
local channelOutput = [ OutputPort("Ch 1", "string")]; // String var that gets sent to PHP script

//Watchdog code below send Ping to Imp server every xx secs
//I added this because the Imp was not Tweeting all switch closures and
//power up/down seems to correct it.  Assuming lost cost with Imp server?
function watchdog() {
  imp.wakeup(120,watchdog);  //xxx is seconds between pings
  server.log("WD ping");
}
watchdog();
//End of my watchdog code experiment

// function swEvent handles looking for action on the door switch
function swEvent() {    
        local d = date();  // Date info not sent to twitter.  Used only for planner debug
        local min = d["min"];
        local hour = d["hour"];
        local sec = d["sec"];
        local state = hardware.pin7.read();
        if (state == 0) {   // "1" Tweets when switch opens (for a NC swtich).  "0" Tweets when switch closes (for a NO swtich).
     
        // Select Random Msg.  Increase %xx as number of random msgs increases
            local r = math.rand()%4;   // generate random number (min val is 0.  max val is %xxx in Decimal)
   
            if (r == 3) {
                channelOutput[0].set("Random message for r = 3 here");
            }
         
            if (r == 2) {
                channelOutput[0].set("Random message for r = 2 here");
            }
         
            if (r == 1) {
                channelOutput[0].set("Random message for r = 1 here");
            }
         
            if (r == 0) {
                channelOutput[0].set("Random message for r = 0 here.");
            }
        // end Random Msg selecton
     
        // Blink the LED Off to show a door swing detected
        hardware.pin9.write(1);  // LED OFF
        imp.sleep(0.5)          // 500mS delay
        hardware.pin9.write(0);  //  LED back ON
     
        server.show("r="+r+" @ "+hour+":"+min+":"+sec);  //echo to the Imp Planner status the generated RANDOM# and time.  Used for debug.
        }   // end if state ==0 (or state ==1 depending on NO or NC switch type)
       
        imp.sleep(1.0);  // switch settle time of x.x seconds (keep greater that 0.5)    
        server.log(state);  //  echo switch state (O or 1) to planner window for debug      
}  // End function swEvent

// Configure pin 9 as an open drain output with internal pull up
// Configure pin 7 as switch
hardware.pin9.configure(DIGITAL_OUT_OD_PULLUP);
hardware.pin7.configure(DIGITAL_IN_PULLUP, swEvent);

imp.configure( "TCD w-Blink", [], channelOutput);
------
PHP Script called from Green Box in the Electric Imp Planner:
<?php
$feed_id = "sen.seAsignedXXX.XXXXXX";
$api_key = "sen.seAssignedXXX.XXXXXX";
if(isset($_POST['value'])) {
$data = array("feed_id" => $feed_id, "value" => $_POST['value']);                                                                    
$data_string = json_encode($data);                                                                                   
$ch = curl_init('http://api.sen.se/events/?sense_key='.$api_key);                                                                      
curl_setopt($ch, CURLOPT_CUSTOMREQUEST, "POST");                                                                     
curl_setopt($ch, CURLOPT_POSTFIELDS, $data_string);                                                                  
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);                                                                      
curl_setopt($ch, CURLOPT_HTTPHEADER, array(                                                                          
    'Content-Type: application/json',                                                                                
    'Content-Length: ' . strlen($data_string))                                                                       
);                                                                                                                   
$result = curl_exec($ch);
}
?>
-----
Link back: Hack a Day
Link back: Hacked Gadgets
-----

Sunday, November 18, 2012

Analog Clock turned DC Voltmeter

Why create, what could be, the most impractical way to measure a DC voltage?  Well, because "Measurement Matters".

Actually, the idea was given to me in the comment section of my Voltmeter Clock project which was featured by the awesome team at "Hack A Day".  That is where rue_mohr wrote the comment, "who can be the first to turn a clock into a volt meter?"  Well, that is (and remains) the stupidest ideal I ever heard.  Now, read on....
----
The concept is easy.  Use the "time" on an analog clock to display measured voltage values between 0-12VDC.  1 o'clock means 1VDC, 2 o'clock means 2VDC; if the time reads 10:30 that means 10.5VDC, etc.   To do this a stepper motor is connected to the adjustment knob of the analog clock.  This short video of the rig being tested should help make things clear:
---
One of the ADC inputs on a PICAXE 18M2 microcontroller is used to read/digitize the voltage to be measured.  After the PICAXE measures the voltage, it gets translated into the number of steps the stepper motor needs to move.  This stepper motor movement adjusts the clock to display the voltage that was measured.  The PICAXE doesn't have enough output current to directly drive a stepper motor so the PICAXE feeds a L293D Motor Driver IC.  The outputs of the L293D are then used drive the stepper motor.

Since the clock can display a maximum value of "12 o'clock", the rig was designed to measure a maximum 12VDC input signal.  However, the max input voltage for the ADC on the PICAXE 18M2 is about 5VDC.  To tame the input signal for the PICAXE a simple 3:1 voltage divider (10K, 10K, 10K) was implemented.  This limited the input voltage into the PICAXE to 4VDC.  A trim pot was also used to adjust for the input impedance of the PICAXE and to help calibrate the measurement results.
----
Here is a video of the rig in action side by side with a DVM.
---
All in all the rig works as designed but has terrible lag and is no way what anybody would consider NIST traceable.  The accuracy is estimated at ~100mV.  The two control buttons pictured below help by allowing manual calibration of the rig to 0VDC (12 o'clock position).
---
I can't imagine that this project will ever be duplicated, but as always I will send schematics and source code to those that request it.  If you're still with us, thanks for checking out our site.
-----
Link back: Hack A Day
Link back: Hacked Gadgets
-----

Saturday, September 29, 2012

FRDM-KL25Z Demo: Freescale Development Platform


We put an early pre-order in with ELEMENT14 for Freescale's Kinetis KL25Z development board and it arrived this week.  The dev board has a very solid feel and cost only $12.95.  A great value when you consider all the features; including a Freescale MMA8451Q 3-axis accelerometer glued right onto the board!  Freescale's description on the dev board is "The Freescale Freedom development platform is a low-cost evaluation and development platform featuring Freescale's newest ARM® Cortex™-M0+ based Kinetis KL25Z MCUs."
-----
Here is a short video demonstrating the MMA8451Q in action.  The tri-color LED is White when flat; Red when tilted up; Blue when tilted sideways:
-----
The kit comes with headers, a quick start guide, and has the following high level feature set:
- KL25128VLK4 - Cortex micro controller with:
     128Kb FLASH, 16Kb SRAM
     48MHz operation
     Full speed USB controller
     OpenSDA USB debug interface
     Tri-color LED
     Capacitive touch slider
     Reset button
     Expansion IO accepts Arduino form factor shields
-----
More fun to come.  Stay tuned.

www.WhiskeyTangoHotel.Com

Wednesday, August 29, 2012

Four Letter Word Clock via uC

Why build a clock that displays four letter words?  The current time is everywhere; on your PC, smartphone, GPS, MP3 player, etc.  Heck, you may even own a watch!  Four letter words are pretty common as well.
-----
So why then?
     1st)  I had this display that I bought from DealExtreme.Com.  The only reason I got it was because it was so cheap.

     2nd) I wanted to experiment with writing/reading data from an EEPROM with a microcontroller.

     3rd) I wanted to experiment with controlling two devices on the I2C bus in one application.

But.... I wanted a fun project idea to make the effort seem somewhat worthwhile and settled on a Four Letter Word Clock.

If you you just want to see the results and are not interested in the build details, here is a short video demo.

The time is shown in 24 hour format on the left four 7-segments.  Every second a different four letter word is shown on the right four 7-segments.  The eight LEDs under the 7-segments progress from left to right as a way to display seconds.  If you listen closely to the video and you can hear a relay that gives the clock a mechanical ticking sound. 

 The buttons under the LEDs are used to set hours (S1), minutes (S2), increase display brightness (S6), decrease display brightness (S7), and turn ON/OFF the mechanical ticking sound (S8) from the relay.

The major components of the build are (full schematic to follow):
     - Eight x 7-Segment + 8 x Red/Green LED + 8 x Input Button Display Module
     - 24LC256 EEPROM to store the 1,003 four letter words
     - DS1307 Real Time Clock (RTC) for time keeping
     - Small relay to provide a clock like, mechanical ticking sound
     - PICAXE 18M2 microcontroller with custom code provides the brains
------

The display from DealExtreme.Com is pretty awesome for the price.  It contains eight 7-segment LED displays, eight LEDs that can be red, green, or red/green, and eight button switches.  The display has a solid, well built feel to it and was a bargain at $4.99.  As a plus, you can control all these feature with only three I/O pins on a microcontroller.  On the downside, it ships with no documentation (zero, zip, nada...) so plan on doing some web searching to understand it.
-----

The 24LC256 EEPROM, DS1307 RTC, and PICAXE 18M2 are easy to get from many web sources.  I rescued the Teladyne 712-5 relay from a trash bound PCB.  A good thing because a web search shows that relay at $28 (it's an RF spec relay!).  No fear, you can leave the relay off or just use any cheap relay as it is not used to switch any current, just for the ticking sound.
-----
Now came the time to load the 24LC256 EEPROM with four letter words.  So... to the internet for a quickie download of all the four letter English words (including all your favorite cuss words) in one tight ASCII text file.  Unfortunately, 7-segment displays don't display letters like "K", "M", "V", "W", "X", and "Z" very readable.  I wrote a short Python script to pull out the offenders, which also meant some of the more 'expressive' words where lost.  After it was all done, there were 1,003 four letters words that easily fit into the 24LC256 EEPROM.  A short (and separate) program was written to tell the PICAXE 18M2 to load these words into the 24LC256 EEPROM.
-----
The harder part was the code to drive the display.  The lack of documentation made it pretty challenging.  I always find the PICAXE forum helpful in these situations (special thanks to "mjy58").  After much coding/debugging, the problem was solved. 

Controlling the two I2C devices (the 24LC256 EEPROM and the DS1307 RTC) from the PICAXE 18M2 was a bit easier than I expected after sorting through the addressing procedures.
----
Here is a short vid (time lapse) of the rig working on the AXE091 development board.  In the vid you can see the eight red LEDs progress from left to right as the seconds tick by.


-----
After verifying the operation for a few days the whole mess was moved off the AXE091 development board and onto a strip board PCB.  Installing the rig into a $3.49 metal project box from Radio Shack provided a clean finished product.
 -----
Below is the build schematic (click to enlarge).  
-----
PICAXE source code:
#rem
 *******************************
 ***** www.WhiskeyTangoHotel.Com  *****
 *******************************   
    Project Name: 4Letter Word Clock

    Start Date: August 2012
   
    Program Rev History:


 *******************************

http://www.dealextreme.com/p/8x-digital-tube-8x-key-8x-double-color-led-module-81873

#endrem

;
;LKM1638 Input pin 3 (CLK)      ---> 18M2 c.0 LEG 17
;LKM1638 Input pin 4 (DIO)      ---> 18M2 c.1 LEG 18
;LKM1638 Input pin 5 (STB0)     ---> 18M2 c.2 LEG 1

;24LC156 EERPOM WP (Write Protect) GND
;24LC156 EERPOM SDA          ----> 18M2 b.1 LEG 7
'24LC156 EERPOM SCL           ----> 18M2 b.4 LEG 10

#picaxe 18m2
#no_data    'do not read internal 18M2 EEPROM

dirsc = 010111        ;c0, c1, c2, c4 as output
symbol clock    = c.0    ;Clock output pin
symbol dio        = c.1    ;Data input output pin
symbol strobe    = c.2    ;Strobe output pin

' s1 thru s8 are the tact swithes under the single RED/Green LEDs
symbol s1        = bit16 ;b2        'to set hours
symbol s2        = bit17 ;b2        ' to set minutes - both to set seconds
symbol s3        = bit18 ;b2
symbol s4        = bit19 ;b2
symbol s5        = bit20 ;b2
symbol s6        = bit21 ;b2
symbol s7        = bit22 ;b2
symbol s8        = bit23 ;b2    'toggle to turn on and off the ticker relay

symbol dataio    = b0 ;w0 and bit 0 to bit 7
symbol pad        = b1 ;w0 and bit 8 to bit 15
symbol iobuf    = w0 ;b0, b1
symbol keys        = b2 ;bit16 to bit 23
symbol fixaddr    = b3 ;start address for DE display

symbol Segment4LEFT    = b4  ;Rightmost 7 seg, LEFT Side
symbol Segment4RIGHT     = b5  ;Rightmost 7 seg, RIGHT Side
symbol Segment2LEFT    = b6  ;Leftmiddle 7 seg, LEFT Side
symbol Segment3LEFT    = b7  ;Rightmiddle 7 seg, LEFT Side
symbol Segment2RIGHT    = b8  ;Leftmiddle 7 seg, Right Side
symbol Segment3RIGHT      = b9  ;Rightmiddle 7 seg, Right Side
symbol Segment1LEFT      = b10 ;Leftmost 7 seg, LEFT Side
symbol Segment1RIGHT    = b11 ;Leftmost 7 seg, Right Side

symbol char        = b12
symbol bank        = b13
symbol tmpry     = b14
symbol dispbrit    = b15
symbol autoaddr    = b16
symbol readmode    = b17
symbol tmpry2    = b18
symbol EEPROMChar = b19
'w10 (b20/21) = used to read var from EEPROM
symbol LEDTicker  = b22

symbol seconds = b23 ' vars for RTC
symbol minutes = b24
symbol hours = b25
symbol blinky = b26 'for RTC 010000 would Enable output at 1Hz blink rate.  000000 is no blink
symbol junkread = b27 'used to read/write RTC day, month, year, date.  Also as a temp var in time set adjust routines

fixaddr        = $c0
dispbrit        = $88    '$88 (136DEC)  min bright.   $8F (143DEC) max bright
autoaddr        = $40
readmode         = $42

init:
high strobe            ;Ensure strobe is initially high
gosub clearchars        ;Clear all characters
blinky = 010000 ' 010000 would Enable output at 1Hz blink rate, start w/ relay click ON..  000000 is no blink.

' Set the time on the DS1307 RTC
i2cslave %11010000, i2cslow, i2cbyte    ; set PICAXE as master and DS1307 slave address
pause 50
'\/ \/ \/ \/ Un_REM THESE LINES (BELOW) IF SETTING UP A NEW RTC  \/ \/ \/ \/
#rem
' Set the RTC chip time
;  write time and date e.g. to 11:59:00 on Thurs 25/12/03
'; would be "writei2c 0,($00, $59, $11, $03, $25, $12, $03, 010000)"
' readi2c 0, (b0,b1,b2,b3,b4,b5,b6,b7) reads back the data

let hours = $19        ; 01-12 Note all BCD format
let minutes = $11         ; 00-59 Note all BCD format  
let seconds = $10    ; 00-59 Note all BCD format

; program does not use for we use seconds.  Set manually in the write statement
' for SQ Wave out on RTC.  Last val: 010000 would Enable output at 1Hz blink rate.  000000 is no blink

writei2c 0, (seconds, minutes, hours, 01, 01, 01, 01, blinky)
pause 50

#endrem
'/\ /\ /\ /\ Un_REM THESE LINES (ABOVE) IF SETTING UP A NEW RTC  /\ /\ /\ /\


;--------------------------------------------------------

'I have laid out the 8 segments in the display as:

'| Segment1LEFT | Segment2LEFT | Segment3LEFT | Segment4LEFT | Segment1RIGHT | Segment2RIGHT | Segment3RIGHT | Segment4RIGHT

    ;Segment Values                0-9   = ( 0 , 1,  2 , 3 , 4 , 5 , 6 , 7, 8 , 9,
    '                              10-19 =   A , b , C , d , E , F , g,  H, i,  J,
    '                              20-29 =   K,  L,  M,  N,  o,  P,  q,  r, S,  T, 
    '                              30-35 =   U, V, W,  X,  y,   Z ,
    '                              36-44 =   segA, segB, segC, segD, segE, segF, segG, dp, off)

'the 'gosub display' routine expect 8 values; SegmentxLEFT and SEGMENTxRIGHT coded as
'lookup values shown in the rem above.

main:

if s1 = 1 or s2 = 1 or s8 = 1 then 'setting the clock time or relay ticker
    if s1 = 1 and s2 = 0 then 'setting hours
        junkread = junkread + 1
        if junkread > 23 then
            junkread = 0
        end if
        lookup junkread, ($00,$01,$02,$03,$04,$05,$06,$07,$08,$09,$10,$11,$12,$13,$14,$15,$16,$17,$18,$19,$20,$21,$22,$23), hours
         i2cslave %11010000, i2cslow, i2cbyte
        writei2c 0, (seconds, minutes, hours, 01, 01, 01, 01, blinky)
        pause 10
    endif ' s1 = 1, setting hours
   
    if s2 = 1 and s1 = 0 then 'setting minutes
        junkread = junkread + 1
        if junkread > 59 then
            junkread = 0
        end if
        lookup junkread, ($00,$01,$02,$03,$04,$05,$06,$07,$08,$09,$10,$11,$12,$13,$14,$15,$16,$17,$18,$19,$20,$21,$22,$23,$24,$25,$26,$27,$28,$29,$30,$31,$32,$33,$34,$35,$36,$37,$38,$39,$40,$41,$42,$43,$44,$45,$46,$47,$48,$49,$50,$51,$52,$53,$54,$55,$56,$57,$58,$59), minutes
         i2cslave %11010000, i2cslow, i2cbyte
        writei2c 0, (seconds, minutes, hours, 01, 01, 01, 01, blinky)
        pause 10
    endif 's2 = 1, setting minute
   
    if s1 = 1 and s2 = 1 then 'reset seconds to 00
        seconds = $00
        i2cslave %11010000, i2cslow, i2cbyte
        writei2c 0, (seconds, minutes, hours, 01, 01, 01, 01, blinky)
        pause 10
    endif 'settin seconds to zero

    if s8 = 1 then ' turn on/off the clicking relay
        'read the RTC to dected the seconds for the write to RTC below keeps them accurate
        i2cslave %11010000, i2cslow, i2cbyte    ; set PICAXE as master and DS1307 slave address
        readi2c 0,(seconds, minutes, hours, junkread, junkread, junkread, junkread, blinky)
        pause 10
        if blinky = 010000 then 'blinky from RTC is ON and clinking the relay. turn it OFF
            blinky = 000000
        else              'blinky from RTC is OFF and NOT clinking the relay. turn it ON
            blinky = 010000
        end if
        i2cslave %11010000, i2cslow, i2cbyte
        writei2c 0, (seconds, minutes, hours, 01, 01, 01, 01, blinky)
        pause 500
    end if
   

else ' not settign the clock, check for brightness adjust and run as normal; so read a new 4letter word
   
    if s7 = 1 then 'increase brightness
        dispbrit = 140 'other values cause random LED7 behavior
    end if

    if s6 = 1 then 'decrease brightness
        dispbrit = 136   ' 136 is min bright
    end if   

sertxd (#dispbrit, 13,10)
   
    'Get SegmentxLEFT values for clock by reading the RTC
    i2cslave %11010000, i2cslow, i2cbyte    ; set PICAXE as master and DS1307 slave address
    readi2c 0,(seconds, minutes, hours, junkread, junkread, junkread, junkread, blinky)
    pause 10
    gosub ReadEEPROM  ' read the four letter word.  These are loaded into SegmentxRIGHT vars
    gosub Ticker    'ticks thru the R/G LEDs to show seconds
endif

Segment1LEFT = hours & %11110000 / 16  'BCD so shift upper 4 bits to lower 4 bits
Segment2LEFT = hours & 001111

Segment3LEFT = minutes & %11110000 / 16   'BCD so shift upper 4 bits to lower 4 bits
Segment4LEFT = minutes & 001111

gosub display   'Put the SegmentxLEFT and SEGMENTxRIGHT characters onto the 7 seg displays.

gosub getkeys        ;Read tact buttons
           
goto main

'-------------------------------------------------------
Ticker: 'ticks thru the R/G LEDs to show seconds by cycling through each LED address

junkread = seconds & %11110000
junkread = junkread / 16 * 10
seconds = seconds & 001111
seconds = junkread + seconds

lookup seconds, (1,1,1,1,1,1,1,1,3,3,3,3,3,3,3,3,5,5,5,5,5,5,5,5,7,7,7,7,7,7,7,7,9,9,9,9,9,9,9,9,11,11,11,11,11,11,11,11,13,13,13,13,13,13,13,13,15,15,15,15), dataio

dataio = dataio + fixaddr    ;LEDs are at odd addresses 1 to 15
junkread = dataio   'used to turn off LED later in this sub
low strobe
gosub sendchar

LEDTicker = LEDTicker + 1

if LEDTicker = 2 then
    LEDTicker = 1
end if

dataio = LEDTicker  'Light the LEDs.  1 = RED.  2 = GREEN.  3 = R/G
gosub sendchar
high strobe

'Turn off LED here
dataio = junkread   
low strobe
gosub sendchar
dataio = 0   '0 turns off the currently selected LED
gosub sendchar
high strobe;

dataio    = dispbrit        ;Display control on, brightness level
low strobe                 ;Strobe low
gosub sendchar
high strobe                ;Strobe high

return 'Ticker




ReadEEPROM:
'24LC256 EEPROM is loaded with 987 four letters words (3948 characters)
'Each character is an address from 0 to 3947
'readi2c addrs, (charvalue)

i2cslave %10100000, i2cslow, i2cword    ; set PICAXE as master and DS1307 slave address

'Read and Translate the char read from the EEPROM for the lookup(.,...), dataio command.
'Read the EEPROM letter then subtract 87 from that ASCII value for the "lookupchar" sub.  Examples:
'ASCII value for a = 97; Lookup in this program value is 10.  So, 97 - 87 = 10
'ASCII value for j = 106; Lookup in this program value is 19.  So, 106 - 87 = 19
'ASCII value for k = 122; Lookup in this program value is 35.  So, 122 - 87 = 35


readi2c w10, (Segment1RIGHT)
Segment1RIGHT = Segment1RIGHT - 87

w10 = w10 + 1
readi2c w10, (Segment2RIGHT)
Segment2RIGHT = Segment2RIGHT - 87

w10 = w10 + 1
readi2c w10, (Segment3RIGHT)
Segment3RIGHT = Segment3RIGHT - 87

w10 = w10 + 1
readi2c w10, (Segment4RIGHT)
Segment4RIGHT = Segment4RIGHT - 87

w10 = w10 + 1
'check if "yurt" (the last possible word) is displayed?
if Segment1RIGHT = 34 AND Segment2RIGHT = 30 AND Segment3RIGHT = 27 AND Segment4RIGHT = 29 then 'yes. it is "yurt"
    w10 = 0   'yurt' found, so go back to address 0 (the first 4letter word)
end if

pause 1000 'keep the secs LED on and slow down the words

return ' ReadEEPROM


;--------------------------------------------------------

display:    ;Displays data on the 7 seg displays, using 2 blocks of 4 digits

    bank = 0   ;LEFT Side: First block of digits

    dataio    = fixaddr + bank + 0 ;Set Leftmost 7 seg, LEFT Side write address
    low strobe                 ;Strobe low
    gosub sendchar
    char = Segment1LEFT        ;Leftmost 7 seg, LEFT Side
    gosub lookupchar
    gosub sendchar
    high strobe                ;End of data - Strobe high
   
    dataio    = fixaddr + bank + 2 ;Set Leftmiddle 7 seg, LEFT Side write address
    low strobe                 ;Strobe low
    gosub sendchar
    char = Segment2LEFT        ;Leftmiddle 7 seg, LEFT Side
    gosub lookupchar
    gosub sendchar
    high strobe                ; End of data - Strobe high
   
    dataio    = fixaddr + bank + 4 ;Set Rightmiddle 7 seg, LEFT Side write address
    low strobe             ; Strobe low
    gosub sendchar
    char = Segment3LEFT    ;Rightmiddle 7 seg, LEFT Side
    gosub lookupchar
    gosub sendchar
    high strobe            ;End of data - Strobe high
   
    dataio    = fixaddr + bank + 6 ;Set Rightmost 7 seg, LEFT Side write address
    low strobe             ; Strobe low
    gosub sendchar
    char = Segment4LEFT    ;Rightmost 7 seg, LEFT Side
    gosub lookupchar
    gosub sendchar
    high strobe            ;End of data - Strobe high
   
    'RIGHT BANK
    bank = 8  ;RIGHT Side: Second block of 4 digits
    dataio    = fixaddr + bank + 0 ;Set Leftmost 7 seg, Right Side write address
    low strobe             ;Strobe low
    gosub sendchar
    char = Segment1RIGHT    ;Leftmost 7 seg, Right Side
    gosub lookupchar
    gosub sendchar
    high strobe            ;End of data - Strobe high
   
    dataio    = fixaddr + bank + 2 ;Set Leftmiddle 7 seg, Right Side write address
    low strobe             ;Strobe low
    gosub sendchar
    char = Segment2RIGHT    ;Leftmiddle 7 seg, Right Side
    gosub lookupchar
    gosub sendchar
    high strobe            ;End of data - Strobe high
   
    dataio    = fixaddr + bank + 4 ;Set Rightmiddle 7 seg, Right Side write address
    low strobe             ; Strobe low
    gosub sendchar
    char = Segment3RIGHT    ;Rightmiddle 7 seg, Right Side
    gosub lookupchar
    gosub sendchar
    high strobe            ; End of data - Strobe high
   
    dataio    = fixaddr + bank + 6 ;Set Rightmost 7 seg, RIGHT Side write address
    low strobe             ; Strobe low
    gosub sendchar
    char = Segment4RIGHT    ;Rightmost 7 seg, RIGHT Side
    gosub lookupchar
    gosub sendchar   
   
    '-----------------
   
    'must refresh dispbrit each time
    dataio    = dispbrit ;Display brightness level. $88 (136DEC)  min bright.   $8F (143DEC) max bright
    low strobe         ; Strobe low
    gosub sendchar
    high strobe        ; Strobe high

return   'display

;--------------------------------------------------------

clearchars:            ;Clear LEDs and 7 seg displays.  ALL LEDS OFF. Segs and LEDs
    dataio    = autoaddr ; Data mode auto increment
    low strobe         ; Strobe low
    gosub sendchar
    high strobe        ; Strobe high
    ;
    low strobe         ; Strobe low
    dataio    = fixaddr ; Set start address
    gosub sendchar
    for tmpry = 1 to $0f    ;$0F = 15, so loop runs 16 times.  7 LEDs and 7 seg displays
        dataio = 0        ;Zero blanks the  display
        gosub sendchar
    next
    high strobe            ;Strobe high, keep low to end of data
return

;--------------------------------------------------------

sendchar:    ;Routine to send all characters to LKM1638 module serially
    pad        = $ff    ;$FF = 255.  Set counter
    high clock        ;Ensure clock is high for pulseout
    do
      pinc.1 = bit0    ;Make c.1 the value in bit0
      iobuf = iobuf/2    ;Shift right
      pulsout clock,1 '10us clock pulse
    loop Until pad = 0  'excecute 256 times
return

;--------------------------------------------------------

getkeys:    ;Reads the input tact buttons in and places them in bits16 to bits23
dataio    = readmode    ; Data mode read
low strobe
gosub sendchar
input c.1            ;set c.1 as input
high clock            ;Ensure clock is high for pulseout
for tmpry = 1 to 16    ;Read in bits 0-15
    bit0 = pinc.1    ;Make bit0 the value on c.1. Need to use c.1 as it is both in & out
    iobuf = iobuf*2    ;Shift bit left
    pulsout clock,1    ;10us clock pulse, read next bit
next
s6 = bit3            ;Move 1st word switch values out of buffer
s2 = bit7
s5 = bit11
s1 = bit15
for tmpry = 1 to 16    ;Read in bits 16-31
    bit0 = pinc.1    ;Make bit0 the value on b.0. Need to use c.1 as it is both in & out
    iobuf = iobuf*2    ;Shift bit left
    pulsout clock,1    ;10us clock pulse, read next bit
next
s8 = bit3            ;Move 2nd word switch values out of buffer
s4 = bit7
s7 = bit11
s3 = bit15   
output c.1            ;Return c.1 to output
high strobe
return

;--------------------------------------------------------

lookupchar:    ;Looks up the code to display the digit in 'char' on the 7 seg display
    ;character  0-9   =    ( 0 , 1,  2 , 3 , 4 , 5 , 6 , 7, 8 , 9,
    '               10-19 =         A , b , C , d , E ,  F , g,  H, i,   J,
    '               20-29 =         K,  L,  M,  N, o,   P,  q,  r,  S,  T, 
    '               30-35 =         U, V, W,  X,  y,   Z ,
    '               36-44 =        segA, segB, segC, segD, segE, segF, segG, dp, off)

    lookup char,(63,6,91,79,102,109,125,7,127,111,119,124,57,94,121,113,111,118,16,30,118,56,21,84,92,115,103,80,109,120,62,28,42,118,110,91,1,2,4,8,16,32,64,128,0),dataio

return
;-----------------------------------------
-----
Link back: Hack A Day
-----

Monday, July 16, 2012

ZIF Socket Allows Programming of PICAXE Family

Lately I have been programming several PICAXEs for people due to my motorcycle gear position indicator project. It is a bit of a pain to insert and remove a PICAXE from my AXE091 dev board just to program a PICAXE. Plus, I often have a PICAXE already pushed into the dev board. Removing it with all the surrounding wires is not easy and depending on the state of the current project it could be harmful to the poor PICAXE I'm trying to program.  Basically, I needed a simple way to plug in a PICAXE and download code to it.  My solution: 
-----
You can see from the diagram in the picture, you plug the PICAXE microcontroller into the ZIF socket one way to program PICAXE-08/14 family devices. To program the PICAXE-18 family place the notch and pin 1 to the opposite side of the ZIF socket. The rig tests fine with all the PICAXE families mentioned.  
-----
I did solder female header rails adjacent to both sides of the ZIF to allow easy hook up of a servo, LED, etc.  However the point of the design was to create an small, tight, easy way to download code into a PICAXE and not create a development board.
-----
The cost was close to "free" since I already had a ZIF socket.  Labeled schematic follows (click to enlarge):
-----


Wednesday, July 11, 2012

Repurpose an Old Disk Drive as a Microcontroller Input Device

Every geek either has and old disk drive or soon will. Here is a way to repurpose that disk drive as an input device for a microcontroller project. This example just shows the disk drive blinking an LED. But you get the idea; with some creativity there are many applications. It's so easy it barely qualifies as a hack, but here are the details.
-----
The device that makes a disk drive spin is a DC spindle motor. If you spin the spindle motor a current is produced. Search youtube for LED Stepper flashlight, etc. and you will find many examples of this experiment.

We need to get two of the spindle motor wires on the disk drive ultimately into the microcontroller.  Take the drive apart and make connections to two of the spindle motor wires.  In the pic you see where we soldered small wires to middle spindle motor connection points.  The other end of these two wires are soldered to two of the drives header pins. This makes for a handy way to plug in a JST connector.

-----
Below is a 'scope shot of what the output signal looks like when you spin the spindle motor.  A purist might consider rectifying the output to keep the microcontroller from seeing a negative voltage.  Since the max output is maybe 500mV, I didn't worry about it.
-----
Here is the custom code for the microcontroller; a PICAXE-08M2.  An Analog to Digital Convertor (ADC) input is monitored.  If a signal is detected of the ADC from the spinning disk drive then flash an LED.  Short and simple.

#picaxe08m2
low 2                'LED on output 2.  Make certain it is off
main:                'Start of main program loop
readadc 1, b0   'Read value of ADC on input 1.  Store in b0
if b0 > 1 then   'If there is a signal on the ADC, the disk is spinning so LED on
toggle 2
pause 50
endif
goto main
----
Thanks for the visit!!!
-----
Link back: Hack A Day
-----

Friday, July 6, 2012

Using a MicroController to Train a Cat

Most of the time Kelso is a great cat.  A few examples of his awesomeness can be seen here, here, and here.  However, he still seems to squeeze in some mischief despite a rigorous schedule that includes sleeping 18 hours a day.

For example, we spotted some paw prints on the stove vent hood.  But wait... Kelso is strictly forbidden to even think about getting on the counters so it couldn't have come from him.  Impossible.  Up goes a security camera to gather more evidence:
-----
Busted!  We need a solution and it needs to be high tech.  

A quick search of the spare parts bin at "The Lab" yields a PICAXE 28X1 custom programmable microcontroller, a piezo speaker (that is really really loud!), a Sharp InfraRed Rangefinder, and a AA battery holder.
-----
All of that stuff in the picture is useless as a solution without some simple custom programming.  Basically, we coded the PICAXE 28X1 to continually monitor the Sharp InfraRed Rangefinder to see if Kelso is in front of it.  If he is, blast five LOUD chirps through the piezo speaker then rearm and wait.  The code was easy and straightforward; less that 20 lines.  The only thing special we did was turn off the PICAXE 28X1 brown out detection (disablebod) and slow the internal clock down from 4MHz to 31KHz in an effort to extend battery life.  Here is a pic of the finished rig that will keep Kelso from ever misbehaving again. ;)

-----
And here is demo of the rig in action:


-----
Does it work?  Hell yes it does!!!
Thanks for checking out the build.
-----
Link back: Hack A Day
Link back: Hatched Gadgets
-----

Saturday, June 23, 2012

"Etch a Sketch" Turned Temperature Data Logger

A friend of mine gave me an OKI office printer.  The thing was HUGE and after about five years it finally broke.  Next step, out comes the screwdriver to rescue any useful parts; of which where several stepper motors.  Since what I didn't know about stepper motors was a lot I searched for a "useful" way to learn about them.  I decided to connect two of the stepper motors to an "Etch a Sketch" and ended up with this rig that graphically logs temperature in a strip chart fashion.


Here is a video if you are not interested in the build details and just the want to see the result.  The beer was cold.  The water in the shot glass hot.  Hot makes the graph go up.  Cold makes the graph go down.  When the graph reaches the far right of the "Etch a Sketch" the stylus moves full left and the process repeats.  In the video a temperature measurement is taken (and graphed) every 750 milliseconds, but that can be adjusted to anything; one reading per hour for example. 


-----
The process of driving the steppers was not trivial in the beginning.  First, I had no documentation on these steppers.  The second being I had no idea how "noisy" and power hungry the steppers could be.    The documentation turned out not to be a big deal.  Via the magic of the internet I learned they were of 4-wire, bi-polar configuration.  An ohm meter is all that is needed to figure out the connection scheme. 

----
Close up of one of the OKI printer 4-wire bipolar stepper motors:

-----
Driving a stepper motor requires a microcontroller.  My choice for a microcontroller was the PICAXE 18M2.  
-----
A stepper motor is not like a 'common' DC motor.  You cannot just apply a current and have the stepper spin.  The current has to be applied in sequence across the four available wires.  You also have to control the polarity (direction) of the current.  That said, steppers motors take way more current than a microcontroller can provide.  An H-Bridge motor driver solves the problem by providing more available drive current for the stepper and the ability to switch current drive polarity.

I was familiar with the SN754410NE H-Bridge motor driver.  Plus, I had some in my kit.  So, originally I decided to use one SN754410NE to drive each stepper motor.  This was a mistake that added much frustration.  The stepper motors are incredibly noisy and current hungry.  The noise caused by the steppers and energy from their back EMF (I think) caused nothing to work reliably.  After seeing on a datasheet that L293D motor drivers have protection diodes and some other features, I gave them a try instead.  The L293D is pin compatible with the SN754420NE so the swap was easy.  After inserting the L293D's everything started moving forward as planned with controlling the steppers.


-----
Now that we can control the stepper motors via the PICAXE 18M2 and L293D's we still need to interface then some way to the "Etch a Sketch".  I had a clear plastic cube thats purpose was to protect a trophy baseball.  Since I didn't have a trophy baseball I dismantled the cube and used the two "C" shaped pieces to mount the steppers to with the help of a Dremmel tool and double sided sticky tape.
-----
After mounting the steppers motors, you still have to mechanically couple them to the "Etch a Sketch".  Rubber hose and zip tie wraps worked perfectly.
-----
After getting the mechanicals figured out a "test" pattern was programmed into the PICAXE.  The test worked on the first run so we grabbed the video camera to document the success.


-----
Now that the stepper motors make the "Etch a Sketch" draw, we still need a way to measure temperature.  The PICAXE 18M2 is used to read a DS18B20 sensor (picture below) via I2C bus for this:

-----
To manually position the "Etch a Sketch" stylus, two buttons are wired into the PICAXE 18M2:
-----
After all of that it is just code and software debugging. 

I have other plans for the rig.  Stay tuned!
-----
If you are still with me, here is the build schematic (click to enlarge):
-----