Форум самогонщиков Сайт Барахолка Магазин Помощь солдатам

Ненавязчивая автоматизация ректификационной установки

Форум самогонщиков Автоматика
1 ... 70 71 72 73 74 75 76 ... 132 73
BogAD Кандидат наук Красногорск - Белово 403 184
Отв.1440  01 Сент. 18, 11:18
...но мне надо было решить еще проблему с перебоями подачи воды...ab57, 01 Сент. 18, 10:38

А если надо подавать в два потока, причем потоки нужно регулировать?
Два насоса ставить?
Проще тогда один насос в постоянный режим работы, далее тройник и 2 краника на сервоприводе.
Да хоть три! Производительности бы хватило...
ab57 Новичок Barnaul 7 1
Отв.1441  01 Сент. 18, 11:52, через 35 мин
Регулировать два потока, по мне избыточно.

При условии постоянства подводимой мощности достаточно поддерживать температуру теплоносителя на выходе. Тогда температура спирта будет стабильна, ее можно контролировать по спиртометру только один раз пересчитав поправку.
Пусть спиртометр плавает в потоке постоянно, мы знаем, что при этой температуре мы должны видеть не 96.6 а 97.1.
Но если готовы усложнить систему ради удобства, то конечно, чем и привлекает тема Ненавязчивой автоматики.

Меня не особо заботит спиртуозность на выходе, она стабильна пока можем удержать температуру в одной точке колонны. Остальное проще и надежней в канализацию, не жадный.

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

Но наши цели сильно об одном, об управлении охлаждением, не суть через что, клапан шаговик или насос.

Сейчас контроллер есть, но он не замкнут по обратной связи на температуру, величину охл выбираю кнопками, температура воды на выходе стабильная без ОС. Но это неправильно..надо учиться им управлять с малины.
ZagAl Доцент Прибалтика 1.9K 916
Отв.1442  01 Сент. 18, 12:24, через 32 мин
Регулировать два потока, по мне избыточно.ab57, 01 Сент. 18, 11:52
Ребята, я понимаю, что в основном у здесь присутствующих, колонны с отбором по жидкости. Но у мения и у других, интересующихся этой темой, колонна с отбором по пару. И если в вашей системе величина отбора регулируется клапаном,то у нас эту функцию выполняет дефлегматор. Может быть и вы когда-нибудь приделе к пониманию необходимости тонкой регулировки подачи воды в дефлегматор. Поэтому я за универсальность развития автоматизации. Можно предусмотреть и подкачивающий насос для тех у кого проблемы со стабильностью подачи воды, и регулируемые сервоприводом (шаговиком) краны.
us_ov Магистр Ярославль 259 54
Отв.1443  01 Сент. 18, 12:28, через 5 мин
Я голосую за насос и регулирование температуры. У меня отбор по пару и большой запас по охлаждению - стабильность водоснабжения не беспокоит, а вот его отсутствие напрягает ещё как!
chicanas Студент Krym 19 1
Отв.1444  19 Сент. 18, 12:18

Здравствуйте. Есть ли законченный, финишный скетч или прошивка, для термосервера (на 4-5 датчиков DC18b20) на Arduino mini с 4-х разрядным индикатором и кнопкой? Прочитал 2 раза тему, но не нашёл. Ткните носом, где этот файл прошивки, есть в этой теме. (и есть ли он вообще?). Для 3-х разрядного индикатора скетч видел.
gol_avto Доцент Москва - Серпухов - Анапа 1.3K 458
Отв.1445  19 Сент. 18, 12:40, через 22 мин


температурный сервер на такой ардуине делаю для себя яdth, 08 Июня 17, 14:14
Обратись в личку к dth
dth Бакалавр Арти 98 39
Отв.1446  20 Сент. 18, 08:37
Обратись в личку к dth
Выкладываю свой вариант термосервера на про мини. Из недостатков: очень редко пропадает изображение на индикаторе (возможно наводки на длинные провода датчиков), на малину при этом идет все исправно. Работает практически без выключений уже более года. Если нужно позже смогу выложить код с малины. (Установка дома).

OldBean Доцент Красноярск 1K 1.4K
Отв.1447  10 Окт. 18, 10:05
17.4. Цифровой модуль и адаптер 1-Wire для аналоговых датчиков

Цифровой модуль делался в сильной суете и оказался разбросанным по ветке. Поскольку этот модуль - довольно важный компонент автоматики в варианте LITE, лучше будет собрать все, что с ним связано, вместе. Ну и заодно я добавил сюда описание 1-Wire адаптера, позволяющего подключать к цифровому модулю любые аналоговые датчики.

Назначение цифрового модуля - сбор информации с цифровых источников (датчиков) и передача этих данных малинке. В принципе прошивку цифрового модуля можно запрограммировать на поддержку любого однопроводного протокола (не слишком шустрого). В данной версии цифрового модуля в качестве протокола физического уровня был выбран 1-Wire. Это связано с тем, что температурные датчики DS18B20 довольно широко применяются в наших задачах. Однако, это совсем не означает, что к цифровому модулю можно подключать только указанные температурные датчики. Во первых, абсолютно безо всяких модификаций прошивки, к нему можно подключать любые "релейные" датчики (концевики, термоконтакты и т.п.) А, во-вторых, используя АЦП с интерфейсом 1-Wire (выполненные, например, на универсальных микроконтроллерах, либо на специализированных чипах, типа DS2450 и т.п.), мы можем подключать к цифровому модулю любые аналоговые датчики (например, аналоговые температурные датчики, датчики давления типа MPX и т.п.). Ниже будет подробно рассмотрен пример такого АЦП, сделанного на базе простого микронтроллера ATtiny85.

Таким образом, в варианте LITE, вся система сбора информации, как и силовые модули, унифицирована и ориентирована исключительно на единообразные цифровые модули. К каждому цифровому модулю можно подключать до 8 датчиков с интерфейсом 1-Wire и/или произвольное количество релейных датчиков, подключенных к шине по "схемному И".

17.4.1. Схема цифрового модуля

Цифровой модуль представляет собой микроконтроллер ATMega328P с минимальной "оснасткой". Схема цифрового модуля предельно проста и в особых комментарих не нуждается. Она представлена на рисунке ниже.
01_dm_18.02.06.1_sch.gif
01_dm_18. Ненавязчивая автоматизация ректификационной установки. Автоматика.

Мы видим, что на каждом пине порта D микроконтроллера организована шина 1-Wire (каналы цифрового модуля). Кроме сигнальной линии, каждая шина 1-Wire содержит линию питания +5В и, естественно, землю. Каждая сигнальная линия подтянута к +5В резисторами 4.7к. Таким образом, к одному цифровому модулю может быть подключено до 8 независимых шин 1-Wire.

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

17.4.2. Печатная плата

Печатная плата цифрового модуля тоже очень проста. Один из вариантов разводки показан на следующем рисунке.
02_dm_18.02.06.1_pbc_05.gif
02_dm_18. Ненавязчивая автоматизация ректификационной установки. Автоматика.

Готовый lay-файл для изготовления платы можно взять в приложении к этому топику (файл dm_18.02.06.1_pcb_05.lay6). Общий вид собранной платы показан на рисунке ниже.
03_dm_готовая_плата.JPG
03_dm_готовая_плата. Ненавязчивая автоматизация ректификационной установки. Автоматика.


17.4.3. Прошивка цифрового модуля

Исходный код прошивки и готовый hex-файл можно взять в приложении к этому топику. Текст прошивки подробно прокомментирован. Поэтому, если понадобится, то разобраться будет несложно. Главная идея заключается в том, что все восемь шин 1-Wire цифрового модуля работают параллельно (синхронно). Т.е на на все сигнальные линии одновременно подается импульсы инициализации (RESET), начальные и конечные моменты тайм-слотов тоже совпадают на всех линиях. Более того, команды на все линии тоже подаются одновременно и одинаковые. В качестве протокола прикладного уровня выбран упрощенный протокол работы с датчиками DS18B20. Т.е на все линии, после импульсы RESET, подается команда игнорирования адресов устройств (датчиков) на шинах (команда SKIP ROM: 0xcc) и запуск преобразования (0x44). После окончания преобразования (через приблизительно 750 мс) опять на все линии подается RESET, затем - SKIP ROM и команда чтения байтов с датчиков на шинах (0xbe). После этого, мастера всех шин (т.е. порт D цифрового модуля) переходят в режим чтения байтов от устройств (датчиков). После одновременного чтения двух байтов с каждой шины, на все шины подается команда RESET, система возвращается в исходное состояние и, по истечению одной секунды (в сумме), цикл повторяется.

Такой протокол позволяет единообразно обрабатывать широкий спектр датчиков: DS18B20, релейные датчики, любые аналоговые датчики, подключенные через бридж на ATtiny85. Рассмотрим простой вариант бриджа для аналоговых датчиков подробнее.

17.4.4. Адаптер 1-Wire для подключения аналоговых датчиков к цифровому модулю

Схема адаптера представлена на рисунке ниже.
04_adc_ow_slave.gif
04_adc_ow_slave. Ненавязчивая автоматизация ректификационной установки. Автоматика.

Ничего кроме микроконтроллера ATtiny85 в адаптере нет. Для тестирования адаптера, в качестве источника аналогового сигнала будет использовать простой делитель напряжения питания на резисторах R2, R3. При использовании резистивных температурных датчиков или тензодатчиков вместо этого делителя будут стоять соответствующие резистивные мосты, операционные усилители и т.п. Но суть от этого не меняется - на пин микроконтроллера ADC2 (PB4) подается аналоговый сигнал в диапазоне от 0 до 1.1В. Сигнальная линия шины 1-Wire подключена к пину PB3. Через эту линию адаптер обменивается данными с цифровым модулем.

Прошивка адаптера тоже довольно проста. Исходный текст ее приведен ниже.

Скрытый текст
//------------------------------------------------------------------------------
// firmware для ATtiny85, используемой как АЦП с интерфейсом 1-Wire (slave)
// Протокол упрощен (только одно устройство на линии и отсутствие CRC)
// OldBean, 10.10.2018
//------------------------------------------------------------------------------
#include <avr/io.h>
#include <avr/interrupt.h>

#define F_CPU 16000000UL
#include <util/delay.h>

//------------------------------------------------------------------------------
static uint8_t ocr0A = 255; // Значение регистра сравнения A таймера 0
static uint8_t flagADC = 0; // Флаг разрешения запуска АЦП
static uint8_t cadc = 0, cADCw; // Вспомогательные переменные
static uint8_t wrk = 0;

static uint8_t wFlag = 0; // Состояние записи в линию 1-Wire
static uint8_t srFlag = 0; // Флаг состояния "skip ROM" (игнорируется адрес)
static uint16_t tau; // Длительность низкого уровня после старта тайм-слота
static uint8_t mask8 = 0x01; // Битовая маска для байта
static uint16_t mask16 = 0x0001; // Битовая маска для двухбайтового слова
static uint8_t data = 0;

static uint16_t adcv; // Текущий код АЦП
static uint16_t adcl, adch;
//------------------------------------------------------------------------------
ISR(PCINT0_vect){ // Обработчик внешнего прерывания на PB3
 if(!(PINB & _BV(PB3))) { // Был переход линии с высокого уровня на низкий
   GTCCR = _BV(PSR0); // Сброс предделителя таймера 0
   TCNT0 = 0; // Обнуляем счетчик таймера 0
   if(wFlag) { // Пишем бит в линию (а байты - сначала младший затем старший)
     if(!(adcv & mask16)) { // Нужно писать 0
       PORTB &= ~_BV(PB3); // Устанавливаем низкий уровень на пине PB3
       DDRB |= _BV(PB3); // Переводим PB3 в режим записи
       _delay_us(20); // Держим паузу (15 мкс с небольшим запасом ;)
       DDRB &= ~_BV(PB3); // Отпускаем линию (PB3 - в режим чтения)
     } // А 1 получится автоматически, если ничего не делать ;)
     mask16 <<= 1; // Модифицируем маску (переход на следующий бит)
   }
 } else { // Наоборот - переход линии с низкого на высокий
   // Оценим длительность импульса (низкого уровня на линии) tau в мкс
   tau = TCNT0; tau <<= 2; // Единица счетчика TIMER0 - это 4 мкс
   if(tau >= 480) { // Это RESET. Для простоты импульс PRESENCE пока не подаем
     wFlag = 0; // Переходим в режим чтения
     srFlag = 0; // Сбрасываем состояние "skip ROM"
     mask8 = 0x01; // Сбрасываем маску на младший бит
     data = 0; // Очищаем принимаемый байт
   } else { // Слот или кусок слота
     if(!wFlag) { // Режим чтения
       if(tau < 15) { // Получен единичный бит
         data |= mask8;
       }
       mask8 <<= 1; // Модифицируем маску
       if(mask8 == 0) { // Считали все восемь бит (маска полностью ушла влево)
         switch(data) { // Анализируем полученную команду
           case 0xcc: // Получена команда игнорирования адреса (skip ROM)
             srFlag = 1;
             break;
           case 0x44: // Получена команда запуск преобразования (АЦП)
             if(srFlag) { // Работаем без адреса (была команда skip ROM)
               ADCSRA |= _BV(ADSC);
             } // В противном случае (без skip ROM) - игнорируем
             break;
           case 0xbe: // Мастер перешел в режим чтения, а slave - записи
             if(srFlag) { // Работаем без адреса (была команда skip ROM)
               wFlag = 1; // Устанавливаем флаг записи на линю
             } // В противном случае (без skip ROM) - игнорируем
             break;
         }
         mask8 = 0x01; // Сбрасываем маску на младший бит
         mask16 = 0x0001;
         data = 0; // Очищаем принимаемый байт
       }
     } // Режим чтения
   }
 }
}
//------------------------------------------------------------------------------
ISR(TIMER0_OVF_vect) { // Обработчик по переполнению (на потом...)
}
//------------------------------------------------------------------------------
ISR(ADC_vect) { // Преобразование закончено
 adcv = ADCL;
 uint16_t h = ADCH;
 adcv += h << 8;
//  adcv = 731;
}
//------------------------------------------------------------------------------
int main(void) {
 // Инициализация внешних прерываний на пине PB3 ------------------------------
 GIMSK = _BV(PCIE);   // Прерывания по изменению уровня на пине
 PCMSK = _BV(PCINT3); // Внешние прерывания ловим на пине PB3
 // Инициализация таймера 0 для тактирования АЦП ------------------------------
 // Счетчик работает в нормальном режиме
 TCCR0B = _BV(CS01) | _BV(CS00); // Предделитель на 64
 TIMSK |= _BV(TOIE0); // Разрешаем прерывания по переполнению
 // Инициализация АЦП ---------------------------------------------------------
 ADMUX = _BV(REFS1); // Внутренний источник опорного напряжения 1.1V
 ADMUX |= _BV(MUX1); // Работаем в ADC2 (источник подключен к пину PB4)
 ADCSRA = _BV(ADEN); // АЦП включен
 ADCSRA |= _BV(ADIE); // По окончанию преобразования - прерывание
 ADCSRA |= _BV(ADPS2) | _BV(ADPS1) | _BV(ADPS0); // Предделитель на 128
 sei(); // Разрешаем глобальные прерывания
 while(1) { // Бесконечный цикл
 }
 return 0;
}

На физическом уровне прошивка реализует упрощенный протокол ведомого устройства шины 1-Wire (без адресации и контрольной суммы). На прикладном уровне - протокол, используемый при работе с датчиками DS18B20. Конкретно: после сигнала RESET и команды игнорирования адреса устройства (skip ROM - 0xcc), адаптер ожидает команды. Если он получает команду запуска преобразования (0x44, как и для DS18B20), то запускается цикл преобразования АЦП. Если же после RESET и 0xcc адаптер получает команду чтения данных (0xbe), то в следующие тайм-слоты мастера он оправляет ему два байта кода АЦП (сначала младший, затем старший). Как видим, все получается очень просто ;)

Исходный файл прошивки адаптера и готовый hex-файл можно взять в приложении к данному топику (файл adc_ow_ATtiny85.zip). Не забудьте перенастроить Geany на работу с ATtiny85 (если IDE было настроено на ATMega328P!

Изготавливаем и прошиваем адаптер. Печатные платы адаптеров сильно зависят от конструкции аналогового датчика. По сути дела, датчик впаивается в плату адаптера и в целом представляет уже цифровой датчик с интерфейсом 1-Wire. Поэтому отладочный вариант адаптера был выполнен только на макете. На фотографии ниже, макет находится в правом нижнем углу.
05_dm_ow_slave_adc.JPG
05_dm_ow_slave_adc. Ненавязчивая автоматизация ректификационной установки. Автоматика.

Теперь нам осталось провести полное испытание всего, что связано с цифровым модулем. Для этого, я подключил к цифровому модулю четыре датчика DS18B20, замкнул одну линию на землю (это у нас будет как бы концевик ;). Далее, подключил к одному каналу термоконтакт, срабатывающий при 30°C (срабатывает от пальцев руки), и, наконец, свежеиспеченный макет адаптера для аналоговых датчиков. В качестве источника аналогового сигнала, как отмечалось выше, мы используем резистивный делитель напряжения. Внешний вид всего этого добра показан на только что приведенном рисунке выше.

Для тестирования нам осталось написать тестовый скрипт для малинки. Текст простого консольного варианта скрипта с подробными комментариями приведен ниже.

Скрытый текст
# _*_ coding: utf8 _*_
import time # В этом модуле - задержки
import smbus # В этом модуле - средства для работы с шиной i2c

""" Консольное приложение для тестирования цифрового модуля
   
   Приложение получает по i2c с цифрового модуля буфер данных, представляющих
   собой 8 двухбайтовых слов, по одному на канал цифрового модуля.
   Интерпретация этих слов зависит от устройств (датчиков), которые подключены
   к каналам цифрового модуля. На данный момент предусмотрены три типа
   датчиков:
   1. Температурные датчики DS18B20. Для того, чтобы получить температуру в
      градусах Цельсия, необходимо код, получаенный от соответствующего канала
      цифрового модуля умножить на 0.0626.
   2. Релейные датчики (концевики, термоконтакты и т.п.). Если контакт
     замкнут - цифровой модуль возвращает с соотвествующего канала 0, а если
     разомкнут - 65535 (т.е. все биты двухбайтового слова - единички)
   3. Аналоговые датчики (аналоговые датчики температуры, датчики давления
      и т.п.), подключенные к АЦП с 1-Wire интерфейсом, выполненными на
      микроконтроллере ATtiny85. В этом случае цифровой модуль с соответствую-
      щего канала выдает непосредственно код АЦП.
"""

bus = smbus.SMBus(1) # Создаем объект "шина"
addrDM = 0x15 # Адрес цифрового модуля

buf = [0]*16  # Буфер для приема байтов от цифрового модуля
cntr = 0      # Счетчик успешный измерений
colls = 0     # Счетчик коллизий

while True: # Бесконечный цикл
 tries = 100 # Максимальное количество попыток доступа к данным модуля
 while tries > 0:
   try: # Попытаемся получить данные
     bus.write_byte(addrDM, 0x00) # Сбрасываем индекс байтов в буфере модуля
     for i in range(16): # Считываем последовательно 16 байтов буфера
       buf[i] = bus.read_byte(addrDM)
     break
   except IOError:   # Устройство еще не готово - подождем 0.1 сек
     time.sleep(0.1) # и опять попробуем
     tries -= 1
     colls += 1      # Модифицируем счетчик коллизий
 if tries <= 0: # Что-то серьезно не так...
   print 'Цифровой модуль не доступен по i2c. Завершение работы.'
   sys.exit(1)
   
 cntr += 1 # Успешное чтение всех данных; модифицируем счетчик
 print cntr,
 for i in range(8):
   w = buf[2*i]*256 + buf[2*i + 1] # Формируем слова из соседних пар байтов
   if i < 4: # Данные с DS18B20 - подсветим зелененьким
     print '\x1b[32m',
   elif i == 6: # Данные с АЦП - подсветим фиолетовым
     print '\x1b[35m',
   print w,
   print '\x1b[0m',
 print 'err = %d' % (colls)
 time.sleep(1) # Секундная пауза

Архив с текстом этого скрипта находится в приложении к данному топику (файл test_14.py.zip).

Распаковываем этот архив в рабочей папке на малинке, делаем эту папку текущей и запускаем скрипт: python test_14.py

Если все собрано и прошито правильно, мы увидим столбцы цифр: коды датчиков DS18B20 (зеленое, а если нужны градусы - умножаем код на 0.0625 ;), состояние концевика, термоконтакта и код АЦП адаптера аналогового датчика (фиолетовое). Самая правая колонка - суммарное количество ошибок шины i2c, к которой подключен цифровой модуль. Левый столбец - количество обращений малинки к цифровому модулю.

Проверяем работоспособность: греем пальцами DS-ки и термоконтакт, крутим потенциометр... Оставил поработать подольше на ночь. Ошибок нет, все ведет себя вполне адекватно. Утренний скриншот - на рисунке ниже.
06_screenshot.png
06_screenshot. Ненавязчивая автоматизация ректификационной установки. Автоматика.


Ну вот и все с "железом"... Точнее - пока все (см. PS ниже).


Предыдущий топик  Вернуться к оглавлению  Следующий топик

PS
Заметил некритичный, но немного обидный нюанс в работе АЦП ATtiny85. Суть его в том, что принимаемые малинкой значения кода АЦП всегда четные (т.е. младший бит всегда 0)! :(((

Проделал следующие "танцы".
0. Попробовал три микроконтроллера из разных упаковок, но посылка (видимо и партия), к сожалению, одна. Результат одинаковый на всех МК.
1. Проверил весь канал связи от АЦП к малинке. Работает нормально: при принудительном присвоении нечетного значения переменной adcv в обработчике прерываний по концу преобразования АЦП нечетные значения передаются правильно. Т.е. причина в самом АЦП тиньки.
2. Разное выравнивание данных в регистрах АЦП (бит ADLAR регистра ADMUX) на результат не влияет. Таки, младший бит кода АЦП всегда 0.
3. Более подробное чтение datasheet на АЦП микроконтроллера ATtiny85 не привело к появлению каких-либо конструктивных мыслей.
4. Немного порылся в Сети, но тоже ничего конкретного не нашел.

Т.е. фактически АЦП тиньки у меня работает с 9-разрядной точностью. Младший бит, увы, не работает. Он всегда нулевой. Почему? Не знаю. Пара возможных причин:
1. Возможно я что-то упустил при настройке и/или работе с их АЦП. У меня очень небольшой и, к сожалению, отрицательный опыт работы с этим типом микроконтроллеров (ATtiny85).
2. Это - дефект данной партии микроконтроллеров. Но из других партий у меня, к сожалению, пока нет. Поэтому проверить эту гипотезу не могу.

Ну или еще какие-нибудь причины...

В принципе, если хватает 9-разрядной точности АЦП, то с описанными в данном топике 1-Wire адаптерами вполне можно работать. Если же не хватает точности - можно поставить другой МК и слегка откорректировать прошивку. Тем не менее, разобраться с этой особенностью все же хотелось бы. Если кто-нибудь сталкивался с таким чудом - буду очень признателен, если расскажете...

Добавлено 11.10.2018

Обход этой проблемы описан в следующем топике


OldBean Доцент Красноярск 1K 1.4K
Отв.1448  11 Окт. 18, 06:04
Забавно, но проблема с младшим битом, описанная в PS к предыдущему топику, не возникает, если в качестве источника опорного напряжения взять не внутренний источник на 1.1 В, а, например, источник питания МК (биты REFS1 и REFS0 регистра ADMUX устанавливаются в 0). Здесь все работает правильно - четные и нечетные коды "равноправно" появляются при изменении напряжения на входе АЦП!

Здесь появляется вполне естественный вопрос - а насколько оправдано использование не очень стабильного источника питания микроконтроллера в качестве источника опорного напряжения для АЦП в нашем 1-Wire адаптере? Самое смешное заключается в том, что в большинстве случаев оно будет даже гораздо более оправдано, чем использование стабильного внутреннего источника опоры 1.1В !!! И вот почему.

Для чего, собственно, нужен 1-Wire адаптер в автоматике варианта LITE? Он нужен для подключения аналоговых датчиком к цифровому модулю и, следовательно, к малинке, у которой, естественно, собственного АЦП нет. А что же это за датчики? Главным образом это, во-первых, резистивные датчики температуры (для тех задач, когда точность DS-ок не устраивает), а, во-вторых, - это тензорезисторы в весах или датчиках давления. И в первом, и во втором случае непосредственно измеряемой величиной является электрическое сопротивление датчика. Ну а более общем случае (это - на потом) будем считать, что выходное напряжение датчика просто пропорционально напряжению его питания. ИМХО, не сильно обременяющее условие ;)

В простейшем случае двухпроводного подключения, это сопротивление датчика включается в плечо делителя напряжения и подключается к некому источнику напряжения. В этом случае напряжение, снимаемое с датчика и подаваемое на вход АЦП, равно Vin = Vr*Rd/(Rd + R0), где Vr - напряжение, подаваемое на делитель, Rd - то самое измеряемое сопротивление датчика, R0 - второе сопротивление (плечо) делителя. С другой стороны, согласно datasheet, код АЦП тиньки равен ADC = 1024*Vin/Vref, где Vin - напряжение на входе АЦП, Vref - опорное напряжение АЦП. Т.е. ADC = 1024*(Vr/Vref)*Rd/(Rd + R0). Если в качестве опорного напряжения АЦП и напряжения, подаваемого на делитель датчика, взять одно и то же напряжение (например, напряжение питания), то Vr/Vref = 1. Получаем ADC = 1024*Rd/(Rd + R0). Т.е. код АЦП зависит только от отношения сопротивления плеч делителя и не зависит от стабильности источника питания. Если, конечно, флуктуации не сильно быстрые. Т.е. медленные по сравнению со временем преобразования АЦП. Но это легко "лечится" использованием фильтрующих емкостей в цепях питания.

Так что, в адаптере, с указанными выше аналоговыми датчиками, имеет глубокий смысл использовать источник питания МК в качестве источника опорного напряжения. Естественно, при условии, что питание самого датчика (т.е. делителя) тоже берется от этого же источника! Стабильность измерений в данном случае определяется стабильностью второго резистора делителя R0 и не зависит от стабильности источника питания (в разумных пределах, указанных выше).

Вот уж, действительно, как говорят - нет худа без добра! ;))))
SergeyMak Студент Брянск 16 2
Отв.1449  11 Окт. 18, 09:41
OldBean, а не пробовали внутреннюю опору на 2.56 вольт включить? Там такая же ситуация? Как вариант, можно добавить в схему внешний ИОН, например дешевый и доступный TL431, подключенный к Aref, хотя для резистивных датчиков, как Вы уже указали, это не очень актуально.
OldBean Доцент Красноярск 1K 1.4K
Отв.1450  11 Окт. 18, 10:36, через 55 мин
а не пробовали внутреннюю опору на 2.56 вольт включить? Там такая же ситуация?SergeyMak, 11 Окт. 18, 09:41
Добрый день, Сергей!
Не пробовал, т.к. в datasheet-е вроде бы написано, что опора 2.56 получается только если питание чипа 3В (см. примечание на стр.134 под табличкой установки опоры: The device requries a supply voltage of 3V in order to generate 2.56V reference voltage.) Удивили, конечно, такие слова, но решил не тратить время на изучение вопроса. Тем более, для резистивных датчиков, если для опоры и делителя брать один и тот же источник, действительно показания АЦП просто стоят "мертво" - в пределах одного кванта. Пробовал и обычный резистивный делитель, и датчик давления MPX5010. И там и там - "мертво". Так что вопрос с опорой снят.
SergeyMak Студент Брянск 16 2
Отв.1451  11 Окт. 18, 10:52, через 16 мин
Да, действительно, не заметил это примечание.
OldBean Доцент Красноярск 1K 1.4K
Отв.1452  13 Окт. 18, 11:19
17.4.5. Датчик кубового давления с интерфейсом 1-Wire

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

Итак, изготавливаем датчик кубового давления с 1-Wire интерфейсом. В качестве основы возьмем дифференциальный датчик давления MPX5010DP, позволяющий измерять перепады давления до 10 кПа (75 мм.рт.ст.). Датчик аналоговый. Поэтому для его подключения к цифровому модулю необходим 1-Wire адаптер. Базовый вариант такого адаптера мы недавно рассматривали во второй части топика, посвященного цифровому модулю. В принципе можно им воспользоваться безо всяких изменений. На макете адаптера (см. рисунок ниже) связь датчик-цифровой модуль-малинка работает отлично.
Ненавязчивая автоматизация ректификационной установки
Ненавязчивая автоматизация ректификационной установки. Автоматика.

Тем не менее, нужно как-то оформить это решение в виде печатной платы, содержащей адаптер и собственно сам датчик давления. Кроме этого, появились некоторые соображения, связанные с изменением прошивки 1-Wire адаптера. Поэтому изготовление датчика давления - неплохой повод и для этого.

Схема датчика с 1-Wire адаптером представлена на рисунке ниже (слева).
Ненавязчивая автоматизация ректификационной установки
Ненавязчивая автоматизация ректификационной установки. Автоматика.

Тут все просто - всего лишь микроконтроллер ATtiny85 и датчик MPX5010DP с соответствующими "обвязками". Такая схема в комментариях не нуждается. Фотография собранного датчика - на этом же рисунке справа. Если кому-нибудь понадобится lay-файл для изготовления печатной платы датчика давления, то он находится в приложении к данному топику (файл ps_18.10.11_pcb.lay6).

Теперь остановимся немного подробнее на прошивке 1-Wire адаптера.В предыдущей версии прошивки было все просто: после получения от 1-Wire мастера (цифрового модуля) кода 0x44, адаптер одни раз запускал АЦП и помещал значение кода в буфер, который потом отдавался мастеру после получения команды (0xbe). В принципе, для многих приложений этого было бы вполне достаточно. Но мы знаем, что в кубе иногда бывает довольно шумно ;) Поэтому желательно, поскольку речь идет о датчике давления, усреднять сигнал в течение какого-то времени для того, чтобы уменьшить шумы сигнала.

Т.к. цифровой модуль использует протокол прикладного уровня ориентированный на термодатчики DS18B20, то у нас есть замечательная возможность с пользой потратить 750-милисекундную паузу (или часть ее) для усреднения. В новой версии прошивки 1-Wire адаптера это сделано следующим образом. После команды запуска преобразования (0x44), АЦП адаптера начинает работать в циклическом режиме и делает 4096 выборок сигнала датчика, прибавляя каждую к сумматору. На это уходит более половины указанной паузы (750 мс). Потом, по значению, накопленному в сумматоре, вычисляется среднее значение, которое и будет отдано мастеру по запросу. Остальные нюансы реализации прошивки прокомментированы в исходном тексте, который приведен ниже.
Скрытый текст
//------------------------------------------------------------------------------
// firmware для ATtiny85, используемой как АЦП с интерфейсом 1-Wire (slave)
// Протокол упрощен (только одно устройство на линии и отсутствие CRC)
// OldBean, 13.10.2018
//------------------------------------------------------------------------------
#include <avr/io.h>
#include <avr/interrupt.h>

#define F_CPU 16000000UL
#include <util/delay.h>

//------------------------------------------------------------------------------
static uint8_t ocr0A = 255; // Значение регистра сравнения A таймера 0
static uint8_t flagADC = 0; // Флаг разрешения запуска АЦП
static uint8_t cadc = 0, cADCw; // Вспомогательные переменные
static uint8_t wrk = 0;

static uint8_t wFlag = 0; // Состояние записи в линию 1-Wire
static uint8_t srFlag = 0; // Флаг состояния "skip ROM" (игнорируется адрес)
static uint16_t tau; // Длительность низкого уровня после старта тайм-слота
static uint8_t mask8 = 0x01; // Битовая маска для байта
static uint16_t mask16 = 0x0001; // Битовая маска для двухбайтового слова
static uint8_t data = 0;

static uint16_t adcv; // Код АЦП, передаваемый мастеру шины
static uint32_t sum; // Сумматор для усреднения
static uint16_t cntr; // Счетчик просуммированных выборок
volatile static uint8_t adcFlag = 0; // Если 1, то измерения разрешены
//------------------------------------------------------------------------------
ISR(PCINT0_vect){ // Обработчик внешнего прерывания на PB3
 if(!(PINB & _BV(PB3))) { // Был переход линии с высокого уровня на низкий
   GTCCR = _BV(PSR0); // Сброс предделителя таймера 0
   TCNT0 = 0; // Обнуляем счетчик таймера 0
   if(wFlag) { // Пишем бит в линию (а байты - сначала младший затем старший)
     if(!(adcv & mask16)) { // Нужно писать 0
       PORTB &= ~_BV(PB3); // Устанавливаем низкий уровень на пине PB3
       DDRB |= _BV(PB3); // Переводим PB3 в режим записи
       _delay_us(20); // Держим паузу (15 мкс с небольшим запасом ;)
       DDRB &= ~_BV(PB3); // Отпускаем линию (PB3 - в режим чтения)
     } // А 1 получится автоматически, если ничего не делать ;)
     mask16 <<= 1; // Модифицируем маску (переход на следующий бит)
   }
 } else { // Наоборот - переход линии с низкого на высокий
   // Оценим длительность импульса (низкого уровня на линии) tau в мкс
   tau = TCNT0; tau <<= 2; // Единица счетчика TIMER0 - это 4 мкс
   if(tau >= 480) { // Это RESET. Для простоты импульс PRESENCE пока не подаем
     wFlag = 0; // Переходим в режим чтения
     srFlag = 0; // Сбрасываем состояние "skip ROM"
     mask8 = 0x01; // Сбрасываем маску на младший бит
     data = 0; // Очищаем принимаемый байт
   } else { // Слот или кусок слота
     if(!wFlag) { // Режим чтения
       if(tau < 15) { // Получен единичный бит
         data |= mask8;
       }
       mask8 <<= 1; // Модифицируем маску
       if(mask8 == 0) { // Считали все восемь бит (маска полностью ушла влево)
         switch(data) { // Анализируем полученную команду
           case 0xcc: // Получена команда игнорирования адреса (skip ROM)
             srFlag = 1;
             break;
           case 0x44: // Получена команда запуск преобразования
             sum = 0; // Очищаем сумматор
             cntr = 0; // Сброс счетчика выборок
             adcFlag = 1; // Разрешаем измерение и суммирование
             break;
           case 0xbe: // Мастер перешел в режим чтения, а slave - записи
             if(srFlag) { // Работаем без адреса (была команда skip ROM)
               wFlag = 1; // Устанавливаем флаг записи на линю
             } // В противном случае (без skip ROM) - игнорируем
             break;
         }
         mask8 = 0x01; // Сбрасываем маску на младший бит
         mask16 = 0x0001;
         data = 0; // Очищаем принимаемый байт
       }
     } // Режим чтения
   }
 }
}
//------------------------------------------------------------------------------
int main(void) {
 DDRB |= _BV(PB0); // Пин для диагностики
 // Инициализация внешних прерываний на пине PB3 ------------------------------
 GIMSK = _BV(PCIE);   // Прерывания по изменению уровня на пине
 PCMSK = _BV(PCINT3); // Внешние прерывания ловим на пине PB3
 // Инициализация таймера 0 для тактирования АЦП ------------------------------
 // Счетчик работает в нормальном режиме
 TCCR0B = _BV(CS01) | _BV(CS00); // Предделитель на 64
 // Инициализация АЦП ---------------------------------------------------------
 ADMUX = 0x00; // В качестве источника опорного напряжения - питание
 ADMUX |= _BV(MUX1); // Работаем в ADC2 (источник подключен к пину PB4)
 ADCSRA = _BV(ADEN); // АЦП включен
 ADCSRA |= _BV(ADPS2) | _BV(ADPS1) | _BV(ADPS0); // Предделитель на 128
 sei(); // Разрешаем глобальные прерывания
 int flag = 0;
 while(1) { // Бесконечный цикл
   if(!adcFlag) continue; // Измерения запрещены
   ADCSRA |= _BV(ADSC); // Запуск АЦП
   while(ADCSRA & _BV(ADSC)); // Ждем пока завершится преобразование

   // Часть операций ниже не являются атомарными, но в периоды времени,
   // когда они выполняются никаких прерываний не инициируется, т.к.
   // мастер делает паузу примерно на 750 мс и не "дергает" шину.
   // В связи с этим никаких дополнительных мер по безопасности следующего
   // ниже кода не применяется
   sum += ADCL;
   sum += (ADCH << 8);
   if(++cntr == 4096) { // Достаточно насуммировали...
     sum += 2048; // Ну усреднять, так усреднять ;)
     adcv = sum >> 12; // Усредненный по 4096 выборкам код АЦП
     adcFlag = 0; // Дальнейшие измерения до следующей команды 0x44 запрещаем
   }
 }
 return 0;
}
Понятно, что усреднение выборок АЦП не помешает и другим аналоговым датчикам, подключаемым к цифровому модулю посредством 1-Wire адаптеров. Поэтому этот вариант прошивки будет базовым для этого типа адаптеров.

Приведенный выше исходный файл прошивки и готовый hex-файл находятся в архиве 1-wire_adapter_firmware_13.10.2018.zip в приложении к данному топику.

Добавлено 15.10.2018 - совсем (и опять) забыл напомнить про фьюзы (fuse). Исправляюсь...
Для того, чтобы прошивка работала правильно, нам нужно изменить заводские установки фьюзов: убрать деление на 8 и использовать High Frequency PLL Clock на 16 МГц для тактирования МК. Ну а если кратко - нам нужно установить младший байт фьюзов в 0xe1. Если "шить" из малинки, то это проще всего сделать при помощи консольной утилиты avrdude.

1. Сначала читаем заводские установки. На всякий случай. Для этого даем в терминале команду:
sudo avrdude -c usbasp -p t85
Если фьюзы этого МК еще не перепрошивались, то на консоли, ближе к концу мы должны увидеть строку с заводскими установками фьюзов:
avrdude: safemode: Fuses OK (E:FF, H:DF, L:62)
2. Теперь пишем команду перепрошивки младшего байта фьюзов:
sudo avrdude -c usbasp -p t85 -U lfuse:w:0xe1:m
3. И еще раз проверяем:
sudo avrdude -c usbasp -p t85
Должны увидеть:avrdude: safemode: Fuses OK (E:FF, H:DF, L:E1)

Добавлено 17.10.2018
О скорости прошивки.

Прошивая новый МК, мы можем столкнуться с ситуацией, когда avrdude не видит его. Обычно это связано с низкой тактовой частотой МК, установленной на заводе-изготовителе (для тиньки - это 1 МГц). Частота прошивки должна быть не выше четверти от тактовой частоты МК, а скорость прошивки avrdude по умолчанию - 1 МГц. Т.е. - слишком высокая. Для первой прошивки фьюзов эту скорость нужно уменьшить. Это можно сделать при помощи специального джампера, обычно присутствующего в USBasp программаторах, либо путем использования параметра -B утилиты avrdude. Этот параметр задает период импульсов синхронизации в микросекундах. По умолчанию - 1 мкс. Если в команде avrdude поставить, например, -B 5, то "частота прошивки" будет уже 200 кГц (период - 5 мкс). Т.е. вполне хватит для начала работы и первой прошивки фьюзов. Потом, когда мы установим тактовую частоту тиньки в 16 МГц, про все это можно будет снова забыть... До следующего нового чипа ;)


Предыдущий топик  Вернуться к оглавлению  Следующий топик
gol_avto Доцент Москва - Серпухов - Анапа 1.3K 458
Отв.1453  14 Окт. 18, 08:55
Сергей, добрый день!
Прошу не бросаться "помидорами", но всё-таки, дилетантский вопрос: - куда подключается нога 2 тиньки (она же 1-Wire)?
==========
т.е. к любому цифровому входу PD ATMega328P ?
Esc Профессор Москва 2K 2K
Отв.1454  14 Окт. 18, 09:07, через 13 мин
в кубе иногда бывает довольно шумно
Поэтому желательно, поскольку речь идет о датчике давления, усреднять сигнал в течение какого-то времени для того, чтобы уменьшить шумы сигнала.OldBean, 13 Окт. 18, 11:19
Кроме программного алгоритма усреднения, добавил своему MPX5010DP и "механический" аналог интегрирующей RС цепочки.
integrator_dlya_datchika_davleniya.jpg
Integrator_dlya_datchika_davleniya. Ненавязчивая автоматизация ректификационной установки. Автоматика.

Элемент "С" - шприц на 20 кубиков.
Элемент "R" - зеленая игла от шприца.
OldBean Доцент Красноярск 1K 1.4K
Отв.1455  14 Окт. 18, 14:56
т.е. к любому цифровому входу PD ATMega328P ?gol_avto, 14 Окт. 18, 08:55
Да. С точки зрения подключения и работы с ним, такой датчик давления (с 1-Wire даптером) полностью эквивалентен, например, датчику DS18B20 (и сигнальная лини, и земля, и +5В берутся от любого из 8 каналов цифрового модуля). Только получаемый малинкой код, естественно, нужно интерпретировать как давление, а не как температуру. Унификация... ;)

Кроме программного алгоритма усреднения, добавил своему MPX5010DP и "механический" аналог интегрирующей RС цепочки.Esc, 14 Окт. 18, 09:07
Очень красивое решение! А все-таки в электро-механических аналогиях есть какой-то особый шарм!
gol_avto Доцент Москва - Серпухов - Анапа 1.3K 458
Отв.1456  16 Окт. 18, 09:07
Возникла проблема с программированием тиньки. Программатор USBasp и ресурсы (малинка) все прежние, которыми программировал модули LITE. В Geany настройки поменял на
Скомпилировать
avr-gcc -mmcu=attiny85 -Os -o %e.o %e.c && avr-objcopy -O ihex %e.o %e.hex
Сборка
avrdude -c usbasp -p t85 -U flash:w:%e.hex
Программатор в упор тиньку не видит. Подумал дефектная, перепробовал все, их у меня 10 шт, результата нет. В терминале команда
sudo avrdude -c usbasp -p t85
выдает ошибку, типа не вижу тиньку.
Попробовал под Win с помощью программы Arduino, результата также нет. Разозлился, собрал программатор ARDUINO as ISP  на плате  Arduino nano. Под Win, программой arduino  тестовый скетч залил, светодиод, подключенный к PB3, моргает, т.е. все тиньки исправны.
Теперь проблема, как заставить USBasp видеть тиньку, чтобы поменять фьюзы, ну и собственно залить прошивку на малинке?
Z_h_e Доцент г. Чайковский 1.1K 310
Отв.1457  16 Окт. 18, 14:54
Теперь проблема, как заставить USBasp видеть тиньку, чтобы поменять фьюзы, ну и собственно залить прошивку на малинке?gol_avto, 16 Окт. 18, 09:07
  На некоторых USBasp есть джампер выбора тактовой частоты. Можно попробовать выбрать низкую частоту программирования. Дело в том, при программировании через SPI  частота тактирования МК должна быть выше частоты программатора не менее чем в 4 раза.

Добавлено через 8мин.:

Для avrdude есть удобная оболочка SinaProg, имхо.
OldBean Доцент Красноярск 1K 1.4K
Отв.1458  16 Окт. 18, 22:40
Теперь проблема, как заставить USBasp видеть тиньку, чтобы поменять фьюзы, ну и собственно залить прошивку на малинке?gol_avto, 16 Окт. 18, 09:07
На некоторых USBasp есть джампер выбора тактовой частоты.Z_h_e, 16 Окт. 18, 14:54
Z_h_e дело говорит, Николай. Слишком высокая частота программатора - наиболее вероятная причина. Заводские установки тактовой частоты у тиньки 1 МГц (8 МГц + предделитель на 8). Т.е. первую перепрошивку фьюзов нужно нужно проводить на малой скорости. Вы же уже один раз разбирались с этим вопросом (начиная с этого поста и ниже).

PS
Я на, всякий случай, вставил напоминание об этой проблеме и некоторые подробности по ее решению в самый конец топика, про прошивку тиньки для датчика давления.
gol_avto Доцент Москва - Серпухов - Анапа 1.3K 458
Отв.1459  17 Окт. 18, 08:19
Спасибо коллеги! Поставил перемычку на J3 - все имеющиеся программы увидели тиньку, фьюзы перешились. В любом деле, когда долго не пользуешься какой либо операцией, навыки забываются.
====
Собрал на макетке 2 аналоговых канала и воткнул в крейт
20181017_085030.jpg
20181017_085030.jpg Ненавязчивая автоматизация ректификационной установки. Автоматика.
20181017_090253.jpg
20181017_090253.jpg Ненавязчивая автоматизация ректификационной установки. Автоматика.