## lab7 -- interrupts

In this lab, we'll implement a not-very useful voltmeter, with a range of of 0-3.3V and a maximum accuracy of one part in 1000, using the same hardware we used for lab6. The voltmeter will continuously measure the voltage on pin 26 of the PIC32MX110F016B, and display the voltage as three decimal digits, with the units digit separated from the tenths by an underscore. So if the measured voltage is 1.82V, the display will read
1 1_ _8 82 2 1 1_ etc.
You worked out display code for lab6. For this lab, we need two additional components, the setup and interrupt routines for the analog-to-digital converter built into the the microcontroller, and the arithmetic routines to convert from the internal representation into three-digit decimal numbers.

The PIC ADC is a successive-approximation converter. It uses a built in digital to analog converter and a comparator to do a binary search for the analog value. Each step of the search takes a fixed amount of time, and there are twelve steps involved in obtaining a 10-bit value.

To use the ADC, you set up various parameters, as described in The ADC manual and, to a lesser extent, in the The PIC32MX110/220 Family manual. You wait until the conversion finishes, and then you can read out the result. You can either wait with a polling loop, checking the DONE bit until the ADC turns it on, or you can set up an interrupt routine to execute when that happens. Once the DONE bit comes on, you can read the result and restart the conversion. If you use interrupts, you may also need The interrupt controller manual.

In our case, we don't have a lot of other things to do, but that polling loop is a waste of CPU time. If you had a lot of computation to do, you would want to avoid using extra cycles on it.

Here is some sample code, based on the ADC manual, which uses an interrupt:

### Fixed-point arithmetic

The ADC can format the ten data bits in a variety of ways, according to the three FORM bits in AD1CON1. In the example above, the FORM bits are set to 000, so the data is returned as a ten-bit positive binary integer with a value between 0000000000 and 1111111111 (or zero and 1023.) A value of zero corresponds to a voltage of zero, and a value of 1023 corresponds to a voltage of just under 3.3 V. One way of thinking about this integer is as a binary fraction, with the binary point in front of the first bit, so that the fraction ranges from .0000000000 to .1111111111 (0.0 to .999)

If you were to multiply that fraction by 330, you'd get an integer value corresponding to the three digits you need to display (but of course followed by ten bits of fraction.) You could mask and shift out the integer, then do appropriate divides to figure out the hundreds, tens, and units places to display.

A simpler scheme would be to multiply the fraction by 3.3; then the integer part would be the integer part of the final answer, and dropping the integer part of the result and multiplying the resulting intermediate fraction by ten would give then next digit, and you can get the third digit by repeating the process another time. In pseudo-code:

t = ADCvalue * 0x34CD // 0x34CD is 3.3 with the hex point between the 3 and 4 // binary point in result will give 22 bit fraction d1 = t>>22 // discard fraction for first decimal digit t &= 0x3FFFFF // discard integer part t *= 10 d2 = t>>22 // discard 22-bit fraction to get 2nd digit t &= 0x3FFFFF // discard integer part; t *= 10 // multiply by ten again. d3 = t>>22 // discard fraction to get third digit
Once you have digit values, you need to convert them to seven-segment display values. A convenient way to do this is by indexing a table of bytes, each one containing the bits to drive a single digit.