MPetrovich 6 9 августа, 2023 Опубликовано 9 августа, 2023 · Жалоба После радости по поводу возможности установки аппаратного Dead-Time в ATMega128 появилась мысль: а что мне даст эта возможность? Если бы я использовал комплементарный ШИМ, то это было бы необходимо. Однако, в моём варианте коммутации нижние ключи просто открываются и закрываются на половину периода синуса. Ну, допустим, я устанавливаю скважность ШИМ на нижних ключах равной нулю или 100%. И как здесь будет влиять Dead-Time? Мне нужна пауза после окончания каждой половины периода синуса во время которой и нижний и верхний ключи будут закрыты. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
Сергей Борщ 134 9 августа, 2023 Опубликовано 9 августа, 2023 · Жалоба 1 час назад, MPetrovich сказал: Мне нужна пауза после окончания каждой половины периода синуса во время которой и нижний и верхний ключи будут закрыты. В 08.08.2023 в 10:24, Сергей Борщ сказал: Для дерганья ногой в строго определенные моменты времени у таймеров в модуле compare есть режимы "Clear OCnA/OCnB/OCnC on compare match" и "Set OCnA/OCnB/OCnC on compare match". Просто в прерывании, где записываете очередной отсчет синуса, на определенном отсчете прописываете нужное значение в OCR нужного выхода таймера и переключаете выход таймера в один из этих режимов. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
MPetrovich 6 9 августа, 2023 Опубликовано 9 августа, 2023 · Жалоба Вот картинка для двух фаз. Красным показаны места, где нужен Dead-Time. Я не улавливаю где нужно Clear OCnA/OCnB/OCnC on compare match" и где "Set OCnA/OCnB/OCnC on compare match". Вот так сейчас выглядит обработчик прерывания: ISR(TIMER1_OVF_vect)//PWM_ON interrupt { num = akk/(36864/36);//for 36-num 36*1024=36864 OCR1A = PH1H[num]; //ШИМ 1 if(OCR1A == 0) {TCCR1A &= ~0x80; _delay_us(1); PORTA |= 1;}//PWM is OFF, LOW key is ON else {PORTA &= ~1; _delay_us(1); TCCR1A |= 0x80;}//LOW key is OFF, PWM is ON OCR1B = PH2H[num]; //ШИМ 2 if(OCR1B == 0) {TCCR1A &= ~0x20; _delay_us(1); PORTA |= 2;}//PWM is OFF, LOW key is ON else {PORTA &= ~2; _delay_us(1); TCCR1A |= 0x20;}//LOW key is OFF, PWM is ON OCR1C = PH3H[num]; //ШИМ 3 if(OCR1C == 0) {TCCR1A &= ~0x08; _delay_us(1); PORTA |= 4;}//PWM is OFF, LOW key is ON else {PORTA &= ~4; _delay_us(1); TCCR1A |= 0x08;}//LOW key is OFF, PWM is ON akk += akk_shift; if(akk >= 36864) akk -= 36864; } Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
Сергей Борщ 134 9 августа, 2023 Опубликовано 9 августа, 2023 · Жалоба 13 минут назад, MPetrovich сказал: Я не улавливаю где нужно Clear OCnA/OCnB/OCnC on compare match" и где "Set OCnA/OCnB/OCnC on compare match". Там, где нужно перевести ногу в 0 - Clear, где нужно в 1 - Set. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
MPetrovich 6 9 августа, 2023 Опубликовано 9 августа, 2023 · Жалоба 7 minutes ago, Сергей Борщ said: Там, где нужно перевести ногу в 0 - Clear, где нужно в 1 - Set. Это как раз не вызывает вопросов) Как это разнести по ключам? Нужно вставить задержки там, где сейчас _delay_us(1); Вернее даже при первом и при последнем выполнении условия if(OCR1A == 0) Это как раз и есть начало и конец отрицательной полуволны синуса. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
Сергей Борщ 134 9 августа, 2023 Опубликовано 9 августа, 2023 · Жалоба 36 минут назад, MPetrovich сказал: Вернее даже при первом и при последнем выполнении условия Поэтому я и писал, что удобнее анализировать фазу (значение фазового аккумулятора) или индекс в таблице. Примерно так, если я правильно понял ваше желание и ничего не напутал: auto Index = f(Phase); // находим текущую позицию в таблице auto Sin_PWM = Envelope_table[Index]; // достаем из таблицы значение ШИМ OCR_HI = Sin_PWM; if((Phase >= ANGLE1 - Phase_step) && (Phase < ANGLE1)) // в следующем цикле перевалим через ANGLE1, надо будет включить транзистор { OCR_HI = Sin_PWM - DEAD_TIME_DELAY; // устанавливаем момент переключения чуть раньше включения верхнего транзистора TCCRxA = ...; // устанавливаем режим Set on compare } else if((Phase >= ANGLE2 - Phase_step) && (Phase < ANGLE2)) // в следующем цикле перевалим через ANGLE2, надо будет выключить транзистор { OCR_LO = Sin_PWM + DEAD_TIME_DELAY; // устанавливаем момент переключения чуть позже отключения верхнего транзистора TCCRxA = ...; // устанавливаем режим Clear on compare } Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
MPetrovich 6 9 августа, 2023 Опубликовано 9 августа, 2023 · Жалоба 1 hour ago, Сергей Борщ said: Поэтому я и писал, что удобнее анализировать фазу (значение фазового аккумулятора) или индекс в таблице. Я попробовал с привязкой к индексу для одной фазы. Таблица для этой фазы 36 значений разделена пополам - 18 значений синуса от 0 до Пи, 18 нулей. Таймер настроен в режиме сброса в ноль на ноге OC1A при совпадении значения счётчика с регистром OCR1A (Clear on Compare). Написал пробный код для проверки установки задержки перед включением нижнего ключа: OCR1A = PH1H[num]; if(Prev_num == 17) {OCR1A -= Dead_time;} if(num > 17){TCCR1A &= ~0x80; PORTA |= 1;}//PWM is OFF, LOW key is ON else {PORTA &= ~1; TCCR1A |= 0x80;}//LOW key is OFF, PWM is ON Вылезли косяки. - значение Dead_Time для 1мкСек в циклах счётчика должно быть: 1мкСек/(1/31250Гц)/256=8. Но значения меньше 80 вообще не влияют на DutyCycle; - Задержка вносится в несколько последних импульсов. Но этого я ожидал. Причём чем меньше будет частота синуса, тем больше будет этих урезаных импульсов. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
MPetrovich 6 9 августа, 2023 Опубликовано 9 августа, 2023 · Жалоба 3 hours ago, Сергей Борщ said: if((Phase >= ANGLE1 - Phase_step) && (Phase < ANGLE1)) Эту строчку наверное можно переписать как if((akk >= 36864/2 - akk_shift) && (akk < 36864/2)) {OCR1A -= 8;} где akk/2 соответствует углу Пи, а полный akk=2*Пи Попробовал вставить в код - задержка не вставляется. Вот так теперь выглядит прерывание для одной фазы: OCR1A = PH1H[num]; //if((Phase >= ANGLE1 - Phase_step) && (Phase < ANGLE1)) if((akk >= (36864/2 - akk_shift)) && (akk < (36864/2))) {OCR1A = PH1H[num]-8;} if(num > 17){TCCR1A &= ~0x80; TCCR3A |= 0x80;}//PWM is OFF, LOW key is ON else {TCCR3A &= ~0x80; TCCR1A |= 0x80;}//LOW key is OFF, PWM is ON Верхний ключ на ОС1А, нижний на ОС3А. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
MPetrovich 6 22 марта Опубликовано 22 марта · Жалоба И снова здравствуйте😄 За время, которое прошло с последнего моего поста в этой теме, я уже запустил несколько асинхронников со своей прогой. Вернулся к теме поскольку захотел отредактировать код для работы с изменяющимся напряжением сети. Есть довольно известная постоянная для асинхронников - v/f. Она означает, что если мотор разработан и изготовление для определённых напряжения и частоты сети, то соотношение v/f - константа для всех напряжений и частот, с которыми будет работать мотор выдавая тот же момент, что и для расчётных напряжения и частоты. Для сети 220вольт 50 Герц эта константа равна 4,4. Регулируя частоту вращения нужно изменять амплитуду напряжения фазовых синусоид. К-т на который нужно множить значения Duty Cycle получается V=f/50. Соответственно, что при частоах меньше 50Гц он будет меньше нуля. Делить значения рабочего цикла ШИМ на числа не кратные степени 2 чревато длинной процедурой деления, а у меня и так контроллер молотит довольно длинные процедуры обработки прерывания с частотой 32кГц. Хотелось бы каким-то образом оптимизировать процесс. Всё, что пока пришло на ум - таблица значений, из которой таскать значения для фиксированного количества частот. Однако, это не решает проблему, поскольку к-ты я буду таскать готовые, но делить то на них значения рабочего цикла всё равно придётся! Может есть какие-то решения и я просто про них не знаю? Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
Сергей Борщ 134 22 марта Опубликовано 22 марта · Жалоба uint16_t Data; uint16_t Scale = 0.7 * (1 << 16); uint16_t Result = (Data * Scale) >> 16; Для 8-битного контроллера uint8_t и сдвиг на 8 Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
jcxz 234 22 марта Опубликовано 22 марта · Жалоба 5 часов назад, MPetrovich сказал: Делить значения рабочего цикла ШИМ на числа не кратные степени 2 чревато длинной процедурой деления, а у меня и так контроллер молотит довольно длинные процедуры обработки прерывания с частотой 32кГц. Хотелось бы каким-то образом оптимизировать процесс. Если коэффициент = const, то деление запросто заменяется умножением. Которое занимает 1-2 такта на >= Cortex-M3. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
Obam 37 22 марта Опубликовано 22 марта (изменено) · Жалоба >= Cortex-M3 32b на 32b аппаратно и делит; вот только у вопрошавшего - восьмибитка ;-) Изменено 22 марта пользователем Obam Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
jcxz 234 23 марта Опубликовано 23 марта · Жалоба 1 час назад, Obam сказал: >= Cortex-M3 32b на 32b аппаратно и делит; вот только у вопрошавшего - восьмибитка 😉 Даже в 8-битках, если они имеют команды умножения (любой разрядности), то замена деления умножением также должна дать выигрыш в скорости. А если у них при этом нет команд деления, то выигрыш будет даже больше, чем на Cortex. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
MPetrovich 6 23 марта Опубликовано 23 марта · Жалоба 19 hours ago, Сергей Борщ said: uint16_t Data; uint16_t Scale = 0.7 * (1 << 16); uint16_t Result = (Data * Scale) >> 16; Для 8-битного контроллера uint8_t и сдвиг на 8 Извиняюсь за бестолковость, но как в 8-битном виде выглядит число 0,7? 13 hours ago, jcxz said: Даже в 8-битках, если они имеют команды умножения (любой разрядности), то замена деления умножением также должна дать выигрыш в скорости. А если у них при этом нет команд деления, то выигрыш будет даже больше, чем на Cortex. Не сочтите за труд, напишите как умножить на 0,7 в 8-битных числах... Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
blackfin 25 23 марта Опубликовано 23 марта · Жалоба On 3/23/2024 at 4:57 PM, MPetrovich said: Извиняюсь за бестолковость, но как в 8-битном виде выглядит число 0,7? 0.7*256 = 179. On 3/23/2024 at 4:57 PM, MPetrovich said: Не сочтите за труд, напишите как умножить на 0,7 в 8-битных числах... a*0.7 = ((a*0.7)*256)>>8 = (a*179)>>8 Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться