Почти во всех системах промышленной автоматизации требуется регулирование какого-либо параметра. А регулирование основано на измерении параметра, например, температуры и воздействие на этот параметр, например, нагреватель с использованием отрицательной обратной связи. Поэтому важной частью этого процесса является измерение этих параметров и получение реальных значений.
У датчиков и контроллеров модулей, таких как, DRM88ER или MSU44R есть аналоговые входы для измерения сигналов с различных сенсоров. Ко входам можно подключить различные типы аналоговых датчиков с выходом по напряжению от 0 до 3 В или 5 В или 10 В или по току от 0 до 20 мА или сопротивлению. Полученные значение от 12 битного АЦП (есть устройства с более высоким разрешением 16 бит, 18 бит и 24 бита) выводятся в виде числа от 0 до 4095. Это полученное число ничего не значит для пользователя, то есть значение получается в попугаях. Конечно с таким числом можно работать при относительных измерениях, но все равно не понятно, что же оно означает. Хочется увидеть значение в тех величинах, которым соответствует датчик, например, градусы Цельсия для датчика температуры.
В этой статье разберемся какие бывают зависимости АЦП от измеряемой величины и как же получить реальные значения этой самой величины, посчитаем коэффициенты для преобразования.
Содержание
Показательная или экспоненциальная функция
3.1. Экспоненциальные датчикиЛинейная функция
4.1. Датчики с зависимостью сопротивления от температуры
4.2. Датчики с зависимостью напряжения от температуры
4.3. Датчики с зависимостью тока от температурыКак рассчитать коэффициенты линейной функции
6.1. Запись коэффициентов в регистры мдуляВстроенный калькулятор коэффициентов
7.1. Как реализован калькулятор в программе устройстваУсреднение значения
9.1. Способы расчёта среднего значенияРасчет среднего арифметического значения в модуле
10.1. Алгоритм среднего арифметического значения
Зависимость выходного значения от физической величины
Любой датчик имеет зависимость выходного значения, например, напряжения или сопротивления, или даже тока от значения, воздействующего на него параметра, например, температуры или давления.
И зависимость эта имеет явно выраженную функцию, например:
- логарифмическую,
- экспоненциальную,
- линейную,
- тригонометрическую (sin, cos, tan) в одной четверти,
- или ещё какую ни будь в определенным диапазоне.
Логарифмическая функция
Логарифмическая функция записывается таким образом:
где a — заданное число, a > 0, a ≠1, x — независимая переменная (аргумент). Логарифмическая функция является обратной для показательной функции, в которой уже неизвестная y и независимая переменная x меняются местами:
Для график будет выглядеть как на этом рисунке.

У логарифмической функции есть определенные свойства:
- , то есть логарифм определён только для положительных чисел. В нашем случае значение сопротивления или входное напряжение всегда положительные;
- График любой логарифмической функции проходит через точку (1; 0), т.е. .
- И другие свойства, непрерывность, бесконечность и прочее. В нашем случае она конечная и работает в диапазоне измеряемой величины.
Показательная или экспоненциальная функция
Переменная этой функции находится в показателе степени. Общий вид:
где и
.
График экспоненциальной функции будет выглядеть как на рисунке ниже.

Отличие от логарифмической функции в том, что в показательной функции мы возводим число a в степень x, а в логарифмической - ищем степень, в которую нужно возвести a, чтобы получить x.
Область определения показательной функции — все действительные числа, а область значений — только положительные действительные числа.
Остальные свойства у них одинаковые. Ключевое отличие в том, что эти функции взаимно обратные. Это значит, что они «отменяют» друг друга:
(для всех значений)
(для
)
Возможно это свойство можно применить для коррекции значений, но я пока не придумал как.
Экспоненциальные датчики
Типичный представитель датчика с логарифмическим графиком является NTC термистор сопротивлением 10 кОм, впрочем, как и с любым другим сопротивлением.
График зависимости сопротивления NTC термистора от температуры
Если внимательно присмотреться, то значения у графика совсем другие и это связано с другими единицами измерения и смещением графика. А вот форма графика очень даже похожа на логарифмическую с явно выраженным прогибом.
У экспоненциальных датчиков точно такая же зависимость, но только направление другое. С ростом температуры увеличивается и сопротивление, к ним относятся PTC термисторы или датчики давления, или датчики анализа газа.
Кстати, заряд ёмкости или индуктивности тоже происходит по такой же зависимости, поэтому некоторые ёмкостные датчики тоже имеют логарифмическую зависимость. Там ещё фигурирует постоянная времени τ (тау), которая равна 63.2% от полного заряда, но это уже совсем другая история.
Рассчитать логарифмическую, экспоненциальную или другую зависимость можно с помощью встроенных сценариев модуля DRM88ER, в которых я уже написал эти функции. Как использовать сценарии это тема отдельной статьи.
Иногда, для узкого диапазона измерений, можно взять небольшой отрезок и принять его за линейный с небольшим искажением и необходимой точностью.
Линейная функция
Чаще всего используется зависимость выходного значения от входного по графику линейной функции. Он представляет собой прямую линию и это сильно упрощает расчёт.
График линейной функции будет выглядеть как на рисунке ниже.

Датчики с зависимостью сопротивления от температуры
Типичным представителем датчиков с зависимостью линейной функции является терморезистор PT100 или PT1000. График зависимости сопротивления от температуры для датчика ПТ100 изображен ниже. У датчика ПТ1000 график аналогичный.
График зависимости сопротивления от температуры для датчика ПТ100

У терморезистора PT100 тоже есть прогиб – синяя линия, относительно линейной красной линии это довольно заметно. Но для небольшого диапазона температур от -50 °C до 150 °C будем считать его линейным для необходимой нам точности.
Датчики с зависимостью напряжения от температуры
Ещё один представитель линейных датчиков температуры - это LM235 (LM135, LM335 или др.). Это интегральная микросхема с полупроводниковым сенсором, запечатанная в корпусе TO-92 или в SO-8 или даже в металлическом TO-46. Выходное значение у этого датчика напряжение, а не сопротивление, которое линейно зависимо от температуры . При температуре 0 °C или 273 °K на выходе будет напряжение 2.73В, а при комнатной температуре 27 °C будет напряжение около 3В.
Датчики с зависимостью тока от температуры
Ещё один представитель линейных датчиков температуры - это датчики с выходом по току, например, с интерфейсом 4 - 20 мА. У этих датчиков линейная зависимость тока от температуры. Что бы измерить ток нужно использовать шунт на резисторе 150 Ом. На этом резисторе преобразуем ток в напряжение по закону Ома и подаем на АЦП. Но это тема отдельной статьи.
Но измерения не ограничиваются только этими датчиками, можно использовать другой датчик с выходом по напряжению, по току или сопротивлению. И измерять можно не только температуру, но и другие параметры: давление, уровень, влажность, концентрацию газов и пр.
Подключение сенсоров
У модулей DDL84R есть 4 аналоговых входа, у DRM88ER есть 8 аналоговых входа. Например, подключаем ко входу 1 датчик температуры – ПТ1000. Он подключается ко входу относительно земли. Внутри модуля есть подтягивающий резистор 12 кОм, который создает ток для датчика.

Кстати, это самая простая схема, но часто применяется схема с интегральным источником стабильного тока, например, LM334 и последующем преобразовании тока в напряжение на резистивном датчике.
Ещё часто применяется схема с мостом Уитстона с образцовым резистором, но для неё нужен дифференциальный вход.

Резистор 12 кОм создает конечно маленький ток и диапазон регулирования будет небольшой. Нужно сверху подкинуть ещё от 2 до 4.7 кОм.
При увеличении температуры PT1000 пропорционально увеличивается сопротивление и увеличивает значение напряжения на входе. Напряжение получаем с помощью закона Ома:
где I - ток с источника, R - сопротивление датчика ПТ1000.

Для датчика PT1000 при температуре 25 °C будет сопротивление 1.1кОм и следующие значения:
К внутреннему резистору 12кОм подключаем внешний 2.7кОм, получаем сопротивление:
Напряжение получили и подали на АЦП для дальнейшего расчета. У модуля DRM88ER на входе стоит делитель, который позволяет измерить напряжение от 0 до 4.5В и значение АЦП будет от 0 до 4095. Поэтому при напряжении 1.65В будет значение .
Схема подключения линейных датчиков температуры LM235 практически такая же. У неё 3 вывода, используется два, а третий нужен только для коррекции, который можно не подключать. Микросхеме нужен начальный ток (от 450 μA до 5 mA), при котором она начинает работать, поэтому нужно ей добавить тока внешним резистором 4.7 кОм или микросхемой источника тока.

Подали напряжение на вход нашего устройства и измерили с помощью АЦП. Теперь что бы из значений АЦП увидеть значение в °C, нужно преобразовать его по формуле линейной функции.
Этот расчет делается в реальном времени внутри устройства. Необходимо указать только коэффициенты.
Как рассчитать коэффициенты линейной функции
И эта задача кажется совсем нетривиальной. Первое что приходит в голову, это подобрать нужные коэффициенты. На это занятие можно потратить много времени и нужной точности не добиться. Но есть способ гораздо лучше – это рассчитать нужные значения коэффициентов.
Итак, вооружившись знаниями, начнём считать.
Для пересчета значений АЦП в единицы измерения для датчиков с линейной зависимостью используется уравнение прямой или линейная функция.
Записывается она в таком виде:
y – это единица измерения датчика, например, температура в градусах Цельсия,
х - это значение АЦП в микроконтроллере.
Поскольку в регистры модуля можно записать только целое число, то коэффициент K записывается не десятичным числом, а двумя числами в виде числителя и знаменателя.
Таким образом формула будет записана в следующем виде:
Все значения целочисленные со знаком.
Например, число 2,34 записывается: числитель K = 234, знаменатель N = 100.
Или 0,857143 записывается: числитель K = 96, знаменатель N = 112.
Уравнение прямой
Уравнение прямой записываем в более правильном виде вот в таком:
Дальше рассчитываем коэффициенты по двум точкам и
.
Например, для температуры при 0 °C считываем значение АЦП и при 100 °C считываем значение АЦП.
Соответственно температура это - y, а АЦП это - x. Получается дробное уравнение.
или в общем виде уравнения прямой:
Сейчас мы получили уравнение прямой по двум точкам.
Преобразуем уравнение прямой наш вариант уравнения в таком виде:
или вариант этой же формулы с координатами точек:
Из полученного уравнения и выводим нужные нам коэффициенты:
, то есть в нашем примере
, то есть в нашем примере
Таким образом мы получили коэффициенты для нашей линейной функции из значений координат двух точек на этой линии.

Запись коэффициентов в регистры модуля
Полученные коэффициенты записываем в регистры коэффициентов датчика. Рассчитываем таким же образом коэффициенты для остальных входов датчика.
Для устройств с WEB интерфейсом, например, DRM88ER коэффициенты можно записать в соответствующие поля на странице аналоговых входов, которые затем записываются в регистры HR40 – HR69. Для схемы с сенсором PT1000 будут вот такие значения.
Точки измерения АЦП могут быть от 0 до 4095, а точки единиц измеряемой величины от -32768 до +32767. Наклон линии может быть в любую сторону. Он задается знаком в коэффициентах K или N.
Встроенный калькулятор коэффициентов
Коэффициенты можно рассчитать вручную на калькуляторе или написать свою программу для их расчета.
Но в большинстве модулей уже есть встроенный калькулятор коэффициентов, с помощью которого можно довольно просто рассчитать необходимые коэффициенты.
Находится калькулятор в регистрах HR70 – HR74.
Регистр |
Адрес |
Диапазон |
Описание регистра |
HR 70 |
40071 |
1…10 |
номер канала |
HR 71 |
40072 |
-32768…32767 |
Параметр 1 |
HR 72 |
40073 |
-32768…32767 |
Параметр 2 (запись в этот регистр запускает расчет и сохранение коэффициентов в указанный HR70 канал) |
HR 73 |
40074 |
-32768…32767 |
результат АЦП 1 (только чтение) |
HR 74 |
40075 |
-32768…32767 |
результат АЦП 2 (только чтение) |
Последовательность действий следующая:
1) нужно подключить датчик ко входу модуля.
2) затем в регистр HR70 записать номер канала (1 … 8), к которому подключен датчик.
3) нужно установить датчик в калибровочную камеру, например, датчик температуры поместить в стакан с холодной водой.
4) как установятся значения вписать значение первого параметра в регистр HR71 и нажать ввод. Вместе с записью значения запишется текущее значение АЦП для первого параметра в регистр HR73.
5) затем изменить величину климатического параметра, например, переложить датчик температуры в стакан с горячей водой.
6) как установятся значения вписать значение второго параметра в регистр HR72 и нажать ввод. Вместе с записью значения запишется текущее значение АЦП для второго параметра в регистр HR74. Затем модуль рассчитает коэффициенты и перепишет эти параметры в регистры коэффициентов номера канала, указанного в HR70.
После этого в регистрах IR11 … IR17 будут выводиться значения в заданных физических величинах, пересчитанных по формуле линейной функции.
Как реализован калькулятор в программе устройства
При записи значения в регистр HR72 производится расчет значений коэффициентов по формуле, описанной выше.
Ниже представлен фрагмент кода для расчета коэффициентов, который я написал в устройстве DDL84R и MSU44R. При желании его можно реализовать в своем устройстве.
case 70: if((value >= 1)&&(value <= AI_NUMBERS)) KNB_CH = value; // Записываем номер канала break; case 71: KNB_IN1 = value;// Значение температуры в первой точке KNB_ADC1 = InputReg[KNB_CH]; // Значение АЦП в первой точке break; case 72: KNB_IN2 = value;// Значение температуры во второй точке KNB_ADC2 = InputReg[KNB_CH]; // Значение АЦП во второй точке KNB_K= KNB_IN2 - KNB_IN1; // рассчитываем коэффициент K KNB_N = KNB_ADC2 - KNB_ADC1; // рассчитываем коэффициент N KNB_B = (KNB_ADC1 * KNB_IN2 - KNB_ADC2 * KNB_IN1)/(KNB_ADC1 - KNB_ADC2); // рассчитываем коэффициент B if((KNB_K > 32767)||(KNB_K < -32767)||(KNB_N > 32767)||(KNB_N < -32768)){ // защита от переполнения KNB_K = KNB_K / 2; KNB_N = KNB_N / 2;} config.analogs_cfg[KNB_CH-1].k = KNB_K; // переписываем значения в регистры config.analogs_cfg[KNB_CH-1].n = KNB_N; config.analogs_cfg[KNB_CH-1].b = KNB_B; break;
Таким образом можно реализовать калькулятор коэффициентов в своем устройстве.
Коэффициенты получили, теперь посчитаем из них реальное значение физической величины.
for(TempADC = 0; TempADC < ADC_NUMBERS; TempADC++){ TempIR2 = InputReg[TempADC] * config.analogs_cfg[TempADC].k; // умножаем на K if(config.analogs_cfg[TempADC].n != 0)// Проверка знаменателя но ноль TempIR2 = TempIR2 / config.analogs_cfg[TempADC].n; // делим на N TempIR2 = TempIR2 + config.analogs_cfg[TempADC].b; // Прибавляем B InputReg[TempADC+BASE_mV_IR]=TempIR2; // Записываем значение в IR11 InputReg[TempADC+BASE_DI_IR] =((InputReg[TempADC+BASE_IR]< Threshold)) ? 0 : 1; // Записываем дискретное значение в регистр DI }
Точность измеряемых значений
Кроме того, у таких устройств есть понятие точности, которое показывает расхождение полученного значения физической величины и измерение эталонного прибора. Это относится к измерению аналоговой величины. А вот у датчиков, измеряющих импульсы нельзя применить понятия точности, так как сколько импульсов на него пришло, столько и показал, у него не должно быть расхождение, он же не пропускает импульсы.
Кстати, понятие аналоговая величина произошло от слова аналогичное физической величине, то есть непрерывное и между любыми двумя значениями можно найти бесконечно много промежуточных значений, в отличии от цифровых.
Если точность будет недостаточная, тогда можно немного скорректировать коэффициенты, увеличив точность датчика.
Теперь в регистрах IR11 - IR19 модуля DRM88ER записывается значение реальной величины, например, температуры в градусах Цельсия или Фаренгейтах, если хотите.
Усреднение значения
Порадовавшись полученным от датчика значениям через некоторое время понимаешь, что точности так и не достиг. Значения прыгают, хотя температура постоянная. Причиной могут быть наводки переменной сети 50 Гц на провода сенсора и шумы самого АЦП и усилителя.
Кстати, изо всех пассивных электронных компонентов шумят только резисторы (ну и полупроводники) и шум зависит от его типа и сопротивления. Чем больше сопротивление, тем больше уровень шума. Конденсаторы и дроссели не шумят.
Для повышения точности и подавления помех можно сделать программный фильтр помех или расчет среднего значения.
Способы расчёта среднего значения
1. Среднее арифметическое значение
Это самый распространённый вариант. Складываются все числа в наборе и делится сумма на их количество. Этот способ и реализован в модуле. Этот способ подходит для измерения климатических параметров. Но у него есть недостаток, он чувствителен к выбросам. Если в данных есть очень большое или очень маленькое значение, оно сильно «сдвинет» среднее, и картина будет искажённой.
Вычисление производится по этой формуле:
2. Среднее геометрическое
Здесь вместо сложения перемножаются все числа, а затем извлекается корень степени, равной количеству чисел. Все числа в наборе должны быть положительными. Промежуточные значения получаются очень большими и способ не очень хорошо подходит для использования в микроконтроллере.
3. Среднее взвешенное
Этот метод применяют, когда разные значения в наборе имеют разную «важность» или вес. Умножается каждое значение на свой вес, складываются эти произведения, а затем делится на сумму всех весов. Так же промежуточные значения получаются очень большими.
4. Медиана
Чтобы найти медиану, нужно упорядочить числа по возрастанию или убыванию. Если количество чисел нечётное, медиана — это число, стоящее ровно посередине. Если чётное — медиана равна среднему арифметическому двух чисел, находящихся в центре. Это не среднее в арифметическом смысле, а мера центральной тенденции.
5. Мода
Мода — это значение, которое встречается в наборе данных чаще всего. В программе потребуется накопление и сортировка значений и в памяти микроконтроллера потребуется излишне много ресурсов.
6. Усреднение со скользящим окном
Здесь берётся фиксированное число последних значений или окно, вычисляется их среднее, а при поступлении нового значения сдвигается окно: самое старое выпадает, новое добавляется, и среднее пересчитывается. Требуется держать в памяти все значения этого окна и это требует дополнительных ресурсов микроконтроллера.
7. Экспоненциальное усреднение
В этом методе вес новых значений убывает экспоненциально по мере их старения. То есть свежие данные влияют на результат сильнее, чем старые.
8. Накопление с делением на счётчик
Ведётся анализ двух переменных: сумма всех полученных значений и счётчик их количества. При новом значении обновляется сумма и делится на обновлённый счётчик:
9. Медианный фильтр
Сохраняется окно значений, сортируется и берётся медиана, то есть среднее по порядку в отсортированном списке. Это помогает игнорировать одиночные аномалии, которые сильно искажают среднее арифметическое. Похоже на усреднение арифметического среднего значения, но метод используется для последовательной обработки данных.
Так же существует множество и других способов усреднения.
Расчет среднего арифметического значения в модуле
В модуле DRM88ER, да и в большинстве других я сделал встроенный алгоритм усреднения по количеству измерений.
Алгоритм расчета следующий, складываются полученные значения заданное количество раз (n) и после окончания сложения делится на это количество (n). Количество задается в регистре HR75.
Вычисление производится по этой формуле:
В регистр HR75 нужно записать число, соответствующее количеству накоплений. Чем оно больше, тем больше значений будет складываться, значение будет точнее, меньше колебаться и дольше измеряться. Если это медленно меняющийся процесс, например, температура, тогда это значение можно сделать максимальным - 255, а если быстро меняющееся, то минимальным - 1.
Программная реализация алгоритма среднего арифметического значения
if(!config.ADC_av) config.ADC_av=1; // Проверка на ноль if(ADC_avcn < config.ADC_av){ // Если ещё не достиг количества ADC_avcn++; // Инкрементируем счетчик ADCReg[chn] += ADCBuffer[chn];// Складываем значения } else{// Если достиг количества InputReg[TempADC] = ADCReg[TempADC] / config.ADC_av; // Делим сумму на количество ADCReg[TempADC] = 0; // Обнуляем для следующего цикла ADC_avcn=0; }
Теперь получили более точное значение нашей измеренной величины. Можно выводить в регистры IR11 – IR19 и с помощью какой ни будь СКАДы обрабатывать измеренные значения.
Заключение
Значение АЦП само по себе ничего не говорит о температуре или давлении. Чтобы превратить его в физическую величину, нужны правильно рассчитанные коэффициенты. Главная сложность всегда была в расчёте коэффициентов линейной функции, и, как выяснилось, задача эта далеко нетривиальная. Описанный в статье метод — не теоретическое изыскание, а рабочий инструмент, который я использую в своих устройствах уже несколько лет. Он отлично зарекомендовал себя для большинства аналоговых датчиков — от термисторов до датчиков давления. И главное: этот подход универсален. Его без труда можно адаптировать под любой другой аналоговый вход устройства в ваших проектах. Его так же можно взять в свой арсенал — для любых аналоговых датчиков в любых проектах на микроконтроллерах.
А как вы рассчитываете физические значения, боретесь с шумом АЦП и нелинейностью датчиков? Делитесь опытом в комментариях — вариантов очень много и мне интересно обсудить альтернативные подходы.