Необъяснимое преобразование из двоичного / шестнадцатеричного кода
Я использую код с веб-сайта Waveshare (для использования с платой ADDA Waveshare, установленной на 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;
}
Пожалуйста, помогите мне разобраться, что этот кусок делает в main():
for (i = 0; i < ch_num; i++)
{
adc[i] = ADS1256_GetAdc(i);
volt[i] = (adc[i] * 100) / 167;
}
Константы (будучи 100 и 167) не объясняются. Что именно они пытаются сделать в этой "калибровке" и от чего зависят эти константы?
2 ответа
Умение читать таблицы данных является важным навыком для встроенного программирования.
АЦП на этом чипе возвращает 24-битное значение со знаком. Лист данных говорит
Полномасштабное входное напряжение ADS1255/6 составляет ±2VREF/PGA.
Полная шкала - 0x7FFFFF или 8388607.
Я считаю, что VRef составляет 2,5 В, и код устанавливает PGA в 1 с ADS1256_CfgADC(ADS1256_GAIN_1, ADS1256_15SPS);
Так что adc[i]
значение 1 представляет 1/0x7FFFFF
(2*2,5/1) Вольт или 0,596 мкВ. Мы можем преобразовать необработанное чтение в микровольты, умножив его на 5000000 / 8388607. Умножив его на большое число, можно переполнить 32-битное целое число, поэтому давайте уменьшим. 5000000 / 8388607 ~= 500/839 ~= 100/167
,
(Можно было бы получить немного больше точности без переполнения, умножив на 250/419)
Рассматривая конкретно этот фрагмент кода (который кажется актуальным вопросом
for (i = 0; i < ch_num; i++)
{
adc[i] = ADS1256_GetAdc(i);
volt[i] = (adc[i] * 100) / 167;
}
Он считывает количество каналов АЦП (от 0 до ch_num-1), а затем выполняет грубое преобразование каждого значения АЦП в процентное значение 167.
Рассмотрим способ, которым мы обычно делаем процентные расчеты, как (a/b)*100. Другими словами, определите, какая дробь a равна b, а затем умножьте на 100. Но с целочисленной математикой начальное деление даст ноль для всех значений
Таким образом, мы переписываем (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.
Это стандартный трюк с целочисленной математикой.