С помощью выполняющейся за короткое время программы и простой схемы микроконтроллер PIC может линеаризовать характеристику термистора, чтобы точно измерить температуру и отобразить результат на дисплее.
Измеряя температуру с помощью термистора, вы сталкиваетесь с проблемой линеаризации его отклика, необходимой для получения результатов требуемой точности. Одним из лучших методов линеаризации термистора является использование полиномиального уравнения Стейнхарта-Харта, дающего ошибку в 0.1 °C. Описываемая ниже конструкция рассчитана на диапазон температур от 0 °C до 100 °C.
Для того чтобы составить уравнение, потребуются три коэффициента термистора – A, B и C. Если изготовитель не предоставил такую информацию, вы можете найти коэффициенты, решив уравнения Стейнхарта-Харта (1…3) для трех различных температурных точек. В нашей схеме микроконтроллер PIC с необходимой точностью решает эти уравнения за 40 мс (Рисунок 1).
![]() |
|
Рисунок 1. | В этой простой схеме высокоточного термометра используется микроконтроллер PIC16F887 и ЖК индикатор. |
Для иллюстрации воспользуемся термистором LM103 с отрицательным температурным коэффициентом (NTC), сопротивление которого при трех различных температурах имеет значения, показанные в Таблице 1.
Таблица 1. | Сопротивление термистора. | ||||||||
|
Полученная в этих трех измерениях температура преобразовывается в градусы Кельвина и подставляется в три уравнения Стейнхарта-Харта:
![]() |
(1) |
![]() |
(2) |
![]() |
(3) |
Решая эту систему из трех уравнений, получаем коэффициенты A, B и C (Таблица 2).
Таблица 2. | Коэффициенты термистора. | ||||||||
|
Подставляя найденные коэффициенты в уравнение Стейнхарта-Харта, получаем выражение для термистора:
![]() |
(4) |
или:
![]() |
(5) |
Задача микроконтроллера PIC16F887 заключается в том, чтобы, используя Уравнение 4, получить истинные показания температуры. Для этого потребуется 1227 слов памяти микроконтроллера. Вывод AN0 объявлен аналоговым входом, а остальные линии порта – цифровыми входами. Аналого-цифровой преобразователь (АЦП) сконфигурирован для 10-битного разрешения с временем выборки 50 мкс.
Напряжение термистора в двоичном формате заносится в переменную volt инструкцией ADCIN 0, volt. Затем для преобразования в двоично-десятичную форму это значение умножается на 48,828 и сохраняется в переменной v1. Чтобы из v1 получить отдельные десятичные цифры, каждая из них с помощью команд DIG3, DIG2 и DIG1 записывается в переменные dig3, dig2 и dig, соответственно.
Исходный код программы термометра доступен для скачивания в разделе Загрузки. В программе объявляются и обрабатываются следующие переменные: B, A, C, L, volt, v1, v2, pattern, pattern2, pattern3, I, digit3, digit2 и digit. Кроме того, в процессе преобразования двоичного кода в двоично-десятичный используются переменные conv1 и conv2. В них содержатся младшие биты результата преобразования 10-разрядного АЦП, значение которых равно 4.8828 мВ.
Алгоритм, разработанный для получения показаний температуры на основе уравнения Стейнхарта-Харта, требует выполнения нескольких шагов.
Прежде всего, вычисляется напряжение источника питания (v1), равное 48828 × volt2. Переменная volt2 считывается с помощью АЦП микроконтроллера. Если напряжение источника соответствует требуемому значению, то volt2 = %1111111111, и тогда v1 = 49,951,044. Далее с помощью инструкции DIV32 переменная volt2 делится на 10,000, давая в результате величину 4995, приблизительно соответствующую напряжению источника питания 5 В.
На втором этапе вычисляется падение напряжения на термисторе. При этом полностью повторяются все действия первого шага, за исключением того, что теперь используется другой канал АЦП. Предположим, мы имеем в АЦП результат считывания напряжения 2.5 В (код АЦП равен 1000000000). После выполнения описанных в предыдущем абзаце манипуляций, получаем число 24,999,936, которое делится на 10 инструкцией DIV32 для получения результата 2499, примерно соответствующего напряжению 2.500 В.
Третьим шагом находим величину сопротивления с помощью следующей формулы:
![]() |
(6) |
Для этого мы запоминаем в переменной dif напряжение источника питания за вычетом напряжения термистора. А затем умножаем напряжение термистора на фиксированное сопротивление 10 кОм, и с помощью DIV32 делим последнее произведение на dif, получая величину сопротивления термистора.
На четвертом шаге, используя Уравнения (7…9), вычисляем логарифм по основанию 2 от сопротивления термистора:
![]() |
(7) |
![]() |
(8) |
![]() |
(9) |
где a0, a1 и a2 – последовательные цифры двоичной мантиссы.
Затем с помощью функции NCD мы находим параметр a0, или целую часть логарифма, представляющую старший значащий бит числа (MSB). Декрементировав его на 1, получим двоичный логарифм параметра. Например, мы хотим использовать четыре значащих цифры двоичного логарифма 47, равного 5.554. NCD(47) = 6, где 47 в двоичном представлении записывается как 00101111, и MSB находится в шестой позиции справа. Если декрементировать его на 1, получим число 5, являющееся целой части логарифма.
Для завершения вычисления логарифма необходимо найти его мантиссу (дробную часть). Для этого потребуется результат последовательных делений w на 2. Однако выполнить такую операцию напрямую невозможно, так как в результате деления 47 на 2 получается 23.5, и мы потеряем дробную часть. (PIC Basic Pro не работает с дробями). По этой причине для нахождения мантиссы мы используем специальную подпрограмму, выполняющую следующую последовательность действий:
47/2 = 23.5,
23.5/2 = 11.75,
11.75/2 = 5.875,
5.875/2 = 2.9375,
2.9375/2 = 1.46875.
При делении 47/2 = 23 с остатком 1, эта «1» появляется в результате первой операции деления из пяти, которые потребуется выполнить. Соответственно, дробь 1/25 = 0.03125. Работать с дробями мы не можем, поэтому вместо того, чтобы делить 1 на 2n, мы берем число 10,000 в качестве числителя и вызываем подпрограмму, вычисляющую знаменатель в зависимости от номера операции деления, в которой появляется остаток 1.
Затем мы суммируем результаты всех делений. Продолжая приведенный ниже пример, мы должны выполнить для этого следующие пять шагов:
- 47/2 = 23 с остатком 1 – это первая операция деления из пяти: 10,000/25 = 312.5 = 312;
- 23/2 = 11 с остатком 1 – это вторая операция деления из пяти: 10,000/24 = 625;
- 11/2 = 5 с остатком 1: 10,000/23 = 1250;
- 5/2 = 2 с остатком 1: 10,000/22 = 2500;
- 2/2 = 1 с остатком 0: прибавлять нечего.
В данном случае переменная ja равна 4687, и теперь только остается инкрементировать ее на 1. Поэтому мы делим ja на 1000, а затем складываем с 1000. Таким образом, ja = 1468, давая нам приблизительно упоминавшуюся выше исходную величину, умноженную на 1000 с четырьмя значащими цифрами.
Определив все M, мы должны найти мантиссу, используя описанные ранее процедуры. Деление на 2an не представляет сложности, поскольку работаем мы в двоичном базисе, и деление выполняется на 20 или 21. Возводя в квадрат, мы должны подумать, куда поместим произведение Ma на Ma, а затем разделить его на 1000, поскольку результат выходит за пределы 16 бит.
После того, как этот процесс будет выполнен необходимое число раз, мы должны привести an к десятичному основанию. Для этого последовательно умножаем его на соответствующие весовые коэффициенты 5, 25, 125, и т.д. И, поскольку работать с дробями мы не можем, умножаем еще на 5000, 2500, и так далее.
И, наконец, мы суммируем все члены мантиссы в десятичной форме, а затем делим сумму на 10. Далее прибавляем a0 × 1000 и записываем результат в переменную l2, в которой теперь будет храниться значение двоичного логарифма сопротивления термистора. На последнем шаге вычислим натуральный логарифм, который будет использован в уравнении. База логарифма изменяется следующим образом:
Поскольку ln(2) = 0.6931, нам достаточно просто умножить l2 на 6931, а затем, используя команду DIV32, разделить это число на 10,000 и сохранить результат в переменной lm, которая будет содержать натуральный логарифм сопротивления резистора, умноженный на 1000.
Для управления общим выводом ЖКИ в цикле for-next на вывод RD1 выводится «1» (Рисунок 2).
![]() |
|
Рисунок 2. | Подаваемый с вывода RD1 на общий вход ЖКИ сигнал частотой 40 Гц управляет регенерацией дисплея. |
Затем вызывается подпрограмма D, преобразующая двоично-десятичные данные в коды 7-сегментного индикатора. Функция LOOKUP конвертирует двоично-десятичное число digit3 в 7-сегментный формат, сохраняемый в pattern3. После чего для синхронизации с ЖКИ выполняется операция «исключающее ИЛИ» над pattern3 и значением RD1, хранящемся в виде байта в переменной L.
![]() |
|
Рисунок 3. | Оранжевая осциллограмма соответствует интервалу времени 33 мс, в течение которого выполняется вычисление логарифма. Еще 7 мс (синяя осциллограмма) требуются для получения достоверного отсчета. Таким образом, общее время обработки данных составляет 40 мс. |
Этот процесс повторяется для двух оставшихся цифр, во время дополнительной 10-миллесекундной паузы. Затем RD1 выключается, а его состояние сохраняется в байтовой переменной L. Вновь вызывается подпрограмма D, и синхровыход RD1 вновь активизируется на следующие 10 мс. После каждого выполнения функции LOOKUP каждому выводу индикатора соответствует вывод порта, управляющий определенным сегментом ЖКИ. Общее время обработки данных составляет 40 мс (Рисунок 3).
Ссылки
- Computing Logarithms Digit-by-Digit, Mayer Goldberg, BRICS RS-04-17. ISSN: 0909-0878
Загрузки
Исходный код программы термометра для микроконтроллера PIC16F887