⚠ 11.2023: Сайт знаходиться в стані перебудови. Можливо тимчасове порушення функціонування.

Підключення кількох термопар до мікроконтролера PIC16F628A через аналогово-цифровий перетворювач AD7792, AD7793 з інтерфейсом SPI. Приклад коду

Основні можливості AD7792 та AD7793

AD7792 та AD7793 - представляють собою (ADC) з мультиплексором на 3 канали, внутнішнє та зовнішнє джерело опорної напруги, інструментальний підсилювач з коефіцієнтом підсилення від 1 до 128 раз, додатковим буферним повторювачем напруги, вбудований датчик температури і інше:

Інші характеристики дивіться в документації.

Блок-схема ікросхеми аналогово-цифрового перетворювача AD7792

Термопара + AD7792 + PIC16F628A

Схему вимірювання було вирішено встановити ближче до датчиків, тому на одній платі з AD7792 розташувався і недорогий мікроконтролер PIC16F628A, який виконує необхідний обмін даними з АЦП за інтерфейсом SPI і передає результати вимірювання (за запитом) каналом RS485.

Схема електрична принципова вимірювання температури за допомогою термопар ТХА, ТКХ на базі: AD7792, PIC16F628 та MAX485

Як видно, схема вийшла дуже проста. Температура холодних спаїв вимірюється вбудованим у мікросхеу AD7792 датчиком температури.

Нижче наведено приклад вихідного коду для керування АЦП.

Приклад вихідного коду для PIC16F628A

Початкова ініціалізація АЦП

//Скидання АЦП. 32 клоки з Dout=1
SendSPI(0xFF,8);
SendSPI(0xFF,8);
SendSPI(0xFF,8);
SendSPI(0xFF,8);
delay_ms(1); //Пауза

while(Din==1);//Очікування завершення процедури скидання


//Налаштування режиму роботи
//IO REG

SendSPI(0b00101000,8); //28h
delay_us(5);
SendSPI(0b00000000,8); //Опорна напруга вимкнена

Вибір каналу АЦП

void ADC_configure_chanel(unsigned char Ch)
//Ch - номер каналу, від 1 до 3 - входи, 4 - внутрішній датчик температури
{
//Config REG
SendSPI(0b00010000,8); // 10h
delay_us(5);
if (Ch==1) SendSPI(0b0100111010010000,16); //CH1: GAIN=64 = 18.28mV; Vbias = -AN1; ref=internal; buf=on
if (Ch==2) SendSPI(0b0100111010010001,16); //CH2: GAIN=64 = 18.28mV; Vbias = -AN2; ref=internal; buf=on
if (Ch==3) SendSPI(0b0100111010010010,16); //CH3: GAIN=64 = 18.28mV ref=internal; buf=on
if (Ch==4) SendSPI(0b0100111110010110,16); //Temperature: GAIN=1/6 ref=1.17V
delay_us(5);
}

Самокалібрування

void ADC_Calibrate(void)
{
//Mode REG
SendSPI(0b00001000,8); //08h
delay_us(5);
SendSPI(0b1000000000001111,16); //Калібрування нуля
while(Din==1); //Чекаємо на завершення самокалібрування
//Mode REG
SendSPI(0b00001000,8); //08h
delay_us(5);
SendSPI(0b1010000000001111,16); //Калібрування шкали
while(Din==1); //Чекаємо на завершення самокалібрування
delay_us(5);
}

Запуск безперервного перетворення

void ADC_Start_Continuous_Conversion_Mode(void)
{
//Mode REG
SendSPI(0b00001000,8); //08h
delay_us(5);
SendSPI(0b0000000000001111,16); //0009h //Cont. conv.
delay_us(5);
}

Зчитування результатів перетворення з ADC

signed int16 ADC_Read_Data(void)
{
//Чекаємо закінчення перетворення
while(Din==1);
//Читаємо
//DATA REG

SendSPI(0b01011000,8); //58h
delay_us(5);
return ReadSPI(16);
}

Переведення АЦП в режим очікування:
void ADC_Shut_Down(void)
{
//Mode REG
SendSPI(0b00001000,8); //08h
delay_us(5);
SendSPI(0b0100000000001111,16); //0009h //Cont. conv.
delay_us(5);
}

Головна функція отримання температури

void RefreshAllData(void)
{
float T4f;
// Налаштовуємо канал 1
ADC_configure_chanel(1);
// Робимо самокалібрування
ADC_Calibrate();
// Запускаємо на перетворення
ADC_Start_Continuous_Conversion_Mode();
// Робимо паузу на 250 мсек. Ми не поспішаємо, нехай все "устаканиться"
delay_ms(250);
// Зчитуємо показання каналу 1 - Т1
T1_RAW=ADC_Read_Data()-0x8000; //Зміщення шкали ADC до нуля"

// Налаштовуємо канал 2
ADC_configure_chanel(2);
// Робимо самокалібрування
ADC_Calibrate();
// Запускаємо на перетворення
ADC_Start_Continuous_Conversion_Mode();
// Робимо паузу на
delay_ms(250);
// Зчитуємо показання каналу 2 - Т2
T2_RAW=ADC_Read_Data()-0x8000;

// Налаштовуємо канал 3
ADC_configure_chanel(3);
// Робимо самокалібрування
ADC_Calibrate();
// Запускаємо на перетворення
ADC_Start_Continuous_Conversion_Mode();
// Робимо паузу
delay_ms(250);
// Зчитуємо показання каналу 3 - Т3
T3_RAW=ADC_Read_Data()-0x8000;

//Було помічено глюк. Якщо щоразу перемикаються на вимірювання температури через вбудований датчик, то в цей час вимикається джерело підтягуючої напруги та конденсатори в ланцюжку фільтра на вході встигають трохи розрядиться, що викликає появу негативної напруги на диференційному вході і як наслідок - помітного зниження відображуваної температури. Тому внутрішню температуру вимірюю рідше, вона змінюється дуже повільно.
if (NeedT4refresh++>10)
{
NeedT4refresh=0;
// Налаштовуємо канал ТЕМПЕРАТУРА
ADC_configure_chanel(4);
// Запускаємо на перетворення
ADC_Start_Continuous_Conversion_Mode();
// Робимо паузу
delay_ms(255);
// Зчитуємо показання каналу ТЕМПЕРАТУРА - Т4
T4_RAW=ADC_Read_Data();

ADC_configure_chanel(1); //Після роботи з вбудованим термодатчиком
delay_s(3); //робимо паузу на відновлення заряду конденсаторів.
}

Завдяки тому, що всі канали АЦП виконані на одному кристалі, в одному технологічному процесі, вони мають дуже близькі характеристики, що дозволяє використовувати одну функцію для перетворення "відліки АЦП" - "температура".

Враховуючи, що у поставленій задачі висока точність вимірювань не потрібна, компенсація температури холодного спаю виконувалася просто приплюсовування температури холодного спаю до температури гарячого спаю. Це дало прийнятну точність у робочому діапазоні температур (від 20 до 350 градусів Цельсія).

Перевірка вбудованого датчика темпери показала його високу лінійність в діапазоні від -16 до +30 градусів (у цих межах виконувалось тестове вимірювання).

Опубліковано

Оновлено 27.11.2023


Serhii K Home Page (c) 2003-2023
(SKNewVersion)