Диммер с стабилизацией напряжения

PiratFox

★★★★★✩✩
13 Фев 2020
1,724
481
Нужно формулу придумать, наверное что то там с корнями и sin
Как по мне - так проще составить таблицу PID, записав её в массив. Несложные контроллеры крайне херово и медленно считают тригонометрию. Может не успеть и пропустить несколько периодов синусоиды. А это не есть гуд.
 

Владимир1971

✩✩✩✩✩✩✩
17 Окт 2020
23
0
Как по мне - так проще составить таблицу PID, записав её в массив. Несложные контроллеры крайне херово и медленно считают тригонометрию. Может не успеть и пропустить несколько периодов синусоиды. А это не есть гуд.
А где про это можно почитать, я полный ноль в этом
 

Владимир1971

✩✩✩✩✩✩✩
17 Окт 2020
23
0
На сегодня хватит информации, я спать. В 5 на работу.

С таймерами засада. Есть скетч диммера от Гувера на таймере, но с ним дисплей не работает конфликт библиотек CyberLib.h и LiquidCrystal_I2C.h

*/
#include <Wire.h>
#include <CyberLib.h>
#include <LiquidCrystal_I2C.h>
#define dimPin 4
#define zeroPin 2
#include <CyberLib.h> // шустрая библиотека для таймера
LiquidCrystal_I2C lcd(0x27,20,4); // set the LCD address to 0x27 for a 16 chars and 2 line display
volatile int tic, Dimmer;

void setup() {
// initialize the lcd
lcd.init();
// Print a message to the LCD.
lcd.backlight();
lcd.setCursor(1,0);
Serial.begin(9600);
pinMode(dimPin, OUTPUT);
digitalWrite(dimPin, 0);
pinMode(zeroPin, INPUT); // настраиваем порт на вход для отслеживания прохождения сигнала через ноль
attachInterrupt(0, detect_up, FALLING); // настроить срабатывание прерывания interrupt0 на pin 2 на низкий уровень

StartTimer1(timer_interrupt, 40); // время для одного разряда ШИМ
StopTimer1(); // остановить таймер

Serial.println("Start");
}

void loop()
lcd.setCursor(1,0);
lcd.print(Dimmer);
// раскомментировать для управления потенциометром (аналоговый А0)
Dimmer = map(analogRead(0), 0, 1023, 240, 0);
}

//----------------------ОБРАБОТЧИКИ ПРЕРЫВАНИЙ--------------------------
void timer_interrupt() {
// прерывания таймера срабатывают каждые 40 мкс

tic++; // счетчик
if (tic > Dimmer) // если настало время включать ток
digitalWrite(dimPin, 1); // врубить ток

}

void detect_up() { // обработка внешнего прерывания на пересекание нуля снизу
tic = 0; // обнулить счетчик
ResumeTimer1(); // перезапустить таймер
attachInterrupt(0, detect_down, RISING); // перенастроить прерывание
}

void detect_down() { // обработка внешнего прерывания на пересекание нуля сверху
tic = 0; // обнулить счетчик
StopTimer1(); // остановить таймер
digitalWrite(dimPin, 0); // вырубить ток
attachInterrupt(0, detect_up, FALLING); // перенастроить прерывание
}
//----------------------ОБРАБОТЧИКИ ПРЕРЫВАНИЙ--------------------------
 

DAK

★★★✩✩✩✩
8 Окт 2020
517
137
Вот есть идея, на входе поставить диодный мост и управлять тиристором, так будет проще в плане отслеживания. Так как нагрузка активная, думаю от данного включения ей хуже не станет. Если подключить математику, то получается, что мощность - это интеграл под синусоидой. Как я понимаю надо стабилизировать не напряжение, не силу тока, а именно мощность переданную на нагреватель. Задача - найти зависимость таймера от напряжения на входе. так же думаю, что измерять напряжение можно 1-2 раза в секунду, и из полученных значений вычислять значение таймера, который потом запускать по прерыванию.
 

PiratFox

★★★★★✩✩
13 Фев 2020
1,724
481
Вот есть идея, на входе поставить диодный мост и управлять тиристором,
Надо заметить, что идея-то с огромной бородой. :giggle: Такое решение применяли ещё когда симисторы были дороги и дефицитны. Недостаток - нужны 4 мощных диода, ну или мощный мост, которые ещё и греться будут.
Как я понимаю надо стабилизировать не напряжение, не силу тока, а именно мощность переданную на нагреватель.
Так тут одно не противоречит другому. Достаточно стабилизировать ток или напряжение, тогда мощность будет стабильной как следствие. Напряжение стабилизировать проще всего, т.к. его проще всего отслеживать.
 
Изменено:

bort707

★★★★★★✩
21 Сен 2020
2,899
862
На мой взгляд, подход регулирования мощности вместо регулировки температуры - изначально порочный. Температура в кубе зависит не только от мощности ТЭНов, но и от количества продукта, теплоизоляции, скорости отбора, режима колонны, даже ее формы и температуры в цехе. Все это отлично учитывается по температуре - и очень сложно учесть по мощности. Так что первый совет про ПИД по температуре - самый правильный.\

Второе - точность регулировки "более чем 4-6%" по мощности тут не нужна... ТС сам пишет, что в большом обьеме ТЭНы имеют огромную инерцию, а значит колебания, вызванные грубым регулированием, будут сглаживаться сами.

На самом деле ТС уже приходил на другие форумы, задавал эти хе вопросы... ему все это уже рассказывали.. а он через несколько месяцев приходит снова и спрашивает то же самое.
 

Эдуард Анисимов

★★★★★★✩
23 Сен 2019
2,282
945
58
Марий-Эл
Берёте вот это. https://owen.ru/product/bust
И вот это https://owen.ru/product/trm1

И прекращаете компастировать мозг ;)
Техника имеет государственную сертификацию.
Используется в военной промышленности.
А требования там поболее, чем в самогонном аппарате.
 

Владимир1971

✩✩✩✩✩✩✩
17 Окт 2020
23
0
Все
На мой взгляд, подход регулирования мощности вместо регулировки температуры - изначально порочный. Температура в кубе зависит не только от мощности ТЭНов, но и от количества продукта, теплоизоляции, скорости отбора, режима колонны, даже ее формы и температуры в цехе. Все это отлично учитывается по температуре - и очень сложно учесть по мощности. Так что первый совет про ПИД по температуре - самый правильный.\

Второе - точность регулировки "более чем 4-6%" по мощности тут не нужна... ТС сам пишет, что в большом обьеме ТЭНы имеют огромную инерцию, а значит колебания, вызванные грубым регулированием, будут сглаживаться сами.

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

Всем спасибо. Тема закрыта.
 

bort707

★★★★★★✩
21 Сен 2020
2,899
862
Нина один форум с этим вопросом я не выходил, да и вообще на форумы связанными с этой темой я вышел первый раз. С кем то вы меня путаете.
не исключено, конечно... но вообще у меня память на такие вещи очень цепкая.
Я точно помню идею поддержания температуры по мощности тенов и даже обьяснение, что это мол, так сложно, что надо два дня рассказывать :)

Но может быть это были не Вы , а Ваш единомышленник :)
 

DAK

★★★✩✩✩✩
8 Окт 2020
517
137
Так тут одно не противоречит другому. Достаточно стабилизировать ток или напряжение, тогда мощность будет стабильной как следствие. Напряжение стабилизировать проще всего, т.к. его проще всего отслеживать.
Меня тут как-то в соседней ветки упрекали, что я в школе плохо учился, так что сильно моим расчётам можно не верить… В общем есть такое понятие, как количество теплоты, или работа. Q = P*t, где P – мощность, t- время.

P=U*I, так как будем считать сопротивление тэна постоянным (допустим, знаю, что в холодном состоянии оно мало, но в наших условиях это допущение вполне справедливо), получаем, что P=U*U/R, итого имеем, что Q=U^2/R*dt, где U, это не просто напряжение, это функция от времени. U=u(t)=Umax*sin(2*pi*v*t)
Так вот, чёт мне стало интересно и я решил заморочится и посчитать интеграл, и понять на сколько отслеживая напряжение можно регулировать передаваемую мощность.
Так как очень неинтересные формулы получаются, не стал решать уравнения типа x+sin(x0)=c, просто решил численно оценить.
Формулы по интегралам приводить не буду, просто выводы и цифры.

Допустим у нас напряжение в сети 200 вольт, сопротивления тэна 10 Ом, а мы настроились на стабилизацию 100 вольт (То есть на спаде синусоиды при 100 Вольт включаем симистор)

100=200*sin(100pit), t=0.0083, через отведённое время после начала полупериода мы включим тэн на 0,017 сек.

Q=0,6 Джоуля теплоты за пол периода (за 1минуту это 3600 Джоуля)

А теперь допустим, что у нас поднялось напряжение до 240 вольт, а мы всё так же настроены на 100 Вольт

100=240*sin(100pit), t=0.0086, через отведённое время включили всего на 0,014 сек.

Q= 0,5 Джоуля теплоты за пол периода (за 1 минуту это 3000 Джоуля)

Судя по всему от амплитуды синусоиды нехило зависит и количество переданного количества тепла за единицу времени

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

Владимир1971

✩✩✩✩✩✩✩
17 Окт 2020
23
0
Вот этот код занимает время обработки 48-52 мкс. Можно ли как то оптимизировать что бы вложится в 40 мкс. Виновник тормозов volt_sum+=pow (volt_m,2);

//----------------------ОБРАБОТЧИКИ ПРЕРЫВАНИЙ--------------------------
ISR(TIMER2_A) {
// прерывания таймера срабатывают каждые 40 мкс

n=n+1;

volt_m = (analogRead(0)); // читаем pin
volt_sum+=pow (volt_m,2); // возводим в квадрат
tic++; // счетчик
if (tic > Dimmer) // если настало время включать ток
digitalWrite(dimPin, 1); // врубить ток
}
 

Владимир1971

✩✩✩✩✩✩✩
17 Окт 2020
23
0
volt_m*volt_m
и врубать ток думаю надо не в прерывании.
судя по времени АЦП уже ускорено.
Ацп ускорено. Ток нужно врубать именно в прерывании. Это скетч AlexGyver
volt_m*volt_m я пробовал но именно в прерывания это не работает, перемножение не работает, результат 0
В другом месте вне прерывания работает, но нужно суммировать именно в прерывании.

volt_m = (analogRead(0)); время 16-20 мкс
volt_sum+=pow (volt_m,2) 20-24 мкс
 

Старик Похабыч

★★★★★★★
14 Авг 2019
4,192
1,281
Москва
атомарный блок пробовали ?
ну как вариант... при запуске таймера сразу запустить АЦП, при вызове прерывания скорее всего результат будет готов и его можно будет забрать. И сразу запустить следующую обработку АЦП. ИЛи вообще запустить непрерывное получение данных на АЦП, тогда в регистре результат будет всегда последнее значение. Получиться сократить analogRead.
Вместо digitalWrite использовать прямое обращение к регистру пина. Будет гораздо быстрее.

Вот ради интереса попробовал такой код:
C++:
volatile uint32_t mm=0;
volatile uint32_t tic=0;

void a2_mult()
{
  //uint32_t m=analogRead(A0);
  uint32_t m=2;
  tic++;
  mm=mm+m*m;
  };
void setup() {
  Serial.begin(115200);
  pinMode(2,INPUT_PULLUP);
  SuperFastADC(4);
 
  attachInterrupt(0,a2_mult,RISING);
}

void loop() {
  Serial.print(tic);Serial.print(" ");Serial.println(mm);
  delay(1000);
}

void SuperFastADC(byte n)
{
  ADCSRA = ADCSRA & B11111000;
  ADCSRA = ADCSRA | n;
}
Все работает исрправно. сначала хотел читать аналог, но потом плюнул и решил, что без него проверить проще. умножение работает.
 

Владимир1971

✩✩✩✩✩✩✩
17 Окт 2020
23
0
В данном варианте да работает. Но мне нужно получить рад измерений за 10 м.с. каждое из них возвести во вторую степень, а потом уже делать остальные вычисления. Нужно для измерения одной полуволны синусоиды, что бы вычислить напряжение RMS
Выкладываю весь скетч. Может так будет понятней.

/*
Диммер переменки на Arduino. Симистор через оптопару
подключен к 4 пину, детектор нуля ко 2 пину.
Переменная Dimmer - величина диммирования, от 0 до 255
В этом коде на пин А0 подключен потенциометр для управления яркостью
Также можно вводить число для переменной Dimmer через
монитор порта, для этого в лупе надо раскомментировать код
*/
#include <Wire.h>
#include <GyverTimers.h>
#include <LiquidCrystal_I2C.h>
#define dimPin 4
#define zeroPin 2
volatile int volt_m; // моментальное значение напряжения
unsigned long volt_sum; // Сумма моментального напряжения в квадрате
volatile unsigned long volt_sum1; // volt_sum / кол-во. измерений
volatile int volt_sum2; //Корень из volt_sum1
volatile int n=0; // Счетчик кол-ва измерений
volatile float volt; //Напряжение rms
volatile int x=0;

LiquidCrystal_I2C lcd(0x27,20,4); // set the LCD address to 0x27 for a 16 chars and 2 line display
volatile int tic, Dimmer;

void setup() {

ADCSRA |= (1 << ADPS2); //Биту ADPS2 присваиваем единицу - коэффициент деления 16
ADCSRA &= ~ ((1 << ADPS1) | (1 << ADPS0)); //Битам ADPS1 и ADPS0 присваиваем нули
lcd.init(); // initialize the lcd
lcd.backlight();
lcd.setCursor(1,0);
pinMode(dimPin, OUTPUT);
digitalWrite(dimPin, 0);
pinMode(zeroPin, INPUT); // настраиваем порт на вход для отслеживания прохождения сигнала через ноль
attachInterrupt(0, detect_up, FALLING); // настроить срабатывание прерывания interrupt0 на pin 2 на низкий уровень
Timer2.setPeriod(60);// время для одного разряда ШИМ
Timer2.stop(); // остановить таймер
Timer2.enableISR(); // прерывание по таймеру
}

void loop() {
lcd.setCursor(6,0);
lcd.print(volt);
lcd.print(" ");


// раскомментировать для управления потенциометром (аналоговый А0)
Dimmer = map(analogRead(0), 0, 1023, 166, 0);


}


//----------------------ОБРАБОТЧИКИ ПРЕРЫВАНИЙ--------------------------
ISR(TIMER2_A) {
// прерывания таймера срабатывают каждые 40 мкс

n=n+1;

volt_m = (analogRead(0)); // читаем pin
volt_sum+=pow (volt_m,2); // возводим в квадрат
tic++; // счетчик
if (tic > Dimmer) // если настало время включать ток
digitalWrite(dimPin, 1); // врубить ток
}

void detect_up() { // обработка внешнего прерывания на пересекание нуля снизу


tic = 0; // обнулить счетчик
Timer2.restart(); // перезапустить таймер
attachInterrupt(0, detect_down, RISING); // перенастроить прерывание
}

void detect_down() { // обработка внешнего прерывания на пересекание нуля сверху
volt_sum1=volt_sum/n;
volt_sum2=sqrt(volt_sum1);
volt=(volt_sum2*5.00)/1024;
//Serial.println (volt);

volt_m=0;
volt_sum=0;
volt_sum1=0;
volt_sum2=0;
n=0;
tic = 0; // обнулить счетчик
Timer2.stop();
digitalWrite(dimPin, 0); // вырубить ток
attachInterrupt(0, detect_up, FALLING); // перенастроить прерывание

}
//----------------------ОБРАБОТЧИКИ ПРЕРЫВАНИЙ--------------------------

В этом варианте я таймер установил 60 мкс. Теперь всё работает, но потерял плавность регулировки. Потенциометр будет заменён на энкодер. Значения с потенциометра снимаю только для пробы, в будущем буду снимать с делителя.
 

Старик Похабыч

★★★★★★★
14 Авг 2019
4,192
1,281
Москва
АЦП ускорен максимально?
У меня есть функция SuperFastADC(byte n), вот если на вход подавать 1 , то это будет самый быстрый и грубый АЦП, 3.4 микросекунды. 324 кГц можно снимать.
Запись состояния в регистр цифрового пина тоже примерно столько же. Ну и остальное на сложение умножение.

Нашел. коэф АЦП 16 это где то 65кГц. Меньше пробовали ?

И да, код лучше в тег кода кинуть, тогда будет на 2 порядка читабельней
 

Владимир1971

✩✩✩✩✩✩✩
17 Окт 2020
23
0
Делитель менять не пробовал. Для меня это сложно, я ардуино увидел пол года назад, До этого с программированием не связан был вообще.
По сей причине половины того что вы пишите я просто не в состоянии понять. Будем учится.
 

Старик Похабыч

★★★★★★★
14 Авг 2019
4,192
1,281
Москва
Ага, берете мою функцию из примера.
Вот это все
C++:
ADCSRA |= (1 << ADPS2); //Биту ADPS2 присваиваем единицу - коэффициент деления 16
ADCSRA &= ~ ((1 << ADPS1) | (1 << ADPS0)); //Битам ADPS1 и ADPS0 присваиваем нули
Меняется на такую строку:
SuperFastADC(4);

Это будет делитель 16. Для 8 надо написать SuperFastADC(3), для 4 соотв. SuperFastADC(2) , для 2-х - SuperFastADC(1)
Ноль подавать нельзя. Выше 4-х будет дольше.
Чем меньше делитель, тем больше даст выгоды чтение регистра АЦП по сравнению с analogRead. Если при делителе 16 выгода будет 5% , то при 4 уже 15%, при 2 - почти 25%.
Чтение регистра АЦП сложнее чем чтение простого регситра пина. Пока, для тестов можно оставить стандартное, а потом уже заменить на прямое. Ссылка в тему: https://sites.google.com/site/100vo...a328p-pod-kakim-sousom-ego-neobhodimo-podavat
Это 1-ый этап.
Второй замена digitalWrite : https://alexgyver.ru/lessons/registers/
 
Изменено:

Владимир1971

✩✩✩✩✩✩✩
17 Окт 2020
23
0
SuperFastADC(4);
void SuperFastADC(byte n)
{
ADCSRA = ADCSRA & B11111000;
ADCSRA = ADCSRA | n;
}
При компеляции
exit status 1
'SuperFastADC' was not declared in this scope
 

Старик Похабыч

★★★★★★★
14 Авг 2019
4,192
1,281
Москва
Вот такую строку добавьте куда нибудь в самое начало - это называется предварительное объявление функции.
void SuperFastADC(byte n) ;
И вот это все должно быть где то в самом конце, после всех }
C++:
void SuperFastADC(byte n)
{
ADCSRA = ADCSRA & B11111000;
ADCSRA = ADCSRA | n;
}
 

Владимир1971

✩✩✩✩✩✩✩
17 Окт 2020
23
0
Большое СПАСИБО. Помогло!!! SuperFastADC(2 ) Время 36 мкс остались правда небольшие рывки, по лампочке видно но это уже мелочи.
Если ставить SuperFastADC(1 ) то перестаёт обновляться показания напряжение на дисплее.