You are on page 1of 7

Birin Yucesan

Lab 8

Lab 8: ATD and Serial


The purpose of this lab was to create a Digital Voltmeter (DMV) and transmit the
data through a serial port to a computer. The power supply was used to supply the
voltage to be measured. The voltage from the power supply was analog so an analog to
digital conversion was needed. The analog to digital conversion result was then used to
calculate the voltage and sent to a computer through a serial port to be displayed on the
computer monitor using 4 decimal places.


This lab requires an application that will measure the voltage supplied by a power
supply and display it on a computer monitor via the use of a serial port. To solve this
problem a series of steps needed to be taken. The first thing was to set up several
registers. These registers included ADCON0, ADCON1, TXSTA, RCSTA, and SPBRG.
These registers were needed in order to convert the analog signal and output the correct
result at the correct rate to the computer monitor. Also data direction needed to be set up
so that the proper inputs and outputs could be used. The next thing was to determine how
to convert the analog to digital conversion result to a meaningful voltage. The analog to
digital converter produces a 12 bit result however the most significant two bits are always
zero. This makes the range of hex values are from 0x00 to 0x400, or in decimal from 0 to
1023. Using this and the fact that the voltage supplied can only range from 0 volts to 5
volts an equation was created that converted the binary number from the analog to digital
conversion to a voltage value. This process will be explained in the main body. The next
thing was to write the program. The first part of this stage was to read the AD result 128
times and keep a running total of all the conversions. The reason the AD needed to be
averaged is because a potentiometer was used to vary the voltage read by the
microcontroller. The average of the running total was taken by dividing by 128.
However before the result could be divided it needed to be multiplied by 1000 so that the
value would not be truncated. This value was then used to convert to a voltage. This will
also be explained in more detail in the main body. This converted value was then put into
a character array. Multiplying the result by 1000 as stated above gave a decimal number
with for decimal digits. Each one of these digits was stored in the proper index of the
character array. The most significant digit was stored in the zero element. The next digit
was stored in the 2nd element because the first element was a decimal point. This
continued until all decimal numbers were in the array. This array was 6 elements long, 4
for the decimal numbers, 1 for the decimal point, and the last for the carriage return.
Using an array like this allowed values such as 2.343 and 4.893 to be displayed. This
array was outputted to the computer through the use of a for loop. Each element was a
character so it needed to be sent individually to the computer via the serial port. Lastly
the AD conversion was started again and the process began all over again.

Main Body

Converting from AD result to meaningful voltage

As stated above integer arithmetic needed to be performed on the AD result to

convert it to a meaningful value. Since the AD converter provides a 12 bit result where
the most significant 2 bits are always zero the possible range of this result is from 0 to
2^10 – 1 or 0 to 1023 in decimal. Using equation N=Cx where N is the decimal number
from AD conversion, C is the correction factor, and x is the voltage representation of N.
The maximum value of the AD conversion is 1023. This would correspond to 5 volts
because the voltage references were ground and Vdd which is 5 volts. Re-arranging the
equation for C, C=N/x. Plugging in 1023 for N and 5 for x C is found to be 1023/5.
Then solving the equation for x yields x=N/C which equals x=N*5/1023. An average of
N is needed so N equals N/128, before the division occurs N needs to be multiplied by
5000 instead of 5 so bits don't get truncated. Multiplying the equation by an extra factor
of 1000 gives a 4 digit value that can be converted into a decimal number with 3 decimal
places to the right of the decimal point. Leaving the equation x=(5000*N)/(1023*128).


In this program does not have multiple subroutines, in fact it only has the main
function. To better explain the code I will split it up into 4 parts: setting up of registers,
reading the AD conversion, converting the AD result and storing it into an array, and
sending the converted value to the computer.
Since this lab requires the use of the analog to digital converter and the USART
several registers needed to be set up. The registers to set up the AD conversion were
ADCON0 and ADCON1. These set up the AD with the correct processing speed, select
which pin was the analog input, choose the voltage references, set up the pin as an analog
input, and turn on the converter. Next the data direction registers needed to be set up.
Pin AN0 that has the analog input needed to be configured as input by writing a 1 to the
appropriate bit of the TRISA register. Also since the USART is needed PORTC pin 7 was
needed to be an input by writing a 1 to TRISC pin 7 and PORTC pin 6 needed to be an
output by writing a 0 to TRISC pin 6. Lastly since serial communication was used the
registers dealing with data transmission to the computer needed to be set up. The first is
the transmit status and control register (TXSTA). This was used to select asynchronous
mode, 8 bit transmission, and to determine when the data has been transmitted. The next
register was the receive status control register (RCSTA). This register was only needed
to enable the port that the serial communication is on. Lastly a value of 64 needed to be
written to SPBRG so that a baud rate of 9600 was used.
Next the running total of 128 AD conversions needed to be done. This was done
simply within an if statement that would execute 128 times. Each time it would start the
AD conversion, wait for it to be done then add the result to a variable called ADresult.
After the if statement has been executed 128 times ADresult contains the sum of all the
individual AD conversions.
Next this result was converted into a meaningful value as described in the section,
Converting from AD result to meaningful voltage. As stated above the AD result was
converted to a meaningful value that represents a voltage. This value is 4 digits long.
This number needed to be converted to a decimal number however integer arithmetic
does not have decimal places, it truncates the number. This is why the result was
multiplied by 1000 so that a not so obvious method could by used to convert the number.
The process would modulo the number with 10 and store that result in the 4th element of
the array as a character. That result was then divided by 10 so that it was only 3 digits
long. Again the operation modulo 10 was performed and stored that result in the 3rd
element of the character array. This process was repeated to more times where the next
number was stored in the 2nd element of the array and the following digit was stored in
the 0th element of the array. The reason it was not stored in the 1st element is because this
is where the decimal point occurs. The result is that it converted a 4 decimal long
number to a decimal number with decimal point 3 places from the left (i.e. 4356 to
Lastly the converted value needed to be sent to the computer through the serial
port. To do this each character element of the array was written to TXREG 1 at a time.
Before a new character could be sent the previous transmission needed to be complete.
This was done by waiting for the transmit shift register to be empty. This was done in a
for loop that would execute 6 times sending the 0th element first and the 5th element last,
the 5th element being a carriage return.

Using the potentiometer to change the voltage supplied to the microcontroller it
was found that the range displayed on the computer was from zero to five volts which is
correct because that is the range of the power supply. It was also found that the number
displayed would constantly update as the potentiometer was turned up or down (by up or
down I mean allowing a higher voltage or only allowing a lower voltage to be read by the
microcontroller). It was also found that the result displayed was 4 digits long with 3
decimal places to the right of the decimal point which was the desired accuracy.

1) Using the simulator it was found that it outputs a voltage value to the computer
every 6.4189 milliseconds. This is a sampling rate of 1/(6.4189*10^-3 s) which equals a
frequency of 156 Hz.

2) To find out what digital 10-bit value an analog input of 2.3 volts corresponds to
the equation N=Cx needs to be used. As stated earlier C is 1023/5 and x = 2.3 volts.
Plugging these values in N=(1023/5)(2.3) which equals 470 truncated. Converting this to
binary it equals 111010110.

3) The accuracy of the DVM is limited by the number of bits in the AD

conversion. The resolution is 1 divided by the correction factor or 1/C. In this case
C=1023/5 so the accuracy would be 1/(1023/5) which equals 5/1023, an accuracy of
.0048 or 0.48%.

This lab emphasized how to set up registers to perform an AD conversion and

serial communication. When using the hyper terminal on the computer to connect to the
microcontroller it was found that the voltage displayed on the screen would vary from 0
volts to 5 volts. This value would vary anywhere in this range as the potentiometer was
adjusted. The value displayed was converted from the AD result through the equation
x=N/C using integer arithmetic. This value was 4 digits long with a decimal point 3
places from the right (i.e. 3.309). Having a 12 bit result where the upper 2 bits are always
zero gives you a range from 0 to 1023 and an accuracy of .48%. Using the simulator to
determine how long it takes to output one value to the computer it was found that it took
6.4189 milliseconds which is a sampling rate of 156 Hz.
#include <p18f452.h>

void main(void)
char array[6]={'0','.','0','0','0',0x0D};
unsigned char temp=0;
unsigned long int ADresult=0;
unsigned long int average,send;
char i;

ADCON0=0x01; //setting up AD registers to use Fosc/4

//use channel AN0 clear go bit, turn on A/D converter
ADCON1=0b11000000; //right justified, use Fosc/4, set up AN0 as anolog input
//use voltage references as Vdd and Vss
TRISAbits.TRISA0=1; //make RA0 an input
TRISCbits.TRISC7=1; //make portC pin 7 input
TRISCbits.TRISC6=0; //make portC pint 6 output
TXSTA=0b00100010; //set up in asynchronous mode
SPBRG=64; //set baud rate at 9600 bits per second

for(i=12;i>0;i--); //wait acquisition time


if(temp<128) //store 128 results of AD conversion

ADCON0bits.GO=1; //start AD conversion
while(ADCON0bits.GO); //wait for conversion to be done
ADresult+=ADRESL; //add result to ADresult
ADresult+=((unsigned int)ADRESH<<8);
for(i=2;i>0;i--) //wait acquisition time
_asm NOP _endasm;
_asm NOP _endasm;
_asm NOP _endasm;
/*using equation N=Cx where N is the number from AD conversion,
C is the correction factor and x is the voltage representation
of N. C is found to be 1023/5. Then solving for x=N/C which
equals x=N*5/1023. But an average of N is needed so N equals N/128
and need to multiply by 5000 instead of 5 so bits don't get
truncated. Leaving the equation x=(5000*N)/(1023*128)*/

send= ((unsigned long int)5000) * ((unsigned long int)ADresult);

send= send / 130944;
array[4]=send%10 + '0'; //store appropriate char into array
array[3]=send%10 + '0';
array[2]=send%10 + '0';
array[0]=send%10 + '0';
while(!PIR1bits.TXIF); //wait for char to be send
TXREG=array[i]; //send i'th element of array
ADCON0bits.GO=1; //start another AD conversion