2010
03.14

Just playing around with some assorted plugins for this blog.  Over on the right you will find a media player for my station, Sublime Geek Radio.  Have fun.

Share on Facebook
2010
03.12

File Downloads Fixed

I review the log files for the site every day or so and had noticed some file not found errors.  Seems I forgot to move the download directory over from my old host…. So, that’s fixed.

Share on Facebook
2010
03.10

I had picked up a Grayhill 61C11-01-08-02 optical encoder quite awhile ago but never got around to interfacing it with a microcontroller.  With my recent purchase of a Sparkfun AD9835 breakout, it’s finally time to get to work and make something of these two items and an LCD.

Encoders are in use notably on higher end radios and tuners.  If your volume control has no stops and feels “steppy”, chances are that’s an encoder.  From the Arduino Playground page on encoders…

A rotary or “shaft” encoder is an angular measuring device. It is used to precisely measure rotation of motors or to create wheel controllers (knobs) that can turn infinitely (with no end stop like a potentiometer has). Some of them are also equipped with a pushbutton when you press on the axis (like the ones used for navigation on many music controllers). They come in all kinds of resolutions, from maybe 16 to at least 1024 steps per revolution…

I’m also thinking of making use of this in my OpenXX, Syntor X controller project.  No, the Sparkfun AD9835 won’t be used in the Syntor, point is, I’ll be doing something radioesque with this.

Connection was very simple, as you can see, only 3 wires to the microcontroller (one is for the pushbutton function and the 4th for a LED) and two to power and ground.

Code on the Arduino playground worked on the first try, notably the interrupt driven code, but I found it susceptible to bounce.  I incorporated a quick and dirty delay loop to calm things down a little, and now, spinning the encoder is smooth and reliable.

Hookup was simple, encoder pin 1& 2 to ground, 3 to Arduino pin 4, 4 to Arduino pin 3, 5 to Arduino pin 2 and 6 to +5V.   What you do with it, is entirely up to you.

Here’s the sourcecode, with plenty of comments…

#include <Bounce.h>  // import debounce library

#define encoder0PinA 2  // encoder pin A on pin 2
#define encoder0PinB 3  // encoder pin B on pin 3
#define button 4  // shaft button on pin 4
#define RED 5  // red LED on proto shield on pin 5

volatile unsigned int encoder0Pos = 0;  // scratchpad within ints
volatile unsigned int x = 0;  // delay loop counter

boolean ledValue = LOW;  // LED on/off flag

// Instantiate a Bounce object with a 5 millisecond debounce time
Bounce bouncer = Bounce(button, 5);  

void setup()
{
  Serial.begin (9600);
  delay(1000);

  pinMode(encoder0PinA, INPUT);
  digitalWrite(encoder0PinA, HIGH);
  pinMode(encoder0PinB, INPUT);
  digitalWrite(encoder0PinB, HIGH);
  pinMode(button, INPUT);
  digitalWrite(button, HIGH);
  pinMode(RED,OUTPUT);

  // encoder pin on interrupt 0 (pin 2)
  attachInterrupt(0, doEncoderA, CHANGE);

  // encoder pin on interrupt 1 (pin 3)
  attachInterrupt(1, doEncoderB, CHANGE);
}

void loop()
{
  if (bouncer.update())
  {
    if ( bouncer.read() == HIGH)
    {
      if ( ledValue == LOW )
      {
        ledValue = HIGH;
      }
      else
      {
        ledValue = LOW;
      }
      digitalWrite(RED,ledValue);
    }
  }
}

void doEncoderA()
{
  // detach interrupts to not interrupt the interrupts
  detachInterrupt(0);
  detachInterrupt(1);

  // a quick and dirty delay to let things settle
  // as delay() doesnt work within interrupts
  for(x=0; x<100; x++)
  {
    asm("nop\n");
  }

  // look for a low-to-high on channel A
  if (digitalRead(encoder0PinA) == HIGH)
  {
    // check channel B to see which way encoder is turning
    if (digitalRead(encoder0PinB) == LOW)
    {
      encoder0Pos = encoder0Pos + 1;  // CW
    }
    else
    {
      encoder0Pos = encoder0Pos - 1;  // CCW
    }
  }

  else   // must be a high-to-low edge on channel A                                       
  {
    // check channel B to see which way encoder is turning  
    if (digitalRead(encoder0PinB) == HIGH)
    {
      encoder0Pos = encoder0Pos + 1;  // CW
    }
    else
    {
      encoder0Pos = encoder0Pos - 1;  // CCW
    }
  }
  // use for debugging - remember to comment out
  Serial.println (encoder0Pos, DEC);          

  // reattach interrupts
  attachInterrupt(1, doEncoderB, CHANGE);
  attachInterrupt(0, doEncoderA, CHANGE);
}

void doEncoderB()
{
  // detach interrupts to not interrupt the interrupts
  detachInterrupt(1);
  detachInterrupt(0);

  // a quick and dirty delay to let things settle
  // as delay() doesnt work within interrupts
  for(x=0; x<100; x++)
  {
    asm("nop\n");
  }

  // look for a low-to-high on channel B
  if (digitalRead(encoder0PinB) == HIGH)
  {
    // check channel A to see which way encoder is turning
    if (digitalRead(encoder0PinA) == HIGH)
    {
      encoder0Pos = encoder0Pos + 1;         // CW
    }
    else
    {
      encoder0Pos = encoder0Pos - 1;         // CCW
    }
  }
  // Look for a high-to-low on channel B
  else
  {
    // check channel B to see which way encoder is turning  
    if (digitalRead(encoder0PinA) == LOW)
    {
      encoder0Pos = encoder0Pos + 1;          // CW
    }
    else
    {
      encoder0Pos = encoder0Pos - 1;          // CCW
    }
  }
  // use for debugging - remember to comment out
  Serial.println (encoder0Pos, DEC);          

  // reattach interrupts
  attachInterrupt(0, doEncoderA, CHANGE);
  attachInterrupt(1, doEncoderB, CHANGE);
}
Encoder photo and datasheet diagram copyright Grayhill Inc.
Share on Facebook
2010
03.10

I have managed to write a suite of programs to effectively tether an Arduino to a computer, and have it interract with the internet, as if it had an ethernet shield attached to it.  This may seem like a step backwards, and in some ways it is, but the reasoning for doing this was as follows.

  • Eliminates the ethernet shield (a $30-45 USD value)
  • Eliminates many ethernet connections to several Arduinos in close proximity. (My basement will have at least 3 monitoring things).
  • For remote sites that do not have high speed ethernet, this allows use of dialup or internet connection sharing.  (For example remote radio/television transmitter sites).
  • Computers are a dime-a-dozen, we dont need speed or huge drives here.  A DOS machine could work!

The programs are not pretty, so complete source is not available yet, but the basic concepts are described below.  This is an ongoing development, but here is the block diagram of the concept.

A very simple serial protocol was developed, essentially a letter and a channel number, followed by an equal sign, then the value, delimited by a pipe.  The raw data, minus the delimiter, forms the argument to the perl script on the server.  This also has the added benefit of making it somewhat human readable.  I plan to add a simple checksum or CRC to the end, to guard against corrupt data.

A fully implemented Arduino tether, with no fancy sensors, serial stream to the computer would look something like:

A0=123|A1=456|A2=789|A3=876|A4=543|A5=210|
D0=0|D1=1|D2=0|D3=1|D4=0|D5=1|D6=0|D7=1|
D8=0|D9=1|D10=0|D11=1|D12=0|D13=1<CR><LF>

Letter assignments, so far, for this protocol are as follows:

  • A = analog (0-5) integer 0-1024 (raw analog data)
  • B = battery (0-n) float 0 – max voltage (formatted voltage data)
  • D = digital (0-13) boolean (raw digital port state)
  • H = humidity (0-n) (format to be determined)
  • I = current (0-n) float 0 – max current (formatted amperage data)
  • L = light level (0-n) (format to be determined)
  • M = motion (0-n) boolean (there is or is not motion)
  • R = rotations per minute (0-n) 0 – max RPM (formatted RPM data (1/4 RPM a-la OBD-II?))
  • S = speed (0-n) 0 – max speed (any unit)
  • T = temp (0-n) (min max determined by sensor) float  (degC or degF)
  • U = latitude (0) [cant be in 2 places at once] float (degrees)
  • V = longitude (0) [cant be in 2 places at once] float (degrees)
  • W = altitude (0) [cant be in 2 places at once] float (height ASL)
  • X = x position (0) [cant be in 2 places at once] (to be determined)
  • Y = y position (0) [cant be in 2 places at once] (to be determined)
  • Z = z position (0) [cant be in 2 places at once] (to be determined)

A simple Arduino sketch was formulated to send temperature readings (using the Modern Devices TMP-421 temp sensor) via the serial port to the computer. In this example, T0=XX.XX, forms the exact argument and will be placed into the http GET statement, by the computer, verbatim.

#include "Wire.h"
#include <LibTemperature.h>

LibTemperature temp = LibTemperature(0);

float tempF;

void setup()
{
  Serial.begin(9600);
  delay(1000);
  for (int x=0; x<5; x++)
  {
    float y = temp.GetTemperature();
  }
}

void loop()
{
  // convert to degF
  tempF = (temp.GetTemperature() * 9 / 5) + 32;  

  Serial.print("T=");
  Serial.println(tempF);
  delay(10000);
}

On the computer, a very rudimentary Processing script was written, to open a web connection to my server, write out a http GET, and close the connection.  Everything was hardcoded to make the example work, but it does work.  The business end of that script (sensitive bits redacted) looks like this;

void serialEvent(Serial p)
{
  // Connect to server on port 80
  c = new Client(this, "www.xxxxxx.com", 80); 

  // grab incoming string off of serial port
  inString = p.readString();

  // inform us we have one and are sending
  println("writing to host");

  // start building HTTP GET statement
  c.write("GET /XXX-XXX/XXXX_XXXXXX.pl?");

  // chop off CR/LF
  outString = inString.substring(0, inString.length() -2); 

  // pass on the serial input to HTTP GET
  c.write(outString);

  // close up the HTTP GET
  c.write(" HTTP/1.1\n"); 

  // needed for apache2's vhosts, same as above
  c.write("Host: www.xxxxxx.com\n\n");
}

I simply used another copy of the perl script used in the temperature graphing application to write to the mySQL database.

The meat of that script looks like this;

# PERL DBI CONNECT
$connect = DBI->connect($dsn, $user, $pw) or
  die "Unable to connect: $DBI::errstr\n";

$vtime = time()*1000;

# PREPARE THE QUERY
$query = "INSERT INTO TETHER_001(Temp0, Time)
  VALUES ($currentvalue,$vtime)";
$query_handle = $connect->prepare($query);

# EXECUTE THE QUERY
$query_handle->execute();

As you can probably see, the database table names are hard coded into the mySQL queries. I hope to eliminate this, and also make the script a bit more bullet proof, adding table creation if it doesn’t exist, field creation if it doesn’t exist, error handling and so forth.

Click to embiggen / get the latest

And finally, I simply made another copy of my flot php script to display the temperature data in a browser.

Share on Facebook
2010
03.07

I had written some time ago about the concept of PWM driven meters.  Here is a perfect application.

The Jeenode will poll the Jeelink occasionally for its meter value to display.  About once every 5-10 seconds should be sufficient.  Power consumption, though will vary considerably, as things turn on and off, is not that vital to warrant real time indication.

Now if my Jeelink would only arrive already… I can get to work on some of these things!

The enclosure for this project will be an Ikea Ribba 5×7″ picture frame, some steel grille from Lowes, an old meter from an AM radio station, and of course a Jeenode, battery holder, driver hardware and so forth.

Share on Facebook
2010
03.07

This is the basic concept of the Jeenode based Home Monitor / Control system.  Each Jeenode board will perform some sort of function, either autonomously or via command, or a combination of both.

For example:  A Jeenode will control an attic ventilation fan.  It will automatically decide to actuate the fans, based on temperature.  A default setpoint will be programmed within, however, the Jeelink can alter this temperature.  Also the Jeenode will report the temperature periodically, and report when it activates and deactivates the fan.

Share on Facebook
2010
03.06

Behold the graphy goodness…

Click To Embiggen / Get The Latest

I have wanted to, for a long time, display, graph, and control various aspects of the home environment.  Temperatures, status of appliances, lights, water heater, furnace, and so on.  Looks like this is finally becoming a reality.

Inspired by the work done at the OpenEnergyMonitor site, I adapted their code to make the above realtime graph of temperature.  I will add more as inspiration hits.

But the steps were basically this.

ARDUINO TEMPERATURE MONITOR:
A very simple Arduino temperature monitor and data reporter was constructed with a Duemilanove, Ethernet Shield and a Modern Circuits TMP-421 temperature sensor.  The code is very simple, with no error detection or correction (for now) {sensitive bits redacted}.

#include “Wire.h”
#include <LibTemperature.h>
#include <Ethernet.h>

//Sets the unique mac address for the ethernet board
byte mac[] = {0xDE,0xAD,0xBE,0xEF,0xFE,0xED};
byte ip[] = {192,168,2,51};
byte gateway[] = {192,168,2,1};
byte server[] = {—,—,—,—};

//Setup a client
Client client(server, 80);

LibTemperature temp = LibTemperature(0);

void setup()
{
Serial.begin(9600);

Ethernet.begin(mac, ip, gateway);
delay(1000);
}

void loop()
{
Serial.print(“Temp: “);
Serial.print(temp.GetTemperature());
Serial.println(” degC”);
delay(100);

//Send the data
if (client.connect())
{

//Accessing a shared server requires the server domain name in here as there
//is no fixed ip address.  If your accessing a shared server you need to add
//your URL “GET http://—–.—/xxxxxxx/????.pl?T=”

client.print(“GET http://—–.—/xxxxxxx/????.pl?T=”);
client.print(temp.GetTemperature());
client.println();
client.stop();
}
else
{
Serial.println(“Failed to connect to client”);
}
delay(10000);
}

PERL SCRIPT ON MY SERVER:
A rather simple perl script was added to my server.  This was rather tough as my server did not allow cgi-bin script execution out of the box.  I won’t go into what it took to get working, as your mileage will vary (sensitive bits have been redacted).  I’ll be spending some time with my perl book and construct an all encompasing, scalable, script that will allow me to write to any database table and field, at any time.  For now things are hard coded.

#!/usr/bin/perl -w
use CGI::Carp qw( fatalsToBrowser );

# PERL MODULES WE WILL BE USING

use Data::Dumper;
use CGI qw/:standard/;

use DBI;
use DBD::mysql;

# HTTP HEADER
print “Content-type: text/html \n\n”;
print header;

my $currentvalue = param(‘T’)    or die “Value1 not in parameter list”;

# CONFIG VARIABLES
$platform = “mysql”;
$database = “home_monitor”;
$host = “localhost”;
$port = “—-”;
$tablename = “DATA”;
$user = “—-_———–”;
$pw = “—-_———–”;

# DATA SOURCE NAME
$dsn = “dbi:$platform:$database:$host:$port”;

# PERL DBI CONNECT
$connect = DBI->connect($dsn, $user, $pw) or die “Unable to connect: $DBI::errstr\n”;

$vtime = time()*1000;

# PREPARE THE QUERY
$query = “INSERT INTO DATA (TEMP_001, Time) VALUES ($currentvalue,$vtime)”;
$query_handle = $connect->prepare($query);

# EXECUTE THE QUERY
$query_handle->execute();

And finally, a PHP script to access the database and graph the results.  The graphic package in use is Flot, a very slick open source, MIT Licensed, library perfect for what we need to do.

Flot is a pure Javascript plotting library for jQuery. It produces graphical plots of arbitrary datasets on-the-fly client-side.

The focus is on simple usage (all settings are optional), attractive looks and interactive features like zooming and mouse tracking.

The plugin works with Internet Explorer 6/7/8, Firefox 2.x+, Safari 3.0+, Opera 9.5+ and Konqueror 4.x+ with the HTML canvas tag (the excanvas Javascript emulation helper is used for IE).

So, there you have it… I will be adding things in the days to come, trying different configurations, fixing up the perl script and tidying up the graphics.  I will couple this with the Jeenodes as outlined earlier, and adding the graphing functionality to whatever platform I use to aggregate the Jeenode data.  The possibilities are endless.

Share on Facebook
2010
03.03

I do development on several different computers, and always forget to sync the files. I’ve tried USB drives, and usually forget them, or again, forget to sync, or do a quick proof of concept on the local disk, and once again, forget to sync.

Fortunately for me I have VNC access to just about all of my computers, both home and work, but this is not an ideal situation. But its not a big deal to log in, grab the files, and get to work… then forget to sync it back to home (or work).

I discovered Dropbox, a free(ish) file syncing service. They offer 2GB free, and to be honest, I cant see using that much space for simple microcontroller development. Installation was painless, I simply work inside my Dropbox folder, even compiling, and all my computers are automagically synced.

I also have an account for work, to sync the two office PCs and a remote location PC with such things as purchase and work orders, quotes, etc.  I have invited my home account to the work folders, and vice versa.  So you can keep things distinctly separated, yet have access, with settable permissions (read or read/write).

I might investigate hosting something similar on my cloud server, but, even the 2GB is already 10% of my 20GB there.

Share on Facebook
2010
03.03

jee-b-gone



jee-b-gone
Originally uploaded by ka1kjz

I managed to successfully port the TV-B-Gone code to the Jeenode. It was not as straightforward as one might think. I reassigned the outputs to port 1 of the Jeenode, and the IR LED would not work. I could make the visible LED work, and I would see the IR port flash sporadically when I connected a visible LED to it. No amount of fiddling would make it work, until I delved into the sourcecode a little deeper.

The IR LED is driven from a PWM port, something that is not obvious. Now I know why Ken had assigned such odd looking numbers to his I/O.

I investigated moving the PWM code to another PWM pin, as pin-3 is taken by the Jeenode “IRQ” signal, but its not that easy. There is some pretty low level register manipulation going on, and that was something I really did not want to get into at this time.

I moved the IR LED to the Jeenode “IRQ” signal, which happens to be the original Arduino Pin 3. IRQ-0 is dedicated to the radio, which works out for me, as I plan to fire the TV-B-Gone code via radio. I had to remove the sleep function for the time being, but once I get the radio going, I will reincorporate it at that time.

Share on Facebook
2010
03.03

I realized that the TV-B-Gone code, at least as presented by Ken Sherriff, was running full speed, full power, all the time. The batteries certainly won’t last long in that state! So adding the sleep() function was necessary, and very easy.

Starting with the code on the Arduino site, I slowly, line by line, adapted the example code to the TV-B-Gone code. This necessitated moving the trigger button to IRQ 0, as IRQ 1 was taken by the IR PWM code.

Worked on the first try! I did not bother to measure the current consumption, my debug serialPrint() lines indicated the sleep code was executing, and the wakeup routine would execute when the button was pressed.

I simply added the include statement:

#include <avr/sleep.h>

And simply tacked the following line of code to the end of loop() :

sleepNow();

And finally, stuck the following function to the end of the source:

void sleepNow()
{
set_sleep_mode(TRIGGER);                    // sleep mode is set here

sleep_enable();                                       // enables the sleep bit in the mcucr register

attachInterrupt(0, wakeUpNow, LOW);       // use interrupt 0 (pin 2) and run function
// wakeUpNow when pin 2 gets LOW

sleep_mode();                                   // here the device is actually put to sleep!!
// THE PROGRAM CONTINUES FROM HERE ON WAKE

sleep_disable();                                // first thing after waking, disable sleep

detachInterrupt(0);                             // disables int 0 as the wakeupnow code will
// not be executed during normal runtime
}

void wakeUpNow()
{
// any needed wakeup code can be placed here
}

To prevent version skew, I leave addition of the sleep routines to the reader.  I’ve notified Ken for possible inclusion in version 2.  Now to port this to the Jeenode.

Share on Facebook