diff --git a/DAQ_FW/include/ISensorDriver.h b/DAQ_FW/include/ISensorDriver.h new file mode 100644 index 0000000..b7eab78 --- /dev/null +++ b/DAQ_FW/include/ISensorDriver.h @@ -0,0 +1,9 @@ +#include + +uint16_t baseTemp(); + + +uint16_t brakePressure(); + + +uint16_t tirePressure(); diff --git a/DAQ_FW/lib/TimerOne.cpp b/DAQ_FW/lib/TimerOne.cpp new file mode 100644 index 0000000..efede8d --- /dev/null +++ b/DAQ_FW/lib/TimerOne.cpp @@ -0,0 +1,209 @@ +/* + * Interrupt and PWM utilities for 16 bit Timer1 on ATmega168/328 + * Original code by Jesse Tane for http://labs.ideo.com August 2008 + * Modified March 2009 by Jérôme Despatis and Jesse Tane for ATmega328 support + * Modified June 2009 by Michael Polli and Jesse Tane to fix a bug in setPeriod() which caused the timer to stop + * Modified June 2011 by Lex Talionis to add a function to read the timer + * Modified Oct 2011 by Andrew Richards to avoid certain problems: + * - Add (long) assignments and casts to TimerOne::read() to ensure calculations involving tmp, ICR1 and TCNT1 aren't truncated + * - Ensure 16 bit registers accesses are atomic - run with interrupts disabled when accessing + * - Remove global enable of interrupts (sei())- could be running within an interrupt routine) + * - Disable interrupts whilst TCTN1 == 0. Datasheet vague on this, but experiment shows that overflow interrupt + * flag gets set whilst TCNT1 == 0, resulting in a phantom interrupt. Could just set to 1, but gets inaccurate + * at very short durations + * - startBottom() added to start counter at 0 and handle all interrupt enabling. + * - start() amended to enable interrupts + * - restart() amended to point at startBottom() + * Modiied 7:26 PM Sunday, October 09, 2011 by Lex Talionis + * - renamed start() to resume() to reflect it's actual role + * - renamed startBottom() to start(). This breaks some old code that expects start to continue counting where it left off + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + * + * See Google Code project http://code.google.com/p/arduino-timerone/ for latest + */ +#ifndef TIMERONE_cpp +#define TIMERONE_cpp + +#include "TimerOne.h" + +TimerOne Timer1; // preinstatiate + +ISR(TIMER1_OVF_vect) // interrupt service routine that wraps a user defined function supplied by attachInterrupt +{ + Timer1.isrCallback(); +} + + +void TimerOne::initialize(long microseconds) +{ + TCCR1A = 0; // clear control register A + TCCR1B = _BV(WGM13); // set mode 8: phase and frequency correct pwm, stop the timer + setPeriod(microseconds); +} + + +void TimerOne::setPeriod(long microseconds) // AR modified for atomic access +{ + + long cycles = (F_CPU / 2000000) * microseconds; // the counter runs backwards after TOP, interrupt is at BOTTOM so divide microseconds by 2 + if(cycles < RESOLUTION) clockSelectBits = _BV(CS10); // no prescale, full xtal + else if((cycles >>= 3) < RESOLUTION) clockSelectBits = _BV(CS11); // prescale by /8 + else if((cycles >>= 3) < RESOLUTION) clockSelectBits = _BV(CS11) | _BV(CS10); // prescale by /64 + else if((cycles >>= 2) < RESOLUTION) clockSelectBits = _BV(CS12); // prescale by /256 + else if((cycles >>= 2) < RESOLUTION) clockSelectBits = _BV(CS12) | _BV(CS10); // prescale by /1024 + else cycles = RESOLUTION - 1, clockSelectBits = _BV(CS12) | _BV(CS10); // request was out of bounds, set as maximum + + oldSREG = SREG; + cli(); // Disable interrupts for 16 bit register access + ICR1 = pwmPeriod = cycles; // ICR1 is TOP in p & f correct pwm mode + SREG = oldSREG; + + TCCR1B &= ~(_BV(CS10) | _BV(CS11) | _BV(CS12)); + TCCR1B |= clockSelectBits; // reset clock select register, and starts the clock +} + +void TimerOne::setPwmDuty(char pin, int duty) +{ + unsigned long dutyCycle = pwmPeriod; + + dutyCycle *= duty; + dutyCycle >>= 10; + + oldSREG = SREG; + cli(); + if(pin == 1 || pin == 9) OCR1A = dutyCycle; + else if(pin == 2 || pin == 10) OCR1B = dutyCycle; + SREG = oldSREG; +} + +void TimerOne::pwm(char pin, int duty, long microseconds) // expects duty cycle to be 10 bit (1024) +{ + if(microseconds > 0) setPeriod(microseconds); + if(pin == 1 || pin == 9) { + DDRB |= _BV(PORTB1); // sets data direction register for pwm output pin + TCCR1A |= _BV(COM1A1); // activates the output pin + } + else if(pin == 2 || pin == 10) { + DDRB |= _BV(PORTB2); + TCCR1A |= _BV(COM1B1); + } + setPwmDuty(pin, duty); + resume(); // Lex - make sure the clock is running. We don't want to restart the count, in case we are starting the second WGM + // and the first one is in the middle of a cycle +} + +void TimerOne::disablePwm(char pin) +{ + if(pin == 1 || pin == 9) TCCR1A &= ~_BV(COM1A1); // clear the bit that enables pwm on PB1 + else if(pin == 2 || pin == 10) TCCR1A &= ~_BV(COM1B1); // clear the bit that enables pwm on PB2 +} + +void TimerOne::attachInterrupt(void (*isr)(), long microseconds) +{ + if(microseconds > 0) setPeriod(microseconds); + isrCallback = isr; // register the user's callback with the real ISR + TIMSK1 = _BV(TOIE1); // sets the timer overflow interrupt enable bit + // might be running with interrupts disabled (eg inside an ISR), so don't touch the global state +// sei(); + resume(); +} + +void TimerOne::detachInterrupt() +{ + TIMSK1 &= ~_BV(TOIE1); // clears the timer overflow interrupt enable bit + // timer continues to count without calling the isr +} + +void TimerOne::resume() // AR suggested +{ + TCCR1B |= clockSelectBits; +} + +void TimerOne::restart() // Depricated - Public interface to start at zero - Lex 10/9/2011 +{ + start(); +} + +void TimerOne::start() // AR addition, renamed by Lex to reflect it's actual role +{ + unsigned int tcnt1; + + TIMSK1 &= ~_BV(TOIE1); // AR added + GTCCR |= _BV(PSRSYNC); // AR added - reset prescaler (NB: shared with all 16 bit timers); + + oldSREG = SREG; // AR - save status register + cli(); // AR - Disable interrupts + TCNT1 = 0; + SREG = oldSREG; // AR - Restore status register + resume(); + do { // Nothing -- wait until timer moved on from zero - otherwise get a phantom interrupt + oldSREG = SREG; + cli(); + tcnt1 = TCNT1; + SREG = oldSREG; + } while (tcnt1==0); + +// TIFR1 = 0xff; // AR - Clear interrupt flags +// TIMSK1 = _BV(TOIE1); // sets the timer overflow interrupt enable bit +} + +void TimerOne::stop() +{ + TCCR1B &= ~(_BV(CS10) | _BV(CS11) | _BV(CS12)); // clears all clock selects bits +} + +unsigned long TimerOne::read() //returns the value of the timer in microseconds +{ //rember! phase and freq correct mode counts up to then down again + unsigned long tmp; // AR amended to hold more than 65536 (could be nearly double this) + unsigned int tcnt1; // AR added + + oldSREG= SREG; + cli(); + tmp=TCNT1; + SREG = oldSREG; + + char scale=0; + switch (clockSelectBits) + { + case 1:// no prescalse + scale=0; + break; + case 2:// x8 prescale + scale=3; + break; + case 3:// x64 + scale=6; + break; + case 4:// x256 + scale=8; + break; + case 5:// x1024 + scale=10; + break; + } + + do { // Nothing -- max delay here is ~1023 cycles. AR modified + oldSREG = SREG; + cli(); + tcnt1 = TCNT1; + SREG = oldSREG; + } while (tcnt1==tmp); //if the timer has not ticked yet + + //if we are counting down add the top value to how far we have counted down + tmp = ( (tcnt1>tmp) ? (tmp) : (long)(ICR1-tcnt1)+(long)ICR1 ); // AR amended to add casts and reuse previous TCNT1 + return ((tmp*1000L)/(F_CPU /1000L))<. + * + * See Google Code project http://code.google.com/p/arduino-timerone/ for latest + */ +#ifndef TIMERONE_h +#define TIMERONE_h + +#include +#include + +#define RESOLUTION 65536 // Timer1 is 16 bit + +class TimerOne +{ + public: + + // properties + unsigned int pwmPeriod; + unsigned char clockSelectBits; + char oldSREG; // To hold Status Register while ints disabled + + // methods + void initialize(long microseconds=1000000); + void start(); + void stop(); + void restart(); + void resume(); + unsigned long read(); + void pwm(char pin, int duty, long microseconds=-1); + void disablePwm(char pin); + void attachInterrupt(void (*isr)(), long microseconds=-1); + void detachInterrupt(); + void setPeriod(long microseconds); + void setPwmDuty(char pin, int duty); + void (*isrCallback)(); +}; + +extern TimerOne Timer1; +#endif \ No newline at end of file diff --git a/DAQ_FW/src/ISensorDriver.cpp b/DAQ_FW/src/ISensorDriver.cpp new file mode 100644 index 0000000..7dd9430 --- /dev/null +++ b/DAQ_FW/src/ISensorDriver.cpp @@ -0,0 +1,24 @@ +#include +#include + +uint16_t baseTemp(data, x) +{ + // for tempurature sensors - analog reading is directly proportional to temperature in deg-C + uint16_t temperature = data*x; //where x = proportionality constant, + return temperature; +}; + +uint16_t brakePressure(data) +{ + //for brake pressure sensor (MIPAN2XX500PSAAX) + uint16_t pressure = 625*(data-0.5); // in PSI, V_supply @ 25 deg-C = 5V (ratiometric) + return pressure; + +}; + +uint16_t tirePressure(data) +{ + //for coolant pressure sensor (116CP31-M04S2-50) + uint16_t pressure = 20*(data-0.5); + return pressure; +}; \ No newline at end of file diff --git a/DAQ_FW/src/main.cpp b/DAQ_FW/src/main.cpp index 39b8185..ec266dd 100644 --- a/DAQ_FW/src/main.cpp +++ b/DAQ_FW/src/main.cpp @@ -1,16 +1,128 @@ -#include "Logger.h" - -void setup() -{ - // put your setup code here, to run once: - Logger::Start(); - Logger::Notice("Setup"); -} - -void loop() -{ - // put your main code here, to run repeatedly: - Logger::Notice("Hello World"); - - delay(1000); -} +#include +#include +#include + +// define sensor pins + +#define frontLeft_WSPIN 14 // wheel #1 +#define frontRight_WSPIN 16 // wheel #2 +#define backLeft_WSPIN 18 // wheel #3 +#define backRight_WSPIN 19 // wheel #4 + +// hardware timer pointer +hw_timer_t * timer = NULL; + +// define variables for counting + +int volatile WP1=0; +int volatile WP2=0; +int volatile WP3=0; +int volatile WP4=0; + +int volatile timerCounter = 0; + +// interrupt service routines: count interrupts + +void IRAM_ATTR ISR1(){ WP1++;} + +void IRAM_ATTR ISR2(){ WP2++;} + +void IRAM_ATTR ISR3(){ WP3++;} + +void IRAM_ATTR ISR4(){ WP4++;} + + +// interrupt reset functions: detach and reset interrupts after each period + +void interruptReset1(){ + detachInterrupt(frontLeft_WSPIN); + WP1= 0; + attachInterrupt(frontLeft_WSPIN, ISR1, FALLING); +} + +void interruptReset2(){ + detachInterrupt(frontRight_WSPIN); + WP2= 0; + attachInterrupt(frontRight_WSPIN, ISR2, FALLING); +} + +void interruptReset3(){ + detachInterrupt(backLeft_WSPIN); + WP3= 0; + attachInterrupt(backLeft_WSPIN, ISR3, FALLING); +} + +void interruptReset4(){ + detachInterrupt(backRight_WSPIN); + WP4= 0; + attachInterrupt(backRight_WSPIN, ISR4, FALLING); +} + + +// timer interrupt service routine + +void IRAM_ATTR onTimer(){ timerCounter ++;} + + +void setup() { + + Serial.begin(9600); + Serial.println("Connected"); + + pinMode(frontRight_WSPIN, INPUT); + pinMode(frontLeft_WSPIN, INPUT); + pinMode(backLeft_WSPIN, INPUT); + pinMode(backRight_WSPIN, INPUT); + + // attach interrupt that adds to pulse count when pin goes from HIGH to LOW + + attachInterrupt(frontLeft_WSPIN, ISR1, FALLING); + attachInterrupt(frontRight_WSPIN, ISR2, FALLING); + attachInterrupt(backLeft_WSPIN, ISR3, FALLING); + attachInterrupt(backRight_WSPIN, ISR4, FALLING); + + // begin timer + + timer = timerBegin(0, 80, true); + + timerAttachInterrupt(timer, &onTimer, true); // attach timer interrupt + timerAlarmWrite(timer, 1000000, true); // 1 second interrupt period + timerAlarmEnable(timer); // enable timer interrupt +} + + +// void wheelSpeedDisplay(int volatile wheelPulses, int wheelNumber){ + +// // calculate RPM from wheel pulse count +// int RPM = wheelPulses/49*60; // subject to change based on tire + +// // print results +// Serial.print("Wheel "); +// Serial.print(wheelNumber); +// Serial.print(" RPM = "); +// Serial.println(RPM); + +// // print wheel pulse count for testing purposes +// Serial.print(wheelPulses); +// } + + +void loop() { + + // after 1 second, timer counter equals 1 + // when timerCounter equals 1, compute wheel speed using wheel pulse values + + if (timerCounter > 0){ + timerCounter --; + + wheelSpeedDisplay(WP1, WP2, WP3, WP4); // prints velocity based on average wheel pulse counts + + + // detach/reattach interrupts + + interruptReset1(); + interruptReset2(); + interruptReset3(); + interruptReset4(); + }; +} \ No newline at end of file diff --git a/DAQ_FW/src/wheelSpeed.cpp b/DAQ_FW/src/wheelSpeed.cpp new file mode 100644 index 0000000..eff9ba0 --- /dev/null +++ b/DAQ_FW/src/wheelSpeed.cpp @@ -0,0 +1,35 @@ +#include +#include +#include + +void wheelSpeedDisplay(int volatile WP1, int volatile WP2, int volatile WP3, int volatile WP4){ + + // average wheel pulse counts + + //int wheelPulses = 0.25*(WP1 + WP2 + WP3 + WP4); + int wheelPulses = WP1; + + // calculate angular velocity from wheel pulse count + + int omega = (wheelPulses / 49.0)*2*3.14; // wheel pulses divided by 49.0 indents per tire, in radians + + // convert to linear velocity + + int velocity = 0.25 * omega * 3.6; // for r = 10", 3.6 is proportionality const from m/s to km/h + + // calculate average RPM from wheel pulse count + //int RPM = (wheelPulses/49.0)*60; // subject to change based on tire + + + // print results + Serial.print("Speed = "); + Serial.println(velocity, 0); // print with no decimal places + + //Serial.print("Wheel "); + //Serial.print(wheelNumber); + //Serial.print(" RPM = "); + //Serial.println(RPM); + + // print wheel pulse count for testing purposes + //Serial.print(wheelPulses); +} \ No newline at end of file diff --git a/DAQ_FW/src/wheelSpeed.h b/DAQ_FW/src/wheelSpeed.h new file mode 100644 index 0000000..7569ac0 --- /dev/null +++ b/DAQ_FW/src/wheelSpeed.h @@ -0,0 +1,9 @@ +#ifndef WHEELSPEED_H +#define WHEELSPEED_H + +#include +#include + +void wheelSpeedDisplay(int volatile WP1, int volatile WP2, int volatile WP3, int volatile WP4); + +#endif \ No newline at end of file diff --git a/main.cpp b/main.cpp new file mode 100644 index 0000000..e278d37 --- /dev/null +++ b/main.cpp @@ -0,0 +1,158 @@ +#include +#include + +#define frontLeft_WSPIN 14 +#define frontRight_WSPIN 16 +#define backLeft_WSPIN 18 +#define backRight_WSPIN 20 + +int volatile WP1=0; // set at random number for testing +int volatile WP2=0; // set at random number for testing +int volatile WP3=0; // set at random number for testing +int volatile WP4=0; // set at random number for testing + +int volatile irFlag1 = 0; +int volatile irFlag2 = 0; +int volatile irFlag3 = 0; +int volatile irFlag4 = 0; + +void IRAM_ATTR ISR1(){ // interrupt service routine + irFlag1 = 1; + WP1++; +} + +void IRAM_ATTR ISR2(){ // interrupt service routine + irFlag2 = 1; + WP2++; +} + +void IRAM_ATTR ISR3(){ // interrupt service routine + irFlag3 = 1; + WP3++; +} + +void IRAM_ATTR ISR4(){ // interrupt service routine + irFlag4 = 1; + WP4++; +} + +void interruptReset1(){ + detachInterrupt(frontLeft_WSPIN); + + irFlag1 = 0; + WP1= 0; + + attachInterrupt(frontLeft_WSPIN, ISR1, FALLING); +}; + +void interruptReset2(){ + detachInterrupt(frontRight_WSPIN); + + irFlag2 = 0; + WP2= 0; + + attachInterrupt(frontRight_WSPIN, ISR2, FALLING); +}; + +void interruptReset3(){ + detachInterrupt(backLeft_WSPIN); + + irFlag3 = 0; + WP3= 0; + + attachInterrupt(backLeft_WSPIN, ISR3, FALLING); +}; + +void interruptReset4(){ + detachInterrupt(backRight_WSPIN); + + irFlag4 = 0; + WP4= 0; + + attachInterrupt(backRight_WSPIN, ISR4, FALLING); +}; + +void setup() { + pinMode(frontRight_WSPIN, INPUT); + + // attach interrupt that adds to pulse count when pin goes from HIGH to LOW + attachInterrupt(frontLeft_WSPIN, ISR1, FALLING); + attachInterrupt(frontRight_WSPIN, ISR2, FALLING); + attachInterrupt(backLeft_WSPIN, ISR3, FALLING); + attachInterrupt(backRight_WSPIN, ISR4, FALLING); + + + Serial.begin(9600); + Serial.println("Connected"); + + +}; + +void loop() { + //-------------- wheel speed interrupt data --------------// + if(irFlag1){ + delay(1000); // interrupt detects pulses over 1000ms + + int RPM1 = WP1/49*60; // 20 pulses from wheel speed sensor corresponds to 1 revolution + + Serial.println(WP1); + Serial.print("Wheel 1 Speed (RPM)= "); + Serial.println(RPM1); + + + interruptReset1(); + }; + + if(irFlag1){ + delay(1000); // interrupt detects pulses over 1000ms + + int RPM1 = WP1/49*60; // 20 pulses from wheel speed sensor corresponds to 1 revolution + + Serial.println(WP1); + Serial.print("Wheel 1 Speed (RPM)= "); + Serial.println(RPM1); + + + interruptReset1(); + }; + + if(irFlag2){ + delay(1000); // interrupt detects pulses over 1000ms + + int RPM2 = WP2/49*60; // 20 pulses from wheel speed sensor corresponds to 1 revolution + + Serial.println(WP2); + Serial.print("Wheel 2 Speed (RPM)= "); + Serial.println(RPM2); + + + interruptReset2(); + }; + + if(irFlag3){ + delay(1000); // interrupt detects pulses over 1000ms + + int RPM3 = WP1/49*60; // 20 pulses from wheel speed sensor corresponds to 1 revolution + + Serial.println(WP3); + Serial.print("Wheel 3 Speed (RPM)= "); + Serial.println(RPM3); + + + interruptReset1(); + }; + + if(irFlag4){ + delay(1000); // interrupt detects pulses over 1000ms + + int RPM4 = WP4/49*60; // 20 pulses from wheel speed sensor corresponds to 1 revolution + + Serial.println(WP4); + Serial.print("Wheel 4 Speed (RPM)= "); + Serial.println(RPM4); + + + interruptReset4(); + }; + +}; \ No newline at end of file