来自代码中二进制/十六进制的无法解释的转换

时间:2017-06-23 17:29:42

标签: c raspberry-pi3 analog-digital-converter

我正在使用Waveshare网站上的代码(用于放置在RPi3上的ADDA Waveshare板):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;
}

请帮我弄清楚这件作品在main()中的作用:

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

没有解释常数(100和167)。他们究竟在这个“校准”中做了什么以及这些常数取决于什么?

2 个答案:

答案 0 :(得分:0)

专门研究这段代码(这似乎是实际的问题

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

它读取多个ADC通道(0到ch_num-1),然后将每个ADC值粗略转换为167的百分比。

考虑我们通常的百分比计算方式为(a / b)* 100。换句话说,计算a的a是a的分数然后乘以100.但是对于整数数学,初始除法将对所有值产生零&lt; b,乘法不会影响它。

因此我们将(a / b)* 100重写为(a * 100)/ b。现在除法发生在乘法之后,你将得到非零结果。

更具体地考虑这个例子

(100/167)* 100应为0.59 * 100 = 59%。但是使用整数数学,你得到(100/167)* 100 =(0)* 100 = 0%。重写后,您有(100 * 100)/ 167 =(10000)/ 167 = 59。

这是整数数学的标准技巧。

答案 1 :(得分:0)

学习阅读数据表是嵌入式编程的一项重要技能。

该芯片上的ADC返回24位有符号值。 datasheet

  

ADS1255 / 6满量程输入电压等于±2VREF / PGA。

满量程为0x7FFFFF或8388607.

我相信VRef是2.5V,代码将PGA设置为1 ADS1256_CfgADC(ADS1256_GAIN_1, ADS1256_15SPS);

因此,adc[i]值为1表示1/0x7FFFFF(2 * 2.5 / 1)伏或0.596微伏。我们可以通过乘以5000000/8388607将原始读数转换为微伏。通过乘以一个大数将溢出32位int的数字,让我们减少。
5000000 / 8388607 ~= 500/839 ~= 100/167

(通过乘以250/419,可以获得更高的精度而不会溢出)