Помощь - Поиск - Пользователи - Календарь
Полная версия этой страницы: Проблема с термопарой
Форум разработчиков электроники ELECTRONIX.ru > Аналоговая и цифровая техника, прикладная электроника > Метрология, датчики, измерительная техника
alux
Делаю терморегулятор для печи. Термопару для отладки взял от китайского тестера (в фторопластовой изоляции с разъемом на конце). Индикация - четыре 7-сегментных знакоместа. Вывожу значение напряжения с первого канала, куда подключена термопара. Отрицательный вывод термопары соединен с опорным напряжением +2,5В, которое является опорным для АЦП (AD7799). Режим измерения - биполярный.

Проблема в том, что при правильном подключении термопары ("-" к AIN1-, "+" к AIN1+) значение напряжения неизменное от температуры (прикладываю конец ТП к включенной настольной лампе). Если же подключить ТП наоборот к АЦП, то, значение меняется по температуре, но, естественно, в обратную сторону. В чем может быть дело?
Tanya
Цитата(alux @ Aug 5 2010, 19:23) *
Отрицательный вывод термопары соединен с опорным напряжением +2,5В, которое является опорным для АЦП (AD7799). Режим измерения - биполярный.

В чем может быть дело?

Лень читать даташит, но что бы Вам не поделить опору пополам, чтобы на входах была половина ее.
alux
по даташиту напряжение на входе при включенном буфере и усилителе должно находиться в пределах GND +300 mV ... AVcc - 1,1 V. Т.е с этим все в порядке, - входное напряжение меняется в пределах +2.5 В +/- (напряжение ТП * 128). Пусть нагреваю ТП до 100 гр. Получается 4.096 * 128 = 524 мВ. До верхней границы 5 - 1.1 = +3.9 В еще далеко. В даташите не сказано, что входное напряжение относительно GND не должно превышать опорное.
Но по всей видимости это так и есть. Завтра попробую притянуть негативный вывод ТП через делитель 20 М + 10 М на опорное +2.5В.
MrYuran
Цитата(alux @ Aug 5 2010, 19:23) *
Отрицательный вывод термопары соединен с опорным напряжением +2,5В, которое является опорным для АЦП (AD7799). Режим измерения - биполярный.

Поясните, пожалуйста, сию глубокую мысль...
Что-то мне кажется, что не должно АЦП мерить напряжение выше опоры.
Может, лучше подцепить опорное напряжение к плюсовому входу АЦП и плюсовому проводу ТП соответственно?
И всё равно непонятно...
Я обычно делаю приподнятую слегка землю и цепляю к ней датчик (неважно какой) и общий вход АЦП.
Никаких проблем и можно пользоваться усилителем.
Tanya
Цитата(alux @ Aug 6 2010, 00:23) *
по даташиту напряжение на входе при включенном буфере и усилителе должно находиться в пределах GND +300 mV ... AVcc - 1,1 V. Т.е с этим все в порядке, - входное напряжение меняется в пределах +2.5 В +/- (напряжение ТП * 128). Пусть нагреваю ТП до 100 гр. Получается 4.096 * 128 = 524 мВ. До верхней границы 5 - 1.1 = +3.9 В еще далеко. В даташите не сказано, что входное напряжение относительно GND не должно превышать опорное.
Но по всей видимости это так и есть. Завтра попробую притянуть негативный вывод ТП через делитель 20 М + 10 М на опорное +2.5В.

Ну, лучше бы Вы все-таки не лампочкой грели... Если входы в коридоре, то значит ошибка в коде, как всегда...
alux
Цитата(MrYuran @ Aug 5 2010, 23:32) *
Поясните, пожалуйста, сию глубокую мысль...

Что именно? Что такое биполярный режим? Это измерение напряжения на положительном входе относительно отрицательного входа АЦП. Покажите, пожалуйста, в даташите, где сказано о том, что напряжение на входе не должно превышать опорное? Есть только требования по значению напряжения относительно общего провода (земли).

Tanya, какая разница, чем греть, лампочкой или утюгом?
MrYuran
Цитата(alux @ Aug 6 2010, 09:57) *
Покажите, пожалуйста, в даташите, где сказано о том, что напряжение на входе не должно превышать опорное?

Ну, судя по тому, что вниз изменяется, а вверх не хочет, похоже на то
Tanya
Цитата(alux @ Aug 6 2010, 09:57) *
Что именно? Что такое биполярный режим? Это измерение напряжения на положительном входе относительно отрицательного входа АЦП. Покажите, пожалуйста, в даташите, где сказано о том, что напряжение на входе не должно превышать опорное? Есть только требования по значению напряжения относительно общего провода (земли).

Tanya, какая разница, чем греть, лампочкой или утюгом?


По поводу коридора - он указан явно для различных усилений и обычно лежит около пополама питания и с ростом усиления становится уже...
А греть лучше просто горячей водой. Можно в термосе. Туда же можно и термометр...
alux
Блин, ерунда какая-то...
Подключил отрицательный вывод ТП через делитель 20М + 10М на +2.5В. Т.е. на отрицательном выводе ТП должно быть 2.5 * 10/(10+20) = +0.83 В. Но проблема осталась - все равно напряжение с ростом температуры практически не меняется. А при обратном включении меняется, как положено, в обратную сторону unsure.gif

В чем дело?

PS. Готов выложить исходники... Дело горит!
MrYuran
Цитата(alux @ Aug 6 2010, 11:54) *
Блин, ерунда какая-то...
Подключил отрицательный вывод ТП через делитель 20М + 10М на +2.5В. Т.е. на отрицательном выводе ТП должно быть 2.5 * 10/(10+20) = +0.83 В.

А на самом деле сколько?
Tanya
Цитата(alux @ Aug 6 2010, 11:54) *
В чем дело?

PS. Готов выложить исходники... Дело горит!

Что-то с кодом... Вы можете прочитать установки?
Или менять АЦП. Сечас все горит...
alux
Цитата(MrYuran @ Aug 6 2010, 11:04) *
А на самом деле сколько?

Тестером померял +0.5В
Цитата(Tanya @ Aug 6 2010, 11:09) *
Вы можете прочитать установки?

Проблема еще в том, что нет возможности для отладки: плата уже разведена, выводы UART заняты.
В принципе, можно подключить по I2C ЖКИ для отладки. Нужно подсуетиться...
Tanya
Цитата(alux @ Aug 6 2010, 12:18) *
В принципе, можно подключить по I2C ЖКИ для отладки. Нужно подсуетиться...

Суетиться не стоит. Неужели ни одной ножки свободной нет? Чтобы сказать, совпадает ли регистр с желаемым...
sensor_ua
Странно это. Выглядит как попутанные шнурки тестераwink.gif и установлен униполярный режим АЦП
alux
Выкладываю сырцы.
Код
// HEADER
//----------------------

// AD7799 macro definitions
#define AD7799_CS_ACTIVE      PORTC &= ~(1 << CS)
#define AD7799_CS_INACTIVE      PORTC |= (1 << CS)

#define NMAX            3

#define AVCC            5.0         // AVCC = +5.0 V
#define VREF            2.5         // VREF = +2.5 V
#define TMP_SEN         0.01        // Temperature sensor sensitivity tmp36, V/C
#define OFFSET_VOLTAGE  0.5         // Offset voltage of TMP36 (0.5 V)

#define STEPS_U         16777216.0  // Full-Scale 2^24 for unipolar operation
#define STEPS_B         8388608.0   // Full-Scale 2^(24-1) for bipolar operation

#define TC    0
#define CJ    1

typedef struct
{
    unsigned char Channel;        // каналы
    //double TemperatureCJ;       // температура TMP36
    double TemperatureTC;         // температура термопары
    long Data[2];                 // Значения АЦП для двух каналов
}RESULT;

extern RESULT Result;

  
typedef struct
{
    int Index;                    // номер диапазона температур
    int Threshold;                // температурный порог
    int Hysteresis;               // гистерезис
    int Average;                  // усреднение
    double Offset[6];             // значения смещений для разных диапазонов температур  
    double Reference[6];          // реперные точки
}VALUE;

extern VALUE Value;

typedef struct
{
    unsigned char volatile One;     // Первое (младшее) знакоместо
    unsigned char volatile Ten;     // Второе знакоместо
    unsigned char volatile Hundred; // Третье знакоместо
    unsigned char volatile Thousand;// Четвертое (старшее) знакоместо
}DIGIT;

////////////////////////////////////////
//      SOURCE
//-----------------------------------

// AD7799 Initialization
//------------------------------------------------------------------------------
void ad7799_Init()
{
    ad7799_Reset();
    delay_ms(500);
    ad7799_InitStatus = ad7799_Status();
}

// Запуск непрерывного преобразования на AIN1
//------------------------------------------------------------------------------
void ad7799_StartMeasure()
{
    AD7799_CS_ACTIVE;
    ad7799_WriteConfig(1, 0, AD7799_128_GAIN, 1, 1, AD7799_AIN1_CHAN);     // burnout, bipolar, gain, ref_det, buf, chan
    ad7799_SetMode(AD7799_CONTINUOUS_CONVERSION_MODE, 0, AD7799_16_7_1_HZ);  // mode, psw=0(OFF), rate    
}


//------------------------------------------------------------------------------
void ad7799_Measure()
{
        Result.Data[Result.Channel] = 0;
    
        while(!ad7799_DataReady());             // Ждать окончания преобразования АЦП (RDY => 0)
        
        ad7799_RequestData(CONTINUOUS_READ);    // 1 -> Continuous Read  
        PORTD &= ~(1 << DIN);                   // Held Low in Continuous-Read mode        
        
        for(unsigned char i = 0; i < Value.Average; i++)   // (1 << NMAX)
        {
            while(!ad7799_DataReady());    // Ждать окончания преобразования АЦП (RDY => 0)
              
            Result.Data[Result.Channel] += ad7799_ReadData(); // Накапливаем результат
        }        
          
        Result.Data[Result.Channel] /= Value.Average; // >>= NMAX;    // Усреднение результата
        
        while(!ad7799_DataReady());            // Ждать окончания преобразования АЦП (RDY => 0)
              ad7799_RequestData(NOT_CONTINUOUS_READ);  // 0 -> Not Continuous Read  
              
        // Maintain multiplexing of input channels
        //if(++Result.Channel > 2)
        //   Result.Channel = 0;  
        
        switch(Result.Channel)
        {
            case AD7799_AIN1_CHAN:
                  ad7799_WriteConfig(1, 0, AD7799_128_GAIN, 1, 1, AD7799_AIN1_CHAN + Result.Channel); // burnout, bipolar, gain, ref_det, buf, chan                
                  break;
                  
            case AD7799_AIN2_CHAN:
                  ad7799_WriteConfig(1, 0, AD7799_2_GAIN, 1, 1, AD7799_AIN1_CHAN + Result.Channel);   // burnout, bipolar, gain, ref_det, buf, chan                
                  break;  
        }
}

void Initialise()
{
.....
    Result.Channel = 0;
    ad7799_Init();
    ad7799_StartMeasure();
}


void main()
{  
    Initialise();           // set up I/O registers, flags & variables

    __enable_interrupt();   // allow all enabled interrupts
        
    for(;;)
    {
        ad7799_Measure();

        Result.TemperatureTC = Vtc(Result.Data[TC]) * 1000;
    

        __sleep();    //Idle. Спать до следующего прерывания
    }
}

//  Вычисление напряжения термопары, В
//------------------------------------------------------------------------------
double Vtc(long AdcValue)
{
    return (AdcValue - STEPS_B) * VREF / 128 / STEPS_B;
}


// Timer/Counter0 Overflow ISR: Вызывается с интервалом 4 мс
// Вывод значения на индикатор и обработка нажатия кнопок.
//------------------------------------------------------------------------------
#pragma vector=TIMER0_OVF_vect
__interrupt void TIMER0_OVF_ISR()
{  
    // Динамическая индикация четырехразрядного индикатора
    switch(znak)
    {
      case 0:
        {
            int temp = (pValue == &Result.TemperatureTC)
                      ? (int)(Result.TemperatureTC * 10) : *(int*)pValue;
            
            // Преобразовать значение *pValue в BCD число:
            bin2bcd(ABS(temp));
            
            if(temp < 0)
            {
                if(temp > -10)
                {
                    Digit.Ten = MINUS;
                    Digit.Hundred = EMPTY;
                    Digit.Thousand = EMPTY;
                }
            
                else if(temp > -100)
                {
                  Digit.Hundred = MINUS;  
                  Digit.Thousand = EMPTY;
                }
                
                else if(temp > -1000)
                  Digit.Thousand = MINUS;  
            }
            else
            {
                if(temp < 10)
                  Digit.Ten = EMPTY;
                
                if(temp < 100)
                  Digit.Hundred = EMPTY;  
                
                if(temp < 1000)
                  Digit.Thousand = EMPTY;  
            }
        }
  
        digit(znak++);  // Включить первый (младший) разряд индикатора
        
        // Преобразовать значение единиц индикатора в 7-сегментный код и вывести в порт
        display(Digit.One);
        break;
  
      case 1:
        digit(znak++);    // Включить второй разряд индикатора
        
        // Преобразовать значение десятков индикатора в 7-сегментный код и вывести в порт
        display(Digit.Ten);
        
        if((pValue == &Result.TemperatureTC) && (Result.TemperatureTC < 1000))
        {
           PORTB |= (1 << POINT);
        }
        else
        {
           PORTB &= ~(1 << POINT);  
        }
        
        break;
        
      case 2:
        digit(znak++);    // Включить третий разряд индикатора
        
        // Преобразовать значение сотен индикатора в 7-сегментный код и вывести в порт
        display(Digit.Hundred);
        break;        
  
      case 3:
        digit(znak);      // Включить четвертый (старший) разряд индикатора
        
        // Преобразовать значение тысяч индикатора в 7-сегментный код и вывести в порт
        display(Digit.Thousand);        
          
        znak = 0;
        break;
    }
}
sgrig
Самое интересное вот здесь:
Цитата(alux @ Aug 6 2010, 18:04) *
ad7799_InitStatus = ad7799_Status();

В исходниках мне не по глазам физическая инициализация АЦП.
А почему не использовали AD7793? И опора встроенная, и делитель внутри...
alux
продолжение...
Код
//------------------------------------------------------------------------------
static unsigned char ad7799_InitStatus;


//------------------------------------------------------------------------------
static void ad7799_Reset()
{
    for(unsigned char i = 0; i < 4; i++)
        SpiTransferByte(0xff);
}


// Helper request function
//------------------------------------------------------------------------------
static inline void ad7799_Comm(unsigned char reg, unsigned char read, unsigned char cont)
{
    SpiTransferByte((read ? 0x40 : 0x00) | (reg << 3) | (cont ? 0x04 : 0x00));
}


// Return the contents of the AD7799 register ( OFFSET or FULL-SCALE )
//------------------------------------------------------------------------------
unsigned long ad7799_Read(unsigned char reg)
{
    ad7799_Comm(reg, 1, 0);
    unsigned long val = 0;
    
    if(ad7799_InitStatus & AD7799_STATUS_IS_AD7799)
       val |= (unsigned long)SpiTransferByte() << 16;
    val |= (unsigned long)SpiTransferByte() << 8;
    val |= (unsigned long)SpiTransferByte();
    
    return val;
}


//------------------------------------------------------------------------------
unsigned char ad7799_Status()
{
    ad7799_Comm(AD7799_STATUS_REG, 1, 0);
  
    return SpiTransferByte();
}


//------------------------------------------------------------------------------
void ad7799_SetMode(unsigned char mode, unsigned char psw, unsigned char rate)
{
    ad7799_Comm(AD7799_MODE_REG, 0, 0);
    SpiTransferByte(mode << 5 | (psw ? 0x10 : 0x00));
    SpiTransferByte(rate);
}


//------------------------------------------------------------------------------
void ad7799_WriteConfig(unsigned char burnout, unsigned char unipolar, unsigned char gain,
                        unsigned char ref_det, unsigned char buf, unsigned char chan)
{
    ad7799_Comm(AD7799_CONFIG_REG, 0, 0);
    SpiTransferByte((burnout ? 0x20 : 0x00) | (unipolar ? 0x10 : 0x00) | gain);
    SpiTransferByte((ref_det ? 0x20 : 0x00) | (buf ? 0x10 : 0x00) | chan);
}


// Write value to the AD7799 register ( OFFSET or FULL-SCALE )
//------------------------------------------------------------------------------
void ad7799_Write(unsigned char reg, signed long value)
{
    ad7799_Comm(reg, 0, 0);  
  
    if(ad7799_InitStatus & AD7799_STATUS_IS_AD7799)
       SpiTransferByte(value >> 16);

    SpiTransferByte(value >> 8);    
    SpiTransferByte(value);
}

// Determine if data is ready to be read, could also be implemented by reading the status register
//------------------------------------------------------------------------------
bool ad7799_DataReady()
{
    return !(PIND & (1 << RDY));      //DD_MISO
}


// Request a read from the data register
//------------------------------------------------------------------------------
void ad7799_RequestData(unsigned char continuous)
{
    ad7799_Comm(AD7799_DATA_REG, 1, continuous);
}


// Read from data register, it should be previously requested from ad7799_request_data, the value is signed
//------------------------------------------------------------------------------
unsigned long ad7799_ReadData()
{
    unsigned long val = 0;

    if(ad7799_InitStatus & AD7799_STATUS_IS_AD7799)
    {
        val = SpiTransferByte();
        val <<= 8;
    }

    val |= SpiTransferByte();
    val <<= 8;
    val |= SpiTransferByte();

    return val;
}

АЦП использовал то, что было под рукой.
Драйвер АЦП отлажен, с этим вопросов быть не должно. Пару лет назад делал под AD7794. Проблем с измерением ТП не возникало...
Tanya
Цитата(alux @ Aug 6 2010, 15:51) *
продолжение...

Вы нас сильно грузите... Может, перепишете программку, чтобы видеть сырой код с АЦП. Или регистры...
Увидела (?) только, что Вы включаете Burnout. Тогда Ваш делитель...
sensor_ua
Код
(AdcValue - STEPS_B) * VREF / 128 / STEPS_B
эквивалентно
Код
(AdcValue - STEPS_B)/(2^(30))* VREF
- похоже, просто не хвататет разрядности
Т.е. я бы предложил переписать примерно так
Код
#define STEPS_B 8388608LL
long long Vtc(long long AdcValue)
{
return ((long long)(AdcValue - STEPS_B)*5000000LL>>31LL);
}

Получится целое значение в микроВольтах. Ошибка должна быть небольшая - где-то в районе 1 мкВ
alux
Цитата(sensor_ua @ Aug 6 2010, 16:37) *
Код
(AdcValue - STEPS_B) * VREF / 128 / STEPS_B
эквивалентно
Код
(AdcValue - STEPS_B)/(2^(30))* VREF
- похоже, просто не хвататет разрядности

#define STEPS_B 8388608.0 // Full-Scale 2^(24-1) for bipolar operation
Обратили внимание, что действия происходят с вещественными числами?
sensor_ua
Цитата
Обратили внимание

Обратил. Но там тоже есть разрядность. И из-за её ограниченности бывают характерные ошибки. http://ltwood.wikidot.com/float Сначала long с реальным значением несколько более 2^23 приводится к float, а не double, потому как STEPS_B имеет тип float, потом это нечто умножается на float 2.5, потом ещё пару действий с float, ну и уж потом выполняется приведение к double.
И чтобы double действительно было double, а не float, часто компилеру опции нужно выставлять, но и то это имеет смысл если ещё и в поставке есть соответствующие либы.
В данном случае (термопара для чего-то там) собственная ошибка сигнала не стОит оперирования с ним как с вещественным значением.
Tanya
Цитата(sensor_ua @ Aug 6 2010, 18:04) *
В данном случае (термопара для чего-то там) собственная ошибка сигнала не стОит оперирования с ним как с вещественным значением.

Добавлю? Можно даже и так.
Чтобы перевести кванты АЦП в микровольты можно подобрать рациональное число, обеспечивающее нужную точность и...
микровольты (или миллиградусы или сотые градуса) = кванты (без смещения)* числитель / знаменатель.
Как подобрать - http://ru.wikipedia.org/wiki/%D0%9D%D0%B5%...%BE%D0%B1%D1%8C
Чтобы правильно переводить в градусы нужно еще вычесть Эдс температуры холодных спаев в квантах. Но это все равно придется делать.
alux
В симуляторе проверил функцию Result.TemperatureTC = Vtc(x) * 1000; // операции с вещественными числами
где x - крайние значения 0х000000 и 0хffffff. Все верно посчиталось : получается в первом случае -19.5 мВ, во втором +19.5 мВ. Если умножить на 128 получим приблизительно соответственно -/+ 2.5 В.

PS. И если бы проблема была бы с переполнением вычислений, то как объяснить тот факт, что при "неправильном" подключении ТП все работает, только наоборот? Хоть бери и значения инвертируй...
MrYuran
А если откинуть пока лишнюю математику и посмотреть непосредственно коды АЦП?
alux
Для этого необходимо либо UART, либо ЖКИ.
Tanya
Цитата(alux @ Aug 6 2010, 22:55) *
Для этого необходимо либо UART, либо ЖКИ.

Это зачем?
alux
чтобы выводить 8-значные числа кодов АЦП.

PS. Очень похоже на нехватку памяти при делении вещественных чисел. В какой-то момент при неизменном коде все вдруг стало работать. Значение напряжения на ТП стало расти с температурой. Включал, выключал прибор несколько раз. Все стало пучком... Затем все стало, как было.

Цитата(sensor_ua @ Aug 6 2010, 16:37) *
Т.е. я бы предложил переписать примерно так
Код
#define STEPS_B 8388608LL
long long Vtc(long long AdcValue)
{
return ((long long)(AdcValue - STEPS_B)*5000000LL>>31LL);
}

Получится целое значение в микроВольтах. Ошибка должна быть небольшая - где-то в районе 1 мкВ


PS.
Код
enum { AD7799_1_GAIN, AD7799_2_GAIN, AD7799_4_GAIN, AD7799_8_GAIN,
       AD7799_16_GAIN, AD7799_32_GAIN, AD7799_64_GAIN, AD7799_128_GAIN };

#define BITS            24

int Vtc(long AdcValue)
{
   return (AdcValue - STEPS_B) * VREF >> (AD7799_128_GAIN + BITS - 1);  //30;  
}

Та же фигня! При правильном подключении ТП - напряжение не меняется (по крайней мере то, что вывожу на индикатор), а при обратном включении все работает, только наоборот sad.gif
sgrig
Burnout выключите. Какой проц используете? JTAG или что-то подобное на борту есть?
alux
Burnout выключен, - проблема та же.
ATmega8535. Буду подключать UART, чтобы посмотреть коды АЦП.
sgrig
А сколько сегментов на индикаторе?

Для меня сомнительно использование float-арифметики на таком дохлом проце. Попробуйте удвоить стек, если компиллятор IAR.
alux
я переделал под целочисленную арифметику, по совету sensor_ua. Проблема осталась.
На индикаторе 4 сегмента
Tanya
Цитата(alux @ Aug 7 2010, 14:53) *
На индикаторе 4 сегмента

Вот на него и выводите регистры АЦП. И сырой код.
sensor_ua
Так сколько показывает? И какое напряжение сигнала термопары?
Насчёт целочисленной арифметики - как минимум не понял насчёт VREF - оно осталось вещественным или как?
alux
Цитата(sensor_ua @ Aug 7 2010, 14:44) *
Так сколько показывает? И какое напряжение сигнала термопары?
Насчёт целочисленной арифметики - как минимум не понял насчёт VREF - оно осталось вещественным или как?

Забыл написать
Код
#define VREF            2500000LL   // VREF = +2.5 V

Цитата(Tanya @ Aug 7 2010, 14:11) *
Вот на него и выводите регистры АЦП.

Объясните, пожалуйста, каким образом вывести значение 24-битного регистра в 4-разрядный индикатор?
Лучше уж подкличить UART, тогда все станет понятно. Я сейчас этим и занимаюсь.

Tanya
Цитата(alux @ Aug 7 2010, 16:11) *
Объясните, пожалуйста, каким образом вывести значение 24-битного регистра в 4-разрядный индикатор?
Лучше уж подкличить UART, тогда все станет понятно. Я сейчас этим и занимаюсь.

1000 способов. Например, номер и значение,... последовательно с паузой между выдачей... 0...9. A..F... или по кнопочке...
Можно только один бит посмотреть - биполярный или униполярный режим...
sensor_ua
Самое простое, если у Вас 8-и-сегментные индикаторы(8 и точка) - выводить по биту целого на сегмент - да не цифры, а козявки, но инфы достаточно

Посмотрел ещё раз на Ваш вариант целого - думаю, что без long long переполнение обеспечено.
При сигнале 3 мВ код АЦП в идеале должен быть 9677098 (0x93A92A)
(AdcValue - STEPS_B)*VREF = 3.221225E+12 (0x2EDFFF8CC40)
0хFFF8CC40>>30 = 0x03
Но Вы написали
Цитата
Код
#define VREF            2500000LL   // VREF = +2.5 V

Может, препроцессор лажанулся и пересчитал и подставил VREF >> (AD7799_128_GAIN + BITS - 1) ? Тогда будет ноль. Скобками можно это проверить
alux
Цитата(sensor_ua @ Aug 7 2010, 16:15) *
Посмотрел ещё раз на Ваш вариант целого - думаю, что без long long переполнение обеспечено.
Может, препроцессор лажанулся и пересчитал и подставил VREF >> (AD7799_128_GAIN + BITS - 1) ?

Я очень сомневаюсь, что компилер будет игнорировать порядок выполнения арифметических операция и правила приведения типов, которые описаны в любом учебнике по С/С++. Согласно общепринятым правилам, выполняются вначале выражения в скобках, затем слева направо учитывая приоритет операций. Когда результат вычитания (ADC_Value - STEP_B), который имеет тип long , умножается на VREF, имеющий тип long long, то первый операнд приводится к типу long long. Операция >> имеет меньший приоритет, чем *. Это даже не стоит проверять.
sensor_ua
Насчёт long long Вы написали всё правильно и я на это обратил внимание (правда не сразу, потому и редактировал пост добавлением).
Цитата
Я очень сомневаюсь, что компилер будет игнорировать порядок выполнения арифметических операция и правила приведения типов, которые описаны в любом учебнике по С/С++.

Я ясно написал, что возможно проблема у препроцессора, но если бы Вы всё-таки чётко выдали нагора то неправильное число, то и гаданий было бы меньше. А приоритет операций кроме арифметическихwink.gif, представьте себе, никогда не запоминал и не собираюсь, ибо не на одном Си свет клином сошёлся. Потому если мне надо, то смотрю не учебник, а справочник. И не стесняюсь. В данном случае выдал предположение насчёт возможного нарушения обработки из-за наличия не переменных или констант в последовательной записи , а только литералов. Вам помочь пытаюсь, а Вы одно число выдать боитесьwink.gif

Ещё у Вас есть усреднение. Интересно было бы узнать значение Value.Average // (1 << NMAX) на предмет опять же переполнения Result.Data[Result.Channel].
alux
Подключил UART. Отдельная плата с MAX232, соединяется через 4 проводка: общий, +5В, RXD, TXD. В программу добавил драйвер UART, которым всегда пользуюсь. Но почему-то всегда передает 0x00, чтобы я не посылал.
Какое-то проклятие!!! smile3046.gif

Сейчас вывожу на 7-сегм индикатор значение напряжения в микровольтах, значение int.
При правильном включении ТП показывает значение -1.5 ... -1.7 мВ. ТП прикладываю к горячему. Показания не меняются.
Но если подключить неправильно ТП ("-" ТП на AIN1+ ) , то значения меняются по температуре, но в отрицательную область!
Я уже все больше склоняюсь к мысли, может просто убрать этот минус и пусть работает так?

Но все же этому должно быть какое-то простое объяснение.

PS. Значение Value.Average = 4, и это нее приведет к переполнению.

PS2. Это ж надо так было облажаться!!!

Код
// Read from data register, it should be previously requested from ad7799_request_data, the value is signed
//------------------------------------------------------------------------------
unsigned long ad7799_ReadData()
{
    unsigned long val = 0;

..................

Нужно возвращать значение типа long !. Главное, что в шапке функции я об этом специально написал smile.gif
Все теперь работает.
Спасибо.
Krys
Цитата(MrYuran @ Aug 6 2010, 03:32) *
Что-то мне кажется, что не должно АЦП мерить напряжение выше опоры.
Полностью поддерживаю! Это следует из принципа работы АЦП, где опора на делителе делится на много-много ответвлений, а потом происходит сравнение.

Цитата(alux @ Aug 6 2010, 12:57) *
Покажите, пожалуйста, в даташите, где сказано о том, что напряжение на входе не должно превышать опорное?
Тогда разность напряжений не должна превышать опору.
А вообще, насколько я разбирался с АЦП в Attiny (это конечно не одно и то же), то биполярный режим - это всего лишь способ представления данных: со знаком минус или без знака. А
Цитата
измерение напряжения на положительном входе относительно отрицательного входа АЦП
- это дифференциальный режим измерений, с биполярным не связанный.
Другими словами, дифференциальность производится аналогово (вычитанием на входном ОУ), а биполярность делается в цифре - смещением нуля по шкале.
И это совершенно независимые параметры.
sensor_ua
Цитата
Полностью поддерживаю! Это следует из принципа работы АЦП

АЦП бывают разных видов. Как и их входные каскады. В данном случае Вы и MrYuran ошибаетесь
Вот выдержка из DS AD7799:
The AD7798/AD7799 can be programmed to have a gain of 1, 2, 4, 8, 16, 32, 64, or 128 using Bit G2 to Bit G0 in the configuration register. Therefore, with a 2.5 V reference, the unipolar ranges are from (0 mV to 19.53 mV) to (0 V to 2.5 V), and the bipolar ranges are from ±19.53 mV to ±2.5 V. When the in-amp is active (gain ≥ 4), the common-mode voltage (AIN(+) + AIN(−))/2 must be greater than or equal to 0.5 V.
If the AD7798/AD7799 operate with a reference that has a value equal to AVDD, the analog input signal must be limited to 90% of VREF/gain when the in-amp is active for correct operation.
BIPOLAR/UNIPOLAR CONFIGURATION
The analog input to the AD7798/AD7799 can accept either unipolar or bipolar input voltage ranges. A bipolar input range does not imply that the parts can tolerate negative voltages with respect to system GND. Unipolar and bipolar signals on the AIN(+) input are referenced to the voltage on the AIN(–) input. For example, if AIN(−) is 2.5 V and the ADC is configured for unipolar mode and a gain of 1, the input voltage range on the AIN(+) pin is 2.5 V to 5 V.
If the ADC is configured for bipolar mode, the analog input range on the AIN(+) input is 0 V to 5 V. The bipolar/unipolar option is chosen by programming the U/B bit in the configuration register.
Krys
Цитата(sensor_ua @ Aug 10 2010, 21:45) *
АЦП бывают разных видов. Как и их входные каскады. В данном случае Вы и MrYuran ошибаетесь
Вот выдержка из DS AD7799:
The AD7798/AD7799 can be programmed to have a gain of 1, 2, 4, 8, 16, 32, 64, or 128
Cогласен, я забыл о наличии усиления перед непосредственно аналого-цифровым преобразованием. Таким образом, все мои утверждения справедливы для сигнала непосредственно перед АЦП, уже после усиления.
В любом случае, автору необходимо не забывать про такую цитату:
Цитата
A bipolar input range does not imply that the parts can tolerate negative voltages with respect to system GND.
Для просмотра полной версии этой страницы, пожалуйста, пройдите по ссылке.
Invision Power Board © 2001-2025 Invision Power Services, Inc.