ПИД-регулятор Arduino для симистора
Я разрабатываю новую паяльную станцию, в которой будет использоваться паяльник на 24 В переменного тока.
Я начал проводить исследования и спроектировал несколько шагов паяльной станции. Я буду использовать тороидальный трансформатор 24 В переменного тока / 100 ВА. Я буду использовать паяльник 24В/50Вт с термопарой типа К. Для термопары я буду использовать усилитель LM358. Пожалуйста, ознакомьтесь с прилагаемой схемой и кодом. Код еще не готов, и мне нужна помощь в установлении связи между библиотекой PID и выводом в коде. Напряжение на паяльнике выглядит так: https://ibb.co/CMF1gQ0 Если я поворачиваю горшок, на экране прицела ничего не происходит.
https://ibb.co/vdDRmnJ
Я написал несколько строк кода, но не знаю, как установить связь между библиотечными функциями PID, функцией прерывания и другими переменными в моем коде.
Пожалуйста, взгляните на код и схему и скажите мне, что вы думаете... Я жду вашей помощи.
#include <PID_v1.h>
int AC_LOAD = 1; // Вывод на вывод Opto Triac
double set_value = 0;
double input = 0;
double output = 0;
PID aaa_PID(&input, &output, &set_value, 1, 0.05, 0.25, DIRECT);
void setup()
{
aaa_PID.SetOutputLimits(0, 128);
aaa_PID.SetMode(AUTOMATIC);
pinMode(AC_LOAD, OUTPUT);// Установить контакт нагрузки переменного тока в качестве выхода
attachInterrupt(0, zero_crosss_int, RISING); // Выбираем прерывание пересечения нуля # из таблицы выше
}
//функция прерывания не должна принимать никаких параметров и ничего не возвращать
void zero_crosss_int() // функция, которая будет запущена при пересечении нуля, чтобы приглушить свет
{
// Расчет угла открытия: 1 полная волна 50 Гц = 1/50 = 20 мс
// Каждое пересечение нуля таким образом: (50Hz)->gt; 10 мс (1/2 цикла)
// Для 60 Гц => 8,33 мс (10 000/120)
// 10 мс=10000 мкс
// (10000 мкс - 10 мкс) / 128 = 75 (приблизительно) Для 60 Гц => 65
int dimtime = (75*output); // Для 60 Гц =>65
delayMicroseconds(dimtime); // Подождите, пока сработает TRIAC
digitalWrite(AC_LOAD, HIGH); // Запустить TRIAC
delayMicroseconds(10); // симистор Задержка распространения (для 60 Гц используйте 8.33)
digitalWrite(AC_LOAD, LOW); // Больше не запускать TRIAC (следующее пересечение нуля отключит его) TRIAC
}
void loop() {
int set_point = analogRead(A1);
set_point = map(set_point, 0, 1023, 150, 400);
int in = analogRead(A0);
input = map(in, 0, 550, 25, 400);
set_value = set_point;
aaa_PID.Compute();
}
@beard999, 👍2
Обсуждение2 ответа
Мне нужна помощь в установлении соединения между библиотекой PID и вывод в коде
PID вычисляет значение output
и используется в int dimtime = (75*output);
.
Объект aaa_PID
получает ссылку на переменную output
с помощью &
, поэтому, когда алгоритм PID устанавливает выходное значение, он устанавливает значение эту переменную в вашем скетче.
output
должен быть volatile double output = 0;
, потому что он используется в прерывании.
РЕДАКТИРОВАНИЕ 2:
Надеюсь, вы подключили детектор пересечения нуля к контакту 2, потому что это контакт для внешнего прерывания 0. И не используйте контакт 1 для симистора, он также подключен к USB-чипу.
ИЗМЕНИТЬ: Ваш код слишком долго остается в прерывании. Вы выходите из прерывания только через время после срабатывания симистора и следующего пересечения нуля.
В этом ответе на Arduino SE я предлагаю два скетча, демонстрирующих управление симистором. Вот один из них:
#include <TimerOne.h>
const byte INTERRUPT_PIN = 2;
const byte TRIAC_PIN = 4;
const byte TRIAC_PULSE_MICROS = 30;
const int FADE_MAX = 9800;
const int FADE_MIN = 2000;
volatile bool triacOn;
volatile int period = FADE_MIN; // микросекунды вырезаны из импульса переменного тока
int fadeAmount = 10;
void zeroCrossing() {
triacOn = false; // симистор отключается при пересечении нуля
Timer1.setPeriod(period); // для вызова triacPulse() после периода отключения
}
void triacPulse() {
if (triacOn) { // остановить импульс
digitalWrite(TRIAC_PIN, LOW);
Timer1.stop();
} else { // запускаем импульс
digitalWrite(TRIAC_PIN, HIGH);
triacOn = true;
Timer1.setPeriod(TRIAC_PULSE_MICROS);
}
}
void setup() {
pinMode(TRIAC_PIN, OUTPUT);
attachInterrupt(digitalPinToInterrupt(INTERRUPT_PIN), zeroCrossing, RISING);
Timer1.initialize();
Timer1.attachInterrupt(triacPulse);
}
void loop() {
period = period + fadeAmount;
if (period <= FADE_MIN || period >= FADE_MAX) {
fadeAmount = -fadeAmount;
}
delay(25);
}
другой использует прямой доступ к регистрам AVR.
РЕДАКТИРОВАТЬ 3: выходной сигнал осциллографа микрофона на скетче выше: https://www.youtube.com/watch?v= dnfy_EsPlVI
РЕДАКТИРОВАТЬ 4: ПИД-регулятор выдает высокие значения для высокой мощности и малые значения для меньшей мощности. но период симистора - время выключения. поэтому период должен быть примерно таким: period = 11000 - (75 * output)
вот входные и выходные значения кода микрофона, основанные на этом ответе (синий — температура, красный — выходной период симистора):
ПИД-регулятор со временем становится более плавным по мере точной настройки его параметров, но я думаю, что простой PID имеет некоторые проблемы с синусоидальной зависимостью между выходной мощностью (временем) и результирующей мощностью нагрева.
Комментарии не для расширенного обсуждения; этот разговор был [перемещен в чат](https://chat.stackexchange.com/rooms/107366/discussion-on-answer-by-juraj-arduino-pid-controller-for-triac)., @VE7JRO
Я вижу здесь несколько проблем.
Самая серьезная проблема связана с проводкой Arduino. Первый аргумент
attachInterrupt()
— это номер прерывания. На Uno «прерывание 0»
подключен к контакту «цифровой 2». Здесь следует подключить
выход детектора пересечения нуля (ZERO_OUT).
Затем, как заметил Юрай, возникает проблема с обработчиком прерываний.
слишком долго выполняется. Обычно это считается плохой практикой,
и это имеет некоторые негативные последствия для работы ядра Arduino.
например, функция millis()
будет полностью отключена. я не делаю
думаю, однако, что это серьезная проблема для вас. Есть один
единственный критичный по времени бит в вашей программе, который является генерацией
триггерные импульсы. Вы действительно не заботитесь о millis()
или любом другом
другие вещи, связанные со временем. Таким образом, по крайней мере, для начальной версии
программа, мне было бы все равно, а просто пусть обработчик прерывания
задержка по мере необходимости.
Третья проблема была отмечена chrisl в комментарии: есть гонка
состояние, при котором и основная программа, и обработчик прерывания обращаются к
ту же переменную output
. Условия гонки - неприятный вид ошибки
потому что обычно все работает нормально «большую часть времени», а затем выходит из строя в какой-то момент.
неожиданные времена. Я бы не рекомендовал, однако, запускать
myPID.Compute()
с отключенными прерываниями: это может
синхронизация импульсов симистора. Вместо этого вычислите задержку, требуемую
прерывание, сохраните его во временную переменную, затем скопируйте в переменную
совместно с обработчиком. Только копирование нужно делать с прерываниями
отключено, и это занимает всего несколько циклов процессора:
// Переменная, используемая zero_crosss_int().
// Не забывайте о квалификаторе volatile.
volatile int dimtime;
void loop() {
// PID и связанные с ним вычисления.
set_value = map(analogRead(A1), 0, 1023, 150, 400);
input = map(analogRead(A0), 0, 550, 25, 400);
aaa_PID.Compute();
int tmp_dim_time = 75*output;
// Критическая секция выполняется с отключенными прерываниями.
noInterrupts();
dimtime = tmp_dim_time;
interrupts();
}
Обновление: если что-то не работает, попробуйте отладить по частям. Отправка отладочных сообщений на последовательный порт должна помочь, хотя серийный общение, вероятно, будет значительно замедлено из-за долго работающий обработчик прерываний. Как вариант можно использовать симистор контрольные импульсы в качестве средства отладки, возможно, при отключенном нагревательном элементе. Например:
В
loop()
задайте дляdimtime
значение, пропорциональноеset_value
. Поверните потенциометр и посмотрите на сигнал FIRING_PULSE. Есть ли пульс ширина меняется пропорционально положению горшка? Синхронно ли это с Vв пересечениях нуля?Установите
dimtime
пропорциональноinput
. Нагрейте термопару на некоторое время. внешние средства. FIRING_PULSE отличается от ожидаемого?Установите
dimtime
пропорциональновыходной мощности
, но оставьте нагревательный элемент отключен. Как меняется пульс, когда вы двигаете кастрюлю или нагреваете термопара?
Я добавил код в свою программу и запускаю ее, но на экране прицела появляется что-то вроде этого: https://www.youtube.com/watch?v=rAK9ounINAQ, и нагрев паяльника не прекращается. С повышением температуры увеличивается и напряжение на нагревателе паяльника..., @beard999
@mike_mike: ты починил проводку?, @Edgar Bonet
Да, «прерывание 0» подключено к контакту «цифровой 2», как вы сказали., @beard999
@mike_mike: Вы уверены, что параметры PID подходят для вашей системы? Как вы их настроили?, @Edgar Bonet
Параметры PID взяты с другой паяльной станции, в которой вместо симистора использовался мосфет., @beard999
- Помощь с ускорением ПИД-двигателя постоянного тока
- Управление скоростью вентилятора с помощью библиотеки Arduino PID
- Как эмулировать аналоговый потенциометр с помощью ШИМ
- Подключение HX711 к трехпроводному датчику нагрузки
- Потенциометр 10 кОм против резистора 10 кОм на ЖК-дисплее
- ПИД-регулятор для управления скоростью двигателя
- ЖК-дисплей странные символы
- Уменьшить яркость светодиода с помощью NPN-транзистора
Мне это кажется законным, хотя вы можете захотеть отключить прерывание при выполнении
myPID.Compute()
, поскольку вы можете получить искаженные данные в своем прерывании, когда это происходит, когда присваивается переменнаяOutput
. В чем именно у вас проблема с кодом?, @chrislпроблема в том, что я не знаю, правильно ли я написал функцию zero_cross_int(), и я не знаю, где связь между выводом вычислений PID и формой выходного сигнала Arduino. Я имел в виду, что в функции zero_cross_int() считываемое значение должно быть значением детектора пересечения нуля или значением потенциометра?, @beard999
Мне непонятно, что вы имеете в виду. Вы снова изменили свой код. Теперь вы читаете второй аналоговый вход в прерывании. Почему? С вашим старым кодом логика была следующей: аналоговое чтение потенциометра для уставки, вычисление выходного сигнала ПИД-регулятора, использование ПИД-регулятора для управления сигналом симистора. Отсутствовало только считывание входа для PID (поскольку вы создаете паяльную станцию, здесь вам придется измерять температуру) и назначение его на «Вход». Дополнительный AnalogRead в новом коде не имеет смысла (вы нигде не используете это значение), @chrisl
Я снова изменил код: вход A1 для потенциометра, а A0 для датчика температуры., @beard999
Я пробовал код выше, и я застрял на потенциометре. Специально проверял, работает. Но когда я поворачиваю ручку, ничего не происходит. Я вижу на осциллографе только эти осциллограммы: https://ibb.co/mBBnmk3, @beard999