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

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

Форум самогонщиков Автоматика
1 ... 54 55 56 57 58 59 60 ... 132 57
Dmi_D Кандидат наук Минск 393 138
Отв.1120  04 Февр. 18, 20:20
OldBean, там между силовыми модулями свободный разъем остался, предлагаю заполнить платкой BMP+RTC, все равно по габаритам (визуально) туда больше ничего не поместится.
 Ненавязчивая автоматизация ректификационной установки
Ненавязчивая автоматизация ректификационной установки. Автоматика.
BME280RTC.JPG
BME280RTC.JPG Ненавязчивая автоматизация ректификационной установки. Автоматика.

BME280RTC.zip 156.0 Кб
BogAD Кандидат наук Красногорск - Белово 403 184
Отв.1121  04 Февр. 18, 20:48, через 29 мин
Было.
OldBean уже отвечал
[сообщение #12976218]
Dmi_D Кандидат наук Минск 393 138
Отв.1122  04 Февр. 18, 21:06, через 18 мин
RTC можно просто не монтировать, но датчик давления без переходника на ЭТОТ крейт не встанет.
BogAD Кандидат наук Красногорск - Белово 403 184
Отв.1123  04 Февр. 18, 21:40, через 35 мин
На мой вариант Крейта BMP-280 встанет как есть, без переходника. Место с 4-мя отверстиями перед 40-ка пиновым разъемом...
 Ненавязчивая автоматизация ректификационной установки
Ненавязчивая автоматизация ректификационной установки. Автоматика.
Crate_1.4.jpg
Crate_1.4.jpg Ненавязчивая автоматизация ректификационной установки. Автоматика.
Dmi_D Кандидат наук Минск 393 138
Отв.1124  04 Февр. 18, 23:00
Согласен, но я работал с оригинальной конструкцией. Хотя не факт, что буду тупо ее повторять. Есть вопросы.
BogAD Кандидат наук Красногорск - Белово 403 184
Отв.1125  04 Февр. 18, 23:58, через 58 мин
Есть вопросы, задавай. Тема предусматривает шикарный подход к "заточке под себя".
Dmi_D Кандидат наук Минск 393 138
Отв.1126  05 Февр. 18, 00:25, через 27 мин
Собственно, первый вопрос уже возник,- расстояние между разъемами крейта. Ты на своем варианте это, кажется, разрулил, но в оригинале между двумя силовыми модулями остается 'мертвый' разъем, использование которого под вопросом,- а что туда подключать?
2. Учитывая универсальность силовых модулей (несомненный плюс!), сама собой напрашивается установка МК на хорошие кроватки: полетела сила,- перекинул МК и работай дальше, делов на три минуты, был бы запас модулей. Просто есть опыт работы в цейтноте, поэтому такой запас не тянет.
Собственно, по мере изготовления может возникнуть что-то еще, мозги-то у нас у всех разные...
BogAD Кандидат наук Красногорск - Белово 403 184
Отв.1127  05 Февр. 18, 00:44, через 20 мин
...расстояние между разъемами крейта...Dmi_D, 05 Февр. 18, 00:25
Хм... мне понятно твой вопрос. Я долго думал. Честно говоря не совсем завершил умозаключения.
Так повелось, что у меня с OldBen зеркально получилась разводка по платам.
Я решил, что от разъема 40-ка пинового будет первая палата RMS.
Иначе транс будет занимать лишнее место.
Последние платы будут типа РМ и управлять или контактором или рубить диф.автомат.
Расстояния между разъемами Крейта 14,2 мм. Обусловлено расстоянием в стандартных силовых шинах РЕ и N, что использует OldBean. Только через одно место. Вообще шаг там 7,1мм...
Неизбежно будет мешать триаки. 14,2 это очень в обрез, чтоб установить триак, и он  не мешал другой плате. А если задумалось поставить триак типа ВТА41-800, то точно другой плате будет помеха. Планирую выход из этой ситуации - там ставить короткие платы, типа сервера температуры или платы GPIO.

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

напрашивается установка МК на хорошие кроваткиDmi_D, 05 Февр. 18, 00:25
Честно говоря, у меня правило, стараться МК ставить всегда на кроватки. Предусмотрен SPI или нет, устарела плата, так можно спокойно вытащить МК и использовать в другом месте...
OldBean Доцент Красноярск 1K 1.4K
Отв.1128  05 Февр. 18, 02:59
между двумя силовыми модулями остается 'мертвый' разъем, использование которого под вопросом,- а что туда подключать?Dmi_D, 05 Февр. 18, 00:25
В данном конструктиве перпендикулярно платам силовых модулей торчат симисторы. Они расположены у задних торцов плат. Поэтому между силовыми модулями (унифицированными, т.е. симисторы одинаково поставлены) получался большой зазор и много объема между платами силовых модулей (в центральной части) пропадало. Чтобы это пространство использовать с пользой, я поставил дополнительные цифровые разъемы между ними. В эти разъемы планировалось вставлять всякую тонкую и относительно короткую мелочь, которая не подключается непосредственно к сети 220В. Это, в частности, унифицированные цифровые модули (они короткие и тоненькие; речь о них пойдет позже), платку-переходник с датчиком давления BMPxxx, платку-переходник с RTC (если понадобится), отладочные переходные платы и т.п. В силовых модулях все переключения (мощные) происходят в нуле тока и напряжения. Поэтому уровень помех мал. В результате цифровые модули вполне можно чередовать с силовыми.
Dmi_D Кандидат наук Минск 393 138
Отв.1129  05 Февр. 18, 03:45, через 47 мин
Абсолтно с вами обоими согласен, кстати, большинство доводов я и себе приводил, но все-таки хочу пойти как бы навстречу,- не подгонять модули под УЖЕ ГОТОВЫЙ крейт, а посмотреть, что получится, живьем, и уже тогда, возможно, использовать шины в режиме 'один-через-две'. (Шаг 21.3 мм)
Размеры конструкции возрастут не сильно, а вот помехоустойчивость и продуваемость явно лучше будут. Но это позже,- жду комплектацию.
OldBean Доцент Красноярск 1K 1.4K
Отв.1130  05 Февр. 18, 05:44
К компоновке системы нет никаких жестких требований. Поэтому здесь имеет смысл ориентироваться исключительно на соображения удобства, имеющихся материалов и личных предпочтений :) Некоторые ограничения свободы могут быть только со стороны шины i2c. Ее желательно не ветвить и длину линий i2c не стоит делать длиннее пары-тройки дециметров.
OldBean Доцент Красноярск 1K 1.4K
Отв.1131  05 Февр. 18, 06:19, через 36 мин
17.3.4. Вариант Lite. Силовые модули. Контроллер ТЭНа. Прошивка

Мощность нагрева ТЭНа, в варианте LITE, регулируется за счет изменения среднего количества полупериодов сетевого напряжения, пропускаемых к нагрузке. В принципе это можно делать разными способами. Здесь используется алгоритм, который на каждом шаге минимизирует ошибку среднего уровня мощности. Алгоритм прост и имеет много названий: метод диффузии ошибки, метод Брезенхема, модуляция плотности импульсов (или - Pulse Density Modulation, PDM на импортном языке) и т.д. Суть алгоритма мы подробно уже рассматривали в этом топике. Поэтому перейдем сразу к его непосредственной реализации в варианте LITE. Текст прошивки приведен ниже:
Скрытый текст
#include <avr/io.h>
#include <util/twi.h>
#include <avr/interrupt.h>

#define F_CPU 16000000UL
#define ADDR 0x13      // Адрес устройства на шине I2C
#define PULSE_WIDTH 78 // Длительность управляющего импульса - около 5 мс
                       
volatile uint8_t pdm = 0;   // Требуемый уровень PDM-модуляции в %
volatile int16_t err = 0;   // Ошибка дискретизации
volatile int8_t pp = 1;     // Относительный знак предстоящего полупериода
                           // 1 - положительный, 0 - отрицательный
volatile int16_t ps = 0;    // Отклонение постоянной составляющей от 0
volatile uint8_t pFlag = 0; // Флаг: 1 - пропускаем полупериод к нагрузке, т.е.
                           // подаем управляющий импульс на моську, 0 - нет
volatile int16_t lev;       // Текущий уровень (pdm + err)
//------------------------------------------------------------------------------
ISR(TWI_vect) { // Обработчик событий модуля TWI
 switch(TW_STATUS) {    // Статус - в 5 старших битах регистра TWSR
   case TW_SR_DATA_ACK: // Данные приняты, ACK отправлен - 0x80
     pdm = TWDR;
     if(pdm > 100) pdm = 100;
     break;
   case TW_ST_SLA_ACK:  // Запрос SLA+R, ACK отправлен - 0xA8
     break;
   case TW_BUS_ERROR:   // Неверные условия "старт" или "стоп" - 0x00
     TWCR = _BV(TWIE) | _BV(TWINT) | _BV(TWEA) | _BV(TWEN); // "Сброс" TWI
     break;
 }
 TWCR |= _BV(TWINT);   // Флаг TWINT здесь НЕ очищается автоматически! Очистим.
}
//------------------------------------------------------------------------------
ISR(INT0_vect) { // Внешнее прерывание INT0 (Zero от детектора нуля)
 lev = pdm + err; // Текущий уровень выходного сигнала (мощности)
 pFlag = (lev >= 50)? 1 : 0; // Предварительное решение
 if(ps*pFlag*pp > 0)         // Однако, если подадим импульс, то постоянная
   pFlag = 0;                // составляющая возрастет. Значит - не будем
                             // подавать - отложим да следующего полупериода
 if(pFlag) { // Положительное решение принято - дадим этот полупериод нагрузке
   PORTD |= _BV(PD0);        // Подаем управляющий импульс
   err = lev - 100;          // Оцениваем ошибку (сколько "переложили")
 } else err = lev;           // Если не дали - сколько "недоложили"
 GTCCR = _BV(PSRASY);        // Сброс предделителя таймера 2
 TCNT2 = 0;                  // Обнуляем счетчик таймера 2
  ps += pp*pFlag;            // Считаем текущую постоянную составляющую
  pp = -pp;                  // Следующий полупериод будет другого знака
}
//------------------------------------------------------------------------------
ISR(TIMER2_COMPA_vect) { // Обработчик по совпадению с регистром A
 PORTD &= ~_BV(PD0); // Завершаем управляющий импульс
}
//------------------------------------------------------------------------------
int main(void) {
 DDRD = _BV(PD0); // Пин PD0 - на вывод (управление оптосимистором)
 // Инициализация TWI-модуля --------------------------------------------------
 TWAR = ADDR << 1;   // Адрес устройства - в старших 7 битах
 TWCR = _BV(TWIE);   // Разрешаем прерывания от TWI
 TWCR |= _BV(TWEA);  // Разрешаем подачу импульса ACK
 TWCR |= _BV(TWINT); // Очистим флаг TWINT (очищается при установке в 1)
 TWCR |= _BV(TWEN);  // Разрешаем работу TWI и активирует TWI-интерфейс
 // Инициализация внешнего прерывания INT0
 EICRA = _BV(ISC01) | _BV(ISC00); // Прерывания по фронту на пине PD2/INT0
 EIMSK = _BV(INT0); // Разрешаем внешние прерывания на пине PD2/INT0
 // Инициализация таймера 2 для формирования управляющего импульса для
 // MOC3083 длительностью приблизительно 5 мс
 // Счетчик работает в обычном режиме (Normal mode)
 TCCR2B |= _BV(CS22) | _BV(CS21) | _BV(CS20); // Предделитель на 1024
 OCR2A = PULSE_WIDTH; // Длительность управляющего импульса
 TIMSK2 = _BV(OCIE2A); // Разрешаем прерывания по совпадению
 
 sei(); // Разрешаем глобальные прерывания
 while(1) { // Бесконечный цикл
 }
 return 0;
}
Прошивка состоит из пяти логических блоков.
1) В первой части (в самом начале) производится объявление и инициализация рабочих переменных.
2) Второй блок - это обработчик прерываний модуля TWI. Обрабатывается только одно событие - прием байта от малинки. В этом байте содержится число от 0 до 100, которое означает процент от полной мощности ТЭНа при текущем напряжении, который должен обеспечить контроллер. Принятое от малинки число сохраняется в рабочей переменной pdm. По сути это число означает количество полупериодов сетевого напряжения, котрое контроллер должен пропустить к нагрузке за одну секунду.
3) Третий блок - это обработчик внешних прерываний от линии Zero. Фронт импульса Zero приходит приблизительно за 100 мкс до истинного нуля напряжения сети. Именно по этому фронту инициируется прерывание, вызывается обработчик, и именно в этом обработчике происходит основная текущая работа по правильной регулировке мощности (см. описание алгоритма в этом топике и комментарии в тексте данной прошивки). После принятия решения о том, что нужно или не нужно пропускать полупериод к нагрузке, устанавливается соответствующий уровень на пине PD0 и сбрасывается таймер 2, который задает длительность импульса, подаваемого на светодиод моськи.
4) Четвертый блок - это обработчик прерываний таймера 2. Он вызывается при совпадении значения его счетчика со значением регистра счетчика A. В этом обработчике на пине PD0 устанавливается низкий уровень (конец управляющего импульса). Т.е. отот блок задает длительность управляющего импульса.
5) Ну и в последнем, пятом блоке (это функция main()) производится инициализация всей необходимой периферии (TWI, аппаратные прерывания INT0 и 8-разрядный таймер 2), разрешаются глобальные прерывания и запускается пустой бесконечный цикл приложения.

Текст прошивки подробно прокомментирован. Поэтому разобраться в деталях будет несложно.

Итак, изготавливаем вторую плату силового модуля и прошиваем ее точно так же, как мы поступали и раньше. В качестве наглядной модели ТЭНа будем использовать небольшую лампочку (например, 100Вт, 220В). Подключаем нагрузку (лампочку) к соответствующим силовым шинам крейта и вставляем в крейт готовый и прошитый контроллер ТЭНа.

Для проведения тестирования, как обычно, нам нужен тестовый питоновский скрипт, выполняемый на малинке. Текст этого скрипта приведен ниже (файл test_11.py в архиве топика):
Скрытый текст
# _*_ coding: utf8 _*_
import time # В этом модуле - задержки
import smbus # В этом модуле - средства для работы с шиной i2c
import kbh # В этом модуле - функция kbhit() для работы с клавиатурой
          # в неблокирующем режиме
#-------------------------------------------------------------------------------
# Тестирование прошивки контроллера ТЭНа
#-------------------------------------------------------------------------------
# Управление контроллером ТЭНа:
# '+' - увелить уровень pdm
# '-' - уменьшить уровень pdm
# 'm' - pdm - на 100%
# '0' - pdm - в 0
# Управление контроллером контактора:
# '1' - включить контактор
# '2' - выключить контактор
#-------------------------------------------------------------------------------
bus = smbus.SMBus(1) # Создаем объект "шина i2c"
addrC = 0x12 # Адрес контроллера контактора
addrT = 0x13 # Адрес контроллера ТЭНа на шине i2c
tt = kbh.TT(500) # Создаем объект - терминал, работающий в неблокирующем режиме
                # timeout = 500 ms
pdm = 0 # Уровень pdm (pulse density modulation, ака Брезенхем)
opdm = 0
while True:
 if tt.kbhit(): # Была нажата какая-то клавиша
   ch = tt.getch() # Получаем введенный символ
   if ch == 'q': # Выход их программы
     bus.write_byte(addrT, 0) # Выключить ТЭН
     bus.write_byte(addrC, 0) # Выключить контактор
     break
   elif ch == '+' or ch == '=': # Увеличим уровень pdm
     pdm += 1
     if pdm > 100: pdm = 100
   elif ch == '_' or ch == '-': # Уменьшим уровень pdm
     pdm -= 1
     if pdm < 0: pdm = 0
   elif ch == '0': pdm = 0      # Минимальный уровень pdm - 0%
   elif ch == 'm': pdm = 100    # Максимальный уровень pdm - 100%
   elif ch == '1': bus.write_byte(addrC, 1) # Включим контактор
   elif ch == '2': bus.write_byte(addrC, 0) # Выключим контактор
 if opdm <> pdm: # Уровень pdm был изменен - пошлем его контроллеру и покажем его на терминале
   bus.write_byte(addrT, pdm)   # Шлем уровень pdm контроллеру ТЭНа
   print pdm; opdm = pdm
Скрипт несложен и подробно прокомментирован. При помощи определенных клавиш клавиатуры (а какие - см.комментарий в скрипте) можно включать или выключать контактор и регулировать уровня мощности ТЭНа (лампочки в данном случае). С Богом! Включаем высокое, запускаем на малинке скрипт, включаем контактор (клавиша 1) и, нажимая и удерживая клавишу '+' увеличиваем уровень модуляции. Яркость свечения лампочки (и, естественно, светодиодика на плате) должна возрастать (см. фотографии ниже):
 Ненавязчивая автоматизация ректификационной установки
Ненавязчивая автоматизация ректификационной установки. Автоматика.

При нажатии клавиши '-' яркость будет убывать. Пробуем разные варианты. Все должно работать без сбоев и дыма.

Как и в предыдущих тестах, для тех, кто не любит работать с консолью, я приготовил вариант тестового скрипта с GUI. Текст скрипта приведен ниже. Соответствующий файл (test_11_gui.py) есть в архиве топика.
Скрытый текст
# _*_ coding: utf8 _*_
import time # В этом модуле - задержки
import smbus # В этом модуле - средства для работы с шиной i2c
from Tkinter import * # Инструментарий для GUI
#-------------------------------------------------------------------------------
# Тестирование firmware контроллера ТЭНа
#-------------------------------------------------------------------------------
addrC = 0x12 # Адрес контроллера контактора
addrT = 0x13 # Адрес контроллера ТЭНа
#-------------------------------------------------------------------------------
def fC(): # Вызывается при изменении состояния чекбокса
 global vC
 bus.write_byte(addrC, vC.get());
#-------------------------------------------------------------------------------
def fT(): # Вызывается при изменении состояния спинбокса
 global sbT, pdm
 pdm = int(sbT.get())
 bus.write_byte(addrT, pdm);
#-------------------------------------------------------------------------------
def wclose(): # Перед закрытием главного окна приложения выключим ТЭН
 bus.write_byte(addrT, 0);
 bus.write_byte(addrC, 0);
 root.destroy()
#-------------------------------------------------------------------------------
bus = smbus.SMBus(1) # Создаем объект "шина i2c"
root = Tk(); root.geometry('122x42') # Создаем и настраиваем главное окно
root.protocol('WM_DELETE_WINDOW', wclose)
vC = IntVar() # Состояние чекбокса (контактора)
# Создаем объект - чекбокс
chC = Checkbutton(text = 'Контактор', command = fC, variable = vC)
pdm = 0 # Уровень pdm-модуляции
lpdm = Label(text = 'PDM (%) = ', width = 12, anchor = 'w') # Метка PDM
# Создаем объект - спинбокс
sbT = Spinbox(from_ = 0, to = 100, width = 3, command = fT, justify = RIGHT)
# Размещаем виджеты в главном окне
chC.place(x = 0, y = 0)
lpdm.place(x = 0, y = 20)
sbT.place(x = 80, y = 20)
root.mainloop() # Главный цикл приложения
Запускаем этот скрипт из консоли (python test_11_gui.py). На рабочем столе появится с одним чекбоксом и одним спинбоксом.
Ненавязчивая автоматизация ректификационной установки
Ненавязчивая автоматизация ректификационной установки. Автоматика.

Щелкая левой клавишей мышки по чекбоксу контактора включаем его. Затем спинбоксом регулируем уровень pdm и наблюдаем изменение яркости свечения лампочки и светодиодика.

Все. На этом изготовление и тестирование контроллера ТЭНа можно считать законченным. Следующий модуль - это контроллер клапана отбора. Его прошивке и тестированию будет посвящен следующий топик.

Что делать, если модуль не работает или работает неправильно? Самое первое, что нужно сделать, это проверить наличие сигнала Zero на соответствующей линии крейта, управляющих сигналов на пине PD0 микроконтроллера модуля, их длительность и взаимное расположение. Конфигурация и несколько характерных осциллограмм приведены на следющем рисунке:
 Ненавязчивая автоматизация ректификационной установки
Ненавязчивая автоматизация ректификационной установки. Автоматика.

Длительность импульсов Zero должна быть порядка 100 мкс, длительность управляющих импульсов (на пине PD0) должна быть около 5 мс (см.верхнюю осциллограмму). Фронт управляющего импульса должен отставать от фронта импульса Zero примерно на 5-6 мкс. Это как раз и есть время принятия решения (отдавать или не отдавать ТЭНу предстоящий полупериод). При 100% PDM (мощности) количество управляющих импульсов должно быть равно количеству импульсов Zero. При уменьшении PDM, количество первых должно уменьшаться.

Какие-то отклонения от вышеописанной картины должны навести вас на мысли о причине неисправности или ошибок в работе.

Предыдущий топик  Вернуться к оглавлению  Следующий топик
045_контроллер_ТЭНа_в_крейте.JPG
045_контроллер_ТЭНа_в_крейте.JPG Ненавязчивая автоматизация ректификационной установки. Автоматика.
046_test_11_gui.png
046_test_11_gui.png Ненавязчивая автоматизация ректификационной установки. Автоматика.
047_Тестирование_контроллера_ТЭНа.JPG
047_Тестирование_контроллера_ТЭНа.JPG Ненавязчивая автоматизация ректификационной установки. Автоматика.

firmware.zip 5.8 Кб
OldBean Доцент Красноярск 1K 1.4K
Отв.1132  05 Февр. 18, 17:45
17.3.5. Вариант Lite. Силовые модули. Контроллер клапана отбора. Прошивка

В отличие от ТЭНа, мощность нагрева которого мы можем изменять довольно быстро, клапан отбора - это устройство механическое. Он не может быстро и часто (с частотой сети) открываться/закрываться. Поэтому для регулирования скорости отбора мы будем использовать не PDM, а широтно-импульсную модуляцию (ШИМ) или, другими словами, pulse width modulation (PWM). Период ШИМ выберем равным 10 сек. Это 1000 полупериодов сетевого напряжения. Поскольку моська у силовых модулей с детектором нуля, то длительность импульса ШИМ тоже будет кратна целому количеству полупериодов сетевого напряжения. Поэтому и период, и длительность импульса ШИМ удобно измерять в целых числах - полупериодах сетевого напряжения. На практике, это означает, что мы можем регулировать ШИМ от 0 до 100% с точностью 0.1%. В старой системе шаг регулятора был 1%, что временами бывало несколько грубовато. В варианте LITE мы это исправим, повысив разрешение ШИМ клапана отбора на порядок.

Прошивка контроллера клапана отбора лишь немного сложнее прошивки контроллера контактора и приведена ниже (есть также файл main.c в архиве топика).
Скрытый текст
#include <avr/io.h>
#include <util/twi.h>
#include <avr/interrupt.h>

#define F_CPU 16000000UL
#define ADDR 0x14      // Адрес устройства на шине I2C
                       
volatile uint16_t pwm = 0;  // Заданный ШИМ в полупериодах (десятых долях %)
volatile uint16_t wpwm;     // Рабочая переменная
static volatile uint8_t index = 0; // Номер байта (0 - младший, 1 - старший)
volatile uint16_t cntr = 0; // Счетчик полупериодов
//------------------------------------------------------------------------------
ISR(TWI_vect) { // Обработчик событий модуля TWI
 uint16_t w;
 switch(TW_STATUS) {    // Статус - в 5 старших битах регистра TWSR
   case TW_SR_DATA_ACK: // Данные приняты, ACK отправлен - 0x80
     w = TWDR;
     if(index) { // Принят старший байт. Значит формируем новое значение pwm
       w <<= 8; pwm = wpwm | w; index = 0;
       if(pwm > 1000) pwm = 1000;
     } else { // Принят младший байт - формируем младшие биты будущего pwm
       wpwm = w; index = 1;
     }
     break;
   case TW_ST_SLA_ACK:  // Запрос SLA+R, ACK отправлен - 0xA8
     TWDR = 0xff;       // По запросу - отправляем малинке кучу единичек (OK),
     index = 0;         // что означает, что контроллер готов принять два
     break;             // последовательных байта (начиная с младшего)
   case TW_BUS_ERROR:   // Неверные условия "старт" или "стоп" - 0x00
     TWCR = _BV(TWIE) | _BV(TWINT) | _BV(TWEA) | _BV(TWEN); // "Сброс" TWI
     break;
 }
 TWCR |= _BV(TWINT);   // Флаг TWINT здесь НЕ очищается автоматически! Очистим.
}
//------------------------------------------------------------------------------
ISR(INT0_vect) { // Внешнее прерывание INT0 (Zero от детектора нуля)
 cntr++; // Считаем полупериоды
 if(cntr == 1000) { // 10 секунд (1000 полупериодов) прошло
   cntr = 0;   // Сбрасываем счетчик
   if(pwm > 0) // Включаем клапан (начало импульса ШИМ)
     PORTD |= _BV(PD0);
 }
 if(cntr >= pwm && (PORTD & _BV(PD0))) // Пора выключать клапан
   PORTD &= ~_BV(PD0);
 if(cntr < pwm && (~PORTD & _BV(PD0))) // Если pdm был изменен, но время
   PORTD |= _BV(PD0);                  // еще не истекло - откроем клапан
}
//------------------------------------------------------------------------------
int main(void) {
 DDRD = _BV(PD0); // Пин PD0 - на вывод (управление оптосимистором)
 // Инициализация TWI-модуля --------------------------------------------------
 TWAR = ADDR << 1;   // Адрес устройства - в старших 7 битах
 TWCR = _BV(TWIE);   // Разрешаем прерывания от TWI
 TWCR |= _BV(TWEA);  // Разрешаем подачу импульса ACK
 TWCR |= _BV(TWINT); // Очистим флаг TWINT (очищается при установке в 1)
 TWCR |= _BV(TWEN);  // Разрешаем работу TWI и активирует TWI-интерфейс
 // Инициализация внешнего прерывания INT0
 EICRA = _BV(ISC01) | _BV(ISC00); // Прерывания по фронту на пине PD2/INT0
 EIMSK = _BV(INT0); // Разрешаем внешние прерывания на пине PD2/INT0
 
 sei(); // Разрешаем глобальные прерывания
 while(1) { // Бесконечный цикл
 }
 return 0;
}
Исходный текст прошивки подробно прокомментирован, поэтому остановимся только на нескольких моментах общего характера. Поскольку длительность импульса ШИМ изменяется от 0 до 1000, то малинка должна передавать контроллеру клапана отбора два байта данных. Для идентификации байтов (старший или младший) будем использовать точно такой же подход, какой мы использовали в датчике RMS - индексировать байты с помощью глобальной переменной index. Если index равен 0, то речь идет о младшем байте, если 1 - то о старшем. Сброс индекса выполняется при помощи противоположной операции обмена. В данном случае контроллер только принимает байты. По крайней мере на этом этапе разработки. Поэтому сброс индекса производится командой чтения. Т.е. малинка запрашивает у контроллера байт. Если контроллер в состоянии принимать байты от малинки, он посылает ей 0xff, сбрасывает индекс на ноль и ждет прибытия сначала младшего байта, затем старшего. Малинка, получив 0xff, отправляет контроллеру необходимые байты в нужной последовательности. Интервал между посылками в данном случае может быть произвольным. Вся эта логика реализована в обработчике прерываний модуля TWI.

Второй обработчик (аппаратные прерывания Zero от детектора нуля) занимается исключительно формированием импульсов ШИМ. Логика работы его тоже очень проста и управляется значением счетчика (глобальная переменная cntr). Счетчик cntr инкрементируется при каждом вызове обработчика прерываний (т.е. незадолго до начала очередного полупериода сети). Значение счетчика 1000 означает конец одного периода ШИМ и начало следующего. При выполнении этого условия, счетчик сбрасывается на 0 и на пин PD0 подается высокий уровень. Клапан отбора в очередном полупериоде откроется. После того, как счетчик досчитает до значения, соответствующее заданной длительности импульса ШИМ (переменная pwm), на пин PD0 подается низкий уровень и клапан закрывается. Остальные детали реализации можно посмотреть непосредственно в тексте прошивки.

Итак, как и раньше, изготавливаем и прошиваем (теперь уже третью) плату силового модуля, который будет контролировать работу клапана отбора. Подключаем клапан (или просто какую-нибудь релюшку на 200В, если клапана еще нет или он уже установлен в установку) к соответствующим силовым шинам крейта и вставляем готовый и прошитый контроллер клапана отбора в крейт.

Для тестирования, опять же, пишем скрипт, который будет выполняться на малинке. Текст этого скрипта приведен ниже (файл test_12.py в архиве топика):
Скрытый текст
# _*_ coding: utf8 _*_
import time # В этом модуле - задержки
import smbus # В этом модуле - средства для работы с шиной i2c
import kbh # В этом модуле - функция kbhit() для работы с клавиатурой
          # в неблокирующем режиме
#-------------------------------------------------------------------------------
# Тестирование прошивки контроллера ТЭНа
#-------------------------------------------------------------------------------
# 'q' - выход из программы
# Управление контроллером контактора:
# 'w' - включить контактор
# 's' - выключить контактор
# Управление контроллером ТЭНа:
# 'e' - увеличить уровень pdm
# 'd' - уменьшить уровень pdm
# 'r' - pdm - на 100%
# 'f' - pdm - в 0
# Управление контроллером клапана отбора:
# 't' - увеличить pwm на 0.1%
# 'g' - уменьшить pwm на 0.1%
# 'y' - увеличить pwm на 1%
# 'h' - уменьшить pwm на 1%
# 'u' - pwm - на 100%
# 'j' - pwm - в 0
#-------------------------------------------------------------------------------
bus = smbus.SMBus(1) # Создаем объект "шина i2c"
addrC = 0x12 # Адрес контроллера контактора
addrT = 0x13 # Адрес контроллера ТЭНа на шине i2c
addrV = 0x14 # Адрес контроллера клапана отбора на шине i2c
tt = kbh.TT(500) # Создаем объект - терминал, работающий в неблокирующем режиме
                # timeout = 500 ms
pdm = 0 # Уровень pdm (pulse density modulation, ака Брезенхем)
opdm = 0
pwm = 0 # Уровень ШИМ клапана отбора
opwm = 0
while True:
 if tt.kbhit(): # Была нажата какая-то клавиша
   ch = tt.getch() # Получаем введенный символ
   if ch == 'q': # Выход их программы - выключаем все
     bus.write_byte(addrC, 0) # Выключить контактор
     bus.write_byte(addrT, 0) # Выключить ТЭН
     bus.read_byte(addrV)     # Выключить клапан
     bus.write_byte(addrV, 0)
     bus.write_byte(addrV, 0)
     break
   elif ch == 'w': bus.write_byte(addrC, 1) # Включим контактор
   elif ch == 's': bus.write_byte(addrC, 0) # Выключим контактор

   elif ch == 'e' or ch == '=': pdm += 1 # Увеличим уровень pdm
   elif ch == 'd' or ch == '-': pdm -= 1 # Уменьшим уровень pdm
   elif ch == 'r': pdm = 100    # Максимальный уровень pdm - 100%
   elif ch == 'f': pdm = 0      # Минимальный уровень pdm - 0%

   elif ch == 't': pwm += 1     # Увеличим уровень pwm на 0.1%
   elif ch == 'g': pwm -= 1     # Уменьшим уровень pwm на 0.1%
   elif ch == 'y': pwm += 10    # Увеличим уровень pwm на 1%
   elif ch == 'h': pwm -= 10    # Уменьшим уровень pwm на 1%
   elif ch == 'u': pwm = 1000   # Максимальный уровень pwm - 100%
   elif ch == 'j': pwm = 0      # Минимальный уровень pwm - 0%

 if pdm > 100: pdm = 100
 if pdm < 0: pdm = 0
 if opdm <> pdm: # Уровень pdm был изменен - покажем его
   bus.write_byte(addrT, pdm)   # Шлем уровень pdm контроллеру ТЭНа
   print 'pdm = ', pdm; opdm = pdm

 if pwm > 1000: pdm = 1000
 if pwm < 0: pwm = 0
 if opwm <> pwm: # Уровень pwm был изменен - пошлем его контроллеру и покажем
   print bus.read_byte(addrV)
   bus.write_byte(addrV, (pwm & 0xff))
   bus.write_byte(addrV, ((pwm >> 8) & 0xff))
   print 'pwm = ', pwm*0.1; opwm = pwm
Сам скрипт несложен и подробно прокомментирован. Единственное, что может смутить коллег, прывыкших к GUI, это несколько непривычное управление системой при помощи клавиатуры. К нему очень легко привыкнуть, но, увы, не мгновенно. Ну примерно так же, как научиться играть "чижика-пыжика" на каком-нибудь клавишном инструменте ;) Назначение управляющих клавиш - в комментарии в верхней части скрипта. Если не получается - ниже вариант теста с GUI (файл test_12_gui.py в архиве топика):
Скрытый текст
# _*_ coding: utf8 _*_
import time # В этом модуле - задержки
import smbus # В этом модуле - средства для работы с шиной i2c
from Tkinter import * # Инструментарий для GUI
import tkMessageBox as mbox # Чтобы ругаться
#-------------------------------------------------------------------------------
# Тестирование firmware контроллера ТЭНа
#-------------------------------------------------------------------------------
addrC = 0x12 # Адрес контроллера контактора
addrT = 0x13 # Адрес контроллера ТЭНа
addrV = 0x14 # Адрес контроллера клапана отбора на шине i2c
#-------------------------------------------------------------------------------
def fC(): # Вызывается при изменении состояния чекбокса
 global vC
 bus.write_byte(addrC, vC.get());
#-------------------------------------------------------------------------------
def fT(): # Вызывается при изменении состояния спинбокса ТЭНа
 global sbT, pdm
 pdm = int(sbT.get())
 bus.write_byte(addrT, pdm);
#-------------------------------------------------------------------------------
def fV(): # Вызывается при изменении состояния спинбокса клапана отбора
 global sbV, pwm
 pwm = int(sbV.get())*10
 if(bus.read_byte(addrV) == 0xff):
   bus.write_byte(addrV, (pwm & 0xff))
   bus.write_byte(addrV, ((pwm >> 8) & 0xff))
 else:mbox.showerror('Ошибка', 'Ошибка контроллера клапана отбора')
#-------------------------------------------------------------------------------
def wclose(): # Перед закрытием главного окна приложения выключим все
 bus.read_byte(addrV)      # Выключить клапан
 bus.write_byte(addrV, 0)
 bus.write_byte(addrV, 0)
 bus.write_byte(addrT, 0); # Выключаем ТЭН
 bus.write_byte(addrC, 0); # Выключаем контактор
 root.destroy()
#-------------------------------------------------------------------------------
bus = smbus.SMBus(1) # Создаем объект "шина i2c"
root = Tk(); root.geometry('122x62') # Создаем и настраиваем главное окно
root.protocol('WM_DELETE_WINDOW', wclose)
vC = IntVar() # Состояние чекбокса (контактора)
# Создаем объект - чекбокс
chC = Checkbutton(text = 'Контактор', command = fC, variable = vC)
pdm = 0 # Уровень pdm-модуляции для контроллера ТЭНа
lpdm = Label(text = 'ТЭН (%) = ', width = 13, anchor = 'w') # Метка PDM
# Создаем объект - спинбокс
sbT = Spinbox(from_ = 0, to = 100, width = 3, command = fT, justify = RIGHT)
pwm = 0 # Уровень pwm-модуляции для контроллера клапана отбора
lpwm = Label(text = 'Клапан (%) = ', width = 13, anchor = 'w') # Метка ШИМ
# Создаем объект - спинбокс
sbV = Spinbox(from_ = 0, to = 100, width = 3, command = fV, justify = RIGHT)
# Размещаем виджеты в главном окне
chC.place(x = 0, y = 0)
lpdm.place(x = 0, y = 20)
sbT.place(x = 80, y = 20)
lpwm.place(x = 0, y = 40)
sbV.place(x = 80, y = 40)
root.mainloop() # Главный цикл приложения
При запуске этого скрипта из консоли, появится небольшое окно с элементами управления (см. рисунок ниже):
Ненавязчивая автоматизация ректификационной установки
Ненавязчивая автоматизация ректификационной установки. Автоматика.

Ну тут уж все совсем просто...

Итак, запускаем из консоли кому что больше нравится (python test_12.py или python test_12_gui.py) и проводим тестирование. Порядок действий таков: запускаем нужный скрипт, затем включаем дифавтомат, далее включаем контактор (клавишей 'w' или мышкой, если работаем с GUI). Увеличиваем уровень PDM контроллера ТЭНа. Смотрим как разгорается и мигает лампочка. Параллельно увеличиваем ШИМ контроллера клапана отбора. Слушаем щелканье клапана. Наблюдаем мигание светодиодиков. В целом, картина должна напоминать ту, которая показана на фотографии ниже (звуки клапана передать не могу ;)
 Ненавязчивая автоматизация ректификационной установки
Ненавязчивая автоматизация ректификационной установки. Автоматика.


Итак, мы сделали и отладили контроллеры минимального набора исполнительных устройств варианта LITE (контактор, ТЭН и клапан отбора). По сути дела - это три базовых типа контроллеров, используемых в системе: релейный, PDM и PWM. Если потребуются контроллеры еще каких-нибудь дополнительных исполнительных устройств (клапаны воды, краны переключения фракций, разгонные ТЭНы и т.п), то они, так или иначе, все равно будут относится к одному из этих типов.

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

Предыдущий топик  Вернуться к оглавлению  Следующий топик
048_тест_исполнительных_модулей_с_GUI.png
048_тест_исполнительных_модулей_с_GUI.png Ненавязчивая автоматизация ректификационной установки. Автоматика.
049_тест_всех_исполнительных_модулей.JPG
049_тест_всех_исполнительных_модулей.JPG Ненавязчивая автоматизация ректификационной установки. Автоматика.

firmware.zip 6.0 Кб
gol_avto Доцент Москва - Серпухов - Анапа 1.3K 458
Отв.1133  05 Февр. 18, 17:59, через 15 мин
мы сделали и отладили контроллеры минимального набора исполнительных устройств варианта LITEOldBean, 05 Февр. 18, 17:45
А может быть сразу подумать о 3-х клапанах отбора? Удобно же ведь!
Dmi_D Кандидат наук Минск 393 138
Отв.1134  05 Февр. 18, 19:08
Исходя из данного готового крейта, места осталось еще на 2 РМ. Так что либо три клапана отбора, либо один и управление водой/ прочие изыски.
Либо наращивать крейт.??
OldBean Доцент Красноярск 1K 1.4K
Отв.1135  06 Февр. 18, 02:55
Емкость крейта, количество силовых модулей и номенклатура исполнительных устройств - целиком определяются задачами, которые должна решать установка и, естественно, определяются разработчиком. Тут единого решения нет. У каждого - разные потребности. Главное - чтобы расширение и наращивание возможностей системы было очень простым. Надеюсь, что в варианте LITE (за счет атомизации бизнес-логики, упрощения и унификации модулей, за счет сквозной шины и крейта) нам уже почти удалось этого достичь. Я имею в виду не конкретный крейт, который я использую для отладки и экспериментов (для моих текущих задач его вполне достаточно). А "вариант LITE", как идею организации такой максимально "распараллеленной" автоматизации. Как концепт. Ну а конкретный "костюм" под свою конкретную фигуру, естественно, подгонять нужно самому ;)
сообщения удалены (2)
Dmi_D Кандидат наук Минск 393 138
Отв.1136  10 Февр. 18, 16:35
BogAD,
Будешь делать печатку, предусмотри место для минимального радиатора на boost, при токе 2 А может конкретно греться микросхема.
Я себе нашел вот такой вариант
https://ru.aliexpress.com/...2816412117.html
Пока ничего рассказать не могу, жду пока придет. Как получу,- потестирую, отпишусь.
BogAD Кандидат наук Красногорск - Белово 403 184
Отв.1137  10 Февр. 18, 17:21, через 47 мин
Будешь делать печатку, предусмотри место для минимального радиатора на boost, при токе 2 А может конкретно греться микросхема.
Я себе нашел вот такой вариант
https://ru.aliexpress.com/...2816412117.html
Пока ничего рассказать не могу, жду пока придет. Как получу,- потестирую, отпишусь.Dmi_D, 10 Февр. 18, 16:35

Увы...DC-DC повышающий/понижающий модуль LM2577 Sepic Boost не выдержал критики. На 150 мА просадка напряжения...
По этому  удалил пост...

Подобрал другой. Продавец пишет что заточен под один элемент LiION.
DC-DC конвертер Step Up Boost, модуль 3 В до 5 В Boost плате 3A
Заказал...
Dmi_D Кандидат наук Минск 393 138
Отв.1138  10 Февр. 18, 19:09
Ты знаешь, какая-то непонятная фотка, неясно на чем он собран. Сверху три кондера, диод и дроссель, что внизу неизвестно. Ты отпишись, когда получишь, что за зверь, потому что характеристики заявлены неплохие, а вот реально?..
Кстати, мой вариант смотрел?
BogAD Кандидат наук Красногорск - Белово 403 184
Отв.1139  10 Февр. 18, 19:37, через 29 мин
Ты знаешь, какая-то непонятная фотка, неясно на чем он собран.Dmi_D, 10 Февр. 18, 19:09
Тут поподробней, но тут минимум 5 шт:
Boost модуль

По моей ссылке:
Boost модуль за 336 руб с доставкой
дешевле не нашел...

Кстати, мой вариант смотрел?Dmi_D, 10 Февр. 18, 19:09
Нет. Дай ссылку