Go Down

Topic: DCDW = Dirt Cheap Dumb Wireless (Read 23 times) previous topic - next topic

AltairLabs

A few Arduino Forum members are undertaking development; you can track our progress at http://www.dcdwireless.com/.  Please note there is currently no product for sale and no support.  It is of course Open Source so you hardcore hackers feel free.  Schematics and board prints are on the site, until www collaboration is fully up just contact us for actual design files.  

If interested but not hardcore hacker, tell us and we will email you back "when soup's ready".

The concept of Dirt Cheap Dumb Wireless was introduced to Arduino forum on http://www.arduino.cc/cgi-bin/yabb2/YaBB.pl?num=1293839127

Circuit boards v0.1 and parts arrived, got 3 sensor nodes built except for the RF modules from SparkFun, which *finally* shipped.  So right now the DCDW prototypes are hardwired to Arduino Uno to support code development.

The initial "frequency counter" code hooks interrupt 0 on digital pin 2 and sets a flag then returns.  The freq measured by Arduino agrees pretty well with my scope.

This ISR "set flag and return" is due to attachInterrupt(interrupt, function, mode)
Quote
Inside the attached function, delay() won't work and the value returned by millis() will not increment. Serial data received while in the function may be lost. You should declare as volatile any variables that you modify within the attached function.

The easy ways to count frequency depend on pulseIn() with millis() or micros(), so I elected to have the interrupt to just set flag "dataComingIn" (and a LED) and return, this minimizes the disruption of timers and serial, and gives other code access to all the time functions.  

Right now the demo idles in the main Loop() until some pulses trigger the ISR.  The ISR sets the flag, turns on a LED (for development) and returns.  Code in Loop() calls countFrequency() when the flag is set, then afterward clears the flag and turns off the LED.  countFrequency() sets a start time-hack in millis(), loops thru 100 pulses with pulseIn(), and then hacks the stop time and returns kHz as a float().  Floating math is costly, so today I'm gonna change to return an int() in Hz.  

Precision is about 10 Hz, or rather the inverse number of millis() in 100 pulses. More pulses would be better, right now accuracy and precision are plenty good to just "drive on" with development, we can sharpen our pencils later.  

Also my prototype code does not gracefully turn loose and return control to void Loop() after the first activation, but thats gonna get ironed out today.  Will also post some prototype code here and however our Dirt Cheap Dumb Webmaster deems fit.

There are many ways to "skin a cat" and we are open to alternative approaches.  By polling in Loop() any digital pin could be used vs the hardware interrupt approach.  We may include both a "lazy" approach and a "serious" approach.  

The ultimate goal is code Newbies can use to get top level functionality like "Node 3 Sensor 2 is 64 degrees F" or "Node 4 Switch 1 just opened" without having to delve into ISR and such.  If this is you, we have nothing ready for you yet, just let us know who you are and be patient.  

Hardcore hackers jump in, build a DCDW circuit, sling some code, have fun!


AltairLabs

Received OOK radio links from SparkFun.  The interrupt driven software is pointless for OOK links, bkoz in absence of a TX signal the RX chases its detector right down into the thermal noise and the data out pin dithers randomly. Main Loop() ends up going off every time to countFrequency(), might as well code it that way instead of wasting an interrupt.  Also we can now use any Arduino data pin.

The good newz is the code reads the identical TX pulse rate thru the OOK radio link as it does hardwired.  This is bkoz the function countFrequency() measures time for 100 (or your number) of complete cycles instead of just measuring pulse width.

AltairLabs

Demo sketch for DCDW Two Button Remote

Code: [Select]
// Dirt Cheap Dumb Wireless  (DCDW)
// Deomo code for DCDW Two Button Remote
// 2011 Jan 09   by AltairLabs <http://www.altair.org>
// This example code is in the public domain.
//
// visit Dirt Cheap Dumb Wireless   www.DCDWireless.com
// for more open source DCDW hardware and software
// Set up DCDW PCB for Two Button Remote
// Oscillator frequencies in this demo use
// Osc A = 0.01 uF and 220k ohms
// Osc B = 0.01 uF and 100k ohms
// Osc C not used, no need to populate these parts
//
// visit Arduino   www.arduino.cc
// for great open source microcontroller hardware and software
//
// declare stuff
int normLED = 13;      // the on-off LED is digital pin 13
int RXpin = 2;         // DCDW data link on digital pin 2
int pulses = 100;      // total number of pulses to time
int pulse;             // pulse count
unsigned long timeout= 10000;   // microsecs for pulseIn() to wait before giving up
unsigned long t0;      // start time hack
unsigned long time;    // delay in millisec
unsigned long duration;  // length of one pulse
long frequency;        // frequency of pulse train
boolean debug = false;   // true = more verbose

void setup()
{
 pinMode(normLED, OUTPUT);        // optional, used for demo only
 pinMode(RXpin, INPUT);           // set RX pin to input
 Serial.begin(9600);              // start up the serial communications USART
 Serial.println(" ");             // test the comm port
 Serial.println("Good morning, Dr. Chandra.  This is HALduino.");    
}


void loop()
{
// DCDW code starts here
 digitalWrite(normLED, HIGH);  // debug: set normLED on before counting freq
 frequency = countFrequency();
 digitalWrite(normLED, LOW);   // debug: set normLED off when done counting
// end of DCDW receive, now display result
 if (debug) {
   Serial.print("Heard Freq = ");  Serial.println(frequency);                
   if (frequency < -1) {
     Serial.print(" (abandoned on pulse) ");
   }
 }
// Anything you want to do with "frequency" goes here
 if (frequency > 764 && frequency < 845) {
   Serial.print("Heard Button A ");  Serial.println(frequency);                
 }
 if (frequency > 1662 && frequency < 1842) {
   Serial.print("Heard Button B ");  Serial.println(frequency);                
 }

// Everything else you want to do goes here
 Serial.println(" . ");                
 delay(1000);
}
 
long countFrequency ()  
{
 frequency = 0;                               // nothin' yet
 t0 = millis();                               // start time
 for(pulse = 0; pulse < pulses; pulse += 1)   // count incoming pulses
 {                                  
   duration = pulseIn(RXpin, LOW, timeout);   // wait for one complete pulse cycle
   if (duration == 0)                         // if pulse timout then give up
   {
     return -(long)pulse;                     // abort, return neg of bad pulse
   }
 }
 time = millis()-t0;                          // got all pulses, so time = now - start
 frequency = 1000 * (unsigned long)pulses / time;  // frequency in Hz
 return (long)frequency;
}  

AltairLabs

The function countFrequency() is now automatically immune to noise.  It also autoscales the sample time to the incoming pulse frequency and desired precision.  Code got fancier than planned but the use is simpler than before.

Heres a DCDW v0.1 set up as single channel temperature with identification:


Copied the Serial Monitor output to a spreadsheet.


Note in this TEST CODE the TIME IS NOT TO SCALE any valid samples are logged as they come in, when the SparkFun RX is just receiving noise, nothing is logged. Since function countFrequency() returns timely with error codes for noisy input you could plot whatever you want. Anyway this test code sampled between 1 and 3 seconds whenever valid data was present, no attempt *yet* to do real time, but thats where we are going.  You can see sample time automatically "shift gears" when temperature rose afetr bringin DCDW back inside warm lab.

Heres code. Function countFrequency() is much more advanced now. It returns quickly if no valid signal is received, and automatically stays gone just long enough to get ~3 digit precision.  The main code has some vestiges of 2-button remote version, and some declarations need to be hidden inside countFrequency() but its working well.
Code: [Select]
// Dirt Cheap Dumb Wireless  (DCDW)
// Deomo code for DCDW Single Channel Sensor with Ident
// 2011 Jan 09   by AltairLabs <http://www.altair.org>
// This example code is in the public domain.
//
// visit Dirt Cheap Dumb Wireless   www.DCDWireless.com
// for more open source DCDW hardware and software
// Set up DCDW PCB for Single Channel Sensor with Ident
// Oscillator frequencies in this demo use
// Osc A = 1000 pF 100k ohms thermistor (large resistor reduces battery drain)
// Osc B = 0.01 uF and 1k ohms
// Osc C = 22 uF Tantalum, R5, R6 = 10 Meg
//
// visit Arduino   www.arduino.cc
// for great open source microcontroller hardware and software
//
// declare stuff
int normLED = 13;             // the on-off LED is digital pin 13
int RXpin = 8;                // DCDW data link on digital pin 2
int pulses = 10000;           // total number of pulses to time
int pulse;                    // pulse count
unsigned long timeout= 10000; // microsecs for pulseIn() to wait before giving up
unsigned long t0;             // start time hack
unsigned long time;           // delay in millisec
unsigned long duration;       // length of one pulse
unsigned long avgDuration;    // average length of first ten pulses
unsigned long minDuration;    // minimum length of a valid pulse
unsigned long maxDuration;    // maximum length of a valid pulse
long frequency;               // frequency of pulse train
boolean debug = false;         // true = more verbose

void setup()
{
 pinMode(normLED, OUTPUT);        // optional, used for demo only
 pinMode(RXpin, INPUT);           // set RX pin to input
 digitalWrite(RXpin, LOW);        // no pullup
 Serial.begin(9600);              // start up the serial communications USART
 Serial.println(" ");             // test the comm port
 Serial.println("Good morning, Dr. Chandra.  This is HALduino.");    
}

void loop()
{
// DCDW code starts here
 digitalWrite(normLED, HIGH);  // debug: set normLED on before counting freq
 frequency = countFrequency();
 digitalWrite(normLED, LOW);   // debug: set normLED off when done counting
// end of DCDW receive, now display result
 if (debug) {
   if (frequency > 0 ) {
     Serial.print("   Freq = ");              
   } else {
     Serial.print("  Error = ");
   }
 Serial.println(frequency);
 }
// Anything you want to do with "frequency" goes here
 if (frequency > 0 || debug) {
   Serial.print(frequency);
   if (frequency > 764 && frequency < 845) {
     Serial.println(" Button A ");                  
   }
   else if (frequency > 1662 && frequency < 1842) {
     Serial.println(" Button B ");
   }
   else {
     Serial.println(" ");
   }
 }
// Everything else you want to do goes here
 delay(100);
}
 
long countFrequency ()  
{
 frequency = 0;                               // nothin' yet
 avgDuration = 0;
 for(pulse = 0; pulse < 10; pulse += 1)       // count 10 incoming pulses
 {                                  
   duration = pulseIn(RXpin, LOW, timeout);   // wait for one complete pulse cycle
   if (duration == 0) {return -(long)pulse;}  // if pulse timout then abort, return neg of bad pulse
   avgDuration += duration;
 }
 maxDuration = avgDuration / 9;
 minDuration = avgDuration / 11;
// now we have a range of average pulse durations
// so start counting "pulses"pulses, increasing "pulses by 10x each time
// until a string of pulses meets the minimum total time for accuracy
 for (pulses = 10; pulses < 100000; pulses = pulses * 10)
   {
   frequency = 0;                               // nothin' yet
   t0 = millis();                               // start time
   for(pulse = 0; pulse < pulses; pulse += 1)   // count incoming pulses
     {                                  
       duration = pulseIn(RXpin, LOW, timeout);   // wait for one complete pulse cycle
     if (duration == 0) {return -(long)pulse;}    // pulse timout: abort, return neg of bad pulse
     if (duration > maxDuration)                  // pulse too long: abort, return error code
       {return -(long)duration;}
     if (duration < minDuration)
       {return -(long)duration;}
     }
   time = millis()-t0;                          // got all pulses, so time = now - start
   if (time > 100)                              // if time is enough for precision we are done
     {
     if (debug)
       {
       Serial.print(pulses);  Serial.print(" pulses = ");  
       Serial.print(time);  Serial.println(" millisecs ");  
       }
     frequency = 1000 * (unsigned long)pulses / time;  // frequency in Hz
     return (long)frequency;
   }
 }
 return -9999;
}  


Off to a great start, much more to do.

OSGrill

I'm very interested in seeing just how small a sensor can be made (thermo).

The goal is to create a probe that can be used in a wireless meat thermometer, so ultra-high precision and fast cycling/updating is not necessary.  Long battery life, small probe size and a 2-4m transmit distance are the objectives.

Go Up