реклама на сайте
подробности

 
 
3 страниц V  < 1 2 3 >  
Reply to this topicStart new topic
> Проблема с термопарой, ... или с АЦП ?
sgrig
сообщение Aug 6 2010, 11:43
Сообщение #16


Участник
*

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



Самое интересное вот здесь:
Цитата(alux @ Aug 6 2010, 18:04) *
ad7799_InitStatus = ad7799_Status();

В исходниках мне не по глазам физическая инициализация АЦП.
А почему не использовали AD7793? И опора встроенная, и делитель внутри...
Go to the top of the page
 
+Quote Post
alux
сообщение Aug 6 2010, 11:51
Сообщение #17


Знающий
****

Группа: Свой
Сообщений: 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. Проблем с измерением ТП не возникало...
Go to the top of the page
 
+Quote Post
Tanya
сообщение Aug 6 2010, 12:10
Сообщение #18


Гуру
******

Группа: Модераторы
Сообщений: 8 752
Регистрация: 6-01-06
Пользователь №: 12 883



Цитата(alux @ Aug 6 2010, 15:51) *
продолжение...

Вы нас сильно грузите... Может, перепишете программку, чтобы видеть сырой код с АЦП. Или регистры...
Увидела (?) только, что Вы включаете Burnout. Тогда Ваш делитель...
Go to the top of the page
 
+Quote Post
sensor_ua
сообщение Aug 6 2010, 13:37
Сообщение #19


Профессионал
*****

Группа: Свой
Сообщений: 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
Go to the top of the page
 
+Quote Post
alux
сообщение Aug 6 2010, 13:45
Сообщение #20


Знающий
****

Группа: Свой
Сообщений: 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
Обратили внимание, что действия происходят с вещественными числами?
Go to the top of the page
 
+Quote Post
sensor_ua
сообщение Aug 6 2010, 14:04
Сообщение #21


Профессионал
*****

Группа: Свой
Сообщений: 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
Go to the top of the page
 
+Quote Post
Tanya
сообщение Aug 6 2010, 14:39
Сообщение #22


Гуру
******

Группа: Модераторы
Сообщений: 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
Чтобы правильно переводить в градусы нужно еще вычесть Эдс температуры холодных спаев в квантах. Но это все равно придется делать.
Go to the top of the page
 
+Quote Post
alux
сообщение Aug 6 2010, 18:36
Сообщение #23


Знающий
****

Группа: Свой
Сообщений: 589
Регистрация: 24-04-05
Пользователь №: 4 447



В симуляторе проверил функцию Result.TemperatureTC = Vtc(x) * 1000; // операции с вещественными числами
где x - крайние значения 0х000000 и 0хffffff. Все верно посчиталось : получается в первом случае -19.5 мВ, во втором +19.5 мВ. Если умножить на 128 получим приблизительно соответственно -/+ 2.5 В.

PS. И если бы проблема была бы с переполнением вычислений, то как объяснить тот факт, что при "неправильном" подключении ТП все работает, только наоборот? Хоть бери и значения инвертируй...
Go to the top of the page
 
+Quote Post
MrYuran
сообщение Aug 6 2010, 18:42
Сообщение #24


Беспросветный оптимист
******

Группа: Свой
Сообщений: 4 640
Регистрация: 26-12-07
Из: Н.Новгород
Пользователь №: 33 646



А если откинуть пока лишнюю математику и посмотреть непосредственно коды АЦП?


--------------------
Программирование делится на системное и бессистемное. ©Моё :)
— а для кого-то БГ — это Bill Gilbert =)
Go to the top of the page
 
+Quote Post
alux
сообщение Aug 6 2010, 18:55
Сообщение #25


Знающий
****

Группа: Свой
Сообщений: 589
Регистрация: 24-04-05
Пользователь №: 4 447



Для этого необходимо либо UART, либо ЖКИ.
Go to the top of the page
 
+Quote Post
Tanya
сообщение Aug 7 2010, 03:36
Сообщение #26


Гуру
******

Группа: Модераторы
Сообщений: 8 752
Регистрация: 6-01-06
Пользователь №: 12 883



Цитата(alux @ Aug 6 2010, 22:55) *
Для этого необходимо либо UART, либо ЖКИ.

Это зачем?
Go to the top of the page
 
+Quote Post
alux
сообщение Aug 7 2010, 06:19
Сообщение #27


Знающий
****

Группа: Свой
Сообщений: 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;  
}

Та же фигня! При правильном подключении ТП - напряжение не меняется (по крайней мере то, что вывожу на индикатор), а при обратном включении все работает, только наоборот sad.gif
Go to the top of the page
 
+Quote Post
sgrig
сообщение Aug 7 2010, 07:12
Сообщение #28


Участник
*

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



Burnout выключите. Какой проц используете? JTAG или что-то подобное на борту есть?
Go to the top of the page
 
+Quote Post
alux
сообщение Aug 7 2010, 07:47
Сообщение #29


Знающий
****

Группа: Свой
Сообщений: 589
Регистрация: 24-04-05
Пользователь №: 4 447



Burnout выключен, - проблема та же.
ATmega8535. Буду подключать UART, чтобы посмотреть коды АЦП.
Go to the top of the page
 
+Quote Post
sgrig
сообщение Aug 7 2010, 08:02
Сообщение #30


Участник
*

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



А сколько сегментов на индикаторе?

Для меня сомнительно использование float-арифметики на таком дохлом проце. Попробуйте удвоить стек, если компиллятор IAR.
Go to the top of the page
 
+Quote Post

3 страниц V  < 1 2 3 >
Reply to this topicStart new topic
1 чел. читают эту тему (гостей: 1, скрытых пользователей: 0)
Пользователей: 0

 


RSS Текстовая версия Сейчас: 9th July 2025 - 01:13
Рейтинг@Mail.ru


Страница сгенерированна за 0.01509 секунд с 7
ELECTRONIX ©2004-2016