This thread has been locked.

If you have a related question, please click the "Ask a related question" button in the top right corner. The newly created question will be automatically linked to this question.

question about adc of msp430f5152

Other Parts Discussed in Thread: MSP430F5152

i have a question about how the adc of msp430f5152 works

i have 2 analog input, i want check these 2 input in a order

following is what i do

for(; ;){

a = adc(0);                      // get value from pin1

b = adc(1);                     // get value from pin2

if(a<0x1FF){

     if(b<0x1FF){

    pwm(50);}                   // duty cycle 50

    }

else

pwm(100);

}

int ADC (char channel){

  // Configure ADC

    ADC10CTL0 |= ADC10SHT_5 + ADC10ON+ADC10MSC;       

// ADC10ON, S&H=1024 ADC clks

    ADC10CTL1 |= ADC10SHP+ADC10DIV_7+ADC10CONSEQ_2; 

// ADCCLK =SMCLK; sampling timer; 

//clock divide by 8; single channel, Repeat-single-channel conversion;

    ADC10CTL2 |= ADC10RES;                   

// 10-bit conversion results

    ADC10IE |= ADC10IE0;

// Enable ADC conv complete interrupt

    ADC10MCTL0 |= ADC10INCH_1;               

// A1 ADC input select; Vref=AVCC

    ADC10CTL0 |= ADC10ENC + ADC10SC;       

// Sampling and conversion start

    __bis_SR_register(CPUOFF + GIE);       

// LPM0, ADC10_ISR will force exit

    ADC10CTL0 &= ~ADC10ENC;

    __no_operation();

// For debug only

}

it seems the value of pin1(input1) doesn't matter.

it turns out that if pin2 value< 0x1FF, pwm(50)

if pin2 value>0x1FF, pwm(100)

what did i do wrong? someone could help me out?

if someone could also make the modification, i will appriciate so much

thx

  • renhai zhou said:
    for(; ;){
    a = adc(0);                      // get value from pin1
    b = adc(1);                     // get value from pin2
    if(a<0x1FF){
         if(b<0x1FF){
        pwm(50);}                   // duty cycle 50
        }
    else
    pwm(100);
    }

    I don't see any synchronisation/timing here. So maybe you're changing/re-setting your PWM faster than one PWM cycle, so the output is reset each loop and never forms a proper PWM cycle, may it be 50 or 100%.

    renhai zhou said:
    it seems the value of pin1(input1) doesn't matter.

    Not with this code. If a>0x1ff, 100% are selected. If a<0x1ff, and b y 0x1ff, 50% are seelcted, and if a<0x1ff but b>=0x1ff, nothing changes. However, both of the two cases that change the PWM, will perhaps reset the PWM cycle, so it never forms a complete PWM unless the third case (nothing is selected) is true. And it appears to you that a is unimportant.

    However, in your ADC funciton, I never see you use the passed channel. Instead you use a fixed ADC10INCH_1. Doesn't the compiler give you a warnign about unused parameters? It looks like this is the main cause of your problems. :)

    If anythign further goes wrong, pleas post your ADC ISR (which you apparently use) and the PWM function.

  • sry, in order to make my code short, i delete some code i thought that won't matter.

    what should i do to make this work as i want.If a>0x1ff, 100 are selected. If a<0x1ff, and b y 0x1ff, 50 are seelcted, and if a<0x1ff but b>=0x1ff, 25 are seelcted.

    here is all my code

    void main(void)

    {

    volatile unsigned int i;

      WDTCTL = WDTPW+WDTHOLD;                  

    // Stop WDT

      P1DIR |= BIT0;                           

    // Set P1.0/LED to output direction

      P1DIR &= ~BIT1;                          

    //Set P1.1 to input direction

      P1DIR &= ~BIT3;                          

    //Set P1.3 to input direction

      P3DIR |= BIT6+BIT5 + BIT3+BIT4;;                      

    // P3.6 and P3.5 output

      P3SEL |= BIT6+BIT5 + BIT3+BIT4;;                      

    // P3.6 and P3.5 options select


      TA0CCR0 = 512-1;                         

    // PWM Period

      TA0CCTL1 = OUTMOD_7;                     

    // CCR1 reset/set

      TA0CCR1 = 0;

      TA0CCTL2 = OUTMOD_7;                     

    // CCR2 reset/set

      TA0CCR2 = 0;                           

    // CCR2 PWM duty cycle

      TA0CTL = TASSEL_2 + MC_1 + TACLR;        

    // SMCLK, up mode, clear TAR

    //UART setup   chapter 35

    //P3SEL = BIT3+BIT4;                        // P3.3,4 = USCI_A0 TXD/RXD P3.3 sent out data, p3.4 recieve

      UCA0CTL1 |= UCSWRST;                     

    // **Put state machine in reset**


      UCA0CTL1 |= UCSSEL_1;                    

    // ACLK mode, PWM choose SMCLK, avoid conflict with it;

      UCA0BR0 = 6;                             

    // Bit clock prescaler setting.  1MHz 9600 (see User's Guide)

      UCA0BR1 = 0;                             

    // 1MHz 9600

      UCA0MCTL = UCBRS_0 + UCBRF_13 + UCOS16;  

    // Modln UCBRSx=0, Second modulation stage select.

                                             

    //UCBRFx=0 First modulation stage select.,

                                               

    //UCOS16 over sampling enable

      UCA0CTL1 &= ~UCSWRST;                    

    // Software reset enable. 0 Disabled.USCI reset released for operation.


      UCA0IE |= UCRXIE;                        

    // Enable USCI_A0 RX interrupt
    flag =0;

    ADC_Result=0;

     

    for(; ;){

    a = adc(0);                      // get value from pin1

    b = adc(2);                     // get value from pin2

    if(a<0x1FF){

         if(b<0x1FF){

        pwm(50);}                   // duty cycle 50

        else

        pwm(25);

        }

    else

    pwm(100);

    }

    int ADC (char channel){


    switch (channel){

    case 0:

       // Configure ADC


        ADC10CTL0 |= ADC10SHT_5 + ADC10ON+ADC10MSC;       

    // ADC10ON, S&H=1024 ADC clks
        ADC10CTL1 |= ADC10SHP+ADC10DIV_7+ADC10CONSEQ_2; 

    // ADCCLK =SMCLK; sampling timer;


    //clock divide by 8; single channel, Repeat-single-channel conversion;


        ADC10CTL2 |= ADC10RES;                   

    // 10-bit conversion results

        ADC10IE |= ADC10IE0;

    // Enable ADC conv complete interrupt
        ADC10MCTL0 |= ADC10INCH_1;               

    // A1 ADC input select; Vref=AVCC

        ADC10CTL0 |= ADC10ENC + ADC10SC;       

    // Sampling and conversion start

        __bis_SR_register(CPUOFF + GIE);       

    // LPM0, ADC10_ISR will force exit

        ADC10CTL0 &= ~ADC10ENC;

        __no_operation();

    // For debug only

    break;

    case 2:

    // Configure ADC

    ADC10CTL0 |= ADC10SHT_5 + ADC10ON+ADC10MSC;       

    // ADC10ON, S&H=1024 ADC clks
    ADC10CTL1 |= ADC10SHP+ADC10DIV_7+ADC10CONSEQ_2;

    //ADCCLK =SMCLK; sampling timer; 

    //clock divide by 8; single channel, Repeat-single-channel conversion;

    ADC10CTL2 |= ADC10RES;                   

    // 10-bit conversion results

    ADC10IE |= ADC10IE0;                     

    // Enable ADC conv complete interrupt

    ADC10MCTL0 |= ADC10INCH_3;               

    // A3 ADC input select; Vref=AVCC

    ADC10CTL0 |= ADC10ENC + ADC10SC;       

    // Sampling and conversion start

    __bis_SR_register(CPUOFF + GIE);       

    // LPM0, ADC10_ISR will force exit

    ADC10CTL0 &= ~ADC10ENC;

    __no_operation();

    // For debug only 

    break;

       } 

    return ADC_Result;

    }

    // ADC10 interrupt service routine

    #pragma vector=ADC10_VECTOR

    __interrupt void ADC10_ISR(void)

    {

    //static unsigned char index = 0;

    switch(__even_in_range(ADC10IV,12))

      {

    case  0: break;                          // No interrupt

    case  2: break;                          // conversion result overflow 

    case  4: break;                          // conversion time overflow

    case  6: break;                          // ADC10HI   

    case  8: break;                          // ADC10LO

    case 10: break;                          // ADC10IN

    case 12:

                 ADC_Result= ADC10MEM0;

                 __bic_SR_register_on_exit(CPUOFF);

                

    break;                          // Clear CPUOFF bit from 0(SR)

    default: break;

      }

    }

    void PWM(int value)

    {

    TA0CCR1 = value;

    TA0CCR2 = value;

    }

  • renhai zhou said:
    ADC10MCTL0 |= ADC10INCH_3; 

    Just use 'channel' for all cases. ADCINCH_0.._15 is equal to the integer values 0..15 - In this case :) (see register description in the users guide)

    About settign the PWM, you must synchronize the settign of the PWM DC with the cycle of th etimer. One possible way is to writ ethe intended value into two global variables, and let CCR0 trigger an interrupt. Inside the ISR, which is called when TAR counts to CCR0 and then overflows, you write the global variables to CCR1/2. THis way, you change the DC at the beginning of a cycle and you have 25% of a cycle for doing so. If you fail to do it in time, you'll have an overlong or underlong cycle. But at least aren't you changing the DC anywhere, e.g. producing additional PWm edges. The TiemrB has means to do the synchronization in hardware, so your code would be perfectly okay.
    However, even for TImerA it isn't as bad as I feared - you could have restarted or cleared the timer on each reprogramming ;)

    However, if value is the intended duty cycle, then it must be multiplied with the CCR0 count factor. The values you write are timer ticks, not percent. currently, the oputput changes state at timer tick #25,50 or 100. Not on 25/50/100% of the full cycle, so use 128, 256 and 512 for 25, 50 and 100%. And use OUTMOD_3, which is suited for DC of >0 to 100%, while OUTMOD7 is for DC of 0 to <100%. You cannot easily have a DC range which includes both, 0% and 100%, as the MSP cannot determine beginning from end of a circle :)
    Well, technically, neither 0% nor 100% form a 'valid' PWM as both have 0Hz frequency.

**Attention** This is a public forum