diff --git a/SketchVxx.cpp b/SketchVxx.cpp index 2627508..f0324f3 100644 --- a/SketchVxx.cpp +++ b/SketchVxx.cpp @@ -7,20 +7,15 @@ /* -v3 working with Uno and Promini. Mirror file on AtmelStudio -v4 with inclusion of OneWire to read DS18b20 digital thermometer -project soilSensev6 has a stable method to measure frequency -the first result is obtained by combining two measurements at different timer2 clock frequencies -the second result is obtained only from the measurement at the lowest frequency -the MC is in powersave during the measurement -measurement is started and terminated on the rising edge of the signal to INT1 (pin3) -there is a problem with the variation calculation for large values of nCount -v7 change timing of measurement loop to reduce polarisation -v8 distribute soil probe measurements uniformly -improve the estimate of measurement time - +forked from sketchV10 adds overrun interrupt for TIMER2 replaces INT1 with direct monitoring of D3 + +v2 modified for pin out of MC1648 board +wire pins 8 and 9 together to boost output current +circuit uses direct power from ports which is not recommended practice! + +v3 combines status and freq count packets */ #include @@ -48,14 +43,16 @@ replaces INT1 with direct monitoring of D3 volatile uint32_t overFlowCount; -const int pinOutputCounter = 3; -const int pinPowerCounter = 5; -const int pinPowerOsc1 = 6; -const int pinPowerOsc2 = 7; -const int pinLed = 13; +/* +pinOutputCounter = 3; +pinPowerCounter = 10; +pinPowerOsc = 9; +pinLed = 13; +*/ +const byte mask = (1 << PIND3); //mask for input pin to frequency counter const byte receive_pin = -1; const byte transmit_pin = 12; -const byte digT_pin = 8; +const byte digT_pin = 11; @@ -63,9 +60,9 @@ uint8_t preScaler[8] = {0, 0, 3, 5, 6, 7, 8, 10}; // powers of 2 const uint8_t clockFrequency = 4; // i.e. 2^4 in MHz uint8_t preScalerSelect = 1; // i.e.divide by 1 const uint8_t nCount = 8; // number to average is 2^nCount +const uint8_t convert2Microsec = clockFrequency + nCount - preScaler[preScalerSelect]; +//to convert to microsec: divide count by clockFrequency; divide by nCount; multiply by prescaler -int pinPower = pinPowerOsc1; -bool measureOsc1 = true; // first measurement is for osc1 bool initialized = false; // when false can use for debug/learn // store results here uint32_t meanResults; @@ -73,7 +70,7 @@ uint32_t meanResults; const int baud = 500; -const byte node = 12; +const byte node = 13; OneWire ds(digT_pin); // a 4.7K pull-up resistor is necessary // digital temperature sensor @@ -92,9 +89,9 @@ const byte nVcc = 6; // ADC reads to determine Vcc; power of 2 extern volatile unsigned long timer0_millis; const uint32_t periodStatusReport = 600000L; -uint32_t periodOscReport = 120000L; // changed to check effect of polarisation -uint32_t nextStatusReport = periodStatusReport; -uint32_t nextOscReport = periodOscReport; +const uint32_t periodMeasurement = 120000L; // changed to check effect of polarisation +uint32_t nextStatusReport = 300000L; +uint32_t nextMeasurement = periodMeasurement; uint32_t now = 0L; // beginning of time @@ -102,34 +99,17 @@ uint32_t roundDiv(uint32_t a, uint32_t b); uint32_t bitDiv(uint32_t a, byte b); ////////////////////////////////////struct PayloadItem///////////////////////////////////// -typedef struct { - byte nodeId; //store this nodeId - byte count; - byte bin2usCoarse; - byte bin2usFine; - byte varCoarse; - byte varFine; - unsigned long coarseTime; - unsigned long fineTime; -} PayloadItem; -// count keeps track of the # packets sent out - -PayloadItem payloadTime; - - -////////////////////////////////////struct PayloadItem2///////////////////////////////////// typedef struct { byte nodeId; //store this nodeId byte count; int temp; int Vcc; - unsigned long millisec; - unsigned long empty; -} PayloadItem2; -// time is approximate since using only watchdog timer - -PayloadItem2 payloadStatus; + unsigned long timeStamp; + unsigned long periodOfSignal; +} PayloadItem; +// count keeps track of the # packets sent out +PayloadItem payload; //////////////////////////////////Initialise the ISR/////////////////////////////////////// @@ -175,23 +155,14 @@ void flashLED(byte nTimes) } } -//////////////////////////////////sendTimePacket/////////////////////////////////////// - -void sendTimePacket() -{ - // send packet - driver.send((uint8_t*)(&payloadTime), sizeof(payloadTime)); - driver.waitPacketSent(); - ++payloadTime.count; -} -//////////////////////////////////sendStatusPacket/////////////////////////////////////// +//////////////////////////////////sendPacket/////////////////////////////////////// -void sendStatusPacket() +void sendPacket() { // send packet - driver.send((uint8_t*)(&payloadStatus), sizeof(payloadStatus)); + driver.send((uint8_t*)(&payload), sizeof(payload)); driver.waitPacketSent(); - ++payloadStatus.count; + ++payload.count; } //////////////////////////////////setPrescaler/////////////////////////////////////// void setPrescaler(byte value) @@ -275,14 +246,6 @@ uint32_t readADC( byte channel, byte noSamples ) // Return the conversion result return sumX; } - - - - - - - - //////////////////////////////////measureVcc/////////////////////////////////////// // From : http://provideyourown.com/2012/secret-arduino-voltmeter-measure-battery-voltage/ uint32_t measureVcc() @@ -302,7 +265,7 @@ uint32_t measureVcc() #endif - uint32_t result = (1 << nVcc) * 1173751L / readADC( muxVal, nVcc); // Calculate Vcc (in mV); estimated as intRef_Volts*1023*1000 = 1125300L + uint32_t result = (1 << nVcc) * 1119483L / readADC( muxVal, nVcc); // Calculate Vcc (in mV); estimated as intRef_Volts*1023*1000 = 1125300L return result; // Vcc in millivolts } @@ -352,28 +315,6 @@ int16_t measureTemp() return(tmp); } -//////////////////////////////////sendStatus/////////////////////////////////////// -void sendStatus() -{ - //assemble packet - payloadStatus.temp = measureTemp(); - payloadStatus.Vcc = measureVcc(); - payloadStatus.millisec = now; - sendStatusPacket(); - #if USE_SER - Serial.begin(115200); - delay(1); - Serial.print(F("temp= ")); - Serial.print(payloadStatus.temp); - Serial.print(F(" Vcc= ")); - Serial.print(payloadStatus.Vcc); - Serial.print(F(" millisec= ")); - Serial.println(payloadStatus.millisec); - Serial.flush(); - Serial.end(); - #endif - -} //////////////////////////////////setup/////////////////////////////////////// @@ -382,24 +323,21 @@ void setup() { - //pinMode(pinOutputCounter, INPUT); - //pinMode(pinPowerOsc1, OUTPUT); - //pinMode(pinPowerOsc2, OUTPUT); - //pinMode(pinPowerCounter, OUTPUT); - //pinMode(pinLed, OUTPUT); - DDRB &= 0b11110000; // pins 8, 9, 10 and 11 inputs - PORTB = 0b00001111; // pull-up pins 8 to 11 - DDRB |= (1 << DDB5); // pin13 output - DDRD &= 0b11100011; // pin 2, 3, 4 inputs - PORTD = 0b00010100; // pull-up pins 2 and 4 - DDRD |= ((1 << DDD5) | (1 << DDD6) | (1 << DDD7)); //pins 5, 6 and 7 outputs + + // PORTB maps pins 8 to 13 of Pro Mini + // PORTD maps Rxd, Txd ,2, 3, 4, 5, 6, 7 of Pro Mini + + DDRB &= 0b11110111; // pin 11 input + PORTB = 0b00001000; // pull-up pin 11 + DDRB |= (1 << DDB0) | (1 << DDB1) | (1 << DDB2) | (1 << DDB5); // pins 8, 9, 10, 13 outputs + DDRD &= 0b00000011; // pins 2, 3, 4, 5, 6, 7 inputs + PORTD = 0b11110100; // pull-up all pins except Rxd, Txd, 3 /* - const int pinOutputCounter = 3; - const int pinPowerCounter = 5; - const int pinPowerOsc1 = 6; - const int pinPowerOsc2 = 7; - const int pinLed = 13; + pinOutputCounter = 3; + pinPowerCounter = 10; + pinPowerOsc = 9; + pinLed = 13; const byte receive_pin = -1; const byte transmit_pin = 12; const byte digT_pin = 8; @@ -408,8 +346,6 @@ void setup() // turn-off the ADC ADCSRA &= ~(1 << ADEN); - // turn-off timer1 - TIMSK1 = 0; //set-up timer2 to "normal" operation mode. See datasheet pg. 147, 155, & 157-158 (incl. Table 18-8). //-This is important so that the timer2 counter, TCNT2, counts only UP and not also down. @@ -433,13 +369,10 @@ void setup() } - payloadTime.count = 0; - payloadTime.nodeId = node; - payloadStatus.count = 0; - payloadStatus.nodeId = node | 0x20; // bit 5 set to indicate status packet - payloadStatus.empty = 0L; + payload.count = 0; + payload.nodeId = node | (convert2Microsec << 4); - flashLED(3); + flashLED(7); #if USE_SER @@ -466,36 +399,41 @@ void loop() if (now > nextStatusReport) { nextStatusReport = now + periodStatusReport; - sendStatus(); + payload.temp = measureTemp(); + payload.Vcc = measureVcc(); + //will send when new frequency data are available } - if (now > nextOscReport) + if (now > nextMeasurement) { - // measure osc - nextOscReport = now + periodOscReport; + // measurePeriodOfSignal + nextMeasurement = now + periodMeasurement; // start measuring using power save - //digitalWrite(pinPower, HIGH); // power-up oscillator - //digitalWrite(pinPowerCounter, HIGH); // power-up counter board - PORTD ^= ((1 << DDD5) | (1 << pinPower)); + // power-up oscillator + // power-up counter board + PORTB ^= ((1 << PORTB0) | (1 << PORTB1) | (1 << PORTB2) | (USE_SER << PORTB5)); - LowPower.powerDown(SLEEP_2S, ADC_OFF, BOD_OFF); // allow oscillator to stabilise before measuring frequency + LowPower.powerDown(SLEEP_500MS, ADC_OFF, BOD_OFF); // allow oscillator to stabilise before measuring frequency - advanceTimer(2000L); + advanceTimer(500L); // To do: check whether can shorten sleep to reduce power consumption uint16_t maxCounts = ( 1 << nCount ); // keep as powers of 2 uint32_t result = 0L; - overFlowCount = 0; - byte mask = (1 << PIND3); + overFlowCount = 0; // volatile + //any interrupt will affect the accuracy of TIMER2 count but cannot screen all interrupts so mask individually + TIMSK0 = 0; // turn off timer0. Used by millis() + byte old_TIMSK1 = TIMSK1; + TIMSK1 = 0; // turn off timer1. Used by RH_ASK + byte old_EIMSK = EIMSK; + EIMSK = 0; // no external interrupts + byte state = PIND & mask; - while((PIND & mask) == state) {;;} // wait for transition TCNT2 = 0; //reset Timer2 counter TIMSK2 |= (1 << TOIE2); // enable overflow interrupt - TIMSK0 = 0; // turn off timer0 for lower jitter. Note disables millis() - // assume that timer1 is not enabled for (uint16_t i = 0; i < maxCounts; i++) @@ -508,29 +446,29 @@ void loop() result = overFlowCount; if( TIFR2 & (1 << TOV2)); //grab the timer2 overflow flag value; see datasheet pg. 160 { - result++; //force the overflow count to increment + result++; //increment the overflow count TIFR2 |= (1 << TOV2); // the flag is cleared by writing a logical one to it } - TIMSK2 &= ~(1 << TOIE2); // mask overflow interrupt + TIMSK2 &= ~(1 << TOIE2); // mask overflow interrupt; ensures no overflow interrupt can occur at the moment the counter is reset sei(); + // reset all other interrupt masks TIMSK0 = 1; // turn timer0 back on + TIMSK1 = old_TIMSK1; + EIMSK = old_EIMSK; result = result << 8; result |= count; - //digitalWrite(pinPower, LOW); // power-down oscillator - //digitalWrite(pinPowerCounter, LOW); // power-down counter board - PORTD ^= ((1 << DDD5) | (1 << pinPower)); + // power-down oscillator + // power-down counter board + PORTB ^= ((1 << PORTB0) | (1 << PORTB1) | (1 << PORTB2) | (USE_SER << PORTB5)); /* locate the binary point for the count: 8 + nCount bits in total; the binary point is to the right of the nCount bit with enumeration of bits 0, 1, 2, 3 . . . */ - //to convert to microsec: divide count by clockFrequency; divide by nCount; multiply by prescaler - payloadTime.bin2usCoarse = clockFrequency + nCount - preScaler[preScalerSelect]; - payloadTime.bin2usFine = 0; uint32_t time2Measure = result << (preScaler[preScalerSelect] - clockFrequency);// approximate estimate in usec advanceTimer(roundDiv(time2Measure , 1000L)); @@ -548,13 +486,16 @@ void loop() divide number of binary places by 3 to find power of 10 */ - - Serial.print(F("time= ")); + Serial.print(F("temp= ")); + Serial.print(payload.temp); + Serial.print(F(" Vcc= ")); + Serial.print(payload.Vcc); + Serial.print(F(" timestamp= ")); Serial.print(millis()); - Serial.print(F(" finalCoarse= ")); - Serial.print(result >> payloadTime.bin2usCoarse); + Serial.print(F(" period= ")); + Serial.print(result >> convert2Microsec); Serial.print(F(".")); - Serial.println(((result & ((1L << payloadTime.bin2usCoarse) - 1L)) * 100) >> payloadTime.bin2usCoarse); + Serial.println(((result & ((1L << convert2Microsec) - 1L)) * 100) >> convert2Microsec); Serial.flush(); Serial.end(); @@ -564,24 +505,12 @@ void loop() // assemble packet // with the original measurements and the positions of the binary point to convert them to microsec // 14 bytes in packet - payloadTime.nodeId = (node | ((byte)measureOsc1 << 4)); // bit 5 - payloadTime.varCoarse = 0; - payloadTime.varFine = 0; - payloadTime.coarseTime = result; - payloadTime.fineTime = 0; - sendTimePacket(); - + payload.timeStamp = millis(); + payload.periodOfSignal = result; + sendPacket(); - - - - - - // switch pins ready for next measurement - measureOsc1 = !measureOsc1; - pinPower = (measureOsc1 ? pinPowerOsc1 : pinPowerOsc2); - } // end measureOsc + } // end measurePeriodOfSignal } // end loop()