Atlanta
Offline
Sr. Member
Karma: 0
Posts: 254
Arduino still rocks
|
 |
« on: January 08, 2011, 01:30:28 pm » |
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=1293839127Circuit 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) 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!
|
|
|
|
|
Logged
|
|
|
|
|
Atlanta
Offline
Sr. Member
Karma: 0
Posts: 254
Arduino still rocks
|
 |
« Reply #1 on: January 09, 2011, 12:32:47 pm » |
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.
|
|
|
|
|
Logged
|
|
|
|
|
Atlanta
Offline
Sr. Member
Karma: 0
Posts: 254
Arduino still rocks
|
 |
« Reply #2 on: January 09, 2011, 07:46:21 pm » |
Demo sketch for DCDW Two Button Remote // 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; }
|
|
|
|
|
Logged
|
|
|
|
|
Atlanta
Offline
Sr. Member
Karma: 0
Posts: 254
Arduino still rocks
|
 |
« Reply #3 on: January 10, 2011, 05:21:56 am » |
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. // 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.
|
|
|
|
|
Logged
|
|
|
|
|
Sweden
Offline
Newbie
Karma: 0
Posts: 8
|
 |
« Reply #4 on: January 18, 2011, 10:04:31 am » |
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.
|
|
|
|
|
Logged
|
|
|
|
|
0
Online
Full Member
Karma: 0
Posts: 128
|
 |
« Reply #5 on: January 18, 2011, 01:14:11 pm » |
would it be possible to have the code run on interrupts rather than a counting loop? that would make this whole thing easier / practical.
|
|
|
|
|
Logged
|
|
|
|
|
Sussex UK / CT USA
Offline
Edison Member
Karma: 0
Posts: 1026
Forums forever
|
 |
« Reply #6 on: January 18, 2011, 03:49:09 pm » |
Would it be possible to have the code run on interrupts rather than a counting loop? Here's the thing... As I understand it. AltairLabs may come in on this an correct me... When no DCDW is transmitting, the receiver "listens" harder and harder, and before long starts "hearing things". At that point, the output of the receiver starts generating lots of spurious positive and negative edges... which would divert the Arduino excessively inside a fancier interrupt handler. With the simple interrupt handler and more code (which taps into what the simple handler is picking up), selectively executed, a happy compromise can be had. The Arduino will do very little with the "noise", but will from time to time make a check to see if more than noise is coming in.
|
|
|
|
|
Logged
|
|
|
|
|
Atlanta
Offline
Sr. Member
Karma: 0
Posts: 254
Arduino still rocks
|
 |
« Reply #7 on: January 21, 2011, 08:36:51 pm » |
Howdy @martin_bg would it be possible to have the code run on interrupts rather than a counting loop? that would make this whole thing easier / practical.
Thats just what we thought too. Interrupts was my very first approach, and it *does* work. But there turned out to be less advantage than I had hoped, and some unexpected drawbacks. (1) the RX noise of an empty channel on these cheeep OOK radio links will consume significant CPU time servicing the interrupt, even to return a result code of "nothing coherent received". (2) interrupts are only available for certain I/O pins, the new approach is possible for any I/O pin (3) interrupts corrupt other Arduino functions such as the millis() counter. So after trying both techniques a while, the interrupts seemed much less attractive. You can still do interrupts if you wish, it would probably work best for a continuous transmit or a quiet link like "real" radios with squelch. Maybe cheeep walkie talkies? Heres some early code that was interrupt based. // Dirt Cheap Dumb Wireless // by AltairLabs <http://www.altair.org> // This example code is in the public domain. // // see www.DCDDumbWireless.com
int normLED = 13; // the on-off LED is digital pin 13 int RXpin = 2; // DCDW data link on digital pin 2 volatile int dataComingIn = 0; int pulses = 1000; // total number of pulses to time int pulse; // pulse count unsigned long timeout= 100000; // microsecs 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
void setup() { pinMode(normLED, OUTPUT); pinMode(RXpin, INPUT); // set RX pin to input // digitalWrite(RXpin, HIGH); // and turn on pullup resistor Serial.begin(9600); // start up the serial communications USART Serial.println(" "); // test the comm port Serial.println("Good morning, Dr. Chandra. This is HAL.");
attachInterrupt(0, blink, HIGH); // grab interrupt for digital pin 2
} void loop() { digitalWrite(normLED, LOW); // set normLED off when in main // pulse measurement goes here if (dataComingIn != 0) { frequency = countFrequency(); } if (frequency > 0) { Serial.print("Heard Freq = "); Serial.println(frequency); } if (frequency < -1) { Serial.print("Freq count abandoned on pulse "); Serial.println(frequency); } /* while (dataComingIn) { digitalWrite(normLED, LOW); // set normLED off when in main duration = pulseIn(RXpin, LOW, timeout); if (duration == 0) {dataComingIn = 0;} } */ dataComingIn = 0; Serial.println("Main Loop Idle"); delay(1000); } long countFrequency () { frequency = 0; // nothin' yet // Serial.print("counting "); t0 = millis(); // start time for(pulse = 0; pulse < pulses; pulse += 1) // count pulses { duration = pulseIn(RXpin, LOW, timeout); if (duration == 0) { // Serial.println("abort countFrequency"); // delta time dataComingIn = 0; return -(long)pulse; } } time = millis()-t0; // time = now - start // Serial.print(" "); Serial.println(time); // delta time frequency = 1000 * (unsigned long)pulses / time; // Serial.println(frequency); // frequency in Hz return (long)frequency; }
void blink() { digitalWrite(normLED, HIGH); // set normLED on when in interrupt dataComingIn = 1; // set flag for incoming data pulse train }
If you would like to run with the interrupt approach, our second set of PC boards may be ordered soon. At this early stage we cant give much support to "appliance operators" but if you are proficient with schematic and soldering iron youre welcome to join the development.
|
|
|
|
« Last Edit: January 21, 2011, 08:38:36 pm by AltairLabs »
|
Logged
|
|
|
|
|
Atlanta
Offline
Sr. Member
Karma: 0
Posts: 254
Arduino still rocks
|
 |
« Reply #8 on: January 22, 2011, 09:49:32 am » |
Howdy, @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. Been thinkin 'bout your meat thermometer idea, the DCDW concept fits well for you. The two approaches I see are (1) the single dedicated sensor. You dont need the quad NAND at all., just use Osc C to send temp. Updates as often as you care to read it. It runs all the time and uses the least components. You can even snap off and discard one half of the circuit board. (2) use Osc C to switch on Osc B every N seconds for an updated reading. This uses the full circuit board with both chips and conserves battery life. We are not prepared to support newbies, we still need good explanations, diagrams and other documentation for the various modes, and a better introduction to the possible modes and how to choose. But if you are proficient with schematics and designing simple circuits, you are welcome to use these ideas. After all, that what Open Source is all about:) The DCDW circuit board is a bit bigger than a 9V battery. You could use one to prototype your circuit and test your code, when you are satisfied with the design you could make your own dedicated PC board out of surface mount components, I reckon the size could be reduced to about an inch square. The antenna wants to be nearly 20 inches, working against a ground at leeast the same size. nobody really wants a 40 inch meat thermometer so the antenna will be a compromise. Probably enclose the thermistor in a thin stainless steel tube, make that "ground". Then have a plastic head to hold battery and PCB and maybe a power switch. The antenna can be a wire coiled up inside the head. The RF modules claim a range of hundres of feet with "proper" antenna so you should still get enough to reach a few meters. If you can glean enough from this post to run with the idea on your own, thats great we can put you down for a beta test board. If the details still seem fuzzy to you , please be patient while we develop better documentation and code examples. Either way hit the website and give us an email, we'll keep ya posted.
|
|
|
|
|
Logged
|
|
|
|
|
Atlanta
Offline
Sr. Member
Karma: 0
Posts: 254
Arduino still rocks
|
 |
« Reply #9 on: January 22, 2011, 07:33:53 pm » |
OKAY here is a major annoyance. The CD4093 from Texas Instruments is purportedly a Quad 2-Input NAND with Schmitt trigger inputs. DCDW depends on the "gated oscillator" or "astable multivibrator" touted by National Semiconductor and Texas Instruments, respectively.   OK fine, that exactly what we want, right down to those equations giving the transition times. The timing dont depend in ANY WAY on the voltage at the Control input, that just turns the oscillator on and off RIGHT? Thats the beauty of a Schmitt trigger input, RIGHT? Can I get an AMEN on that? Well heres what REALLY happens when I use the Texas Instrument part and vary the control voltage.  The osc freq varies 10X as the control voltage drops, before it shuts off. WHERE is the Schmitt Trigger? I'll be in contact with TI about this, as well as ordering equivalent parts from the other 3 suppliers represented at Digi Key. In the mean time we would greatly appreciate hearing from anyone about this.
|
|
|
|
|
Logged
|
|
|
|
|
Atlanta
Offline
Sr. Member
Karma: 0
Posts: 254
Arduino still rocks
|
 |
« Reply #10 on: January 23, 2011, 05:00:10 pm » |
OK need some help here.
We have 2 DCDW in "single sensor plus ident" and a simple data logger to demo them. Left it running to low inside and outside temperature for a day. Problem is Win7 keeps turning off the Acer Aspire netbook. Disabled WinDoze Update to prevent reboots, went to "power options" and set everything to "NEVER" (the netbook is on AC power adapter the whole time) but still I go down and find the DCDW happily chirping out temperature readins, the Arduino is receiving data (according to the LEDs) and trying to log to the stinkin' WinDoze that has turned itself off.
Where are all the OTHER power settings hidden?
|
|
|
|
|
Logged
|
|
|
|
|
São Paulo/SP/Brazil
Offline
Sr. Member
Karma: 2
Posts: 293
Brazilian Arduino Team
|
 |
« Reply #11 on: January 23, 2011, 05:10:47 pm » |
First, have sure that your netbook are not overheating. If processor is heating too much it'll turn-off the netbook. Main cause: Burned fan(I don't know if your netbook have a fan) Also, I found this: http://www.techspot.com/vb/topic138655.htmlCMOS corruption! LOL!
|
|
|
|
|
Logged
|
|
|
|
|
Atlanta
Offline
Sr. Member
Karma: 0
Posts: 254
Arduino still rocks
|
 |
« Reply #12 on: January 23, 2011, 10:25:25 pm » |
THANKS @ Wagner Sartori Junior !
Its almost time for me to go to sleep and see if the laptop can stay awake. I created a new power profile called "AlwaysON" but didnt find any settings I havent used before. If this doesnt work tonight then your link is what I will try next night.
BTW the netbook was sitting on a shop rag, the heater in lab keeps us between 20 C and 25 C. Tonight before going upstairs I will be sure to elevate the netbook where all vents are free and clear. Thanks again.
|
|
|
|
« Last Edit: January 23, 2011, 11:23:39 pm by AltairLabs »
|
Logged
|
|
|
|
|
Atlanta
Offline
Sr. Member
Karma: 0
Posts: 254
Arduino still rocks
|
 |
« Reply #13 on: January 23, 2011, 11:07:52 pm » |
Tonight status is : Working on SSID (Single Sensor plus IDent, but thats easily confused with the WiFi term). We currently have 2 problems. (1) the CD 4093 Quad NAND with Schmitt Trigger Inputs produced by Texas Instruments is not acting like it has Schmitt trigger inputs. This makes the "gated oscillator" frequency chirp downward badly. Currently using slow packets of 10 sec every 3 minutes and the software can latch the data before the chirp becomes too bad. Likely solution is avoiding this particular manufacturer for this chip (2) when a collision of packets occurs, the software is sometimes does not recognize the error but rather mistakes the ID part of the second packet as the data part of the first one. Over night this happened about 10 times in 500 sensor readings, or in other terms about half the packet collisions were erroneously accepted as valid data. These are easily recognized as invalid readings but are still nuisances. Solution is a more robust state machine, which is being tested overnight tonight. Here is the master station  [glow] When DCDW development is finished, only the l33t beta testers will have the genuine DCDW master station official mounting string. Compatible with all genuine Arduino boards. Cost is just one carton of Samuel Adams for the development team! Supplies are limited, Sign up today![/glow] Here is the indoor temperature sensor node  Here is the outdoor temperature sensor node  PCB layout v0.01 requires the ugly hack to scab on a diode, resistor and capacitor to put the DCDW in SSID mode. This will be cleanly accommodated on all PCB versions going forward. Here is a Open Office import of what the DCDW master received from its nodes  Long straight lines are missing data when WinDoze7 ( >:(DONT get me STARTED >  ) despite all power profile settings fell asleep and stopped listening to Arduino Uno. Time is Arduino millis(), we have no Real Time Clock as you would use in a proper data logging project. We also have made no effort yet to convert frequency (Y axis) backto temperature. This is only a proof-of-concept for DCDW with one master node monitoring a swarm of sensors on a single channel. The collisions are evident. Most falsely accepted collisions the outdoor node was sending its ID and was interrupted by (much stronger) indoor node ID which was erroneously accepted as the data for the outdoor temperature. Better spaghetti code software will fix this. You software mugs will get a laugh out of this: // Dirt Cheap Dumb Wireless (DCDW) // Demo 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 1 meg ohms // Osc C = 22 uF Tantalum, R5 = 10 Meg, R6 = 330k // // visit Arduino www.arduino.cc // for great open source microcontroller hardware and software // // declare stuff #include "WProgram.h" void setup(); void loop(); long countFrequency (int pin, int precision);
int normLED = 13; // the on-off LED is digital pin 13 int RXpin = 8; // DCDW data link on digital pin 2 long frequency; // frequency of pulse train long freq1; // frequency recognized as tone 1 long freq2; // frequency recognized as tone 2 unsigned long interval; // millisecs interval between samples logged unsigned long logTime; // time to start log entry
boolean debug = false; // true = more verbose
const int idle=0; const int tone1=1; const int tone2=2; const int tGap=3; const int silentGap= 2; const int toneDurat = 1; int rxtone; int silent; int state; int lastState;
const int numSensors = 6; int sensorNode; long sensorTone; const int IDtones[numSensors]={80,165,368,740}; // IDent tones (B)of each sensor int freqT2[numSensors]={0,0,0,0,0,0}; // last Sensor Tone (A) from each sensor unsigned long lastTime[numSensors]={0,0,0,0,0,0}; // last time each sensor was heard
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."); Serial.println("Ready to log Dirt Cheep Dumb Wireless sensor data"); interval = 1000; // log data every 1 second logTime = millis() + interval; // starting next sample time }
void loop() { // DCDW code starts here digitalWrite(normLED, HIGH); // debug: set normLED on before counting freq frequency = countFrequency(RXpin, 3); // count freq at RXpin with 3 digit precision 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); } // Log the data sample if (frequency < 0) frequency =0; if (debug) { print_time(logTime); Serial.print(", "); Serial.print(frequency); Serial.print(", "); Serial.println(" "); }
// // state machine for recognizing remote sensors // lastState = state; if (frequency > 0 ) { rxtone++; silent=0; } else { rxtone=0; silent++; } if (silent > silentGap) { state = idle; freq1 = 0; freq2 = 0; } if (rxtone >= toneDurat && state == idle) { state = tone1; freq1 = frequency; } if (rxtone >= toneDurat && state == tone1 && (abs(frequency-freq1) > 100)) { state = tone2; freq2 = frequency; } if (state == tone2 && state != lastState) { // we have a new SSID sensor reading float ratio = 999.0; float bestRatio = 999.0; for (int i = 1; i <= numSensors; i++) { // find closest match to known ID tone if (freq1 > IDtones[i]) { // make the ratio >1 ratio = float(freq1) / float(IDtones[i]); } else { ratio = float(IDtones[i]) / float(freq1); } if (ratio < bestRatio) { // if better match thsn before bestRatio = ratio; sensorNode = i; // sensorNode is index of best match sensorTone = freq2; } } freqT2[6]=int(100.0*bestRatio); // fake sensor to log match ratio freqT2[5]=sensorNode; // fake sensor to log snesorNode freqT2[sensorNode]=sensorTone; print_time(logTime); for (int i = 1; i <= numSensors; i++) { Serial.print(", "); Serial.print(freqT2[i]); } Serial.println(" "); }
// Set time for next sample logTime = logTime + interval; // usual time if (logTime > 4294967295)logTime -= 4294967295; // need in case of rollover? while (logTime < millis()) logTime = logTime + interval; // in case we miss a sked while (millis() < logTime) { }; // now wait }
|
|
|
|
« Last Edit: January 24, 2011, 12:13:23 am by AltairLabs »
|
Logged
|
|
|
|
|
Atlanta
Offline
Sr. Member
Karma: 0
Posts: 254
Arduino still rocks
|
 |
« Reply #14 on: January 23, 2011, 11:17:32 pm » |
Sorry some code got chopped off at post limit. Here is the workhorse of DCDW the function countFrequency() which is less spaghettified than the demo. Still a few of you could improve on it. To go with the last post, the remaining two functions are: long countFrequency (int pin, int precision) counts frequency on a pin, rejects noise and returns quickly as int precision allows. void print_time(unsigned long t_milli) a handy function from @davekw7x to print millis() in hh:mm:ss.sss form here they are: long countFrequency (int pin, int precision) { // counts frequency of an incoming pulse train // // pin any digital input pin (int) // precision number of significant digits, 2, 3 or 4 (int) // returns: frequency in Hz (long) // // written for Dirt Cheep Dumb Wireless sensor telemetry boards // using OOK radio links (SparkFun etc) which output noise on no RF in // so this looks for consistent pulse width as criterion against noise // returns negative numbers for all errors such as noise // int pulses; // 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 needTime = 1; // delay needed for precision in millisec unsigned long duration; // length of one pulse unsigned long totDuration; // total duration of first ten pulses unsigned long minDuration; // minimum length of a valid pulse unsigned long maxDuration; // maximum length of a valid pulse constrain (precision, 1, 5); // keepin it sane for (int i = 1; i < precision; i++) { needTime = needTime * 10; } // millisecs needed long frequency = 0; // nothin' yet totDuration = 0; // clear this to start 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 totDuration += duration; } maxDuration = totDuration / 7; minDuration = totDuration / 14; // 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 > needTime) // if time is enough for precision we are done { if (debug) { Serial.print(precision); Serial.print(" digits "); Serial.print(needTime); Serial.println(" ms need: "); 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; }
void print_time(unsigned long t_milli) // inspired by a very handy function by @davekw7x // argument is time in milliseconds // prints days, hours, min, sec, fraction in millis as // dd hh:mm:ss.fff { char buffer[23]; int days, hours, mins, secs; int fractime; unsigned long inttime; inttime = t_milli / 1000; // total number of number of seconds fractime = t_milli % 1000; // thousandths of a second // number of days is total seconds divided by number of seconds per day days = inttime / (86400); // days inttime = inttime % (86400); // remainder in secs // hours is remainder of secs divided by secs per hour hours = inttime / 3600; // hours inttime = inttime % 3600; // remainder in secs // mins is remainder of secs divided by secs per min mins = inttime / 60; // mins inttime = inttime % 60; // remiander in secs // secs is the remaining number of seconds. secs = inttime; // Don't bother to print days sprintf(buffer, "%02d %02d:%02d:%02d.%03d", days, hours, mins, secs, fractime); Serial.print(buffer); }
|
|
|
|
|
Logged
|
|
|
|
|
|