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.

converting the digital value in ADC10MEM to floating point

Other Parts Discussed in Thread: MSP430G2231

Hi,

 

I am developing an application wherein i read an analog value through the ADC of msp430g2231 and output a PWM signal of another voltage level. But I'm having problems converting the digital value in ADC10MEM to floating point. Can somebody help out in this? Any code available in C for it ? I'm using CCS for debugging... please help.

 

Tressa

  • From the user guide: Nadc = 1023 x ( [Vin - Vr-] / [Vr+ - Vr-] )

    Assuming you use a reference connected to 0V you can rearrange to say:

    Vin = Vref x Nadc / 1023

     

    e.g. for an ADC reading of 500bits using a 2.5V reference the result Vin = 1.22V.

     

    Floating point values are very inefficient - it is possible to store the result as an integer instead (e.g. using "123" to represent "1.23").  Have a look at some of older threads on the forum for more information.

     

    Regards,

    Chris.

  • Teressa,

    This formula maybe helps you;

        unsigned int volt;

        volt=(float)(ADC10MEM*0.0034799) * 1000; //Voltage Formula

        // Voltage = ADC10MEM * (~3,56v / 1023)

       // 1000 for how many digits after the comma 

    Ex : ADC10MEM  = 512

    volt = (float) (512*0.0034799) = 1.781733...

    volt = volt * 1000 => volt = 1781


    lcd_putch(volt/1000+48); // '1'

    lcd_putch('.'); // '.'

    lcd_putch((volt/100)%10+48); //'7'

    lcd_putch((volt/10)%10+48); //'8'

    lcd_putch(volt%10+48); // '1'

     

     

  • Thanks .... I tried it and its working .....thank you so much

  • M.Fatih INANC said:
    Ex : ADC10MEM  = 512
    volt = (float) (512*0.0034799) = 1.781733...
    volt = volt * 1000 => volt = 1781

    A much, much faster (yet not as accurate, at least with these values)  version is

    volt = (ADC10MEM*56)>>16;
    Gives 1792 for ADC10MEM=512 and is by several magnitudes faster and does not nead any floating point operation (and not the float multiplicaiton function).
    What have I done? I have multiplied the factor by 16000 and then divided the result by 16 with a shift operation (takes only 4 clock cycles).
    Since 56 is a 6 bit value and ADC10MEM is 10 bit at max, the intermediate multiplication result still fits into 16 bit.

    A little bit slower (as it requires 32 bit multiplication) but more accurate is the following:

    volt = (ADCMEM*228058L)>>16;  // now I multiplied the factor with 65536000, the multiplication result fits into a long (28 bit size max) and the shift just takes the upper word as result.
    This gives teh expected 1781. (1781.703125, to be exact, the fraction in the lower word of the multiplication result) If you want rounding, simply add 32768 before applying the shift.

  • How do we change the amplitude of the PWM waveform ?

  • MSP430G2231 has Timer_A2. This means you have only 2 CCR registers.

    So one CCR register is sets PWM frequency, oher CCR register is sets duty cycle. 

     

    If you use TimerA this purpose(PWM) you must clear CAP bit (in CCTLx register) and select an output mode(OUTPUT_x)

    Most useful output mode is OUTPUT_7. Here are the exapmle code;

    .

    .

     

      CCR0 = 99-1;                              // Sets PWM Period

      CCR1 = 33;                                // CCR1 -> Sets PWM duty cycle

      CCTL1 = OUTMOD_7;              // CCR1 reset/set mode

      TACTL = TASSEL_2 + MC_1;                  // SMCLK, up mode

     

      _BIS_SR(LPM1_bits + GIE);                       // for SMCLK -> LPM1

     

    this code generating PWM on selected TimerA Out pin. According the duty cycle your amplitude change to.

  • PWM is a digital output from the microcontroller, The amplitude is the same as that of its supply voltage.

    To get a variable amplitude proportional to the PWM duty cycle, a low pass filter ( integrator) is necessary after the PWM output pin.

  • I've been using that same way of coding. I'm changing the value of CCR1 for different values of duty cycle but get the same voltage level. So if I use a LPF will it work fine?

  • For a good help you should share this part of code.

    You will read this topic. Maybe it will helps you.

    http://e2e.ti.com/support/microcontrollers/msp43016-bit_ultra-low_power_mcus/f/166/p/126597/453973.aspx#453973

  •  

    This is part of my coding.  analogRead() gets the value of ADCMEM10 and converts to floating point. 

    CCR0 i've initialised to 256 (just any value ).  But I think i've done the mistake of initialising CCR1 to another  floating value( amplitude of PWM o/p)

     

    eg : if ADCMEM = 922

    analogValue = 3.2

    CCR1 = interpolate (analogValue ) ---------------------------- gives corresponding PWM amplitude value.

     

     

    void main(void){

    long int adcValue = 0;

      float analogValue = 0.0

     

    WDTCTL = WDTPW + WDTHOLD;

    P1DIR |= BIT0; // P1.0 output

     

      while(1){

      adcValue = analogRead();

        analogValue = (float)(adcValue * 0.0034799);

     

    CCTL0 = CCIE; // CCR0 interrupt enabled

    CCTL1 = CCIE; // CCR1 interrupt enabled

    CCR0 = 256; // Set PWM period to 256 clock ticks

    CCR1 = interpolate(analogValue); // Set first duty cycle value

    TACTL = TASSEL_2 + MC_1 + TAIE + TACLR; // SMCLK, upmode, enable interrupt, clear TA1R

    _BIS_SR(LPM0_bits + GIE); // Enter LPM0 w/ interrupt

        }

    }

     

     

     

    Now i'm confused about how to change the duty cycle to get the required amplitude = interpolated value?

    Can i use it this way - CCR1 = (supply voltage * 256) / intepolated value ? 

  • M.Fatih INANC said:
    CCR1 = 33-1;                              // CCR1 -> Sets PWM duty cycle

    Jus tto make this clear: the -1 is wrong if the timer runs in up mode. It is only required for CCR0, as the TAR turnaround time has an additional tick from ccr0 to 0, so the numbe rof ticks per cycle is 1 more than CCR0. For the other CCRs, the double-actions take place (in up mode!) when the timer rolls over to 0 and when the timer counts to CCRx, so CCRx = n will have an ON time of n ticks.

    Tressa mary jose said:
    Now i'm confused about how to change the duty cycle to get the required amplitude = interpolated value?


    With CCR0, you define the turnaround time of the timer, and therefore the PWM frequency, as CCR0+1 timer ticks. Setting CCR0 to 99 will give you a PWM frequency created by 100 timer ticks.

    The other CCRs need to be set to the fraction of this value. So on CCR0=99, CCR1=50 will give you 50% duty cycle, CCR1=100 (or >100, makes no difference) gives you 100% duty cycle and CCR1=1 gives you 1%. For 0% there is an instability as this means the output is set and reset at the same time (one of them winning, but it is undefined, which one). In this case you should switch to OUTMOD0 and set the OUT bit to 0. Or switch the port pin to low GPIO output.

    In your case, with CCR0=256, you'll have to write your interpolate function so it will return a value from 0 to 256 for 0 to 100% duty cycle.

    The output, however, is always either VCC or GND, with varying timing based on the different duty cycles. To get an analog voltage from this, you'll have to put the output signal through a low-pass filter. The higher the PWM frequency (small CCR0, high timer clock) and the lower the low-pass cutoff frequency, the smoother the resulting output voltage is.
    A low cutoff frequency, however, doesn't allow for sudden output voltage changes, so it is up to you to decide what behavior you need on the output.

**Attention** This is a public forum