View Single Post
Old 07-20-2013, 11:50 AM   #28 (permalink)
t vago
MPGuino Supporter
 
t vago's Avatar
 
Join Date: Oct 2010
Location: Hungary
Posts: 1,807

iNXS - '10 Opel Zafira 111 Anniversary

Suzi - '02 Suzuki Swift GL
Thanks: 829
Thanked 708 Times in 456 Posts
Quote:
Originally Posted by nickdigger View Post
I can't think of a car that could use an 8-bit value for VSS/mile.
Ooops! I meant to say that the VSS debounce factor got turned into an 8-bit value. The VSS pulses/mile factor is still a 32-bit value (for now).

Code:
volatile uint8_t lastPINCstate = PINC;
uint8_t VSSCounts = 0;

...

ISR( PCINT1_vect ) {

	static uint8_t p;
	static uint8_t q;

	p = PINC; // read current pin C state
	q = p ^ lastPINCstate; // detect any changes from the last time this ISR is called

	timerStatus |= timerWakeUp; // tell system timer to wake up the main program

	if (q & vssBit) { // if a VSS pulse is received

		if (vssPause == 0) { // if there is no VSS pulse delay defined

			vssPulseCount++; // immediately update the VSS pulse count
			dirty |= dirtyVSS; // tell system timer that raw readings changed, and that the VSS reading itself has changed

		} else VSSCounts = vssPause; // otherwise, set VSS debounce count and let system timer handle the debouncing

	}

	if (q & buttonsUp) { // if a button press is detected

		keyCounts = keyDelay; // set keypress debounce count, and let system timer handle the debouncing

	}

	lastPINCstate = p; // remember the current pin C state for the next time this ISR gets called

}
This above is the current keypress/VSS interrupt handler. It, of course, fires any time a VSS pulse or a keypress is detected. It is important to note that this ISR will get called more than once each time a button is pressed, and that the debounce is handled by the use of a counter that is updated by the system timer. Once the counter winds down to zero, the new keypress has been stable for that amount of time, and the system timer then passes the keypress off to the main program. This is also how I created "long" button press detection.

Code:
ISR(TIMER2_OVF_vect) { // system timer interrupt handler

(...)

	if (VSSCounts != 0) { // if there is a VSS debounce countdown in progress

		VSSCounts--; // bump down the VSS count
		if (VSSCounts == 0) { // if count has reached zero,

			vssPulseCount++; // update the VSS pulse count
			dirty |= dirtyVSS; // tell system timer that raw readings changed, and that the VSS reading itself has changed

		}

	}

	if (keyCounts) { // if there is a button press debounce countdown in progress

		keyCounts--; // bump down the button press count by one

		if (keyCounts == 0) { // if the count has reached zero

			lastKeyPressed |= vssBit; // use vssBit to signal that a "long" keypress has been detected
			buttonState = lastKeyPressed; // pass off the remembered keypress status to the main program
			timerStatus &= ~timerKeyWait; // signal main program that a key press was detected

		}

		if (keyCounts == keyShortDelay) { // if button debounce countdown reaches this point

			tempFlags = buttonsUp & lastPINCstate; // figure out what buttons are being pressed

			if ((tempFlags != buttonsUp) || (lastKeyPressed & vssBit)) { // if any buttons are pressed, or there is a long press status

				lastKeyPressed = tempFlags; // remember the keypress status for later

			} else { // all buttons have been released, and there is no long keypress status detected

				buttonState = lastKeyPressed; // pass off the remembered keypress status to the main program
				timerStatus &= ~timerKeyWait; // signal main program that a key press was detected 
				keyCounts = 0; // reset button press debounce countdown to zero

			}

		}

	}

(...)

}
This code is in the system timer ISR. It enables a couple of things. First, if the user presses a button, then releases it, it will release just that keypress. If the user presses two buttons together, and releases them, it will release this combination. However, if the user presses the two buttons, and there is a slight delay between, say, pressing the center button and the left button, then the code will wait for the buttons to stabilize. Finally, if the user holds down the button combination for more than one second, the code will pass that along. The difference there is that the short keypresses require that the user release the buttons first, while the long keypresses only require that the buttons have been pressed for a second.

Quote:
Originally Posted by nickdigger View Post
One thing about your injOpenStop = timer2_overflow_count | TCNT2; code: Are you using the same prescale factor=64 (TCCR2B= 1<<CS22;); If so, I believe each tick is worth 4usec, so your calculation should be multiplied by 4. (I think. I've only just started looking into timers.)
Heh. It's good that you noticed that.

After going through the code, I decided I just didn't need that any more. For one thing, it wasn't really returning values in true microseconds. For 16 MHz systems, it'd return values in units of (16 000 000 / 64), or 4 us, but for 20 MHz values, it't return values in units of (20 000 000 / 64), or 3.2 us. Besides that, doing the conversion was just another arithmetic operation that could have been folded into the mileage/distance/economy/time calculations. So, fuel injector pulse times, idle times, and even the system time are now measured in timer2 cycles

Also, to optimize calculations involving timer2_overflow_count, I decided to have the timer2 overflow handler bump timer2_overflow_count by 256 instead of by 1. That got rid of constantly having to multiply timer2_overflow_count by 256 whenever it was desired to read the time.

The timer2 overflow has been vastly expanded, to get rid of microseconds() altogether. The main loop uses timer2 to do its loop delays now, instead of having to track the time by itself. I'm thinking that this may have gotten rid of that freeze-up bug altogether. Also, function delay2() now "calls" the overflow timer to do its delays, but also I'm thinking to get rid of that, in favor of having timer2 drive the LCD output directly by using an output buffer.

Code:
	injOpenStop = timer2_overflow_count + TCNT2; // read current TCNT2
	if (TIFR2 & (1 << TOV2)) injOpenStop = timer2_overflow_count + 256 + TCNT2; // if overflow occurred, re-read TCNT2 and adjust for overflow
That above is a slightly modified version that actually manages to save about 18 bytes or so in compilation. Who knew that logical OR-ing would take up more space than just adding? Heh.
  Reply With Quote