Алгоритм равномерного распределения

yul-i-an
yul-i-an аватар
Offline
Зарегистрирован: 10.12.2012

Известно что отдаваемую мощность прибора работающего на переменном напряжении можно регулировать пропуская в неё не все полупериоды напряжения сети. Если взять сеть частотой 50Гц, то в 1с проходит 100 полупериодов, значит если в 1с пропустить допустим 10 полупериодов то получим 10% мощности, и точность регулирования составит 1%. Ниже предлогаю реализацию алгоритма который распределяет заданый процент мощности на 1с равномерно т.е. представим что нужно пропустить 50% то будет не так 1111100000, а так 1010101010.

Алгоритм оформлен в виде функции, которая вызывается от внешнего прерывания вызванного ZeroCross (Детектором нуля сети).

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

Если вызывать функцию по таймеру можно на её основе получить некое подобие шим на любом дискретном выходе МК.

 //тип переменных pwr - int, er- int, reg- int, out- boolean
void OutPWR()
{
   reg = pwr + er; //pwr- задание выходной мощности в %, er- ошибка округления
     if (reg < 50)
       {
         out=0;
         er = reg ; // reg- переменная для расчетов
       }
          else 
        {
          out=1;
          er=reg-100;
        }
 digitalWrite(13,out);//пин через который осуществляется дискретное управление
}

 

msg31
Offline
Зарегистрирован: 01.12.2013

Алгоритм Брезенхема для Ардуино. Полезная штука, в свое время искал такой.

yul-i-an
yul-i-an аватар
Offline
Зарегистрирован: 10.12.2012

Устранил небольшую ошибку. После вызова прерыввания необходимо сделать задержку. Т.к. при шумах и нечетком сигнале внешнего прерывания происходило хаотичное управление нагрузкой и управляющие импульсы подавались на 1мск раньше прохождения напряжения через 0, апри введение задержки в 1мск данный баг пропал и управляющие импульсы стали генерироваться строго в момент прохождения синуса через 0. Думаю что данную задержку можно подбирать опытным путем в зависимости от схемы отслеживания 0. Я пользую вот эту схему.

Теперь код выглядит так.

//управление симистором
void ResOut(){
  delay(1);// задержка о которой я писал
  reg = zad + er;
  if (reg < 50){
    out=0;
    er = reg ; 
  }
  else {
    out=1;
    er=reg-100;
    }
 digitalWrite(13,out);
 }

 

ites
Offline
Зарегистрирован: 26.12.2013

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

Gomjke76
Offline
Зарегистрирован: 07.04.2016

Если не затруднит кто-нибудь может данный код преобразовать к блок-схеме.

Прошу помощи по скольку от программирования далёк не могу понять как организована программа.

 

yul-i-an
yul-i-an аватар
Offline
Зарегистрирован: 10.12.2012

Примерно так.

Там и так всё понятно.

Gomjke76
Offline
Зарегистрирован: 07.04.2016

Благодарю.

DeGlucker
Offline
Зарегистрирован: 23.07.2014

Вставлю пару букав:

вместо digitalWrite:

  bitSet(PORT,pin);

  bitClear(PORT,pin);

тип переменных может быть int8_t, одного байта хватит

Извините, что встрял.

Gomjke76
Offline
Зарегистрирован: 07.04.2016

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

програмирования в виде блок-схемы?

 

Michael234
Offline
Зарегистрирован: 15.01.2017

Можно попроще. Пример на "чистом" С

int leistung;	// установка мощности
int modulator;	// рабочая переменная
int reg_max;	// макс. значение периода регулирования
		// выходная мощность = leistung / reg_max

#define OUT_EIN (PORTB |= (1<<PB0)); // для примера выход на PB0
#define OUT_AUS (PORTB &= ~(1<<PB0));

void brasenham(void){
	modulator += leistung;
	if(modulator >= reg_max){
			modulator -= reg_max;
			OUT_EIN;
		}
		else	OUT_AUS;
}

 

Принцип простой: считаем переполнения переменной modulator по модулю reg_max. Выходная мощность = leistung / reg_max. Есть переполнение - включаем выход. Нет переполнения - не включаем. Импульсы равномерно распределяются по интервалу. Функцию надо вызывать при переходе напряжения сети через нуль. Выключать управление тиристором лучше заранее, не дожидаясь конца полупериода (например через 4 мс. как это сделано в регуляторе "Радио 2000 №10 стр. 28) - чтоб исключить ошибочное его открывание в следующий полупериод (из-за помех).

Если желательно исключить постоянную составляющую тока нагрузки, то функцию надо вызывать только при одном из фронтов перехода через нуль, к примеру при положительном. Ценой будет вполовину меньшая частота коммутации. Если и это нежелательно, то можно коммутировать всё-таки при каждом переходе через нуль, но тогда нужно выбрать нечётный модуль счёта, он в переменной reg_max (например вместо 100 взять 99 или 101). будет правда несколько непривычно: 100% мощности будет соответствовать значению leistung сооответственно 99 или 101. Но зато не будет постоянной составляющей. Всё имеет свою цену в общем. 

Для языка Ардуино (дериват C++) надо немного подкорректировать, но это очевидно.

Не знаю, как в среде Ардуино, но к примеру в WinAVR выражения PORTB |= (1<<PB0) и PORTB &= ~(1<<PB0) скомпилируются в ассемблерные sbi PORTB,0 и cbi PORTB,0, занимают они 2 такта всего, так что можно эту функцию и в прерывании использовать.
arDubino
Offline
Зарегистрирован: 12.01.2017

физики теоретики практические измерения то проводили не?! :)))))

и самое главное практическое применение сего бреда для чего?!!

 

Michael234
Offline
Зарегистрирован: 15.01.2017

В качестве примера смотрите журнал Радио 2000 год номер 10 стр. 28. Там всё объяснено, зачем и почему.

Правда там в программе (в первой, на вторую терпения не хватило :) ) ошибка есть, по адресу 0143  85 28 23, должно быть наоборот: 85 23 28. Источник с приёмником перепутали. Но это мелочи, там вообще другой контроллер, так что не так важно. Главное принцип.