0% found this document useful (0 votes)
117 views

How Do I Use An ADC Peripheral?: HI or LO. For Example, The Button Is Pushed and The

The document describes how to use an analog-to-digital converter (ADC) peripheral to convert analog sensor voltages to digital values that a microcontroller can process. It explains that ADCs convert analog voltages to binary numbers represented as fractions of the microcontroller's power supply voltage. It provides examples of converting specific analog voltages to their equivalent 12-bit binary values using a 3.3V power supply. It also includes sample code that initializes an ADC peripheral, continuously reads conversion results, and illuminates an LED if the result exceeds a threshold voltage.

Uploaded by

patelgaus
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
117 views

How Do I Use An ADC Peripheral?: HI or LO. For Example, The Button Is Pushed and The

The document describes how to use an analog-to-digital converter (ADC) peripheral to convert analog sensor voltages to digital values that a microcontroller can process. It explains that ADCs convert analog voltages to binary numbers represented as fractions of the microcontroller's power supply voltage. It provides examples of converting specific analog voltages to their equivalent 12-bit binary values using a 3.3V power supply. It also includes sample code that initializes an ADC peripheral, continuously reads conversion results, and illuminates an LED if the result exceeds a threshold voltage.

Uploaded by

patelgaus
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd
You are on page 1/ 37

How Do I Use an ADC Peripheral?

1. As we have previously seen, digital inputs and outputs are associated with binary states: YES or
NO, ON or OFF, TRUE or FALSE, and HI or LO. For example, the button is pushed and the
light is on.

In our world, however, there is often a wide range of values that we need to consider. Instead of
the weather being hot or cold, we look at a large spectrum of different temperatures.

2. When we build embedded systems, we can use sensors that convert a physical parameter (like
temperature or mass) and convert it into a voltage that is proportional to the parameter we are
measuring. For example, a temperature sensor may output:

If the temperature was -40C, the sensor would output 0V.

If the temperature was +100C, the sensor would output +3V.

Since the temperature can vary continually across the -40C to +100C range, the sensor output
voltages will also vary continually across the 0V to +3V range. Temperatures between -40C and
+100C would generate outputs that could be interpolated from the minimum and maximum
values. For example, if a temperature was +30C (half-way between -40C and +100C), the sensor
output would be half-way between the two limits, or +1.5V.

In this way, we say that the output voltage of the sensor is analogous to the temperature that is
being measured, and we consider voltages that can vary across a range continuously as analog
voltages.

3. A microcontroller’s digital inputs, however, cannot properly work with analog voltages. They are
simply looking for HI or LO values. For this reason, embedded systems use analog-to-digital
converters that translate analog voltages into digital (or binary) equivalents that the
microcontroller can process.

Page 1 of 37
4. An analog-to-digital converter (ADC) is a peripheral that takes an analog voltage and
converts it to a binary “equivalent.”

5. The MSP430FR6989 microcontroller that we are using has a 12-bit ADC peripheral. This means
that any analog voltage that is converted to its binary equivalent will be 12-bits long.

6. Just like we saw with binary numbers a long time ago, the ADC peripheral will work with
numbers that are powers of 2.

7. Here was one of our first examples of working with binary numbers: 1110101B has the decimal
equivalent of 26 + 25 + 24 + 22 + 20 = 117.

8. ADC peripherals continue the same power of 2 counting method, but this time, they use negative
powers of 2:

2-1 2-2 2-3 2-4 2-5 2-6 2-7 2-8 2-9 2-10 2-11 2-12

Page 2 of 37
9. If we expand the negative powers of 2 into fractions, we get:

10. The analog value that is to be converted is then expressed as a fraction of the microcontroller’s
power supply voltage.

For example, on our MSP430FR6989 Launchpad, the supply voltage is 3.3V.

If we had an analog input voltage of 1.65V (half of the supply voltage), we would expect that the
ADC peripheral provide a binary equivalent of 1000 0000 0000B.

11. What happens if we have an ADC input of 1V? In this case, the analog input is not a simple
fraction:

1V / 3.3V ≈ 0.30303

There is no combination of the fractions 2-1 to 2-12 that exactly sum to 0.30303…. In this case, the
ADC peripheral provides us with an approximate binary equivalent:

1 1 1 1 1 1
0.30303 ≈ 4 + 32 + 64 + 256 + 512 + 4096 = 0.302978515625

0.30303 ≈ 2-2 + 2-5 +2-6 +2-8 +2-9 +2-12 = 0.302978515625

0.30303 ≈ 0100 1101 1001B = 0.302978515625

Therefore, we would expect that for an input of 1V and a 3.3V supply voltage, the ADC
peripheral output would approximately be the binary equivalent of 0100 1101 1001B.

We say approximately because ADCs will always have some small amount of error. The exact
amount of error is usually impossible to determine, and will vary from microcontroller to
microcontroller. However, for a 12-bit ADC, we would expect that the amount of error would be
less than 1%.

Page 3 of 37
12. Ok, one more example. What if the ADC peripheral output was a binary equivalent of
1100 1100 0000B?

If we have the same 3.3V power supply, we would find that the analog input voltage was:

1 1 1 1
1100 1100 0000B = + + + = 79.6875%
2 4 32 64

3.3V * 79.6875% ≈2.63V

13. The program on the next page shows you how the ADC peripheral can be setup and used. We
will go through the program step-by-step in the next several pages.

In short, after the ADC peripheral is initialized, the peripheral is enabled and started.

After the conversion process is started, the program continuously monitors the 12-bit conversion
result (stored in a 16-bit register called ADC12MEM0). If the result is more than half of the
power supply value (1.65V or 50% of 3.3V), the red LED is illuminated. If not, the red LED is
turned off.

The process repeats continuously.

Page 4 of 37
#include <msp430.h>
#define ENABLE_PINS 0xFFFE // Enables inputs and outputs
void ADC_SETUP(void); // Used to setup ADC12 peripheral

main()
{
WDTCTL = WDTPW | WDTHOLD; // Stop WDT
PM5CTL0 = ENABLE_PINS; // Enable inputs and outputs
P1DIR = BIT0; // Set RED LED to output

ADC_SETUP(); // Sets up ADC peripheral

while(1)
{
ADC12CTL0 = ADC12CTL0 | ADC12ENC; // Enable conversion
ADC12CTL0 = ADC12CTL0 | ADC12SC; // Start conversion

// Looking for threshold of 50% of 3.3V


// with binary equivalent of
// 1000 0000 0000B = 0x8000

if (ADC12MEM0 > 0x800) // If input > 1.65V


{
P1OUT = BIT0; // Turn on red LED
}

else // Else input <= 1.65V


{
P1OUT = 0x00; // Turn off red LED
}

}// end while(1)

}// end main()

//************************************************************************
//* Configure Analog-to-Digital Converter peripheral**********************
//************************************************************************
void ADC_SETUP(void)
{
#define ADC12_SHT_16 0x0200 // 16 clock cycles for sample and hold
#define ADC12_ON 0x0010 // Used to turn ADC12 peripheral on
#define ADC12_SHT_SRC_SEL 0x0200 // Selects source for sample & hold
#define ADC12_12BIT 0x0020 // Selects 12-bits of resolution
#define ADC12_P92 0x000A // Use input P9.2 for analog input

ADC12CTL0 = ADC12_SHT_16 | ADC12_ON ; // Turn on, set sample & hold time
ADC12CTL1 = ADC12_SHT_SRC_SEL; // Specify sample & hold clock source
ADC12CTL2 = ADC12_12BIT; // 12-bit conversion results
ADC12MCTL0 = ADC12_P92; // P9.2 is analog input
}

Page 5 of 37
14. As in many of our previous programs, this one starts by disabling the WDT peripheral, and
making P1.0 an output.

WDTCTL = WDTPW | WDTHOLD; // Stop WDT


PM5CTL0 = ENABLE_PINS; // Enable inputs and outputs
P1DIR = BIT0; // Set RED LED to output

15. Next, we have a function that is used to setup the ADC peripheral. It does not need any input or
output.

ADC_SETUP(); // Sets up ADC peripheral

16. The ADC_SETUP() function begins with a list of labels that are #defined. These are all
labels that we have created to make the next several instructions a little more intuitive.

//************************************************************************
//* Configure Analog-to-Digital Converter peripheral**********************
//************************************************************************
void ADC_SETUP(void)
{
#define ADC12_SHT_16 0x0200 // 16 clock cycles for sample and hold
#define ADC12_ON 0x0010 // Used to turn ADC12 peripheral on
#define ADC12_SHT_SRC_SEL 0x0200 // Selects source for sample & hold
#define ADC12_12BIT 0x0020 // Selects 12-bits of resolution
#define ADC12_P92 0x000A // Use input P9.2 for analog input

17. The rest of the function includes all the instructions that set-up the ADC peripheral. The ADC
has more features than most other peripherals in the microcontroller, and it has many, many
different modes of operation. In fact, it has about 100 different control registers! Don’t worry -
the four instructions below place the peripheral into its simplest mode

ADC12CTL0 = ADC12_SHT_16 | ADC12_ON ; // Turn on, set sample & hold time
ADC12CTL1 = ADC12_SHT_SRC_SEL; // Specify sample&hold clock source
ADC12CTL2 = ADC12_12BIT; // 12-bit conversion results
ADC12MCTL0 = ADC12_P92; // P9.2 is analog input

Page 6 of 37
18. The first instruction sets the bits inside the 12-bit ADC ConTroL register 0 (ADC12CTL0) to do
two things. First, the ADC peripheral is turned on (ADC12_ON).

ADC12CTL0 = ADC12_SHT_16 | ADC12_ON ; // Turn on, set sample & hold time

19. Additionally, the first instruction specifies how long the ADC will “look” at the analog input
before starting the conversion (ADC12_SHT_16). This “look” time is referred to as the Sample
and Hold Time.

Sample and Hold Time refers to the amount of time that the ADC peripheral captures or grabs the
analog input voltage and then holds it in place at a constant level so the conversion can be
performed. This is often required in embedded systems because many analog input voltages we
are trying to convert vary over time. Some vary quite slowly (like temperature and battery
voltage), while others can vary quite quickly. As I said before, there are many, many different
options for the ADC peripheral, but the Sample and Hold Time 16 represents a good compromise
in speeds vs. accuracy. (It uses 16 clock cycles.)

20. The second instruction used to setup the ADC peripheral sets the bits in the 12-bit ADC ConTroL
register 1 (ADC12CTL1) to specify how the sample and hold clock source is selected. Again,
there are different options that could be used, but this one works well for most applications.

ADC12CTL1 = ADC12_SHT_SRC_SEL; // Specify sample & hold clock source

21. The third instruction used specifies that we want a full 12-BIT binary equivalent of our analog
input voltage. This is specified as the resolution of the ADC peripheral.

In many microcontrollers, you can specify a lower resolution binary equivalent if you want to
speed up the conversion process. For the MSP430FR6989, however, the 12-bit output only takes
approximately 0.00001 seconds (10µs), so we will not worry about speeding the conversion up.

ADC12CTL2 = ADC12_12BIT; // 12-bit conversion results

Page 7 of 37
22. Finally, the fourth instruction specifies which microcontroller pin will be used for the conversion.
In this case, we will use pin P9.2.

ADC12MCTL0 = ADC12_P92; // P9.2 is analog input

23. The microcontroller then returns to main() and enters a while(1) loop.

The loop begins by setting a bit inside the 12-bit ADC ConTroL register 0 (ADC12CTL0) to
ENable a Conversion.

After that, another bit is set in ADC12CTL0 to actually Start the Conversion.

while(1)
{
ADC12CTL0 = ADC12CTL0 | ADC12ENC; // Enable conversion
ADC12CTL0 = ADC12CTL0 | ADC12SC; // Start conversion

// Looking for threshold of 50% of 3.3V


// with binary equivalent of
// 1000 0000 0000B = 0x8000

}// end while(1)

24. Note, these two instructions could actually be combined into a single instruction.

ADC12CTL0 = ADC12CTL0 | ADC12ENC | ADC12SC; // Enable & start conversion

However, we have kept them as two separate instructions for our explanations.

In any case, you cannot simply do this:

ADC12CTL0 = ADC12ENC | ADC12SC; // Enable & start conversion

If you simply assign the new value to ADC12CTL0, you will clear the ADC12_ON bit we set in the
function and turn off the ADC peripheral altogether.

Page 8 of 37
25. After the ADC conversion starts, the program continuously ensures that the peripheral has
enabled/started and observes the binary equivalent output.

To observe the binary equivalent output, we look at the least-significant 12-bits of the
ADC12MEM0 register. For our example, if the binary equivalent is above 1000 000 0000B (or
50% of the 3.3V power supply), the red LED will be turned on. Otherwise, the red LED will be
turned off.

While not exactly eloquent, the program works, and that’s all we want for right now. We will
improve it in a couple pages.

while(1)
{
ADC12CTL0 = ADC12CTL0 | ADC12ENC; // Enable conversion
ADC12CTL0 = ADC12CTL0 | ADC12SC; // Start conversion

// Looking for threshold of 50% of 3.3V


// with binary equivalent of
// 1000 0000 0000B = 0x8000

if (ADC12MEM0 > 0x800) // If input > 1.65V


{
P1OUT = BIT0; // Turn on red LED
}

else // Else input <= 1.65V


{
P1OUT = 0x00; // Turn off red LED
}

}// end while(1)

26. Create a new CCS project called ADC. Copy and paste the entire program from above into your
new main.c file.

27. Save, Build, and launch the CCS Debugger. Do NOT run your program yet, however. We
still need to build your circuit!

Page 9 of 37
28. To build the circuit, you will need a 470 resistor, the potentiometer, three male-female wire
jumpers (we used red, black, and brown), and the protoboard.

29. Plug the 470 resistor into holes (b,1) and (f,1) of the protoboard.

30. Plug the 2-pins of the short end of the potentiometer into (i,1) and (j,1). This should then align
the opposite short end single pin into hole (j,30).

Page 10 of 37
31. Plug the female end of the red wire jumper on the 3V3 pin in the lower right-hand corner of the
Launchpad.

Plug the female end of the black wire jumper on the GND pin in the lower right-hand corner of the
Launchpad.

32. Plug the male end of the red wire jumper into hole (a,1) on the protoboard.

Page 11 of 37
33. Plug the male end of the black wire jumper into hole (f,30) on the protoboard.

34. All that is left is to connect the P9.2 analog input pin to the circuit.

Plug the female end of the brown wire jumper on the P9.2 pin on the left side of the Launchpad.

Page 12 of 37
35. Plug the male end of the brown wire jumper into hole (g,1) on the protoboard.

36. That is it. You are ready to go! : )

Go ahead and start your program in the CCS Debugger.

Now, as you move the potentiometer slider up and down, the red LED should turn on and off.

Your ADC peripheral is working!

37. Now, if the P1.0 red LED is not turning on or off, it is probably not an issue with the
microcontroller, the ADC peripheral, or your program.

Instead, you probably have an issue with the circuit you just build. Microcontrollers and their
peripherals and their program are remarkably robust devices. It is much more likely that there is
a wiring error on your protoboard that you just put together, or that one of the wires or pins has
come loose.

Page 13 of 37
38. When everything is working correctly, notice that there is a threshold at the point that the red
LED turns on. Move the slider in one direction, and the red LED is strongly on. Move the slider
in the opposite direction, and the red LED will be off.

However, over a very narrow range, even when the slider is stationary that the red LED will
either appear dim or look like it is blinking on and off. This is due to variations in the conversion
process.

In CCS, click Suspend to momentarily pause your program.

39. In the Registers pane, expand the ADC12 list.

Page 14 of 37
40. Scroll down through the ADC12 Registers. There is a lot of them, so be patient. Eventually,
you will find the ADC12MEM0 register that holds the binary equivalent.

On my board, while the LED was flickering, the value stored in the ADC12MEM0 register was
0x07F4. Your value will probably not be the same, but it should be close to 0x0800.

41. The 0x07F4 stored in ADC12MEM0 is very close to the 0x800 value we are using as a threshold.

0x07F4 0111 1111 0100 → 50.000%


0x0800 1000 0000 0000 → 49.707%

This helps to demonstrate the slight amount of variation you can expect from an ADC reading.

42. When you are ready, click Terminate to return to the CCS Editor.

Page 15 of 37
43. As mentioned above, this particular program was effective at demonstrating how the ADC works,
even if it was not very eloquent.

The program below improves upon our previous program and uses an interrupt service routine.

#include <msp430.h>
#define ENABLE_PINS 0xFFFE

void ADC_SETUP(void); // Used to setup ADC12 peripheral

main()
{
WDTCTL = WDTPW | WDTHOLD; // Stop WDT
PM5CTL0 = ENABLE_PINS; // Enable inputs and outputs
P1DIR = BIT0; // Set red LED to output

ADC_SETUP(); // Sets up ADC peripheral

ADC12IER0 = ADC12IE0; // Enable ADC interrupt

_BIS_SR(GIE); // Activate interrupts

ADC12CTL0 = ADC12CTL0 | ADC12ENC; // Enable conversion


ADC12CTL0 = ADC12CTL0 | ADC12SC; // Start conversion

while(1);
}

//************************************************************************
//* ADC12 Interrupt Service Routine***************************************
//************************************************************************
#pragma vector = ADC12_VECTOR
__interrupt void ADC12_ISR(void)
{
if(ADC12MEM0 > 0x800) // If input > 1.65V (50%)
{
P1OUT = BIT0; // Turn red LED on
}
else // Else input <= 1.65V
{
P1OUT = 0x00; // Turn red LED off
}

ADC12CTL0 = ADC12CTL0 | ADC12SC; // Start next conversion


}

Page 16 of 37
44. The program begins as before by disabling the WDT peripheral and enabling P1.0 to be an
output.

WDTCTL = WDTPW | WDTHOLD; // Stop WDT


PM5CTL0 = ENABLE_PINS; // Enable inputs and outputs
P1DIR = BIT0; // Set red LED to output

45. This is followed by the ADC_SETUP() function. This function is unchanged from our previous
program.

ADC_SETUP(); // Sets up ADC peripheral

46. After setting up the ADC peripheral, we next enable and activate the pertinent ADC interrupt.
(As mentioned above, the ADC peripheral on the MSP430FR6989 has many, many features and
many, many different types of interrupts. This one here, however, takes care of the basic
functionality you might expect. An interrupt will be generated whenever an ADC conversion is
complete.

ADC12IER0 = ADC12IE0; // Enable ADC interrupt

_BIS_SR(GIE); // Activate interrupts

47. Finally, we enable the conversion process and start the first conversion. The program is then put
into an infinite loop to wait for the interrupt service routine.

ADC12CTL0 = ADC12CTL0 | ADC12ENC; // Enable conversion


ADC12CTL0 = ADC12CTL0 | ADC12SC; // Start conversion

while(1);

Page 17 of 37
48. Below we have repeated the interrupt service routine.

The ISR begins by simply checking the result of the just completed conversion. If the result is
above 0x800, the red LED is turned on. Otherwise, the red LED is turned off.

The last instruction in the ISR simply starts the next conversion. The ISR then ends, and the
microcontroller returns to the main() function until the just started conversion is complete.

#pragma vector = ADC12_VECTOR


__interrupt void ADC12_ISR(void)
{
if(ADC12MEM0 > 0x800) // If input > 1.65V (50%)
{
P1OUT = BIT0; // Turn red LED on
}
else // Else input <= 1.65V
{
P1OUT = 0x00; // Turn red LED off
}

ADC12CTL0 = ADC12CTL0 | ADC12SC; // Start next conversion


}

49. Create a new CCS project called ADC_ISR. Copy and paste the entire program from above into
your new main.c file.

50. Save, Build, and launch the CCS Debugger.

51. Make sure your circuit is still connected.

52. Run your program and verify the program works as expected.

Page 18 of 37
53. When you are ready, click Terminate to return to the CCS Editor.

54. So, now you have a well-functioning ADC program, using an ISR, that you can modify as needed
to acquire analog data for your embedded system.

But, what happens if you do not want to use pin P9.2?

Our Launchpad features the 100-pin version of the microcontroller, and therefore, has 16 analog
inputs. However, not all 16 analog inputs are accessible with the 40 male-pin connectors.

Only 40 pins easily accessible on the Launchpad

Page 19 of 37
55. On our Launchpad, the following pins can be used for analog inputs:

P8.4, P8.5, P8.6, P8.7 and P9.0, P9.1, P9.2, P9.3, P9.5, P9.6

P8.4 P9.0
P8.5 P9.1
P8.6 P9.2
P8.7 P9.3
P9.5
P9.6

56. Below, we have rewritten the ADC_SETUP() function to include #define statements for the
other analog inputs. Now, you only need to change one line (highlighted) to change the pin used
for the analog input. For example, below we have selected to use P8.7.

//***********************************************************************************
//* Configure Analog-to-Digital Converter peripheral*********************************
//***********************************************************************************
void ADC_SETUP(void)
{
#define ADC12_SHT_16 0x0200 // 16 clock cycles for sample and hold
#define ADC12_ON 0x0010 // Used to turn ADC12 peripheral on
#define ADC12_SHT_SRC_SEL 0x0200 // Selects source for sample & hold
#define ADC12_12BIT 0x0020 // Selects 12-bits of resolution

#define ADC12_P84 0x0007 // Use input P8.4 for analog input


#define ADC12_P85 0x0006 // Use input P8.5 for analog input
#define ADC12_P86 0x0005 // Use input P8.6 for analog input
#define ADC12_P87 0x0004 // Use input P8.7 for analog input

#define ADC12_P90 0x0008 // Use input P9.0 for analog input


#define ADC12_P91 0x0009 // Use input P9.1 for analog input
#define ADC12_P92 0x000A // Use input P9.2 for analog input
#define ADC12_P93 0x000B // Use input P9.3 for analog input
#define ADC12_P95 0x000D // Use input P9.5 for analog input
#define ADC12_P96 0x000E // Use input P9.6 for analog input

ADC12CTL0 = ADC12_SHT_16 | ADC12_ON ; // Turn on, set sample & hold time
ADC12CTL1 = ADC12_SHT_SRC_SEL; // Specify sample & hold clock source
ADC12CTL2 = ADC12_12BIT; // 12-bit conversion results
ADC12MCTL0 = ADC12_P87; // P8.7 is analog input
}

Page 20 of 37
57. Finally, we need to consider how to use multiple analog inputs in one program.

Even though the microcontroller has 16 analog inputs (with 10 of them readily available on the
Launchpad), it still only has one ADC peripheral. ADC peripherals are actually relatively
expensive to implement on a microcontroller, so all the different analog inputs have to take turns
sharing the ADC peripheral – one at a time.

In the next program, we will switch between two different analog inputs.

58. The program begins as before by disabling the watchdog timer and enabling the input and output
pins. We also make pins P1.0 (red LED) and P9.7 (green LED) outputs.

main()
{
WDTCTL = WDTPW | WDTHOLD; // Stop WDT
PM5CTL0 = ENABLE_PINS; // Enable inputs and outputs

P1DIR = BIT0; // Set red LED to output


P9DIR = BIT7; // Set green LED to output

59. We then call the ADC_SETUP() function.

ADC_SETUP(); // Sets up ADC peripheral

Page 21 of 37
60. The ADC_SETUP() function is unchanged from before, except we select P8.4 to be our first
analog input.

//************************************************************************
//* Configure Analog-to-Digital Converter peripheral**********************
//************************************************************************
void ADC_SETUP(void)
{
#define ADC12_SHT_16 0x0200 // 16 clock cycles for sample and hold
#define ADC12_ON 0x0010 // Used to turn ADC12 peripheral on
#define ADC12_SHT_SRC_SEL 0x0200 // Selects source for sample & hold
#define ADC12_12BIT 0x0020 // Selects 12-bits of resolution

#define ADC12_P84 0x0007 // Use input P8.4 for analog input


#define ADC12_P85 0x0006 // Use input P8.5 for analog input
#define ADC12_P86 0x0005 // Use input P8.6 for analog input
#define ADC12_P87 0x0004 // Use input P8.7 for analog input

#define ADC12_P90 0x0008 // Use input P9.0 for analog input


#define ADC12_P91 0x0009 // Use input P9.1 for analog input
#define ADC12_P92 0x000A // Use input P9.2 for analog input
#define ADC12_P93 0x000B // Use input P9.3 for analog input
#define ADC12_P95 0x000D // Use input P9.5 for analog input
#define ADC12_P96 0x000E // Use input P9.6 for analog input

ADC12CTL0 = ADC12_SHT_16 | ADC12_ON ; // Turn on, set sample & hold time
ADC12CTL1 = ADC12_SHT_SRC_SEL; // Specify s & h clock source
ADC12CTL2 = ADC12_12BIT; // 12-bit conversion results
ADC12MCTL0 = ADC12_P84; // P8.4 is analog input
}

61. After the ADC_SETUP() function, the program returns to main() and the ADC interrupt is
enabled and activated.

ADC12IER0 = ADC12IE0; // Enable ADC interrupt


_BIS_SR(GIE); // Activate interrupts

62. We then enable the ADC peripheral and start the first conversion. The program then waits.

ADC12CTL0 = ADC12CTL0 | ADC12ENC; // Enable conversion


ADC12CTL0 = ADC12CTL0 | ADC12SC; // Start conversion

while(1);

Page 22 of 37
63. When the first conversion is complete, the program jumps to the ADC ISR.

At the top of the ISR, we have two #define statements repeated, one for each of the analog
input channels we will used, P8.4 and P9.2. These were previously included in the
ADC_SETUP() function, but the ADC ISR needs to “see” them locally.

Next, we define a static variable input which we will give either a value of 84 (if the conversion
that was just completed came from P8.4) or 92 (if the conversion that was just completed from
P9.2).

Since we started the first conversion on P8.4, the variable is initialized the first time to 84.

Because the variable is static, it will retain its contents each time we return to the ISR.

//************************************************************************
//* ADC12 Interrupt Service Routine***************************************
//************************************************************************
#pragma vector = ADC12_VECTOR
__interrupt void ADC12_ISR(void)
{
#define ADC12_P84 0x0007 // Use input P8.4 for analog input
#define ADC12_P92 0x000A // Use input P9.2 for analog input

static unsigned char input = 84; // input = 84 if P8.4 sampled


// = 92 if P9.2 sampled

Page 23 of 37
64. The next section of the ISR first has to determine which ADC input was just used. It does this by
using an if statement to check the value of the variable input.

If the input was from P8.4, the program will then check the value of the ADC conversion in
ADC12MEM0 register. If the output was greater than 1.65V, the red LED is turned on. If the
output as less than or equal to 1.65V, the red LED is turned off.

After the red LED is turned on or off, we update the variable input to reflect that the next analog
conversion will be performed on the pin P9.2 analog voltage. Again, we will use this value of
input when we return next time to the ISR.

Finally, we need to tell the ADC to actually move the conversion from P8.4 to P9.2. To do this,
however, we must first disable the ADC peripheral. This is just the way that TI designed the
ADC. We cannot change in the ADC input while the peripheral is enabled. After we clear the
ADC12ENC bit in the ADC12CTL0 register, we can then update the peripheral with the new input
pin.

if(input == 84) // If sample was from P8.4


{
if (ADC12MEM0 > 0x800) // If input > 1.65V (50%)
If the input was P8.4

{
P1OUT = BIT0; // Turn red LED on
}
else // Else input <= 1.65V
{
P1OUT = 0x00; // Turn red LED off
}

input = 92; // Next sample from P9.2

ADC12CTL0 = ADC12CTL0 & (~ADC12ENC); // Need to disable peripheral


ADC12MCTL0 = ADC12_P92; // to change to input P9.2
}

else // Else, sample was from P9.2


{
if (ADC12MEM0 > 0x800) // If input > 1.65V (50%)
{
If the input was P9.2

P9OUT = BIT7; // Turn green LED on


}
else // Else input <= 1.65V
{
P9OUT = 0x00; // Turn green LED off
}

input = 84; // Next sample from P8.4

ADC12CTL0 = ADC12CTL0 & (~ADC12ENC); // Need to disable peripheral


ADC12MCTL0 = ADC12_P84; // to change to input P8.4
}

Page 24 of 37
65. The process is repeated is the input was from P9.2. The program will then check the value of the
ADC conversion in ADC12MEM0 register. If the output was greater than 1.65V, the green LED is
turned on. If the output as less than or equal to 1.65V, the green LED is turned off.

After the green LED is turned on or off, we update the variable input to reflect that the next
analog conversion will be performed on the pin P8.4 analog voltage. Again, we will use this
value of input when we return next time to the ISR.

Finally, we need to tell the ADC to actually move the conversion from P9.2 to P8.4. To do
this, however, we must first disable the ADC peripheral. This is just the way that TI designed the
ADC. We cannot change in the ADC input while the peripheral is enabled. After we clear the
ADC12ENC bit in the ADC12CTL0 register, we can then update the peripheral with the new input
pin.

if(input == 84) // If sample was from P8.4


{
if (ADC12MEM0 > 0x800) // If input > 1.65V (50%)
If the input was P8.4

{
P1OUT = BIT0; // Turn red LED on
}
else // Else input <= 1.65V
{
P1OUT = 0x00; // Turn red LED off
}

input = 92; // Next sample from P9.2

ADC12CTL0 = ADC12CTL0 & (~ADC12ENC); // Need to disable peripheral


ADC12MCTL0 = ADC12_P92; // to change to input P9.2
}

else // Else, sample was from P9.2


{
if (ADC12MEM0 > 0x800) // If input > 1.65V (50%)
{
If the input was P9.2

P9OUT = BIT7; // Turn green LED on


}
else // Else input <= 1.65V
{
P9OUT = 0x00; // Turn green LED off
}

input = 84; // Next sample from P8.4

ADC12CTL0 = ADC12CTL0 & (~ADC12ENC); // Need to disable peripheral


ADC12MCTL0 = ADC12_P84; // to change to input P8.4
}

Page 25 of 37
66. Finally, after changing the input channel for the next conversion, the program re-enables the ADC
peripheral and starts another conversion before ending the ISR and returning to main().

ADC12CTL0 = ADC12CTL0 | ADC12ENC; // Re-enable conversion


ADC12CTL0 = ADC12CTL0 | ADC12SC; // Start next conversion
}

67. Create a new CCS project called ADC_2_Inputs_ISR. Copy and paste the program from the
next three pages into your new main.c file.

68. Save and Build your program. Click the Debugger, but do NOT start your program yet. We
need to create our analog circuit to test the program.

Page 26 of 37
#include <msp430.h>
#define ENABLE_PINS 0xFFFE

void ADC_SETUP(void); // Used to setup ADC12 peripheral

main()
{
WDTCTL = WDTPW | WDTHOLD; // Stop WDT
PM5CTL0 = ENABLE_PINS; // Enable inputs and outputs
P1DIR = BIT0; // Set red LED to output
P9DIR = BIT7;

ADC_SETUP(); // Sets up ADC peripheral

ADC12IER0 = ADC12IE0; // Enable ADC interrupt

_BIS_SR(GIE); // Activate interrupts

ADC12CTL0 = ADC12CTL0 | ADC12ENC; // Enable conversion


ADC12CTL0 = ADC12CTL0 | ADC12SC; // Start conversion

while(1);
}

Page 27 of 37
//************************************************************************
//* ADC12 Interrupt Service Routine***************************************
//************************************************************************
#pragma vector = ADC12_VECTOR
__interrupt void ADC12_ISR(void)
{
#define ADC12_P84 0x0007 // Use input P8.4 for analog input
#define ADC12_P92 0x000A // Use input P9.2 for analog input

static unsigned char input = 84; // input = 84 if P8.4 sampled


// = 92 if P9.2 sampled

if(input == 84) // If sample was from P8.4


{
if (ADC12MEM0 > 0x800) // If input > 1.65V (50%)
{
P1OUT = BIT0; // Turn red LED on
}
else // Else input <= 1.65V
{
P1OUT = 0x00; // Turn red LED off
}

input = 92; // Next sample from P9.2

ADC12CTL0 = ADC12CTL0 & (~ADC12ENC); // Need to disable peripheral


ADC12MCTL0 = ADC12_P92; // to change to input P9.2
}

else // Else, sample was from P9.2


{
if (ADC12MEM0 > 0x800) // If input > 1.65V (50%)
{
P9OUT = BIT7; // Turn red LED on
}
else // Else input <= 1.65V
{
P9OUT = 0x00; // Turn red LED off
}

input = 84; // Next sample from P8.4

ADC12CTL0 = ADC12CTL0 & (~ADC12ENC); // Need to disable peripheral


ADC12MCTL0 = ADC12_P84; // to change to input P8.4
}

ADC12CTL0 = ADC12CTL0 | ADC12ENC; // Re-enable conversion


ADC12CTL0 = ADC12CTL0 | ADC12SC; // Start next conversion
}

Page 28 of 37
//************************************************************************
//* Configure Analog-to-Digital Converter peripheral**********************
//************************************************************************
void ADC_SETUP(void)
{
#define ADC12_SHT_16 0x0200 // 16 clock cycles for sample and hold
#define ADC12_ON 0x0010 // Used to turn ADC12 peripheral on
#define ADC12_SHT_SRC_SEL 0x0200 // Selects source for sample & hold
#define ADC12_12BIT 0x0020 // Selects 12-bits of resolution

#define ADC12_P84 0x0007 // Use input P8.4 for analog input


#define ADC12_P85 0x0006 // Use input P8.5 for analog input
#define ADC12_P86 0x0005 // Use input P8.6 for analog input
#define ADC12_P87 0x0004 // Use input P8.7 for analog input

#define ADC12_P90 0x0008 // Use input P9.0 for analog input


#define ADC12_P91 0x0009 // Use input P9.1 for analog input
#define ADC12_P92 0x000A // Use input P9.2 for analog input
#define ADC12_P93 0x000B // Use input P9.3 for analog input
#define ADC12_P95 0x000D // Use input P9.5 for analog input
#define ADC12_P96 0x000E // Use input P9.6 for analog input

ADC12CTL0 = ADC12_SHT_16 | ADC12_ON ; // Turn on, set sample & hold time
ADC12CTL1 = ADC12_SHT_SRC_SEL; // Specify sample & hold clock source
ADC12CTL2 = ADC12_12BIT; // 12-bit conversion results
ADC12MCTL0 = ADC12_P84; // P8.4 is analog input
}

69. For this last circuit, you will need your prototype board, one 470 resistor, two 100 resistors,
and four of the male-female wire jumpers.

Page 29 of 37
70. Connect the female end of the red wire jumper to the 3V3 pin in the lower right corner of the
Launchpad.

Connect the female end of the black wire jumper to the GND pin the lower right corner of the
Launchpad.

71. Plug the male end of the red wire jumper into hole (a,1).

Plug the male end of the black wire jumper into hole (j,1).

Page 30 of 37
72. Take one of the 100 resistors. Plug one end into hole (b,1) and the other end into (a,10).

73. Take the 470 resistor. Plug one end into hole (e,10) and the other into (f,10).

Page 31 of 37
74. Plug one end of the other 100 resistor into hole (j,10). Plug the other end into (i,1).

Page 32 of 37
75. Almost done. All we need to do now is connect the wire jumpers for the two analog input
channels.

Take one wire jumper (we used white) and plug the female end onto the P9.2 pin.

Take one wire jumper (we used brown) and plug the female end onto the P8.4 pin.

Page 33 of 37
76. Plug male end of the wire jumper connected to pin P9.2 into hole (b,10).

Plug male end of the wire jumper connected to pin P8.4 into hole (i,10).

Page 34 of 37
77. The electrical circuit we have just completed is show below.

Pin P9.2 will be connected to a voltage above 1.65V, and we will expect the green LED to turn
on.

Pin P8.4 will be connected to a voltage below 1.65V, and we will expect the red LED to turn off.

Pin P9.2 Pin P8.4

100 470 100

+3.3V

Ground, 0V
~ 2.8V ~ 0.5V

78. At this point, it is probably a good idea to double-check your circuit. Make sure all your connects
are in the right place and plugged in firmly.

79. When you are ready, run your program.

Again, you should expect that the green LED will turn on because P9.2 is above 1.65V.

You should expect the red LED will turn off because P8.4 is below 1.65V.

If your program isn’t working as expected, it is probably due to an electrical connection on the
protoboard, so please check them again. You can always let us know if you are having problems,
but debugging circuits like this via message boards is not the easiest thing to do. Be patient, and
we will get you up and running! : )

Page 35 of 37
80. You can try swapping the male ends of the P9.2 and P8.4 jumpers to turn on and off the green
and red LEDs.

However, you may see some unexpected behavior when the male ends are unplugged from
anything. Unless they are physically plugged into the protoboard circuit, the voltage on the wires
(and therefore, P9.2 and P8.4) cannot be predicted. Once you plug them back into the circuit,
the expected behavior will return.

81. Wow! That was a lot of stuff!

Between the analog circuits handout and the ADC peripheral handout, we are looking at almost
50 pages! Congratulations on making it all the way through.

Again, we hope by now we have convince you of the value of going step-by-step throughout the
circuit and code development.

Congratulations once again. : )

Page 36 of 37
All tutorials and software examples included herewith are intended solely for
educational purposes. The material is provided in an “as is” condition. Any
express or implied warranties, including, but not limited to the implied warranties
of merchantability and fitness for particular purposes are disclaimed.

The software examples are self-contained low-level programs that typically


demonstrate a single peripheral function or device feature in a highly concise
manner. Therefore, the code may rely on the device's power-on default register
values and settings such as the clock configuration and care must be taken when
combining code from several examples to avoid potential side effects.
Additionally, the tutorials and software examples should not be considered for use
in life support devices or systems or mission critical devices or systems.

In no event shall the owner or contributors to the tutorials and software be liable
for any direct, indirect, incidental, special, exemplary, or consequential damages
(including, but not limited to, procurement of substitute goods or services; loss of
use, data, or profits; or business interruption) however caused and on any theory
of liability, whether in contract, strict liability, or tort (including negligence or
otherwise) arising in any way out of the use of this software, even if advised of
the possibility of such damage.

Page 37 of 37

You might also like