Deciphering the sensor polling code


I’m a beginner programmer trying to understand how some of the sensor polling is done.

From src\PololuQTRSensors\PololuQTRSensors.cpp:

# time = 0;  
# last_time = TCNT2;  
# while (time < _maxValue)  
# {  
#     // Keep track of the total time.  
#     // This implicity casts the difference to unsigned char, so  
#     // we don't add negative values.  
#     unsigned char delta_time = TCNT2 - last_time;  
#     time += delta_time;  
#     last_time += delta_time;   

when TCNT2 reaches 255, it’ll starting counting from 0 again right? Now, doing TCNT2 - last_time (which maybe be like 3 - 250) will give a negative value. When it’s assigned to the unsigned char, what will delta_time be? Will it be 0? Also, why is last_time being incremented by delta_time rather than just being assigned the current (soon to become previous) value of TCNT2? Incrementing last_time by delta_time will keep raising it, above 255 eventually, and then doing TCNT2 - last time will keep giving negative values.

Hope someone can clear my confusions. Thanks

Good question. But as the comment says, an unsigned char cannot be negative. If you set delta_time equal to “3 - 250”, the value it gets is 9. So time and last_time will keep going up and up!

By the way, be very careful with implicit casting - you can easily get into big trouble by doing something like

if(x < b - a)

when x, a, and b are all different types, some signed and some unsigned. Always add the explicit casts when you are unsure to make sure you are doing the computation the way you want it.



Just to address one thing you mentioned and clarify something paul said, the variable last_time is an unsigned char (a single byte), just like TCNT2, so it will not keep getting bigger and bigger. It will increase to 255 and then overflow back to 0, just like TCNT2 does as the timer ticks. Adding delta_time to last_time is equivalent to setting last_time equal to the value TCNT2 held when delta_time was set. It’s sort of a roundabout way of doing this, but it makes sure that last_time and time are operating off of the same value of TCNT2.

- Ben

Thanks guys! I think I get it now. There’s heaps for me to learn from all this code.

I’ve got another question:

	// set all ports to inputs
	DDRB &= ~_portBMask;
	DDRC &= ~_portCMask;
	DDRD &= ~_portDMask;
	// turn off pull ups
	PORTB &= ~_portBMask;
	PORTC &= ~_portCMask;
	PORTD &= ~_portDMask;

What does it mean turn off pull ups? (I read somewhere that I/O pins have pullup resistors but not sure what they’re for). Do the pull ups need to be on in the first place for the sensor to work?

Digital inputs on the AVR can either be floating (high-impedance) or weakly pulled up to 5V (pull-ups enabled). Pull-ups are useful when dealing with input sources that change between high-impedance and low (such as a SPST switch or pushbutton), since it’s good to have the input be at a known voltage when the input source is floating. The pull-ups will negatively affect reading the QTR sensors, however, so the sensor-reading code disables pull-ups (just in case the user has previously enabled them in his code).

- Ben

Hello !!

I have doubts with this code:

	start_time = TCNT2;																
	while (time < _maxValue)
		delta_time = TCNT2 - start_time;										
		time += delta_time;
		start_time += delta_time;

		// continue immediately if there is no change
		if (PINB == last_b && PINC == last_c && PIND == last_d)

		// save the last observed values
		last_b = PINB; 
		last_c = PINC;
		last_d = PIND;

		// figure out which pins changed
		for (i = 0; i < _numSensors; i++)
		if (sensor_values[i] == 0 && !(*_register[i] & _bitmask[i]))
				sensor_values[i] = time;

If the register TCNT2 is 8bit, and the timer increments every 0,4us (working at 2,5MHz), it means that this register can overflow every 102us.

The uC is executing the line until the pin change?:
if (PINB == last_b && PINC == last_c && PIND == last_d) continue;"

What occurs if there is no change in any PORT during 200us?



The statement you quoted in bold isn’t a loop in itself; rather, it is a condition that executes a “continue” if no pins have changed state, which in turn jumps program execution back to the top of the while loop and the portion of the code that adds the elapsed time to a 16-bit variable. This process won’t take anywhere near 102us.

- Ben

Sorry, my programming language is a little rusty :unamused: :unamused: :unamused:

Not to worry; I’m glad you’re looking over the code and trying to understand how it works. We’re happy to explain the code, and we definitely want to hear about any potential bugs users think they’ve found.

- Ben