Работа с PWM для ПУш-ПУЛ.

3dmax
Offline
Зарегистрирован: 09.05.2016

Здравствуйте уважаемые форумчане, прошу сильно не пинать я только начина в этом разбираться. Постараюсь покроче. На просторах интернета нашёл сделующий скетч,  вопрос следующий, как сделать еще один (3-й) сигнал, с той же частотой что и первые два, такой же фазы как и первый но чтобы можно было независимо меняеть его скважность.
поснительная картинка к тексту, если не понятно.

https://yadi.sk/i/xkpfXXWhrm5o3

#define PIN_PRI_A   9    // OCR1A - high-active primary drive
#define PIN_PRI_B   10   // OCR1B - low-active primary drive

#define PUSH_PULL   false // false = OCR1A only, true = OCR1A + OCR1B


#define TIMER1_PRESCALE   1     // clock prescaler value
#define TCCR1B_CS20       0x01  // CS2:0 bits = prescaler selection


#define PERIOD_US   5.1
#define PERIOD_TICKS (microsecondsToClockCycles(PERIOD_US / 2) / TIMER1_PRESCALE)



int count=0;
int duty=2;
float Verror=0;

float Vset=512.0;
float Vact;

unsigned long last=0;
unsigned long wait=20;
boolean first=true;

void setup()
{ 
// pinMode(A0, INPUT); //input tensione         НЕ знаю что это но без него работает.
 //digitalWrite(A0, LOW);
 
 
 analogWrite(PIN_PRI_A,128);    // let Arduino setup do its thing
 analogWrite(PIN_PRI_B,128);
 TCCR1B = 0x00;                 // stop Timer1 clock for register updates
 
   // Clear OC1A on match, P-F Corr PWM Mode: lower WGM1x = 00
 TCCR1A = 0x80 | 0x00; //128 | 

// Configure Timer 1 for Freq-Phase Correct PWM
//   Timer 1 + output on OC1A, chip pin 15, Arduino PWM9
//   Timer 1 - output on OC1B, chip pin 16, Arduino PWM10

// If push-pull drive, set OC1B on match
TCCR1A |= 0x30; //48

ICR1 = PERIOD_TICKS;           // PWM period
OCR1A = duty;      // ON duration = drive pulse width//ucita 9
OCR1B = duty+156;      //  ditto - use separate load due to temp buffer reg //usita 10
TCNT1 = OCR1A - 1;             // force immediate OCR1x compare on next tick

// upper WGM1x = 10, Clock Sel = prescaler, start Timer 1 running
TCCR1B = 0x10 | TCCR1B_CS20;
}

void loop() ///////// Тут дальше меняем скважность 
{ OCR1A = duty+count;     
  OCR1B = duty+36-count;  
     
     if(first)
     {
         //delay(2000);
         first=false;
     }
     
     Vact=analogRead(A0);
     
     Verror=100.0*(Vset-(float)(Vact))/Vset;
        
   
       if(millis()-last>=wait)
       {
         last=millis();
         
           if(Verror<0) count--;
           if(Verror>0) count++;

         if(count<0) count=0; //min duty 2%
         if(count>=15) count=15; //max duty 95%
       }
   

}
MagicianT
Offline
Зарегистрирован: 03.10.2015
На УНО так сделать нельзя, там все три таймера имеют по два канала А и Б. К другим платам с АтМега328 то же самое относится, а вот на Мега2560 или Леонардо (АтМега32ю4) кажется возможно.
Какая частота, для 50 Гц и в софте можно реализовать, ошибка фазы в 2-3 микросекунды будет незаметна.
3dmax
Offline
Зарегистрирован: 09.05.2016

сейчас частота 200 кГц. Можно ли включить 2-й таймер синхронно первому?

MagicianT
Offline
Зарегистрирован: 03.10.2015

Это как пытаться синхронизировать часы, нужна логика сверки показаний. Не видел что-бы на практике кто-то делал, проще взять другой МК.

dimax
dimax аватар
Offline
Зарегистрирован: 25.12.2013

3dmax, в принципе можно.

GTCCR=(1<<TSM)|(1<<PSRASY)|(1<<PSRSYNC); //остановить все 3 таймера 
//... произвести настройку таймеров, обнулить все счётные регистры итд итп 
GTCCR=0; // Запустить все таймеры одновременно

Но без глубинного понимания работы таймеров вы не настроите таймеры на одну частоту. Тем более на 200кГц может полноценно работать только таймер1. И то, не совсем полноценно. Сколько градаций регулировки скважности будет на такой частоте? Не трудно подсчитать 16000000 /2 / 200000 = 40 шагов. Думаю реально запустить в синхроне  -на 8 битах ( 62,5 кГц)  в режиме FastPWM.

3dmax
Offline
Зарегистрирован: 09.05.2016

А можно ли на еще один выход продублировать  показания с другого ?

ведь частота мне нужна та же, только фазу сдвинуть и скважность поменять.

dimax
dimax аватар
Offline
Зарегистрирован: 25.12.2013

3dmax, нет ничего дублировать невозможно. Есть простой способ сделать любое кол-во выводов всего на одном таймере - это программная генерация ШИМ. Но будут недостатки, -невысокая частота, дрожание фазы,сильная загрузка контроллера. Лучше всего взять ардуино с трех-канальными таймерами, как вам уже советовали в первом посте.

3dmax
Offline
Зарегистрирован: 09.05.2016

какой максимальной  частоты я могу достигнуть используя 2 таймера ?

MagicianT
Offline
Зарегистрирован: 03.10.2015
Интересно стало, решил посмотреть. Коммент неверный:
  GTCCR=(1<<TSM)|(1<<PSRASY)|(1<<PSRSYNC); //остановить все 3 таймера
Остановить два таймера можно, 0-й и 1-й, у них общий прескэллер.
Недостатки, таймер-0 на ардуино используется для делэй, миллис(), микросек() и ещё чего то там, в референсе посмотрите сами. Я попробовал установить 0-й таймер примерно как и 1-й, мода у него другая - таймер попроще. Но интересный факт, синхронизации нет, один такт 62.5 микросекунды разница.
Т.е. теоретически как бы можно скорректировать  TCNT0 = 0;  или TCNT1 = 0;  на +-1, но надо смотреть прибором чего там на самом деле на выходах.
pin-9 pin-10 min
pin-9 pin-10 max
pin-9 pin-5 -min
pin-9 pin-5 -offset

Pin-9 &amp; pin-10 minimumPin-9 &amp; pin-10 maximumPin-9 &amp; pin-6 minimumPin-9 &amp; pin-6 Offset

#define PIN_PRI_A    9   // OCR1A - high-active primary drive
#define PIN_PRI_B   10   // OCR1B - low-active primary drive
#define PIN_PRI_C    5   // OCR0B - low-active primary drive

#define TIMER1_PRESCALE   1     // clock prescaler value
#define TCCR0B_CS20    0x01     // CS2:0 bits = prescaler selection
#define TCCR1B_CS20    0x01     // CS2:0 bits = prescaler selection

#define PERIOD_US   5.1
#define PERIOD_TICKS (microsecondsToClockCycles(PERIOD_US / 2) / TIMER1_PRESCALE)
//#define OFFSET  PERIOD_TICKS /2

             int    count   =     0;
             int    duty    =     2;
//             float  Verror  =     0;             
//             float  Vset    = 512.0;
//             float  Vact    =   0.0;
    
void setup()
{ 
// analogWrite(PIN_PRI_A, 128);    // let Arduino setup do its thing
// analogWrite(PIN_PRI_B, 128);
 pinMode(PIN_PRI_A, OUTPUT);
 pinMode(PIN_PRI_B, OUTPUT);
 pinMode(PIN_PRI_C, OUTPUT);

 // TIMER-1  Mode 8 PWM ICR1 - WGM13
 TCCR1B = 0x00;        // stop Timer1 clock for register updates 
 TCCR1A = 0x80;        //0x1000 0000 <- COM1A1
 // COM1A1 COM1A0 COM1B1 COM1B0 – – WGM11 WGM10
 TCCR1A |= 0x30;       //0x0011 0000 <- COM1B1 COM1B0

 ICR1  = PERIOD_TICKS; // PWM period
 TCCR1B = 0x10 | TCCR1B_CS20; //0x0001 0000 <- WGM13 Mode 8 PWM ICR1
 //ICNC1 ICES1 – WGM13 WGM12 CS12 CS11 CS10

 // TIMER-0  Mode 5 PWM OCRA - WGM02& WGM00
 TCCR0B = 0x00;        // stop Timer1 clock for register updates 
 TCCR0A = 0x21;        //0x1000 0001 <- COM0B1 (pin 5) & WGM00
 //COM0A1 COM0A0 COM0B1 COM0B0 – – WGM01 WGM00
 OCR0A  = PERIOD_TICKS; // PWM period

 TCCR0B = 0x08 | TCCR0B_CS20; //0x0000 1000 <- WGM02 Mode 5 PWM
 //FOC0A FOC0B – – WGM02 CS02 CS01 CS00

 GTCCR = (1<<TSM) | (1<<PSRASY) | (1<<PSRSYNC); //остановить таймер 0 & 1 
 //... произвести настройку таймеров, обнулить все счётные регистры итд итп 
 TCNT0 = 0; 
 TCNT1 = 0; 
 GTCCR=0; // Запустить все таймеры одновременно 
}

void loop() ///////// Тут дальше меняем скважность 
{ 
  OCR1A = duty + count;     
  OCR1B = duty + 36 - count;  
     
  OCR0B = duty + count;     

//  Vact = analogRead(A0);     
//  Verror = 100.0 *(Vset - Vact) /Vset;
                 
//  if(Verror < 0) count--;
//  if(Verror > 0) count++;

  count = analogRead(A0) /16;  
  if(count  <   0) count =  0; //min duty 2%
  if(count  >= 15) count = 15; //max duty 95%
}

 

dimax
dimax аватар
Offline
Зарегистрирован: 25.12.2013

MagicianT, в чём мой коммент не верный? 0 и 1 таймер сбрасываются битом PSRSYNC, второй битом PSRASY

Попробуйте залить этот скетч, увидите что все три таймера молотят синхронно такт в такт:

void setup() {
pinMode (11,OUTPUT); 
pinMode (9,OUTPUT); 
pinMode (6,OUTPUT); 
GTCCR=(1<<TSM)|(1<<PSRASY)|(1<<PSRSYNC); 

TCNT0=0;
TIMSK0=0;
TCCR0A=(1<<COM0A1)|(1<<WGM00)|(1<<WGM01);
TCCR0B=(1<<CS00);
OCR0A=127;


TCNT1=0;
TIMSK1=0;
TCCR1A=(1<<WGM10)|(1<<COM1A1);
TCCR1B=(1<<WGM12)|(0<<WGM13)|(1<<CS10); 
ICR1=0; 
OCR1A=127; 

TCNT2=0;
TIMSK2=0;
TCCR2A=(1<<COM2A1)|(1<<WGM20)|(1<<WGM21);
TCCR2B=(1<<CS20);
OCR2A=127;


GTCCR=0;


}
void loop() {}

 

MagicianT
Offline
Зарегистрирован: 03.10.2015
Пардон, месье, моя ошибка. Недоглядел PSRASY PSRSYNC что один синхронный а другой ассинхронный.
Ваш пример работает как надо, хотя мне непонятно в каком режиме таймер -1, мода 13 написано зарезервирована.
TCCR1A=(1<<WGM10)|(1<<COM1A1);
TCCR1B=(1<<WGM12)|(0<<WGM13)|(1<<CS10); // Moda 13 ??? 1 1 0 1 (Reserved)

И как вы обьясните что в моём примере есть оффсет, может фаза-коррект мода виновата, она в два раза медленнее вроде?

И зачем сбрасывать прескаллер, если он равен 1? У автора таймер на максимуме 16МГц крутится?

 

dimax
dimax аватар
Offline
Зарегистрирован: 25.12.2013

MagicianT, таймер1 в моём скетче работает в 5 моде(fastpwm), wgm13 не ставится, он же =0, просто забыл стереть.Почему у вас фазы разъехались -это нужно изучать исходный скетч, (лень:)   скорее всего таймеры работают в разных режимах. Должны в одинаковом.

MagicianT
Offline
Зарегистрирован: 03.10.2015

Да, сейчас нашёл, действительно мода 5. Если ему в эту моду, то все 3 таймера придётся задействовать, канал А будет определять частоту а Б дрыгать пин. Я поигрался ещё, и удостоверился что с таймерами 0 и 2 такой проблемы нет, если у них мода - 7, задавая TCNT можно сдвигать начальный оффсет фазы. Таймер-1 считает то ICR1, и иа-за этого похоже все проблемы, он напрочь отказывается синхронизироваться и в 14 моде фаст-PWM, не только в 8-ой где фаза-коррект, оффсет может быть 1, а если в коде что-нибудь поменять - то непредсказуемый.

void setup() {
pinMode( 9, OUTPUT); // A
pinMode(10, OUTPUT); // B
//pinMode( 6, OUTPUT); // A
pinMode( 5, OUTPUT); // B
//pinMode(11, OUTPUT); // A
pinMode( 3, OUTPUT); // B

GTCCR=(1<<TSM)|(1<<PSRASY)|(1<<PSRSYNC); 

  TCNT0   = 0;
  TIMSK0  = 0;
  TCCR0A  = (1<<COM0B1) | (1<<WGM00) | (1<<WGM01); // Moda 7 Fast PWM OCRA BOTTOM TOP
  TCCR0B  = (1 << CS00) | (1<<WGM02);
  OCR0A   = 40;
  OCR0B   = 20;
  
  
  TCNT1   = 0;
  TIMSK1  = 0;
  
  TCCR1A  = (1<<COM1A1) | (1<<COM1B1) | (1<<COM1B0) | (1<<WGM11 );
  TCCR1B  = (1 << CS10) | (1<<WGM12 ) | (1<<WGM13 ); // Moda 14 Fast PWM ICR1 BOTTOM TOP
  ICR1    = 40; 
  OCR1A   = 20; 
  OCR1B   = 20; 

  TCNT2   = 0;
  TIMSK2  = 0;
  TCCR2A  = (1<<COM2B1) | (1<<WGM20) | (1<<WGM21); // Moda 7 Fast PWM OCRA BOTTOM TOP
  TCCR2B  = (1 << CS20) | (1<<WGM22);
  OCR2A   = 40;
  OCR2B   = 20;
  
GTCCR=0;
}
void loop() {}

 

3dmax
Offline
Зарегистрирован: 09.05.2016

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

MagicianT в предыдущем вашем скетче в посте 8, все как надо за исключением того что задние фронты сильно прыгают, о чем кажеться и предупреждал dimax .  А в последнем я растерялся и не знаю где меняеться частоста и скважность сигналов. Хотя с самими сигналами все просто прекрасно !

В любом случае, ребята спасибо вам большое !!!

MagicianT
Offline
Зарегистрирован: 03.10.2015
Где там прыгает, там не совсем тот код, который вам нужен, посмотрите повнимательнее, много коментс-аут (//). 
Меня собственно заинтересовала теоретическая возможность синхронизации таймеров, может самому где в другом проэкте сгодиться. 
Писать за вас, дорогой товарищ, всё равно не собирался, извините если вёл вас в заблуждение своей наивностью.
3dmax
Offline
Зарегистрирован: 09.05.2016

Нет нет нет -- у меня никаких притензий,  я ж говорю : "большо спасибо!!" Я уже поковырялся в последнем коде и почти все что надо понял.  Это даже больше, чем я ожидал!  Спасибо !!!

MagicianT
Offline
Зарегистрирован: 03.10.2015

Ну тогда ладно, а то я подумал претензии какие. Ради любопытства я полазил по и-нету, и накопал что с разницей на единицы фазы (62.5 микросек) таймеров 0-2 и первого сталкивались, но обьяснения этому нету. Впрочем как и в ДШ атмеловском, если кратко - глюк, или недокументированные возможности....

http://www.openmusiclabs.com/learning/digital/synchronizing-timers/

Переписал скетч с поста 8, там был таймер-0, что как я писал не есть хорошо. Теперь на таймере-2, пин-3 дублирует пин-9 точно, пришлось подобрать стартовое значение таймера-2 = 17. Почему 17 не спрашивайте. Вобщем получилось как вам и надо, на 3-ем скважность регулируется независимо, а частота а фаза те-же что и на 9-ом. 

#define PIN_PRI_A    9   // OCR1A - high-active primary drive
#define PIN_PRI_B   10   // OCR1B - low-active primary drive
#define PIN_PRI_C    3   // OCR2B - low-active primary drive

#define TIMER1_PRESCALE   1     // clock prescaler value
#define TCCR1B_CS20    0x01     // CS2:0 bits = prescaler selection
#define TCCR2B_CS20    0x01     // CS2:0 bits = prescaler selection

#define PERIOD_US   5.1
#define PERIOD_TICKS (microsecondsToClockCycles(PERIOD_US / 2) / TIMER1_PRESCALE)

             int    count   =     0;
             int    duty    =     2;
//             float  Verror  =     0;             
//             float  Vset    = 512.0;
//             float  Vact    =   0.0;
    unsigned long   last    =     0;
    unsigned long   wait    =    20;
    
void setup()
{ 
 pinMode(PIN_PRI_A, OUTPUT);
 pinMode(PIN_PRI_B, OUTPUT);
 pinMode(PIN_PRI_C, OUTPUT);

cli();
GTCCR=(1<<TSM)|(1<<PSRASY)|(1<<PSRSYNC); 

 // TIMER-1  Mode 8 PWM ICR1 - WGM13
 TCCR1A = 0x80;        //0x1000 0000 <- COM1A1
 TCCR1A |= 0x30;       //0x0011 0000 <- COM1B1 COM1B0
 // COM1A1 COM1A0 COM1B1 COM1B0 – – WGM11 WGM10
 TCCR1B = 0x10 | TCCR1B_CS20; //0x0001 0000 <- WGM13 Mode 8 PWM ICR1
 //ICNC1 ICES1 – WGM13 WGM12 CS12 CS11 CS10

 TIMSK1 = 0;
 TCNT1  = 0; 
 ICR1   = PERIOD_TICKS; // PWM period

 // TIMER-2  Mode 5 PWM OCRA - WGM22& WGM20
 TCCR2A = 0x21;        //0x0010 0001 <- COM2B1 (pin 3) & WGM20
 //COM2A1 COM2A0 COM2B1 COM2B0 – – WGM21 WGM20
 TCCR2B = 0x08 | TCCR2B_CS20; //0x0000 1000 <- WGM22 Mode 5 PWM
 //FOC2A FOC2B – – WGM22 CS22 CS21 CS20

 TIMSK2 =  0;
 TCNT2  = 17; 
 OCR2A  = PERIOD_TICKS; // PWM period

GTCCR=0;
sei();
}

void loop() ///////// Тут дальше меняем скважность 
{ 
  OCR1A = duty + count;     
  OCR1B = duty + 36 - count;  
     
  OCR2B = duty + count;     

//  Vact = analogRead(A0);     
//  Verror = 100.0 *(Vset - Vact) /Vset;
                 
//  if(Verror < 0) count--;
//  if(Verror > 0) count++;

  count = analogRead(A0) /16;  
  if(count  <   0) count =  0; //min duty 2%
  if(count  >= 15) count = 15; //max duty 95%
}

 

3dmax
Offline
Зарегистрирован: 09.05.2016

Спасибо за труды, мне не ловко говорить, но в последнем коде задние фронты скачут :(

https://yadi.sk/i/tMguclcXrnxuu

MagicianT
Offline
Зарегистрирован: 03.10.2015

Код смотрели? Там на аналог-0 напряжение подать надо, а у вас куда подключено? И ещё там я убрал часть, можете вернуть назад - теперь таймер-2 и милис() не вопрос.

3dmax
Offline
Зарегистрирован: 09.05.2016

Вауу, если бы вы не сказали я бы и не знал что такое   count = analogRead(A0) /16;

 Ок, вечером проверю.  Спасибо !!!

3dmax
Offline
Зарегистрирован: 09.05.2016

Подал 5 вольт с RX на A0  --- все дребезги фронтов пропали !!! :)

Вопрос:

что вот это  cli();   и   sei();  ???

Jeka_M
Jeka_M аватар
Offline
Зарегистрирован: 06.07.2014

3dmax пишет:

Вопрос:

что вот это  cli();   и   sei();  ???


Запрет и разрешение прерываний.

3dmax
Offline
Зарегистрирован: 09.05.2016

не знаю что оно запрещает, но рабатет и без него :)

Вроде бы самое главное для себя нашел! Сдвиг фаз, скважность все есть !!

MagicianT огромное вам спасибо !!!!  :)

MagicianT
Offline
Зарегистрирован: 03.10.2015

На здоровье. Я и для себя что то новое открыл.

3dmax
Offline
Зарегистрирован: 09.05.2016

обнаружил непонятную штуку,  с помощью кнопок пытаюсь менять PERIOD_TICKS или PERIOD_US, но частота не меняеться :(

на мониторе значения перемиенных меняються но частота -нет.

с частотой разобрался.

zhakler
Offline
Зарегистрирован: 28.12.2017

3dmax пишет:

Здравствуйте уважаемые форумчане, прошу сильно не пинать я только начина в этом разбираться. Постараюсь покроче. На просторах интернета нашёл сделующий скетч,  вопрос следующий, как сделать еще один (3-й) сигнал, с той же частотой что и первые два, такой же фазы как и первый но чтобы можно было независимо меняеть его скважность.
поснительная картинка к тексту, если не понятно.

https://yadi.sk/i/xkpfXXWhrm5o3

#define PIN_PRI_A   9    // OCR1A - high-active primary drive
#define PIN_PRI_B   10   // OCR1B - low-active primary drive

#define PUSH_PULL   false // false = OCR1A only, true = OCR1A + OCR1B


#define TIMER1_PRESCALE   1     // clock prescaler value
#define TCCR1B_CS20       0x01  // CS2:0 bits = prescaler selection


#define PERIOD_US   5.1
#define PERIOD_TICKS (microsecondsToClockCycles(PERIOD_US / 2) / TIMER1_PRESCALE)



int count=0;
int duty=2;
float Verror=0;

float Vset=512.0;
float Vact;

unsigned long last=0;
unsigned long wait=20;
boolean first=true;

void setup()
{ 
// pinMode(A0, INPUT); //input tensione         НЕ знаю что это но без него работает.
 //digitalWrite(A0, LOW);
 
 
 analogWrite(PIN_PRI_A,128);    // let Arduino setup do its thing
 analogWrite(PIN_PRI_B,128);
 TCCR1B = 0x00;                 // stop Timer1 clock for register updates
 
   // Clear OC1A on match, P-F Corr PWM Mode: lower WGM1x = 00
 TCCR1A = 0x80 | 0x00; //128 | 

// Configure Timer 1 for Freq-Phase Correct PWM
//   Timer 1 + output on OC1A, chip pin 15, Arduino PWM9
//   Timer 1 - output on OC1B, chip pin 16, Arduino PWM10

// If push-pull drive, set OC1B on match
TCCR1A |= 0x30; //48

ICR1 = PERIOD_TICKS;           // PWM period
OCR1A = duty;      // ON duration = drive pulse width//ucita 9
OCR1B = duty+156;      //  ditto - use separate load due to temp buffer reg //usita 10
TCNT1 = OCR1A - 1;             // force immediate OCR1x compare on next tick

// upper WGM1x = 10, Clock Sel = prescaler, start Timer 1 running
TCCR1B = 0x10 | TCCR1B_CS20;
}

void loop() ///////// Тут дальше меняем скважность 
{ OCR1A = duty+count;     
  OCR1B = duty+36-count;  
     
     if(first)
     {
         //delay(2000);
         first=false;
     }
     
     Vact=analogRead(A0);
     
     Verror=100.0*(Vset-(float)(Vact))/Vset;
        
   
       if(millis()-last>=wait)
       {
         last=millis();
         
           if(Verror<0) count--;
           if(Verror>0) count++;

         if(count<0) count=0; //min duty 2%
         if(count>=15) count=15; //max duty 95%
       }
   

}

Всем здравствуйте. я в этом деле новичок, подскажите как собрана плата для этого скетча. собираю индукционный котел и мне надо чтоб частота фиксированная была 47.9391 а скважность менялась. силовую плату собрал на игбт 25n120 полный мост. и хотелось бы лсд запустить на плате. лсд1602 у меня с кнопками

DetSimen
DetSimen аватар
Offline
Зарегистрирован: 25.01.2017

Думаю, через годика полтора это будет тебе под силу. Если книги читать прилежно будешь. А счас пока - забуть. 

zhakler
Offline
Зарегистрирован: 28.12.2017

так хочется отопление запустить

bwn
Offline
Зарегистрирован: 25.08.2014

zhakler пишет:

так хочется отопление запустить

А мне Ламборджини на огороде из металлолома выстругать, да, еще сварочник есть и эта, кувалда.)))