|
|
  |
Проблема с термопарой, ... или с АЦП ? |
|
|
|
Aug 6 2010, 11:43
|
Участник

Группа: Участник
Сообщений: 45
Регистрация: 4-11-05
Из: Tomsk
Пользователь №: 10 464

|
Самое интересное вот здесь: Цитата(alux @ Aug 6 2010, 18:04)  ad7799_InitStatus = ad7799_Status(); В исходниках мне не по глазам физическая инициализация АЦП. А почему не использовали AD7793? И опора встроенная, и делитель внутри...
|
|
|
|
|
Aug 6 2010, 11:51
|
Знающий
   
Группа: Свой
Сообщений: 589
Регистрация: 24-04-05
Пользователь №: 4 447

|
продолжение... Код //------------------------------------------------------------------------------ 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. Проблем с измерением ТП не возникало...
|
|
|
|
|
Aug 6 2010, 13:37
|
Профессионал
    
Группа: Свой
Сообщений: 1 266
Регистрация: 22-04-05
Из: Киев
Пользователь №: 4 387

|
Код (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 мкВ
--------------------
aka Vit
|
|
|
|
|
Aug 6 2010, 13:45
|
Знающий
   
Группа: Свой
Сообщений: 589
Регистрация: 24-04-05
Пользователь №: 4 447

|
Цитата(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 Обратили внимание, что действия происходят с вещественными числами?
|
|
|
|
|
Aug 6 2010, 14:04
|
Профессионал
    
Группа: Свой
Сообщений: 1 266
Регистрация: 22-04-05
Из: Киев
Пользователь №: 4 387

|
Цитата Обратили внимание Обратил. Но там тоже есть разрядность. И из-за её ограниченности бывают характерные ошибки. http://ltwood.wikidot.com/float Сначала long с реальным значением несколько более 2^23 приводится к float, а не double, потому как STEPS_B имеет тип float, потом это нечто умножается на float 2.5, потом ещё пару действий с float, ну и уж потом выполняется приведение к double. И чтобы double действительно было double, а не float, часто компилеру опции нужно выставлять, но и то это имеет смысл если ещё и в поставке есть соответствующие либы. В данном случае (термопара для чего-то там) собственная ошибка сигнала не стОит оперирования с ним как с вещественным значением.
--------------------
aka Vit
|
|
|
|
|
Aug 6 2010, 14:39
|
Гуру
     
Группа: Модераторы
Сообщений: 8 752
Регистрация: 6-01-06
Пользователь №: 12 883

|
Цитата(sensor_ua @ Aug 6 2010, 18:04)  В данном случае (термопара для чего-то там) собственная ошибка сигнала не стОит оперирования с ним как с вещественным значением. Добавлю? Можно даже и так. Чтобы перевести кванты АЦП в микровольты можно подобрать рациональное число, обеспечивающее нужную точность и... микровольты (или миллиградусы или сотые градуса) = кванты (без смещения)* числитель / знаменатель. Как подобрать - http://ru.wikipedia.org/wiki/%D0%9D%D0%B5%...%BE%D0%B1%D1%8CЧтобы правильно переводить в градусы нужно еще вычесть Эдс температуры холодных спаев в квантах. Но это все равно придется делать.
|
|
|
|
|
Aug 7 2010, 06:19
|
Знающий
   
Группа: Свой
Сообщений: 589
Регистрация: 24-04-05
Пользователь №: 4 447

|
чтобы выводить 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; } Та же фигня! При правильном подключении ТП - напряжение не меняется (по крайней мере то, что вывожу на индикатор), а при обратном включении все работает, только наоборот
|
|
|
|
|
Aug 7 2010, 07:12
|
Участник

Группа: Участник
Сообщений: 45
Регистрация: 4-11-05
Из: Tomsk
Пользователь №: 10 464

|
Burnout выключите. Какой проц используете? JTAG или что-то подобное на борту есть?
|
|
|
|
|
Aug 7 2010, 08:02
|
Участник

Группа: Участник
Сообщений: 45
Регистрация: 4-11-05
Из: Tomsk
Пользователь №: 10 464

|
А сколько сегментов на индикаторе?
Для меня сомнительно использование float-арифметики на таком дохлом проце. Попробуйте удвоить стек, если компиллятор IAR.
|
|
|
|
|
  |
1 чел. читают эту тему (гостей: 1, скрытых пользователей: 0)
Пользователей: 0
|
|
|