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.1 1_ _8 82 2 1 1_ etc.
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:
# the following code is based on Example 17-4 in the PIC32 family datasheet section 17: # Analog to Digital Converter. The input routine just picks up the value of the ADC # by reading from memory; so the whole consists of three parts: # astart174 sets up the interrupt, and starts the ADC # ainput174 just reads the current value in the memory location # inte23 is the interrupt routine, which copies the completed value from the # ADC result buffer in the SFRs into RAM LatestADC = 0xA0000000 # a location in RAM # start things up. AD1 is interrupt 28, vector 23 # assumes that CPU is already initialized to multi-vector mode astart174: add sp,sp,-8 sw ra,0(sp) # first value is a bogus value addi v0,zero,0b01010000000 # save bogus value in RAM sw v0,LatestADC ori t0,zero,0x8000 sw t0,AD1CON1CLR # turn off AD1. leave bits as set up lui t0,1<<(28-16) # set bit 28 in t0 for INT setup sw t0,IFS0CLR # clear interrupt flag sw t0,IEC0SET # enable interrupt lui t0,0x1e00 #this is bits 28:25 (of 28:24) sw t0,IPC5SET # set AD1IP=7,AD1IS=2 // setup ADC, based on assignments from Example 17-4 in PIC32 Family datasheet // section 17: ADC ori t0,zero,0xE0 # SSRC = 0b111 sw t0,AD1CON1 # store lui t0,0x9 # input from AN9 sw t0,AD1CHS sw zero,AD1CSSL # no scanning addi t0,zero,0x1f02 # is 0x0f00 in example 17-4 sw t0,AD1CON3 # differs from example 17-4 -- see above sw zero,AD1CON2 # differs form example 17-4 -- there 4, here zero // now start ADC running ei # enable interrupts ori t0,zero,0x8000 sw t0,AD1CON1SET # turn on ADC ori t0,zero,4 # ASAM starts sampling sw t0,AD1CON1SET lw ra,0(sp) jr ra addiu sp,sp,8 # pop stack ainput174: lw v0,LatestADC #pick up most recent value jr ra # and return nop # jump here on interrupt inte23: addiu sp,sp,-8 sw k0,4(sp) sw k1,0(sp) la k0,ADC1BUF0 # address of buffer lw k0,0(k0) # content of buffer lui k1,LatestADC>>16 sw k0,0xFFFF&LatestADC(k1) # save for pickup lui k0,1<<(28-16) la k1,IFS0CLR # get address sw k0,0(k1) # clear AD1 interrupt flag in IFS0 lw k0,4(sp) lw k1,0(sp) addiu sp,sp,8 eret # return from interrupt # load the interrupt vector with a reference to the interrupt routine .section .vector_23,code j inte23 nop
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:
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.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
You may want to start with my sample code, which initializes the PIC for I/O and includes the analog input code above.