41 (2019-04-07 20:36:19 отредактировано Kusnezov Oleg)

Re: Стабилизированный регулятор на базе Arduino с управлением через UART

kvic ©:

сейчас обдумываю...

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

С уважением, Олег Кузнецов.

42

Re: Стабилизированный регулятор на базе Arduino с управлением через UART

Kusnezov Oleg ©:

мог бы  при старте рассчитать задержку включения симистора, исходя из заданного оператором напряжения и идеального состояния сети

А зачем ? Есть заданное и измеренное. По разности регулятор и так за секунду максимум сравняет их. Или приблизит максимально близко.

Kusnezov Oleg ©:

что оператор хотел, когда выставлял напряжение, то и запоминать, до следующего вмешательства оператора.

Ресурс EEPROM всего 100.000 циклов.
Кто бы подсчитал, сколько в среднем за погон оператор корректирует напряжение?
Ты же предлагаешь каждое движение оператора запоминать.
А этих телодвижений не так уж мало.
Есть, конечно, алгоритм записи во флеш по кольцу, но я с ним особо не разбирался, да и не такой уж большой выигрыш по отзывам.
В общем в этом вопросе меня сомнения гложут.
Кстати насчет сбоев. Уже пару ректификаций по 10-11 часов провел с этим регулятором. Сбоев не было.

Kusnezov Oleg ©:

как с погрешностью детектора ноля боролся?

Никак, оно и так вроде работает.

Kusnezov Oleg ©:

...если алгоритм подробно расскажешь, - перепрем эту полечку на родной язык

Расскажу, если общество настаивает, только надо с духом собраться.
Там всё на прерываниях сделано, если что.
И два таймера из трех задействованы.
Как это в си будет я хз.

Kusnezov Oleg" ©:

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

Это какое-то очень сильное колдунство.  o_O  Я так не умею.

РК 35х1600

43 (2019-04-08 19:14:07 отредактировано Kusnezov Oleg)

Re: Стабилизированный регулятор на базе Arduino с управлением через UART

kvic ©:

Как это в си будет я хз.

Для ардуины можно как-то вот так. Пример-иллюстрация. Сам набросал, не проверял. Пока без таймеров.

// RMS вольтметр. Пример настройки прерываний

#define DETECTOR 2        //пин детектора ноля
// аналоговый вход задается в настройках АЦП

volatile unsigned long voltageSumSQ = 0; // служебная переменная для хранения суммы квадратов напряжения
volatile int countADC = 0; // счетчик прерываний АЦП
const int  CYCLE = 99; // измерение проводим на 100 полуциклах
volatile int countCycle = 0; // счетчик циклов
unsigned int voltageRMS = 0; //рассчитанное среднеквадратичное напряжение
const int KVOLT = 1059; //коэффициент пересчета АЦП в миливольты 270 000 мВ = 255 единиц АЦП

void setup(void) {
// Настройки АЦП
ADMUX  = B00100000 ;  //  первые две цифры определяют ИОН (внешнмй), третья – порядок  записи результата, четвертая – не используется, последние четыре цифры определяют пин, в данном случае A0
ADCSRA = B11100101 ; // первая цифра – разрешить АЦП, вторая – запуск преобразования, третья – режим автоматический, четвертая и пятая – компаратор, шестая, седьмая, восьмая – делитель, в данном случае 32
attachInterrupt(digitalPinToInterrupt(DETECTOR), zero_cross, RISING); // настройка прерывания детектора ноля
Serial.begin(9600);
}
void loop(void) {
if (countCycle >= CYCLE) {   //расчет RMS
    voltageSumSQ = voltageSumSQ / countADC; 
    voltageRMS = sqrt(voltageSumSQ); 
    voltageSumSQ = 0;
    countCycle = 0;
    countADC = 0;
    Serial.print("RMS =   ");   Serial.print(voltageRMS * KVOLT); Serial.println("   мВ");
  }
}

void zero_cross() {// счетчик полуциклов по растущему фронту
  countCycle++; 
}
ISR(ADC_vect)
{
  unsigned int voltageCurrent = ADCH;  // Считываем только значимые 8 бит, учитывая что ADLAR=1
  voltageCurrent *= voltageCurrent;// возводим в квадрат
  voltageSumSQ += voltageCurrent; // складываем квадраты измерений
  countADC++;
}
С уважением, Олег Кузнецов.

44

Re: Стабилизированный регулятор на базе Arduino с управлением через UART

kvic, извини вопрос не по теме, если нет желания можно не отвечать, всё ОК!.
На фото 1 экземпляра на дисплее автоматики есть отображение отбора и объёма. Если можно в двух словах(без подробностей) что это и как измеряется? Очень интересно.

Человека губят не принципы, а отступления от своих принципов.

45

Re: Стабилизированный регулятор на базе Arduino с управлением через UART

Тимош ©:

что это и как измеряется?

Даже если это не ответ на твой вопрос, обрати внимание
Узел отбора на перистальтическом насосе

С уважением, Олег Кузнецов.

46

Re: Стабилизированный регулятор на базе Arduino с управлением через UART

Kusnezov Oleg, Спасибо! Видел, но выходит невнимательно. Рассмотрю подробней.

Человека губят не принципы, а отступления от своих принципов.

47 (2019-04-08 22:57:29 отредактировано )

Re: Стабилизированный регулятор на базе Arduino с управлением через UART

Тимош ©:

Если можно в двух словах

Конечно.
Kusnezov Oleg уже дал ссылку на эту часть моего очередного хреносозидательства в предыдущем посте
Это узел отбора на основе перистальтического насоса.
Отбор на дисплее - условная скорость отбора.
На тот момент тем показаниям соответствует скорость 68 мл/час.
А объем, это объем отобранной жидкости(спирт) с момента сброса счетчика.
Это значение уже откалиброванное и соответствующее реальному.

Kusnezov Oleg ©:

алгоритм подробно расскажешь, - перепрем эту полечку

Назовем так.
Алгоритм регулятора с обратной связью.
Фрагмент.
----
Используется 16-разрядный таймер T1, АЦП по входу ADC7 и вход INT0 как детектор нуля сетевого напряжения.
В основе алгоритма лежит обработка прерываний по событию перехода сетевого напряжения через 0 на входе INT0,
прерываний по событиям 16-разрядного таймера Т1, прерываний от АЦП.
----
Входное значение «заданное выходное напряжение».
----
Начнём с прерываний АЦП.
Использует переменные «сумма квадратов» 32 бита  и «число отсчетов» 16 бит.
В подпрограмме обработки прерывания
    - считываем измеренное значение,
    - умножаем его само на себя,
    - прибавляем к нему «сумму квадратов»,
    - сохраняем новую «сумму квадратов»,
    - увеличиваем «число отсчетов» на 1.
Всё, больше там ничего не делается.
Во время между измерениями укладываемся с запасом.
Измерение занимает 26 мкс = 416 циклов, подпрограмма 133 цикла.
----
Прерывания таймера.
Их используется три, они просты до безобразия:
    - по совпадению с регистром А включает оптрон управления симистором;
    - по совпадению с регистром В выключает оптрон управления симистором (в этот регистр загружено значение, обеспечивающее закрытие симистора
      за 250 мкс до конца полупериода);
    - по переполнению тоже выключает оптрон управления симистором (на всякий случай, а то вдруг детектор нуля накрылся).

Далее более интересное прерывание.
----
В момент перехода через 0 генерируется прерывание INT0.

По этому событию всегда выполняются следующие действия:
    - выключается оптрон управления симистором;
    - останавливается и обнуляется таймер Т1;
    - загружается в регистр совпадения А таймера Т1 « задержка включения симистора»;
    - запускается таймер.

Есть различия в том, какой переход через ноль был отловлен вниз или вверх.
---
Если отловлен переход через 0 вверх (подъем), то:
    - запускаем заранее настроенный АЦП на непрерывные преобразования;
    - включаем режим прерывания INT0 на ожидание перехода вниз (спада) через 0.
Всё.
---
Если отловлен переход через 0 вниз (спад), то:
    - останавливаем АЦП;
    - включаем режим прерывания INT0 на ожидание перехода вверх (подъема) через 0.
Так как измерения в отрицательном полупериоде не ведём, делаем следующее:
    - вычисляем измеренное выходное Urms = корень квадратный из «сумма квадратов» деленной на «количество отсчетов»»;
    - запоминаем вычисленное значение;
    - обнуляем «сумму квадратов» и «количество отсчетов» для следующего цикла преобразований.
---
В этой точке уже имеем необходимые данные для регулирования.
Примерно в этих местах делаем вычисление усредненного Urms за какое-то количество периодов.
Вычисляем вхождение в заданный коридор точности и т.п. функции.
---
Используются переменные
     «заданное выходное напряжение»,
     «измеренное выходное напряжение»,
     « задержка включения симистора».
Сравниваем «заданное выходное напряжение» и «измеренное выходное напряжение».
    - если первое больше второго, то уменьшаем « задержку включения симистора»;
    - иначе увеличиваем « задержку включения симистора».
   Это значение будет использовано при ближайшем переходе через 0.
Сравнения и вычисления идут непрерывно каждый отрицательный полупериод каждого периода сетевого напряжения,
вводятся коррекции в « задержку включения симистора» 
и в конце концов выходное напряжения становится равным заказанному.
С некоторой точностью.
---
Разумеется, всё это подвергается проверке на допустимые значения, используются корректирующие коэффициенты для лучшего использования разрядной сетки и упрощения вычислений.
---
Все вычисления идут исключительно целочисленные разрядностью 16 или 32 бита.
Всякие свистелки, перделки и управлялки реализованы другими кусками кода.
---
Под занавес картинка для наглядности, что ли.

Желтая линия – входное напряжение, зеленая – выходное, синяя – управляющий симистором сигнал, красная – переходы входного напряжения через 0.

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

  • regpic00.JPG
    size: 80.58Кб type: JPG
РК 35х1600

48 (2019-04-11 20:16:30 отредактировано Kusnezov Oleg)

Re: Стабилизированный регулятор на базе Arduino с управлением через UART

Четланин ©:

Совершенно согласен.

Kusnezov Oleg ©:

перепрем эту полечку

Перепер...
У меня весь опыт программирования - пол сотни скетчей для ардуино (включая blink).
Но как-то нацарапал, как смог.
kvic, осознано ничего не менял, кроме ADLAR = 1.
Если какие другие изменения - то это мои ошибки  :[
Вот: UPD 11.04.2019

#define    MOC_PORT        PORTD    // Порт подключения MOC
 #define    MOC_PIN         PORTD6       // Нога подключения MOC

 #define    CU_HISTORY_LENGTH   31     // Длина истории значений CURRENT_U
 #define    DEFAULT_ON_VALUE    19500    // момент включения оптрона по умолчанию. отсчитывается от перехода через ноль сетевого напряжения
 #define    DEFAULT_OFF_VALUE     19500    // момент отключения оптрона
 #define    DEFAULT_TARGET_U    1100     // Значение выходного напряжения при старте с зажатой кнопкой энкодера 
 
 #define ADC_ON      ADCSRA=0b11101101  // Заклинание включения  АЦП
 #define ADC_OFF     ADCSRA=0b01101101  // Заклинание выключения АЦП


//!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
const uint8_t optimKoef = 4; // Технический улучшающий коэффициент

volatile uint32_t  ADC_CURRENT_SUM_QUAD  ;  // Сумма квадратов отсчетов  АЦП в текущем периоде       
volatile uint16_t  ADC_CURRENT_VALUE_COUNT ;  // Количество  преобразований  АЦП в текущем периоде         
volatile uint16_t  OPTO_ON_TICK  ;  // Значение  момента включения оптрона записывается  в OCR1A       
volatile uint32_t  CURRENT_QUAD_U  ;  // Квадрат напряжения                  
volatile uint16_t  TARGET_U  ;  // Задаваемое  напряжение                  
volatile uint16_t  CURRENT_U ;  // Текущее значение  URMS                
volatile uint16_t  CURRENT_U_HISTORY[CU_HISTORY_LENGTH] ;  //                     

void setup() {

//=========================================================================
//Настройка таймера 1 
//режим Normal Mode WGM[13:10] = 0000
  TCCR1A = 0x00;  // обнуляем все биты
  TCCR1B = 0x00;    // обнуляем все биты
  // CS12..10 = 010  прескалер FCLK/8, 0,5 мкс/тик, 32,768 мс/цикл   20000 отсчетов за полуцикл
  TCCR1A = (0<<COM1A1)|(0<<COM1A0)|(0<<COM1B1)|(0<<COM1B0)|(0<<WGM11)|(0<<WGM10);
  TIMSK1 = (0<<ICIE1)|(1<<OCIE1A)|(1<<OCIE1B)|(0<<TOIE1);
  TCCR1B =  (0<<ICIE1)|(1<<OCIE1A)|(1<<OCIE1B)|(0<<TOIE1);
  OCR1B =  DEFAULT_OFF_VALUE ; // 
  OCR1A = OPTO_ON_TICK; //
//=========================================================================  
 //  Настройка внешнего прерывания 0 на отлов изменения уровней это детектор нуля сетевого напряжения
 //включим прерывания INT0 по нисходящему фронту
  EICRA &= ~3;  // сбрасываем существующие флаги
  EICRA = 0b00001011; //   ; настраиваемся на ожидание фронта INT0;  
  EIMSK |= (1<<INT0);//разрешим внешние прерывания INT0
//=========================================================================
// Настройка АЦП 
ADMUX  = B00100000 ;  //  первые две цифры определяют ИОН (внешнмй), третья – порядок  записи результата, четвертая – не используется, последние четыре цифры определяют пин, в данном случае A0
ADC_OFF;   // часть настройки и запрещение АЦП - определяется в шапке  
}


//=========================================================================
//************************************************************************
//  обработчики прерываний
//************************************************************************
// Внешнее прерывние INT0 - детектор ноля
ISR( INT0_vect ){
// По этому событию всегда выполняются следующие действия
// - выключается оптрон управления симистором 
MOC_PORT &=  ~(1 << MOC_PIN);
//запомним режим работы Т1  
 byte tccr =  TCCR1B;
// останавливается и обнуляется таймер Т1
 GTCCR = B00000001;
 TCNT1 = 0;
// загружается в регистр совпадения А таймера Т1 "задержка включения симистора"
OCR1A = OPTO_ON_TICK;
//запускается таймер
TCCR1B = tccr;
//Выясняем, какой перепад пришел
if ( (EICRA & 3 ) == 3) {   // рост
   ADC_ON;  // Старт АЦП
   // включаем режим прерывания INT0 на ожидание перехода вниз
   EICRA |= 2;
}
else {   // падение
  ADC_OFF;//  останавливаем АЦП; 
  EICRA = 0b00001011; //  настраиваемся на ожидание фронта 
  // вычисляем измеренное выходное Urms = корень квадратный из «сумма квадратов» деленной на «количество отсчетов»»;
   CURRENT_U =  sqrt   ( (( ADC_CURRENT_SUM_QUAD * optimKoef) / ADC_CURRENT_VALUE_COUNT ) * optimKoef); //Умножаем его на 4 и  делим на количество выборок Еще раз умножаем на 4 Находим квадратный корень s.ru ©
   
   // здесь необходимо организовать хранение истории измеренных напряжений
   // и вычисление усредненного Urms
   // CURRENT_U_HISTORY[ 0 .... CU_HISTORY_LENGTH]= CURRENT_U; // массив для  вычисление усредненного Urms
  
// - обнуляем «сумму квадратов» и «количество отсчетов» для следующего цикла преобразований.
 ADC_CURRENT_SUM_QUAD = 0;
 ADC_CURRENT_VALUE_COUNT = 0;
 // ---  имеем необходимые данные для регулирования.
OPTO_ON_TICK = OPTO_ON_TICK + (CURRENT_U - TARGET_U);
//здесь необходимо проверка на предмет выхода за допустимый диапазон
}
}
//************************************************************************
// Включение оптрона управления симистором 
// Прерывание по совпадению Т1A
ISR (TIMER1_COMPA_vect)
{
MOC_PORT |=  (1 << MOC_PIN);
}
//************************************************************************
// Выключение оптрона управления симистором 
// Прерывание по совпадению Т1B
ISR (TIMER1_COMPB_vect)
{
MOC_PORT &=  ~(1 << MOC_PIN);
}
//************************************************************************
// Обработчик преобразования АЦП
ISR(ADC_vect) {
CURRENT_QUAD_U = ADCH;  // Считываем только значимые 8 бит, учитывая что ADLAR=1
CURRENT_QUAD_U *= CURRENT_QUAD_U;// возводим в квадрат
ADC_CURRENT_SUM_QUAD += CURRENT_QUAD_U; // складываем квадраты измерений
ADC_CURRENT_VALUE_COUNT++;
}
//###########################################################################
void loop() {
 // Всякие свистелки, перделки и управлялки 
}
С уважением, Олег Кузнецов.

49

Re: Стабилизированный регулятор на базе Arduino с управлением через UART

Осталось прикрутить управление и можно запускать на испытания.  *THUMBSUP*

Kusnezov Oleg ©:

byte voltageCurrent = ADCH;  // Считываем только значимые 8 бит, учитывая что ADLAR=1

Можно и так.
---
Я оставил ADLAR=0, чтобы иметь возможность менять разрешение в процессе экспериментов, накладывая маску.
Соответственно учитываю, что мои данные на 2 разряда левее, чем в твоем варианте.
Другая причина это стремление по максимуму использовать разрядность с минимальными потерями точности на делении и извлечении корня.
Преобразование - 10 бит.
Квадрат преобразования - 20 бит.
Сумма квадратов преобразования за полупериод - 29 бит. (для используемой скорости выборок)
Умножаем его на 4 - 31 бит. (за сетку не вылезли)
Делим на количество выборок - 22 бита.
Еще раз умножаем на 4 - 24 бита.
Находим квадратный корень - 12 бит.
А потом уже с этими 12 битами работаем.
---
Для чего так ?
Изначально была мысль регулировки с дискретностью 0.1 вольта.
А тут как раз 4096 это 289 раз по 0,1 вольт умноженных на корень из 2.
Выбрав соответствующим образом делитель измерительного входа,
в программе сравниваются непосредственно заданное напряжение с измеренным,
без всяких нормирующих коэффициентов.
Это удобно.

РК 35х1600

50

Re: Стабилизированный регулятор на базе Arduino с управлением через UART

Kusnezov Oleg ©:

Перепер...

Kusnezov Oleg, а в железе когда воплощать будешь?

51

Re: Стабилизированный регулятор на базе Arduino с управлением через UART

Kusnezov Oleg ©:

if (i > CU_HISTORY_LENGTH){
// Примерно в этих местах делаем вычисление усредненного Urms
// за какое-то количество периодов.

i = 0;

}

Здесь несколько некорректно.
Усредненное вычисляется в каждом периоде, а не по истечении некоторого времени.

РК 35х1600

52

Re: Стабилизированный регулятор на базе Arduino с управлением через UART

kvic, ОК, понял, спасибо.

Четланин ©:

а в железе когда воплощать будешь?

Kusnezov Oleg ©:

kvic, так самого нужного(и простого) пока в этой теме нет: подключение развязки и управление стабилизатором через эту развязку другим контролером.

Да и железо - это 1% проблем, а алгоритм - 99%, на мой взгляд.
Ну и (это про алгоритм)

Kusnezov Oleg ©:

Вот тема. Полупериодный регулятор с фазовым совместить

С уважением, Олег Кузнецов.

53

Re: Стабилизированный регулятор на базе Arduino с управлением через UART

Kusnezov Oleg ©:

uint16_t  OPTO_ON_TICK  ;  // Значение  момента включения оптрона записывается  в OCR1A       
uint32_t  CURRENT_QUAD_U  ;  // Квадрат напряжения                 
uint16_t  TARGET_U  ;  // Задаваемое  напряжение                 
uint16_t  CURRENT_U ;  // Текущее значение  URMS               
uint16_t  CURRENT_U_HISTORY[CU_HISTORY_LENGTH] ;  //

Эти переменные, наверное тоже нужно объявить volatile ?

РК 35х1600

54

Re: Стабилизированный регулятор на базе Arduino с управлением через UART

Да, и CURRENT_QUAD_U, надо вернуть, я эту переменную удалил, по ошибке. Вечером поправлю.

С уважением, Олег Кузнецов.

55

Re: Стабилизированный регулятор на базе Arduino с управлением через UART

Kusnezov Oleg ©:

железо - это 1% проблем

Я бы не был так категоричен. Сейчас колдую с датчиком тока ASC712 и датчиком напряжения ZMPT101B. Слепил скетч для стабилизации тока. На мощности 1 Квт всё просто замечательно, а на 3 Квт начинаются пляски выходного напряжения в пределах 10 вольт, а соответственно и тока.

56

Re: Стабилизированный регулятор на базе Arduino с управлением через UART

Четланин ©:

Сейчас колдую с датчиком тока ASC712 и датчиком напряжения ZMPT101B

Китайские модули мучаете или своя схема? ACS712 на какой ток?

С уважением, <дата, подпись>, отвечайте нам, а то...
РК 28/1500
Простой стабилизированный регулятор

57

Re: Стабилизированный регулятор на базе Arduino с управлением через UART

JohnJohnov ©:

Китайские модули мучаете

Китайские на 20 А. Нормальный датчик, можешь тоже помучить, если есть желание.

58

Re: Стабилизированный регулятор на базе Arduino с управлением через UART

Четланин ©:

можешь тоже помучить

Уже мучаю.
Китайцы, уроды, модуль с ZMPTшкой прислали с одноканальным инструментальным операционником, впаяным на плату с разводкой под двухканальную LM358. Оно в принципе работать не могло. Пока догадался на микруху пристально поглядеть, изматерился. )

А схема подключения? ZMPTшкой сеть меряешь или нагрузку?
Разъем с модуля ACS712 заменил на нормальные провода квадрат на полтора?

С уважением, <дата, подпись>, отвечайте нам, а то...
РК 28/1500
Простой стабилизированный регулятор

59 (2019-04-17 18:38:23 отредактировано Четланин)

Re: Стабилизированный регулятор на базе Arduino с управлением через UART

JohnJohnov,
Дабы не флудить , ответил в теме Регуляторы мощности для ТЭНов

60 (2019-04-18 09:07:54 отредактировано kvic)

Re: Стабилизированный регулятор на базе Arduino с управлением через UART

Пришли Adum-ы. Потихоньку начал городить обмен данными через UART.
Внезапно стало интересно посмотреть, какой вид имеет переходный процесс.
Так как железо еще не подключено, а кусок кода уже есть, то смоделировал момент включения с заданным выходным напряжением 185 вольт.
Выглядит красиво. И даже похоже на реальность.

Синий - целевое значение 185 вольт.
Красный - действующее значение.
Зеленый - усредненное за 32 периода.
Ось Х - в секундах, Y - в десятых долях вольта.
Через какое-то время буду смотреть уже в реале.
----------
Еще одна картинка из того же набора данных.

Процесс регулирования в окрестности заданного выходного напряжения.
Видны небольшие колебания.
Наверное придется вводить зону нечувствительности в регулировочную характеристику.

  • 185volt.PNG
    size: 54.32Кб type: PNG
  • 185_2s.PNG
    size: 48.36Кб type: PNG
  • 185_2s.PNG
    size: 53.4Кб type: PNG
РК 35х1600