Пещера отшельного фердопердозника

2009-11-10

Теория и практика применения термосопротивления на ADuC847

Рубрика: low-level programming, programming — Метки: , , , , — datacompboy @ 02:05:01 | 1,158 views

В прошлый раз, было описано как измерить температуру с помощью термопары. Термопара позволяет производить измерение в довольно широком диапазоне, но в случае, когда нужна высокая стабильность измерения и чуствительность к малым изменениям — применяют термосопротивления.
Термосопротивления работают в меньшем диапазоне (до 600 градусов в пределе), зато они описываются полиномом второй степени (третьей, если включать отрицательный диапазон), имеют очень высокую стабильность считываемого показания (поскольку сигнал измеряется десятками Ом на градус, а не милливольтами).

Чтобы измерить температуру с помощью термосопротивления, нужно замерить его сопротивление, и по его передаточной характеристике определить температуру. Для измерения сопротивления через резистор пропускают ток и с помощью АЦП замеряют напряжение на резисторе. Не вдаваясь в схемотехнику, примем следующее: к паре AIN1-AIN2 подведены выводы с термосопротивления, к паре AIN3-AIN4 подведены выводы с опорного стабильного сопротивления. Через оба резистора идёт один и тот же ток. Теперь, чтобы получить текущее сопротивление терморезистора нужно сделать следующее:
1. Измеряем напряжение на опорном сопротивлении. Uo=I*Ro (где Uo — напряжение опоры, Ro — опорное сопротивление).
2. Измеряем напряжение на термосопротивлении. Uт=I*Rт.
3. I = Uo/Ro, Rт = Uт/I = Uт/Uo * Ro
Таким образом, чтобы выяснить текущее сопротивление нам нужно измерить отношение напряжений между опорным и измерительным резисторами и домножить на сопротивление опорного резистора. Поскольку операция деления является черезвычайно дорогой, воспользуемся тем, что пара AIN3-AIN4 может использоваться как опора. При этом, снимаемый код будет ни чем иным, как «какое напряжение имеет сигнал с пары, считая что опора на REFIN(или REFIN2) равна 2.5В». То есть, измеренный сигнал приводится к «известной» опоре.

При этом следует помнить, что мы так же можем включить умножение измеряемого сигнала такое, чтобы полный диапазон температур использовал все доступные эффективные биты ацп. Следует так же помнить, что напряжение с опорного сопротивления желательно иметь близким, но не большим чем 2.5В.

В моем случае, опорное сопротивление составляет 5КОм (2 резистора по 10КОм в параллель), напряжение с опорного сопротивления около 2В.
При этом, включив делитель измерения 0.064, полный диапазон температур (до 600 градусов) умещается во все 24 разряда АЦП.

В результате исследования шумов измерительного тракта, оказалось, что «осмысленными» являются толькол 14.5 бит измеряемого сигнала, что означает, что из измеряемых 24 разрядов можно использовать только старшие 16, так как младшие представляют собой только шум.

Итак, у нас есть опорное напряжение около 2В на AIN3-AIN4, термосопротивление (платина 100Ом) подключено к паре AIN1-AIN2, и мы хотим узнать температуру в градусах. Первым делом, нам нужно измерить отношение напряжения на термосопротивлении к опорному напряжению. Для этого

                 MOV  ADC0CON2, #10001010b ; Измерение AIN1-AIN2 относительно AIN3-AIN4 (REFIN2)
                 MOV  ADC0CON1, #00100011b ; Измерение 0...160mV (REF*0.064)
                 MOV  ADCSF, #REQ_SF
                 MOV  ADCMODE, #00100100b ; Калибровка нуля
                 MOV  ADCMODE, #00100101b ; Калибровка максимума
                 MOV  ADCMODE, #00100010b ; Запросить 1 измерение на основном АЦП

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

; INTERRUPT from ADC
         ORG 0033H
ADCInt:  MOV DataH, ADC0H ; Термопару сохраняем в DataH/M/L
         MOV DataM, ADC0M
         MOV DataL, ADC0L
         SETB ADCReady    ; И ставим бит ADCReady. Бит ADCBusy сбросит основная программа
         CLR RDY0
         RETI

,
считываем код ацп и выходим. Итак, у нас есть измеренное с АЦП значение (Кт), которое представляет собой Uт, считая что Uо=2.5В, еще и усиленное.
В числах, после удаления делителей, некратных степени двойки, получаем:
8000*Rт = 2*Rо*Кт / 256
Взяв 2*Rо за калибровочный коэффициент (в случае использования идеальных компонент 2Rо = 10000), построим таблицу соответствия 8000*Rт => Температура. Для этого накидаем маленькую простенькую программку, которая через каждые 65536 значений для 8000*Rт выдаст соответствующую температуру. Аналогично прошлому разу, температуру будем задавать в квантах по 1/32 градуса (фиксированная двоичная точка в 5 бит).

В сухом остатке, у нас есть: таблица из 40 точек термосопротивления, между каждой из которых 65536 отсчетов, а сама таблица содержит линейную температуру в кельвинах (чтобы работать с беззнаковыми числами), код с АЦП и калибровочный коэффициент наклона. Дальше вычисления просты:
1. Перемножаем 16бит кода АЦП на 16бит коэффициент. Из результата оставляем только 3 старших байта (для деления на 256 нужно отбросить младший байт).
2. Из полученных 24 бит, старшие 8 бит — точка входа в таблицу (она построена через 65536 значения)
3. Из таблицы выбираем пару чисел в точке входа, выбираем следующую пару и вычисляем разницу между следующей парой и текущей — получаем температурную длину диапазона
4. Умножаем разницу по таблице на младшие 16бит произведения, считая только старшие 16 бит результата — получаем фактическую добавку температуры внутри диапазона
5. Прибавляем к фактической добавке начало диапазона — мы определили температуру.

В коде это выглядит примерно так:

CalcMainRes:
    ; Вычислить как термосопротивление
    ; В Data1 - напряжение на терморезисторе, относительно опоры
    ; U0 = I*R0; }  I=U0/R0
    ; U1 = I*R1; }  R1=U1/U0*R0
    ; где Data1 < => U1, R0 = 5K, U0=2.5В
    ; ================================= Таблица температур в 40 точках через
    ; == 8000*R1 = [2R0]*Data1 / 256 == 65535 от 8000*R1
    ; ================================= Калибровочный 2R0 изначально 10000
    ; R2:R1:R0 = Data1*Coeff/256
    MOV A, Data1H ;  R2:R1 = Data1H*CoeffH
    MOV B, CoeffH
    MUL AB
    MOV R2, B
    MOV R1, A
    ; ---
    MOV A, Data1M ; R1:R0 = Data1M*CoeffH
    MOV B, CoeffH
    MUL AB
    MOV R0, A
    MOV A, B
    ADD A, R1
    MOV R1, A
    JNC CMRNoOv1
    INC R2
CMRNoOv1:
    ; ---
    MOV A, Data1H ; R1:R0 = Data1H*CoeffL
    MOV B, CoeffL
    MUL AB
    ADD A, R0
    MOV R0, A
    MOV A, B
    JNC CMRNoOv2
    INC A
    JNZ CMRNoOv2
    INC R2
CMRNoOv2:
    ADD A, R1
    MOV R1, A
    JNC CMRNoOv3
    INC R2
CMRNoOv3:
    ; ---
    MOV A, Data1M ; R0:Tmp = Data1M*CoeffL
    MOV B, CoeffL
    MUL AB
    JNB ACC.7, CMRNoOv4
    INC R0
    CJNE R0, #0, CMRNoOv4
    INC R1
    CJNE R0, #0, CMRNoOv4
    INC R2
CMRNoOv4:
    MOV A, B
    ADD A, R0
    JNC CMRNoOv5
    INC R1
    CJNE R1, #0, CMRNoOv5
    INC R2
CMRNoOv5:
    ; R2:R1:R0 = [2R0]*Data1/256.
    ; R2 = Вход в таблицу термосопротивления
    ; R1:R0 = интерполянт в таблице
    MOV A, R2
    ADD A, R2 ; A=2*R2
    ADD A, #LOW(RTD_100_385)
    MOV DPL, A
    MOV A, #HIGH(RTD_100_385)
    ADDC A, #0
    MOV DPH, A ; DPTR=таблица
    CLR A
    MOVC A, @A+DPTR
    MOV R4, A
    CLR A
    MOVC A, @A+DPTR
    MOV R5, A ; R5:R4 = текущая точка таблицы
    CLR A
    MOVC A, @A+DPTR
    CLR C
    SUBB A, R4
    MOV R6, A ; R7:R6 = разница следующей и текущей точек таблицы
    CLR A
    MOVC A, @A+DPTR
    SUBB A, R5
    MOV R7, A
    ; ThermoHL = R5:R4+(R7:R6*R1:R0)/65536
    ; R7*R1 => ThermoHL
    MOV A, R7
    MOV B, R1
    MUL AB
    MOV ThermoH, B
    MOV ThermoL, A
    ; R6*R1 => ThermoL:Tmp
    MOV A, R6
    MOV B, R1
    MUL AB
    MOV Tmp1, A
    MOV A, B
    ADD A, ThermoL
    MOV ThermoL, A
    JNC CRMTNoOv1
    INC ThermoH
CRMTNoOv1:
    ; R7*R0 => ThermoL:Tmp
    MOV A, R7
    MOV B, R0
    MUL AB
    ADD A, Tmp1
    JNB ACC.7, CRMTNoOv2
    INC ThermoL
    MOV A, ThermoL
    JNZ CRMTNoOv2
    INC ThermoH
CRMTNoOv2:
    MOV A, B
    ADDC A, ThermoL
    ;MOV ThermoL, A
    JNC CRMTNoOv3
    INC ThermoH
CRMTNoOv3:
    ; THermoHL += R5:R4
    ADD A, R4
    MOV ThermoL, A
    JNC CRMTNoOv4
    INC ThermoH
CRMTNoOv4:
    MOV A, R5
    ADD A, ThermoH
    MOV ThermoH, A
    ; ThermoH вычислено
    JMP CalcEnd

Отдельного внимания, конечно, заслуживает генератор таблицы… Однако, поскольку «математик» у меня только слово в дипломе, пытаться вывести обратный полином я не стал, а нарисовал просто итерационный процесс, который пробегает по одному градусу весь диапазон, на границах диапазона уточняя числа до 1e-5.
Подробно приводить код не буду, смотрите в приложенном gen_rtd.pl

Комментариев нет »

Комментариев нет.

RSS-лента комментариев к этой записи. URL обратной ссылки

Оставить комментарий

Сайт работает на WordPress