1

I am using code from the Waveshare website ( for use with the ADDA Waveshare board put on a RPi3 ) : http://www.waveshare.com/wiki/File:High-Precision-AD-DA-Board-Code.7z

*********************************************************************************************************
*   name: main
*   function:  
*   parameter: NULL
*   The return value:  NULL
*********************************************************************************************************
*/

int  main()
{
    uint8_t id;
    int32_t adc[8];
    int32_t volt[8];
    uint8_t i;
    uint8_t ch_num;
    int32_t iTemp;
    uint8_t buf[3];
    if (!bcm2835_init())
        return 1;
    bcm2835_spi_begin();
    bcm2835_spi_setBitOrder(BCM2835_SPI_BIT_ORDER_LSBFIRST );      // The default
    bcm2835_spi_setDataMode(BCM2835_SPI_MODE1);                   // The default
    bcm2835_spi_setClockDivider(BCM2835_SPI_CLOCK_DIVIDER_1024); // The default
    bcm2835_gpio_fsel(SPICS, BCM2835_GPIO_FSEL_OUTP);//
    bcm2835_gpio_write(SPICS, HIGH);
    bcm2835_gpio_fsel(DRDY, BCM2835_GPIO_FSEL_INPT);
    bcm2835_gpio_set_pud(DRDY, BCM2835_GPIO_PUD_UP);        
    //ADS1256_WriteReg(REG_MUX,0x01);
    //ADS1256_WriteReg(REG_ADCON,0x20);
    // ADS1256_CfgADC(ADS1256_GAIN_1, ADS1256_15SPS);
    id = ADS1256_ReadChipID();
    printf("\r\n");
    printf("ID=\r\n");  
    if (id != 3)
    {
        printf("Error, ASD1256 Chip ID = 0x%d\r\n", (int)id);
    }
    else
    {
        printf("Ok, ASD1256 Chip ID = 0x%d\r\n", (int)id);
    }
    ADS1256_CfgADC(ADS1256_GAIN_1, ADS1256_15SPS);
    ADS1256_StartScan(0);
    ch_num = 8; 
    //if (ADS1256_Scan() == 0)
        //{
            //continue;
        //}
    while(1)
    {
        while((ADS1256_Scan() == 0));
        for (i = 0; i < ch_num; i++)
        {
            adc[i] = ADS1256_GetAdc(i);
            volt[i] = (adc[i] * 100) / 167;    
        }

        for (i = 0; i < ch_num; i++)
        {
            buf[0] = ((uint32_t)adc[i] >> 16) & 0xFF;
            buf[1] = ((uint32_t)adc[i] >> 8) & 0xFF;
            buf[2] = ((uint32_t)adc[i] >> 0) & 0xFF;
            printf("%d=%02X%02X%02X, %8ld", (int)i, (int)buf[0], 
                   (int)buf[1], (int)buf[2], (long)adc[i]);                

            iTemp = volt[i];    /* uV  */
            if (iTemp < 0)
            {
                iTemp = -iTemp;
                printf(" (-%ld.%03ld %03ld V) \r\n", iTemp /1000000, (iTemp%1000000)/1000, iTemp%1000);
            }
            else
            {
                printf(" ( %ld.%03ld %03ld V) \r\n", iTemp /1000000, (iTemp%1000000)/1000, iTemp%1000);                    
            }

        }
            printf("\33[%dA", (int)ch_num);  
        bsp_DelayUS(100000);    
            }   
    bcm2835_spi_end();
    bcm2835_close();

    return 0;
}

Please help me figure out what this piece does in the main():

for (i = 0; i < ch_num; i++)
{
    adc[i] = ADS1256_GetAdc(i);
    volt[i] = (adc[i] * 100) / 167; 
}

The constants (being 100 and 167) are not explained. What exactly are they trying to do in this 'calibration' and what do these constants depend upon?

Sam Bob
  • 15
  • 6
  • Related (perhaps dup?) https://stackoverflow.com/questions/38487250/concatenating-32-bit-integers-in-c – leonbloy Jun 23 '17 at 17:33
  • Whatever this is, it's not a conversion to or from floating point, because both `adc[i]` and `volt[i]` are of integer types. – trent Jun 23 '17 at 17:44

2 Answers2

0

Looking specifically at this piece of code (which seems to be the actual question

for (i = 0; i < ch_num; i++)
        {
            adc[i] = ADS1256_GetAdc(i);
                 volt[i] = (adc[i] * 100) / 167;    
        }

It reads a number of ADC channels (0 through ch_num-1) and then does a crude conversion of each ADC value to a percentage of 167.

Consider the way we normally do percentage calculations as (a/b)*100. In other words, work out what fraction a is of b and then multiply by 100. But with integer math, the initial division will yield zero for all values < b, and the multiply won't affect that.

So we rewrite (a/b)*100 as (a*100)/b. Now the division occurs after the multiply and you will get non-zero results.

More specifically consider this example

(100/167) * 100 should become 0.59 * 100 = 59%. But with integer math you get (100/167) * 100 = (0) * 100 = 0%. After the rewrite you have (100*100)/167 = (10000)/167 = 59.

This is a standard trick with integer math.

kdopen
  • 8,032
  • 7
  • 44
  • 52
0

Learning to read datasheets is an important skill for embedded programming.

The ADC on this chip returns a 24 bit signed value. The datasheet says

The ADS1255/6 full-scale input voltage equals ±2VREF/PGA.

Full-scale is 0x7FFFFF or 8388607.

I believe VRef is 2.5V, and the code sets PGA to 1 with ADS1256_CfgADC(ADS1256_GAIN_1, ADS1256_15SPS);

So an adc[i] value of 1 represents 1/0x7FFFFF of (2*2.5/1)Volts or 0.596 microvolts. We can convert the raw reading to microvolts by multiplying by 5000000 / 8388607. By multiplying by a number that large would overflow a 32 bit int, so let's reduce.
5000000 / 8388607 ~= 500/839 ~= 100/167.

(It would be possible to get a little more precision without overflow by multiplying by 250/419)

AShelly
  • 34,686
  • 15
  • 91
  • 152