MSP430 LaunchPad Tutorial - Part 3 - ADC

Finally, here's the last part of this little tutorial series about LaunchPad.
I'll explain the basics of Analog to Digital Conversion on the MSP430G2231.



EDIT 01-10-12: Multi-channel conversions added!
EDIT 01-23-12:Added "Watch variable" instructions.

Basically we'll  write a program that will read an ADC channel and will toggle some leds based on the result of the conversion.

We start as usual with the inclusion of the header file for the MSP430G2231, the leds stuff and with the definition of a variable that will store the result of the conversion. We also declare a function that will initialise the ADC module.

#include  "msp430g2231.h"

#define     LED0                  BIT0
#define     LED1                  BIT6

unsigned int value=0;

With this function we setup the ADC module.
With the ADC10CTL1 register we select the input channel for the ADC and the ADC clock division (from the ADC10 internal oscillator ~5MHz).
Then we select the internal voltage reference for the ADC module (Vcc) with SREF_0, turn it on (ADC10ON) and enable the ADC10 interrupt (ADC10IE).
Finally we connect P1.5 to the ADC module by setting the ADC10AE0 register accordingly.

void ConfigureAdc(void)
{
  /* Configure ADC  Channel */
  ADC10CTL1 = INCH_5 + ADC10DIV_3 ;         // Channel 5, ADC10CLK/4
  ADC10CTL0 = SREF_0 + ADC10SHT_3 + ADC10ON + ADC10IE;  //Vcc & Vss as reference
  ADC10AE0 |= BIT5;                         //P1.5 ADC option    
}

In the main()  we stop as usual the Watchdog timer, set up the clocks and the leds.
Then we select the input pin for the ADC module by setting the P1SEL register. After that, we initialise the ADC with ConfigureAdc() and enable the interrupts, otherwise we won't know when a conversion has been made.

void main(void)
{
  WDTCTL = WDTPW + WDTHOLD;                 // Stop WDT  
  BCSCTL1 = CALBC1_1MHZ;                    // Set range
  DCOCTL = CALDCO_1MHZ;
  BCSCTL2 &= ~(DIVS_3);                  // SMCLK = DCO = 1MHz  
  P1DIR |= LED0 + LED1;   
  P1SEL |= BIT5;                             //ADC Input pin P1.5          
  P1OUT &= ~(LED0 + LED1);  
  
  ConfigureAdc();    
  __enable_interrupt();                     // Enable interrupts.

After the init stuff, we wait some cycles to let the ADC voltage reference settle to a stable level and then we start the conversion by setting the ADC10CTL0 register.
Then we enter a low-power mode to save juice: we'll have the result of the conversion directly in our "value" variable from the ADC10MEM register thanks to the ADC10 interrupt.
At last we simply toggle the leds on the LaunchPad according to the number stored into "value" (don't forget that we have a 10-bit ADC module, so the maximum value will be 1023).
You could do some further calculations, maybe averaging the results to get a more precise reading.

while(1)
  {    
    __delay_cycles(1000);                   // Wait for ADC Ref to settle 
    ADC10CTL0 |= ENC + ADC10SC;             // Sampling and conversion start
    __bis_SR_register(CPUOFF + GIE);        // LPM0 with interrupts enabled    
    value = ADC10MEM;
    if (value>511)
    {
       P1OUT &= ~(LED0 + LED1);
       P1OUT |= LED0;
    }
    else
    {
       P1OUT &= ~(LED0 + LED1);
       P1OUT |= LED1;}
    }  
}

This is the ADC10 interrupt service routine, as we've seen for the TimerA module.
We simply exit the low-power mode to let the main program make some computations with the result from the ADC.

// ADC10 interrupt service routine
#pragma vector=ADC10_VECTOR
__interrupt void ADC10_ISR (void)
{
  __bic_SR_register_on_exit(CPUOFF);        // Return to active mode
}

And that's it! Pretty simple huh?
This concludes our tutorial series for the LaunchPad, this is all you need to get started with MSP430 MCUs.
I hope you liked this series, for any questions or suggestions don't hesitate to contact me!

Addendum:
As someone requested, here's how you do multiple conversions!

First of all, we define an array that will store the conversion results from each channel


#define     ADC_CHANNELS     5  //We will sample 5 channels
unsigned int samples[ADC_CHANNELS];


In the main loop, before the start of conversion, we add

  ADC10CTL0 &= ~ENC;
  while (ADC10CTL1 & BUSY);
  ADC10SA = (unsigned int)samples; 

With this line we specify that the conversion results should be automatically stored in the previously created array: in such way, there's no need to access the ADC10MEM register anymore. The data will be immediately ready for calculations.

The ConfigureAdc function becomes

void ConfigureAdc(void)
{
  /* Configure ADC  Channel */
  ADC10CTL1 = INCH_4 + ADC10DIV_0 + CONSEQ_3 + SHS_0;   //Multi-channel repeated conversion starting from channel 5 
  ADC10CTL0 = SREF_0 + ADC10SHT_2 + MSC + ADC10ON + ADC10IE; 
  ADC10AE0 = BIT4 + BIT3 + BIT2 + BIT1 + BIT0; 
  ADC10DTC1 = ADC_CHANNELS;    //ADC_CHANNELS defined to 5   
}


CONSEQ_3 enables multi-channel repeated conversion mode.
With INCH_4 we select the starting channel (in this case we start from channel 5 the sample channel 4 and so on all the way down to channel 0). We enable ADC on those pins with the ADC10AE0 register.
MSC enables multi-channel conversions.
ADC10DTC1 defines how many blocks of data (one for each channel conversion) we transfer into the array  adc_channels that we previously created.

Addendum 2:
Here's an image that will explain how to watch variables with CCS while debugging.



I hope that your concerns are resolved, otherwise don't hesitate to ask!

55 comments:

Prince of Mirkwood said...

What exactly do the lines:-

BCSCTL1 = CALBC1_1MHZ;
DCOCTL = CALDCO_1MHZ;
BCSCTL2 &= ~(DIVS_3);

refer to?

Enrico Garante said...

BCSCTL1 = CALBC1_1MHZ;
DCOCTL = CALDCO_1MHZ;
These two lines set the DCO to 1MHz with calibrated values programmed in the flash at the factory.


BCSCTL2 &= ~(DIVS_3);
This line of code ensures that the SMCLK divider is 0, so we have SMCLK=DCO=1MHz (in fact if we are to have a /8 divider, it should be BCSCTL2 |= DIVS_3;).

If you want to read more, here's an interesting tutorial http://mspsci.blogspot.com/2010/07/tutorial-08-b-configuring-dco.html

Anonymous said...

para iniciar una secuencia de conversión de una matríz de canales, cual sería el codigo que se implementaría?

Enrico Garante said...

I'm facing multiple channel conversions right now,somehow I get wrong results (it seems that the ADC module interferes with the analog voltage itself).
When I find the solution I'll post it, for now I can suggest you this link
http://electronics.stackexchange.com/questions/13662/reading-from-multiple-channels-using-adc10-and-dtc

Anonymous said...

How did you manage to come up with the 511 decimal value.

I am using the formula provided in the users guide for the MSP family:

N = 1023 *(Vin-Vr)/(Vref_Vr)

Enrico Garante said...

As you can see from the user guide, the correct formula is
N=1023* (Vin - VRminus)/(VRplus - VRminus) .

You have to be careful though, because on the launchpad by default VRminus (the negative reference voltage) is GND, or 0 volts, and VRplus (the positive reference voltage) is VDD, or 3.3 volts.

So the final formula would be
N=1023*Vin/3.3.

The reference voltages are selected with the ADC10CTL0 register.

Anonymous said...

BCSCTL2 &= ~(DIVS_3);
The comment of this sentence is wrong. As Enrico Garante said "This line of code ensures that the SMCLK divider is 0, so we have SMCLK=DCO=1MHz (in fact if we are to have a /8 divider, it should be BCSCTL2 |= DIVS_3;)."
But if we want SMCLK divider is 0, why don't we use method below?
BCSCTL2 |= DIVS_0;

Enrico Garante said...

Because if you put a string of bits in OR with 0 you are not sure that the resulting bits are 0.
You should do BCSCTL2 &= DIVS_0; which is equal to BCSCTL2 &= ~(DIVS_3); (maybe easier to write :D ).
That line could even be suppressed if we don't need to be sure of the SMCLK frequency.
Anyway the comment of that line of code is wrong, thanks for noting it!

Anonymous said...

Thank you for the excelent tutorials.
Could you post a SPI Tutorial? For master and slave communication?
I want to work with two msp430 launchpads at the same time.

thanks,

Anonymous said...

can we have multiple inputs for ADC?? and how?

Enrico Garante said...

I've added a section to explain multiple ADC conversions!

Dudu said...

@Enrico There is a mistake in multiple conversions and maybe on single conversions too, u forget to check BIT BUSY of ADC10CTL1. It will be a mess if you do multiple conversions without it. Try to do this:

void dispara_adc10_all_repetitivo(void){
ADC10CTL0 &= ~ENC; // turn off
while (ADC10CTL1 & BUSY); // this is important!
ADC10SA = (unsigned int) samples;
ADC10CTL0 |= ENC + ADC10SC;
}

Enrico Garante said...

@Dudu You are right! I forgot to add it...
However in single conversion mode we don't need to check the BUSY bit because the interrupt from the ADC implicitly means that the module is not busy.
Thanks for your feedback!

Anonymous said...

Hi there, I'm working in a similar projet.. I Have to measure the voltage drop on a 1.3V battery until it reaches 0V, do you think this code with some alterations could do the trick ? And could I store the voltage and time of the measurement into the laptop ?
thank you

Enrico Garante said...

Of course! You could measure the voltage of the battery without a resistor divider if it remains below 3.3V.
Use the ADC single conversion like in this tutorial.
You can use an ADC reference voltage of 1.5V with ADC10CTL0 = SREF_1 + ADC10SHT_2 + REFON + ADC10ON + ADC10IE;
Then you can send the result to a PC using serial transmission like I showed here http://www.egarante.net/2012/01/msp430-launchpad-tutorial-bonus-uart.html

Anonymous said...

I need to sample 4 battery at once, also can use the multiple conversations in this tutorial?

Thank You!

Enrico Garante said...

Yes you can, if you don't exceed 3.3v with each battery, otherwise you have to use a voltage divider.
To select 1.5v reference be sure to use SREF_1 and REFON.

Anonymous said...

Yes, the maximum voltage of the battery is 1.3V! In this program you only can differentiate the voltage with a threshold of 511, but in my case I would like to constatitly monitor the voltage drop, or at least with more levels (1,3V;1V;0,7V and so on) and storage this information with the time it was taken. What type of alterations to the code do you suggest ?
Sorry if I’m making trivial question but I’m recently starting programming with the MSP430.
Thank You.

Enrico Garante said...

The 511 threshold in this code is just an example: you have a 10-bit ADC so the measured value will vary from 0 to 1023 with about 1.5mV sensitivity @Vref=1.5V. Let's assume the battery is at 0.85V, the measured value will be about 567.
You can store this value in an int and send it over UART with the code from other tutorial.
The PC will log it with the system time.

Anonymous said...

Do you know how can I have a constantly view of witch number is in variable "value" ? So that I can monitor the voltage and send to the PC.

I can see the number stored in value but only after I stop the program.

Enrico Garante said...

I've added an image to explain that!

Anonymous said...

Do you know what type of code should I add if want to sample the pins only in intervarls of 30min? and store it on the pc with the time it was taken?

Thank You for the help, it has been very useful!

Anonymous said...

I already have the voltages, but I'm having trouble to pass then on to the PC so they can be stored for analysis along with the time it was taken. You already recommended use UART, but I'm looking at the code and I don't know how I can send the data on samples, and how would then I read it.

Thank You for your help

Anonymous said...

Maybe it is a stupid question but when I try to compile this I get this error:

unresolved symbol ADC10CTL0
unresolved symbol ADC10CTL1
unresolved symbol ADC10AE0
unresolved symbol ADC10MEM

I have included the header file for 2231. So how should I declare those registers?

Thanks for your help!

Enrico Garante said...

Check again the header file inclusion, or try to check in the project options if you are compiling for the right MCU (Right click Project Name->Properties->General->Device->Variant).

Anonymous said...

I really appreciate your tutorials. I am trying to read from 6 channels and send data based on the readings to the PC. Since I am using the TXD and RXD pins (1.1 and 1.2) for RS-232 communication, how do I set up the multichannel ADC for 6 channels? Since I want to sample ADC for 1.0, 1.3, 1.4, 1.5, 1.6, and 1.7 only?

Thanks a bunch!

Anonymous said...

I appreciate your effort in explaining the tutorial very well.
But, is there any document where can i get to know about the ADC registers in detail, as in the function of each bit within the register.

Anonymous said...

can you please provide some more explanation about the function of the "BUSY" bit.

Enrico Garante said...

@Anon1
Here's the user's guide for the MSP430x2xx Family, you'll find everything on this document.
http://www.ti.com/lit/ug/slau144i/slau144i.pdf

@Anon2
The BUSY (active high) bit indicates whether the ADC is working on a conversion operation or not.
You shouldn't touch the ADC module if this bit is 1.

Enrico Garante said...

>I really appreciate your tutorials. I am trying >to read from 6 channels and send data based on >the readings to the PC. Since I am using the TXD >and RXD pins (1.1 and 1.2) for RS-232 >communication, how do I set up the multichannel >ADC for 6 channels? Since I want to sample ADC >for 1.0, 1.3, 1.4, 1.5, 1.6, and 1.7 only?

I don't think it's possible to do such thing, I can suggest to use 1.6 and 1.7 pins for the RS232 communication (but this way you can't use the launchpad's built-in serial-usb converter) and use pins from 1.5 down to 1.0 for the multiple AD conversion.
Otherwise you have to do a single conversion for each channel (configure for 1.0, do conversion, disable adc, configure for 1.3, do conversion and so on), store the results in some variables and then send them via RS232.

Anonymous said...

ADC10CTL1 = 0x1010;
ADC10CTL0 = 0x0010;
ADC10CTL0=ADC10CTL0|0x0002;
while(1)
{
ADC10CTL0=ADC10CTL0&0x0000;
ADC10CTL1 = 0x1010;
ADC10CTL0 = 0x0010;
ADC10CTL0=ADC10CTL0|0x0002;
sw_delay(1);

ADC10CTL0=ADC10CTL0|0x0001;
while((ADC10CTL1&0x0001)==0x0001)
{
}
result = ADC10MEM; // First result stored in memory *******
if(result<=460) // yes light LED for x-axis movement
{
P1OUT=P1OUT|0x01; // Change to P1.0 ,0000 0001
}

else
{
P1OUT=P1OUT&0xfe; // 1111 1110
}


Will that work on 2231 on A0 lighting LED

Anonymous said...

Hello Enrico. I have a question. You said that:
ADC10CTL1 = INCH_5 + ADC10DIV_3
"With the ADC10CTL1 register we select the input channl for the ADC and the ADC clock division (from the SBMCLK)"
But I don't see the command that make ADC10SSELx
bits 11 thus I'm a little fuzzy. Wait for your answe. Thanks

Enrico Garante said...

That was a typo, if you see in the comment I wrote "ADC10CLK/4".
As you said, if you want to select other clock sources (MCLKS, SMCLK or ACLK) you have to set the ADC10SSELx bits.
Thanks for the feedback!

Anonymous said...

Helo Enrico.In the tutorial above you said you used single conversion mode. That means that the adc convert one time the analog input and then does nothing ? For example a i have a variable temperature that I want to be displayed on a lcd.
This code will do it? Sorry for my bad english

Enrico Garante said...

I used single conversion mode because thre's the while(1){} cycle that keeps executing conversions indefinitely. You can use this code to monitor a single variable like a temperature sensor.

Francesco said...

Excellent Tutorial!
Dear Enrico I would ask you how to raise the frequency of ADC10 (sampling rate) of my msp430g2553.
Here my code:


BCSCTL2 = SELM_0 + DIVM_0 + DIVS_0;
DCOCTL = 0x00;
BCSCTL1 = CALBC1_16MHZ;
DCOCTL = CALDCO_16MHZ;

ADC10CTL0&=~ENC;
ADC10CTL0=SREF_0+ADC10SHT_0+ADC10ON; ADC10CTL1 = INCH_3+ SHS_0 + ADC10SSEL_2 + ADC10DIV_0 + CONSEQ_0;
ADC10AE0=A3;
ADC10CTL0 |= ENC;

Where wrong?
Thanks

Francesco

Enrico Garante said...

You are selecting the MCLK as ADC10CLK by setting the ADC10SSEL_2 bit in the ADC10CTL1 register.
In your program, the MCLK will run at the same frequency as the DCO, which is 16MHz, the maximum frequency available for this MCU.
Thus you can't get any faster, but only slower by using the ADC10 clock divider.

Rodrigo Miranda Santana said...

Hello Enrico, I`m having an issue with the ADC10 interrupt service routine. When I compile the code it says there is an error (on line 4 above), because there was a ";" expected. I tried putting it after the interruption declaration, but then it says "__bic_SR_register_on_exit" is only available within interrupt routines.

1 // ADC10 interrupt service routine
2 #pragma vector=ADC10_VECTOR
3 __interrupt void ADC10_ISR (void)
4 {
5 __bic_SR_register_on_exit(CPUOFF);
6 }

Anonymous said...

Hi Enrico, I am a novice in electronics. Pardon my naivety. Could I integrate LCD display with this kit? If yes, what could be the best choice?
Btw, I want to measure 1mV to 1V with 0.1mV resolution, which I believe is not possible with the ADC provided. Any suggestion please?

Enrico Garante said...

Hi,
you could use one of these serial display https://www.sparkfun.com/products/9066 , they only need a serial port(check out my uart snippet in the Tutorials page) and 3.3V power.
As for the ADC,there are two ways to do this:
1) You can supply an external voltage reference for the ADC of 1V, giving you a theoretical accuracy of 0.97mV with the on-board 10 bit ADC. This will occupy the 1.3/1.4 pins (Vref-/Vref+) on the g2231 permanently.

2)You can use the internal 1.5v reference and amplify your 1V maximum signal to 1.5V with an opamp. This will give you an accuracy of 1.4 mV, requiring an additional component but freeing two input pins on the MCU.

Kyle said...

Hi Enrico, I am trying to do a single-conversion adc with several arbitrary inputs, i.e config pin 1, convert, stop then config pin 2, convert, stop etc, take average of 50 samples, store in memory and display via UART. I have luck with single input, but not with several inputs. Can you point out what's wrong? I just started learning C and hardware programming, so bear with me. Below is my code:

#include
#include "ADC.h"
#include "UART.h"

volatile int voltRaw[5];
volatile float voltage = 0;
unsigned int avg_voltage = 0;
unsigned int average[50];
unsigned int i = 0;
int ii = 0;
int a = 0;

void main(void) {
Config_ADC();

Start_ADC3();
_enable_interrupt();
Display_ADC(voltRaw[1]);

Start_ADC0();
_enable_interrupt();
Display_ADC(voltRaw[2]);

}

void Config_ADC()
{
ADC10CTL0 = SREF_1 + REF2_5V + REFON + ADC10ON + ADC10IE + ADC10SHT_3 + MSC;
ADC10CTL1 = ADC10DIV_5 + ADC10SSEL_3 + CONSEQ_2;
}


void Start_ADC3()
{
ADC10CTL1 &= 0x0FFF;
ADC10CTL1 |= INCH_3;
ADC10AE0 = BIT3;
ADC10CTL0 |= ENC + ADC10SC;
while(ADC10CTL1 & ADC10BUSY);
a = 3;
voltRaw[1] = avg_voltage;

void Start_ADC0()
{
ADC10CTL1 &= 0x0FFF;
ADC10CTL1 |= INCH_0;
ADC10CTL0 |= ENC + ADC10SC;
while(ADC10CTL1 & ADC10BUSY);
a = 0;
voltRaw[2] = avg_voltage;
}

void Display_ADC(int a)
{
uart_puts_numbers(a);
put('-');
uart_puts_numbers(avg_voltage);
put(' ');
voltage = (avg_voltage * 2.5)/1024;
_delay_cycles(8000000);
}

#pragma vector = ADC10_VECTOR
__interrupt void ADC10_ISR(void)
{
average[i] = ADC10MEM;
if (i < 50)
{
i++;
}
else
{
avg_voltage = 0;
for(ii = 0; ii < 50; ii++)
{
avg_voltage = avg_voltage + average[ii];
}
avg_voltage = avg_voltage/50;
i = 0;
ADC10CTL0 &= ~ENC;
}
}

Thanks.

Kyle said...

Oh, I am using the MSP430G2553

aliya said...

pls help me ,,, is it possible to use launchpad/msp430 to control a relay according to a external current source to automatically shut down an over rated power appliance?

Anonymous said...

In multiple conversion mode, this line of code has to be executed only once?

__delay_cycles(1000);// Wait for ADC Ref to settle

Thanks

veyron999 said...

hey enrico, i'm pretty much a noob about the programming part, I ran this code to read temperature from a sensor and it worked flawlessly. But i tried changing the input pin to P1.2 or P1.3 and it wouldn't work, it works on all remaining input pins, what could be wrong?

avinash dubey said...

respected sir,very nice description of adc of msp430.sir,i am really facing a lot of problems while writing the code for adc of msp430f425 ussualy used in single phase energy meters .following the same methods as you have described above for msp430g2231 i am facing the problems like
compiler is showing two many errors regarding adc control registers.
sir can you plaease explain me the adc coding of 'msp430f425'.sir i am using code composer studio.sir i expect that you will please help me.

akshay koparde said...

hello sir,
I am currently working on MSP430G2553. I am trying to read P1.4. P1.5,P1.6 but i am able to read only 1 channel at a time. I am trying to display the adc results via UART. Below is the code, Please let me know where i am going wrong and also let me know what changes i need to make please.

#include "msp430g2553.h"
#include "uart.h"
//#define water BIT5
#define LED1 BIT6
char test_string[8];
//unsigned char c ;
volatile unsigned int temp,value;
void ADC_init(void);
void ADC1_init(void);
void CONVERT_DISPLAY(unsigned int d);
void soil_moisture();
void temperature();
void water_level();



int main(void)
{
WDTCTL = WDTPW + WDTHOLD; //Stop WDT
BCSCTL1 = CALBC1_8MHZ; //Set DCO to 8Mhz
DCOCTL = CALDCO_8MHZ; //Set DCO to 8Mhz
//P1DIR &= ~BIT4;
//P1DIR &= ~BIT3;
P1DIR |=0xff;
P2DIR |= BIT3;
P2DIR |= BIT4;
P2DIR &= ~BIT5;
P2OUT &= ~BIT3;
P2OUT &= ~BIT4;



uart_init(); //Initialize the UART connection
__enable_interrupt(); //Interrupts Enabled

uart_puts((char *)"DRIP IRRIGATION\n\r");
__delay_cycles(1000);
ADC1_init();
ADC_init();
while(1)
{

water_level();
__delay_cycles(1000);
temperature();
__delay_cycles(1000);
soil_moisture();



}


}
void soil_moisture()
{
__delay_cycles(1000); // Wait for ADC Ref to settle
ADC10CTL0 |= ENC + ADC10SC; // Sampling and conversion start
__bis_SR_register(CPUOFF + GIE); // LPM0 with interrupts enabled
value = ADC10MEM;
temp=value;
temp=temp/10;

if(temp<100)
P2OUT |= BIT3;

else if(temp>160)
P2OUT &= ~BIT3;

uart_puts((char *)"soil moisture=\t");
CONVERT_DISPLAY(temp);
uart_putc(0X0A);
uart_putc(0X0D);
__delay_cycles(100000);


}
void temperature()
{
__delay_cycles(1000);
ADC10CTL0 |= ENC + ADC10SC; // Sampling and conversion start
__bis_SR_register(CPUOFF + GIE); // LPM0 with interrupts enabled
value = ADC10MEM;
temp=value*0.367;
uart_puts((char *)"temperature=\t");
CONVERT_DISPLAY(temp);
uart_putc(0X0A);
uart_putc(0X0D);
__delay_cycles(50000000);

}
void water_level()
{

//if(water == 1)
if(P2IN & BIT5)
{

P2OUT &= ~BIT4;

uart_puts((char *)"water normal\t");
uart_putc(0X0A);
uart_putc(0X0D);
}
else
{
P2OUT |= BIT4;

uart_puts((char *)"water low\t");
uart_putc(0X0A);
uart_putc(0X0D);
}


}





void ADC1_init()
{
/* Configure ADC Channel */
ADC10CTL1 = INCH_4 + ADC10DIV_3 ; // Channel 5, ADC10CLK/4
ADC10CTL0 = SREF_0 + ADC10SHT_3 + ADC10ON + ADC10IE; //Vcc & Vss as reference
ADC10AE0 |= BIT4; //P1.4 ADC option


}
void ADC_init()
{
/* Configure ADC Channel */
ADC10CTL1 = INCH_5 + ADC10DIV_3 ; // Channel 5, ADC10CLK/4
ADC10CTL0 = SREF_0 + ADC10SHT_3 + ADC10ON + ADC10IE; //Vcc & Vss as reference
ADC10AE0 |= BIT5; //P1.5 ADC option


}



void CONVERT_DISPLAY(unsigned int d)
{

unsigned char dig1,dig2,dig3,dig[3];
unsigned char x;
unsigned char temp;
temp=d;
temp=temp/10;
dig1=d%10;
dig2=temp%10;
dig3=temp/10;


dig[0]=dig3;
dig[1]=dig2;
dig[2]=dig1;


for(x=0;x<3;x++)
{
temp=dig[x]|0x30;

uart_putc(temp);
}

}

// ADC10 interrupt service routine
#pragma vector=ADC10_VECTOR
__interrupt void ADC10_ISR (void)
{
__bic_SR_register_on_exit(CPUOFF); // Return to active mode
P1OUT ^= LED1;
}

akshay koparde said...

@enrico sir i am using my uart.h library for my project.

Trung Quốc Trịnh said...

P1SEL |= BIT5;
I think this construction don't need

kiranvarma-npeducations said...

well explained! i want to see the output of ADC in msp430 on Codecomposer studio graph! no one clearing telling about that. If you provide the details about, it would be helpful.
Thanks in advance

parth joshi said...

will this code work ,if the value is in mv or need to amp ???

Anonymous said...

Thanks a bunch for this tutorial, helped me an infinite amount getting multiple potentiometer inputs working.

Juan Gomez said...

HEY enrico...can u post an example code on how would you use this code to read the temp from an analog sensor? thank you !! great tutorial!!

Juan Gomez said...

also... how would you save your results into a text file.!

Binu Kannur said...

Hai,
Now iam trying with msp430g2553 and i want to read p1.0,p1.3,p1.4 . This values want to send over UART (p1.1,p1.2)

from above discussion
ADC10CTL0 &= ~ENC;
while (ADC10CTL1 & BUSY);
ADC10SA = (unsigned int)samples;
then how can split values of each channel and store in separate variables.

Post a Comment