04-03-2008, 09:07 PM
|
#1 (permalink)
|
needs more cowbell
Join Date: Feb 2008
Location: ÿ
Posts: 5,038
Thanks: 158
Thanked 269 Times in 212 Posts
|
Opengauge/MPGuino development: Freeduino signal processing
Here is what I put together to simulate a working signal processor. It *SHOULD* be possible to hook your soundcard output to the freeduino and come up with similiar readings. Hope HEX is ok, should be quicker than decimal, but I can live with decimal too.
Code:
//program to send dummy data over the serial port for prototyping the gui(s).
void setup()
{
Serial.begin(9600);
}
int number = 0; // dummy injector high and low values parsed from http://planetchampions.org/diympggauge/i1.wav
unsigned long injHiMS[]={69002,117777,101972,138435,148117,174988,98775,164693,165873,176190,113628,148571,120702,58276,39501,37891,38435,37369,37006,37142,39433,62879,71179,71995,77074,95215,86281,75419};
unsigned long injCount[]={37,40,34,51,37,43,48,50,42,46,49,38,37,39,38,37,37,36,34,33,32,32,31,32,31,32,32,33};
unsigned long vssCount[]={0,2,6,10,13,15,18,20,22,25,25,27,28,29,28,28,28,26,26,25,24,23,24,23,24,24,24,24};
void loop()
{
Serial.print(injHiMS[number], HEX);
Serial.print(",");
Serial.print(injCount[number], HEX);
Serial.print(",");
Serial.println(vssCount[number], HEX);
if(number == 27) {
// loop forever
while(true) {
continue;
}
}
number++;
delay(1000);
}
Here is the output from the Arduino monitor serial port function in the ide (one line prints out a second):
10D8A,25,0
1CC11,28,2
18E54,22,6
21CC3,33,A
24295,25,D
2AB8C,2B,F
181D7,30,12
28355,32,14
287F1,2A,16
2B03E,2E,19
1BBDC,31,19
2445B,26,1B
1D77E,25,1C
E3A4,27,1D
9A4D,26,1C
9403,25,1C
9623,25,1C
91F9,24,1A
908E,22,1A
9116,21,19
9A09,20,18
F59F,20,17
1160B,1F,18
1193B,20,17
12D12,1F,18
173EF,20,18
15109,20,18
1269B,21,18
__________________
WINDMILLS DO NOT WORK THAT WAY!!!
|
|
|
Today
|
|
|
Other popular topics in this forum...
|
|
|
04-04-2008, 08:28 AM
|
#2 (permalink)
|
needs more cowbell
Join Date: Feb 2008
Location: ÿ
Posts: 5,038
Thanks: 158
Thanked 269 Times in 212 Posts
|
Quote:
Originally Posted by s2man
I thought we were sending three values from the controller: 1) VSS pulse count per second (or other interval). 2) Injector pulse count per second. 3) Injector pulse width. Which cycles are you referring to?
|
Three is probably good enough and what I have the dummy signal generator doing above. The other value was the elapsed time according to the freeduino, but in thinking about it we probably don't need it.
Quote:
Originally Posted by s2man
data will be sent as characters, one byte each, via serial communication.
|
Can we use the above output format?
Quote:
Originally Posted by s2man
Gathering these data will use all of three our timer/counters.
|
Is there a way to just use one timer to figure out when a second has passed? Coyote mentioned that an interrupt could be made to occur when the injector goes hi and again when low, so it should be a matter or recording the "current time" on the injectorHI interrupt and subtracting it from the "current time" on the injectorLO interrupt and adding it to this seconds totals. I.e. borrow the code from millis() and see if we can make a micros() function? I can look into that if you like.
My understanding is that external interrputs are handled by specific functions, not necessarily timers.
so very rough sketch (assuming we can come up with micros()):
Code:
unsigned long injHiMS
unsigned long injCount
unsigned long vssCount
unsigned long injHiStart
processInjHi(){
injHiStart = micros();
}
processInjLo(){
injHiMS += micros()-injHiStart
injCount ++
}
processvssHI(){
vssCount++
}
processOneSecondEvent(){
//copy and reset the values first thing in case an interrupt occurs
// serial comm (or LCD displaying) is going to take awhile
//and shouldn't be top priority.
unsigned long tmpInjHiMS = injHiMS
injHiMS=0
unsigned long tmpInjCount = injCount
injCount=0
unsigned long tmpvssCount = vssCount
vssCount=0
Serial.print(tmpIinjHiMS, HEX);
Serial.print(",");
Serial.print(tmpInjCount, HEX);
Serial.print(",");
Serial.println(tmpvssCount, HEX);
}
unsigned long micros(){
uhh....
}
See also: http://www.arduino.cc/en/Reference/AttachInterrupt
__________________
WINDMILLS DO NOT WORK THAT WAY!!!
Last edited by dcb; 04-04-2008 at 08:59 AM..
|
|
|
04-04-2008, 11:35 AM
|
#3 (permalink)
|
I"m not lurking!
Join Date: Jan 2008
Location: Kansas City, MO
Posts: 128
Thanks: 0
Thanked 1 Time in 1 Post
|
Quote:
Originally Posted by dcb
Three is probably good enough and what I have the dummy signal generator doing above. The other value was the elapsed time according to the freeduino, but in thinking about it we probably don't need it.
|
I gotcha. We're just using different terms for the same data. Elapsed time is no problem. millis() rolls over about every 9 hours, but I doubt anyone will drive more than 9hrs straight.
Quote:
Originally Posted by dcb
Can we use the above output format?
|
Sure we can.
Quote:
Originally Posted by dcb
Is there a way to just use one timer to figure out when a second has passed?
|
Yep, [delete, delete, see below]
Quote:
Originally Posted by dcb
I.e. borrow the code from millis() and see if we can make a micros() function? I can look into that if you like.
My understanding is that external interrupts are handled by specific functions, not necessarily timers.
|
Ah, yes. Good thought. That would free up a timer, but would be less accurate. +-1ms out of one second is minimal, but +-1ms error out of the injector pulse could be major. That's why I suggested the 16bit timer for the injector pulse width. micros() would be better than millis(), but isn't that why we've got the timers? Perhaps we should use a timer on the injector pulse width, and code the one-second timer and/or the VSS counter. Or, we could the timer/counters now for expediency, and code our own later if we need to free them up. Hmm, lot's of solutions.
Your code sketch lays things out pretty well. I think we should put the Injector pulse width in an array, then average the array before sending it to the Palm. Nevermind. I see you're totaling the microseconds.
I'm working a river clean up this weekend, so I'll be offline. No coding or testing But I'll be camping and boating
__________________
Roll on,
Stew
|
|
|
04-05-2008, 01:41 AM
|
#4 (permalink)
|
needs more cowbell
Join Date: Feb 2008
Location: ÿ
Posts: 5,038
Thanks: 158
Thanked 269 Times in 212 Posts
|
Quote:
Originally Posted by s2man
millis() rolls over about every 9 hours
|
Ok, I think I have microSeconds just about figured out, see below code.
1. on the start of a timed event, save microSeconds()
2. at the end of a timed event, call elapsedMicroSeconds(startMicroSeconds)
It was a lot harder than it looks It digs into wiring.c and AVR, but it also demonstrates how simply the arduino integrates with them, once you know where to look.
Quote:
Originally Posted by s2man
micros() would be better than millis(), but isn't that why we've got the timers?
|
We now have microseconds, well close enough anyway. I still don't quite get the timer interrupts myself, and the more we do with one timer, the more PWM pins we leave for future expansion. You can time a whole lot of things accurately with microSeconds without knowing anything about timer interrupts or how many timers you have or what else they are connected to.
I'm kind of tempted to say our main loop should be written like delay() with the loop guts in the middle, I used this technique below also, most things come back in 1000ms, a few were in 1001ms, don't know if a timer interrupt every second would actually be any more accurate with the other injector and vss interrupts going on.
Quote:
Originally Posted by s2man
I'm working a river clean up this weekend, so I'll be offline. No coding or testing But I'll be camping and boating
|
No fair, I want to go too!
Code:
/*
* microSeconds, convert timer0 register and the timer 0 overflow
* count (defined in wiring.c) into a microsecond value
* for more accurate timing needs.
*/
//overflow counter used by millis()
extern volatile unsigned long timer0_overflow_count;
//will reset after 71.5 minutes, so don't time anything longer than that
//about 4 microsecond resolution @ 16mhz
unsigned long microSeconds (void){
return ((timer0_overflow_count << 8) + TCNT0) * 4;
}
//return the elapsed microseconds, accounting for overflows
unsigned long elapsedMicroseconds(unsigned long startMicroSeconds ){
unsigned long msec = microSeconds();
if(msec >= startMicroSeconds)
return msec-startMicroSeconds;
return 4294967295 - (startMicroSeconds-msec);
}
void setup (void){
Serial.begin(9600);
}
unsigned long looptime=1000;
void loop (void){
unsigned long loopStart=millis();
unsigned long start=microSeconds();
Serial.print(elapsedMicroseconds(start));
Serial.print(",");
Serial.print(millis());
Serial.print(",");
Serial.print(microSeconds());
Serial.print(",");
Serial.print(elapsedMicroseconds(start));
Serial.print(",");
while (millis()-loopStart < looptime);
//below lines are for testing,
//there should not be anything outside the timed loop
//at runtime
Serial.print(millis()-loopStart); //testing only, messes up actual loop timing out here
Serial.print(",");
Serial.println(elapsedMicroseconds(start));
}
Output:
4,0,2304,7376,1000,1003852
4,1014,1020620,15556,1000,1002320
4,2026,2032344,15556,1000,1003324
4,3039,3045068,15556,1000,1003332
0,4051,4057808,15552,1000,1002288
0,5063,5069500,15556,1000,1002340
4,6075,6081244,15556,1000,1003320
4,7088,7093972,15556,1000,1003316
4,8100,8106692,15556,1000,1002328
4,9112,9118424,15556,1000,1003328
4,10125,10132196,17636,1000,1003348
4,11138,11144948,17636,1000,1003304
4,12150,12157652,17636,1000,1002308
0,13162,13169364,17636,1000,1003352
4,14175,14182124,17636,1000,1003336
4,15187,15194864,17636,1000,1002296
4,16199,16206564,17636,1000,1002308
4,17211,17218276,17636,1000,1003340
4,18224,18231020,17636,1000,1003328
4,19236,19243752,17636,1000,1002296
4,20248,20255452,17636,1000,1003348
4,21261,21268204,17636,1000,1003308
4,22274,22280916,17636,1000,1003348
4,23286,23293668,17636,1000,1002304
4,24298,24305372,17636,1000,1003340
4,25311,25318120,17636,1000,1003336
4,26323,26330860,17636,1000,1002300
4,27335,27342564,17636,1000,1002296
4,28347,28354264,17636,1000,1003328
4,29360,29366996,17636,1000,1003336
4,30372,30379736,17636,1000,1002320
4,31384,31391460,17636,1000,1003336
4,32397,32404200,17636,1000,1003336
4,33410,33416936,17640,1000,1003344
4,34422,34429684,17636,1000,1002288
4,35434,35441376,17636,1000,1003348
4,36447,36454128,17636,1000,1003296
4,37459,37466828,17636,1000,1002336
0,38471,38478564,17636,1000,1002300
4,39483,39490272,17636,1000,1003320
0,40496,40502996,17632,1000,1003332
4,41508,41515736,17636,1000,1002296
4,42520,42527436,17636,1000,1003356
0,43533,43540192,17636,1000,1003348
4,44546,44552944,17640,1000,1003332
__________________
WINDMILLS DO NOT WORK THAT WAY!!!
Last edited by dcb; 04-05-2008 at 01:47 AM..
|
|
|
04-05-2008, 11:14 AM
|
#5 (permalink)
|
needs more cowbell
Join Date: Feb 2008
Location: ÿ
Posts: 5,038
Thanks: 158
Thanked 269 Times in 212 Posts
|
putting it together
Code:
/* draft of signal processor for the opengauge project, untested
sends the injector open time (in microseconds), the number of injector
pulses, and the number of vss tics out the serial port once a second.
*/
//overflow counter used by millis()
extern volatile unsigned long timer0_overflow_count;
//will reset after 71.5 minutes, so don't time anything longer than that
//about 4 microsecond resolution @ 16mhz
unsigned long microSeconds (void){
return ((timer0_overflow_count << 8) + TCNT0) * 4;
}
//return the elapsed microseconds, accounting for overflows
unsigned long elapsedMicroseconds(unsigned long startMicroSeconds ){
unsigned long msec = microSeconds();
if(msec >= startMicroSeconds)
return msec-startMicroSeconds;
return 4294967295 - (startMicroSeconds-msec);//someone check my work here
}
//use pins 2 and 3 because that is how the arduino is set up
//we use timer0 for ALL our event timing.
int injectorPin = 2; // connected to the injector signal
int vssPin = 3; // connected to the vss signal
int ledPin = 13; // display one second heartbeep
unsigned long injHiMS;
unsigned long injCount;
unsigned long vssCount;
unsigned long injHiStart;
void processInjChange(void){
detachInterrupt(0);
boolean injHI=digitalRead(injectorPin);
if(injHI){
injHiStart = microSeconds();
}else{
injHiMS += elapsedMicroseconds(injHiStart);
injCount++;
}
//really should re-attach the interrupt after the injector settle time
attachInterrupt(0, processInjChange, CHANGE);
}
void processvssHI(void){
vssCount++;
}
void setup (void){
Serial.begin(9600);
pinMode(injectorPin, INPUT);
pinMode(vssPin, INPUT);
attachInterrupt(0, processInjChange, CHANGE);
attachInterrupt(1, processvssHI, RISING);
}
unsigned long looptime=1000;
void loop (void){
unsigned long loopStart=millis();
digitalWrite(ledPin,HIGH); //heartbeat indicator
// buffer the values to send and reset them
unsigned long tmpInjHiMS = injHiMS;
injHiMS=0;
unsigned long tmpInjCount = injCount;
injCount=0;
unsigned long tmpvssCount = vssCount;
vssCount=0;
//send the values out the serial port.
//LCD display routines triggered here also
Serial.print(tmpInjHiMS, HEX);
Serial.print(",");
Serial.print(tmpInjCount, HEX);
Serial.print(",");
Serial.println(tmpvssCount, HEX);
//heartbeat indicator off.
//If the led is mostly on then way too much time is spent
//sending/displaying the data
digitalWrite(ledPin,LOW);
while (millis()-loopStart < looptime);
}
__________________
WINDMILLS DO NOT WORK THAT WAY!!!
Last edited by dcb; 04-27-2008 at 01:19 PM..
Reason: more updates
|
|
|
04-05-2008, 02:09 PM
|
#6 (permalink)
|
needs more cowbell
Join Date: Feb 2008
Location: ÿ
Posts: 5,038
Thanks: 158
Thanked 269 Times in 212 Posts
|
Other notes:
1. the basic signal processor is 3458 bytes (of a 14336 byte maximum). If I take out any references to serial, it goes down to 1922 bytes.
2. the main loop is taking about 6 milliseconds, without any vss or injector interrupts, but with serial transmission of "0,0,0" before it waits for the second to be over.
3. it might be better to use microseconds to control the main loop or otherwise detect that the 9 hour millis rollover has occured and adjust accordingly, it should be able to run forever without breaking, not 9 hours.
__________________
WINDMILLS DO NOT WORK THAT WAY!!!
|
|
|
|