Проблема с ADC dsPIC33

Я изо всех сил пытаюсь заставить АЦП работать с моим устройством. Я использую dsPIC33FJ128GP802 и пытался начать медленно с ручной выборки и преобразования.

Мой код размещен ниже, я установил каждый регистр для АЦП, а затем попытался выполнить выборку только один раз, чтобы получить напряжение от датчика, который я прикрепил. Значение, которое я должен видеть, составляет около 0,7 В, но то, что я получаю, находится в районе -17408 (10111100 00000000). Это значение может доходить до -2000, но значение не должно быть отрицательным.

#include <p33Fxxxx.h>

_FOSCSEL(FNOSC_FRCPLL) // select internal 7.37MHz osc with PPL
_FOSC(OSCIOFNC_OFF & POSCMD_XT) // no clock output, external OSC disabled
_FWDT(FWDTEN_OFF) // disable the watchdog timer
_FPOR(FPWRT_PWR1) // Turn off the power-up timers.

int ADCValue;

void DELAY(unsigned ms) {
    unsigned j;
    unsigned i;
    for (j = 0; j < ms; j++) {
        for (i = 0; i < 0x1F40; i++);
    }
 }

 int main(void) {

    // set up clock to 80MHz
    PLLFBD = 41; // sets M = 41+2 = 43
    CLKDIVbits.PLLPRE = 0; // sets N1 = 2
    CLKDIVbits.PLLPOST = 0; // sets N2 = 2
    while (!OSCCONbits.LOCK); // wait for PLL ready

    AD1CON1 = 0; // set everything to zero to start with.
    AD1CON1bits.ADON = 0; // turn ADC off.
    AD1CON1bits.ADSIDL = 0; // continue module operation in idle mode.
    AD1CON1bits.ADDMABM = 1; // DMA buffers are written in the order of conversion.
    AD1CON1bits.AD12B = 0; // set to 10bit mode.
    AD1CON1bits.FORM = 3; // set data output to signed fractional.
    AD1CON1bits.SSRC = 0; // manual conversion. clearing sample bit manually.
    AD1CON1bits.SIMSAM = 1; // collect samples from channels 0, 1, 2, 3 simultaneously.
    AD1CON1bits.ASAM = 0; // manual sample. samples when SAMP bit is set.
    AD1CON1bits.SAMP = 0; // sample enable bit.
    AD1CON1bits.DONE = 0; // ADC conversion status bit.

    AD1CON2 = 0; // set everything to zero to start with.
    AD1CON2bits.VCFG = 0; // converter voltage ref. set to AVdd and AVss.
    AD1CON2bits.CSCNA = 0; // input scan select bit. set to do not scan.
    AD1CON2bits.CHPS = 0; // channel select bits. set to just channel 0;
    AD1CON2bits.BUFS = 0; // buffer fill status (invalid as BUFM is 0);
    AD1CON2bits.SMPI = 0; // ADC interrupt is generated after every sample/conversion.
    AD1CON2bits.BUFM = 0; // buffer fill mode. set to always start filling from start address.
    AD1CON2bits.ALTS = 0; // Alternate input sample mode. set to always uses channel input from sample A.

    AD1CON3 = 0; // set everything to zero to start with.
    AD1CON3bits.ADRC = 0; // ADC conversion clock derived from system clock.
    AD1CON3bits.SAMC = 0; // auto sample time bits, TAD, set to 0.
    AD1CON3bits.ADCS = 0; // ADC conversion clock set to 0. 1 * TCY = TAD.

    AD1CON4 = 0; // set everything to zero to start with.
    AD1CON4bits.DMABL = 0; // allocates 1 word of buffer to each analogue input.

    AD1CHS123 = 0; // everything set to zero as not using channels 1, 2, or 3.

    AD1CHS0 = 0; // set everything to zero to start with.
    AD1CHS0bits.CH0NB = 0; // channel 0 negative input, set by CH0NA. sample B.
    AD1CHS0bits.CH0SB = 0; // channel 0 positive input, set by CH0SA. sample B.
    AD1CHS0bits.CH0NA = 0; // channel 0 negative input, for sample A. set to VREFL.
    AD1CHS0bits.CH0SA = 0; // channel 0 positive input is AN0.

    AD1CSSL = 0; // input scan register set to zero as not using it.

    AD1PCFGL = 0; // port configuration, set to analogue mode, ADC samples voltage.

    AD1CON1bits.ADON = 1; // turn on ADC

    AD1CON1bits.SAMP = 1; // Start sampling
    DELAY(1); // Wait for sampling time (1ms)
    AD1CON1bits.SAMP = 0; // Start the conversion
    while (!AD1CON1bits.DONE); // Wait for the conversion to complete
    ADCValue = ADC1BUF0; // Read the conversion result

    while (1);

}

У меня датчик питается от тех же шин, что и PIC, и у меня есть выход датчика на AN0 (контакт 2), как я установил в коде. PIC получает питание от стандартных Vss и Vdd (контакты 8 и 13), аналоговых контактов питания AVdd и AVss (контакты 28 и 27) и конденсатора емкостью 33 мкФ через Vcap и Vss (контакты 20 и 19). Есть ли что-нибудь еще, что мне нужно сделать с аппаратной точки зрения? Меня немного смущает регистр AD1CHS0bits.CH0NA, так как я не знаю, нужно ли мне подключать землю к VREFL или что делать в этом случае.

Любая помощь в том, что я должен делать, чтобы исправить эту проблему, будет очень признательна! Кроме того, будет очень полезна любая помощь о том, как преобразовать значение после того, как оно получено правильно.


person ritchie888    schedule 04.04.2013    source источник
comment
Если вы не думаете, что значение должно быть отрицательным, не используйте int. Ваш битовый шаблон, интерпретируемый как unsigned int, равен 48128.   -  person unwind    schedule 04.04.2013
comment
@unwind: Если комментарии в коде верны, то выходной формат данных - это формат с фиксированной точкой со знаком. Выходное значение в буфере преобразования находится в диапазоне от -1,0 до +1,0, представляя диапазон напряжения от опорного низкого до опорного высокого. Если OP предоставляет только 0 В для опорного минимума, то ему, вероятно, потребуется использовать дробный формат без знака, а также использовать беззнаковый тип данных в коде C. В его нынешнем виде -17408 можно разделить на 32768 в диапазоне от -1,0 до 1,0, а затем линейное масштабирование для AVss до AVdd (я предполагаю, 3V3) дает значение 0,77. Использование 3 В дает 0,7 В.   -  person tinman    schedule 04.04.2013
comment
От какого напряжения вы питаете свой PIC?   -  person tinman    schedule 04.04.2013
comment
Спасибо, жестянщик. Напряжение действительно составляет 3,3 В. Вы говорите, что эти значения выглядят правильными? Думаю, я просто неправильно конвертирую значение. Комментарии в коде верны, значение - целое число со знаком.   -  person ritchie888    schedule 04.04.2013
comment
Значение может быть правильным, это зависит от того, насколько близко к 0,7 значение, которое вы должны видеть. Я бы попробовал это с парой других известных напряжений, если возможно, и проверил преобразование. Если вы подаете только однополярный сигнал на свой вход, а ваши высокие и низкие опорные значения ›= 0 В, тогда вы можете использовать беззнаковый формат, как предлагается, хотя это не имеет особого значения, поскольку это просто линейное отображение от От ‹минимума выхода АЦП› до ‹максимума выхода АЦП› до ‹опорного низкого уровня› до ‹опорного высокого уровня›.   -  person tinman    schedule 05.04.2013
comment
Я почти уверен, что значения верны, просто я, должно быть, неправильно понял преобразование. Спасибо за помощь!   -  person ritchie888    schedule 08.04.2013


Ответы (1)


Если значение не должно быть отрицательным для начала, вам не следует использовать этот параметр:

AD1CON1bits.FORM = 3; // set data output to signed fractional.

Если бы я ожидал, что ваше значение будет (оценено с использованием Python):

int((2**10) *      # 10-bit operation
    (0.7/3.3)      # 0.7 volts on a 3.3 volt system
    - (2**9)       # Center at VDD / 2 because of signed operation
    ) << 6         # Fractional output left-shifted the 10-bit up by 6 to fill 16-bits
= -18816

Что звучит о том, что выводит ваш код.

Вместо этого используйте:

AD1CON1bits.FORM = 0; // set data output to integer.

Используя эти настройки вместе с 10-битным режимом, я ожидал бы, что ваше значение будет

int((2**10) *      # 10-bit operation
    (0.7/3.3))     # 0.7 volts on a 3.3 volt system
= 217
person DrRobotNinja    schedule 25.08.2013