ПИД-регулятор 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();

}

, 👍2

Обсуждение

Мне это кажется законным, хотя вы можете захотеть отключить прерывание при выполнении myPID.Compute(), поскольку вы можете получить искаженные данные в своем прерывании, когда это происходит, когда присваивается переменная Output. В чем именно у вас проблема с кодом?, @chrisl

проблема в том, что я не знаю, правильно ли я написал функцию zero_cross_int(), и я не знаю, где связь между выводом вычислений PID и формой выходного сигнала Arduino. Я имел в виду, что в функции zero_cross_int() считываемое значение должно быть значением детектора пересечения нуля или значением потенциометра?, @beard999

Мне непонятно, что вы имеете в виду. Вы снова изменили свой код. Теперь вы читаете второй аналоговый вход в прерывании. Почему? С вашим старым кодом логика была следующей: аналоговое чтение потенциометра для уставки, вычисление выходного сигнала ПИД-регулятора, использование ПИД-регулятора для управления сигналом симистора. Отсутствовало только считывание входа для PID (поскольку вы создаете паяльную станцию, здесь вам придется измерять температуру) и назначение его на «Вход». Дополнительный AnalogRead в новом коде не имеет смысла (вы нигде не используете это значение), @chrisl

Я снова изменил код: вход A1 для потенциометра, а A0 для датчика температуры., @beard999

Я пробовал код выше, и я застрял на потенциометре. Специально проверял, работает. Но когда я поворачиваю ручку, ничего не происходит. Я вижу на осциллографе только эти осциллограммы: https://ibb.co/mBBnmk3, @beard999


2 ответа


1

Мне нужна помощь в установлении соединения между библиотекой 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


1

Я вижу здесь несколько проблем.

Самая серьезная проблема связана с проводкой 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