В первой части мы под общим ракурсом рассмотрели, что такое коллекторные двигатели постоянного тока, и как ими управляют с помощью модулированных по широте сигналов. Теперь самое время рассмотреть на довольно простом примере, как все это работает на практике.
Как-то понадобилось мне запустить движок Д21 У3. Это ДПТ средней мощности с независимым возбуждением. Вот его основные электрические параметры:
- номинальная мощность 4,5 кВт
- номинальное напряжение 220 В
- номинальный ток 26 А
- скорость 1030 оборотов в минуту.
В качестве силовых ключей были выбраны MOSFET-транзисторы IRF644, хотя сначала выбор пал на мощные IGBTIRG4PC50 с напряжением 600 В и током 39 А. Но поскольку согласно технологическому процессу не требовалась высокая скорость и работа двигателя под большими токами, то с экономической точки зрения MOSFETтипа IRF644 с напряжением 250 В и током 14 А оказался куда выгоднее (либо четыре штуки IRF644 за 32 рубля, либо столько же IRG4PC50 за 180 рублей, думаю, разница есть). В общем, при выборе оборудования нужно всегда учитывать различные условия тех.процесса, и при разработке критически важных приложений (если в случае аварии могут пострадать люди или дорогостоящее оборудование), следует выбирать элементы с запасом по параметрам, например, IRG4PC50 был бы хорошим выбором, а в случае систем с ограниченным бюджетом можно проанализировать «потолок» требуемых параметров и взять оптимальные с экономической точки зрения вещи. Но даже в этом случае нужно обязательно предусматривать защиты (по превышению напряжения, тока).
Для того, чтобы подавать на затворы транзисторов правильное напряжение в правильном порядке необходимы драйверы, на входы которых через опторазвязку будут поступать управляющие импульсы с контроллера. Драйверы IRS21094 и двухканальные оптопары HCPL-2231 оказались вполне подходящими для данной задачки. Схему с их участием можно увидеть на рисунке 1.
Рисунок 1 – принципиальная схема системы ШИМ-управления ДПТ
Подробного описания принципа работы здесь заслуживают полумостовые драйверы. Полумостовые они потому, что имеют два канала – HO, управляющий затвором транзистора верхнего плеча и LO, управляющий затвором транзистора нижнего плеча. Зачем нужны вообще драйверы подобного рода? Разве нельзя просто подавать с управляющего устройства на транзисторы нужные импульсы? Для транзистора, что находится внизу, может быть и можно. Но для того, что уютно расположился в верхнем плече, нужно смещение управляющего напряжение на приличное количество вольт. Данный драйвер позволяет довести это напряжение (VB) до 625 В, «накачав» его через диод. Землей для верхнего плеча здесь будет являться (VS), относительно которой и будут подаваться управляющие импульсы. Землю же для нижнего плеча будет определять вывод COM.
Со стороны информационной системы драйвер имеет два входа для управляющих сигналов – INи SD. Диаграмма зависимости выходных сигналов от входных приведена на рисунке 2.
Рисунок 2 – пояснение принципа работы драйвера IRS21094
Во-первых, мы видим, что драйвер обеспечивает невозможность одновременной подачи импульсов на HOи LO, и это хорошо, иначе образовалась бы закоротка и, возможно, получился бы небольшой праздничный фейерверк. Теперь о том, как конкретно управляют выходом входы INи SD. SD решает всё – не будет логической «1» на этом контакте, значит не будет ничего и на выводах HOи LO. Если же на SD будет «1», а на INбудет «0», то на нижнее плечо будет подан импульс. Но если INбудет в состоянии «1», то импульс отправится на верхнее плечо. Внимательно проанализировав рисунок, всё станет понятно.
В обвязке драйвера также следует упомянуть резистор, подключаемый к выводу DT. Он необходим для установки «мертвого» времени, то есть промежутка, в котором гарантированно не будут подаваться импульсы, что позволит избежать одновременного открытия плечей моста, приводящего транзисторы в скоропостижной смерти. Этот резистор может отсутствовать (закоротка на землю), что гарантирует минимальное «мертвое» время 540 нс, максимальное время 5 мкс обеспечивается при 200 КОм.
Учитывая всё вышесказанное, можно изобразить диаграмму управляющих импульсов по входу и выходу драйверов, из которой будет ясен принцип программирования контроллера и работы устройства в целом.
На диаграмме показаны случаи движения в обоих направлениях с торможением и остановом в каждом случае.
Итак, теперь как это запрограммировать? Ниже будет приведен код, написанный на языке C для МК dsPIC30F6014A и реализующий диаграмму рисунка 3. Из него выкинуто все лишнее, связанное с инициализацией контроллера и прочими вспомогательными элементами. Данный код подойдет практически к любому контроллеру, так как в целях масштабируемости (планировался переход на более простые восьмиразрядники) здесь не используются модули ШИМ, а синтезируются сигналы требуемой ширины «вручную» с помощью прерываний. Это снижает требование к микроконтроллеру, у которого может быть меньше четырех ШИМ-выводов или вовсе их может не быть.
Краткий пересказ алгоритма таков… С панели оператора, системы регулирования или откуда-либо еще поступает сигнал задания, который записывается в переменную Uz_pwm. Чтобы величина задания не превышала определенного максимального уровня, нужно предусмотреть ограничение как для работы в положительной полярности, так и в отрицательной (у меня эти величины 2000 и -2000, соответственно, при этом период таймера равен 0x07FF). Затем поведение программы зависит от того, какой полярности было подано задание, или вообще не подано (т.е. задание в нуле). Рассмотрим случай прихода положительного сигнала задания. С помощью конструкции switch-case «переключаем» переменную Phs_p_pwm1. Изначально она должна равняться 0, и в этом случае для порядка обнуляем «переключалки» других состояний: отрицательного задания Phs_n_pwm1 и задания в нуле Phs_z_pwm1. Здесь же обнуляем рабочий таймер (в данном случае TMR2), разрешаем от него прерывания и включаем его.
Выводы драйверов сидят на порту D в такой последовательности: IN1 – нулевой бит, SD1 – первый, IN2 – второй и SD2 – третий бит. Для формирования первого импульса в соответствии с рисунком 3 в порт запишем b1011 (0x0B). Затем присвоим Phs_p_pwm1 значение 1, чтобы дальше перейти на условие, которое присваивает порту b1111 (0x0F) при значении TMR2 больше или равном текущему заданию на ШИМ, что в итоге «закончит» этот импульс. Далее делаем Phs_p_pwm1 = 2 для перехода на следующий этап, который будет находиться в обработчике прерываний. В нем по окончанию счета таймера при заданном периоде в случае, если Phs_p_pwm1==2, на порт выдаем b1011 (0x0B), что начнет новый импульс, и Phs_p_pwm1 приравняем этапу номер 3, который будет уже в основном цикле программы.
В случае Phs_p_pwm1=3 на порт выводим b1010 (0x0A), это гасит очередной импульс, и задаем этап №4 (Phs_p_pwm1 = 4), который снова ищем в обработчике. Здесь мы снова генерируем импульс (PORTD=0x0B) и возвращаемся в основную программу, приравняв Phs_p_pwm1=1 для того, чтобы цикл формирования импульсов начался заново. Алгоритм работы в отрицательной полярности выполняется аналогичным образом с поправкой на выходные значения порта D.
Теперь все описанное изобразим в виде кода. Часть, выполняемая в основном цикле программы:
if (Uz_pwm>2000) Uz_pwm=2000; //верхняя граница положительного диапазона
if (Uz_pwm<-2000) Uz_pwm=-2000; ////верхняя граница отрицательного диапазона
if (Uz_pwm>0) //если задание положительно
{
switch (Phs_p_pwm1)
{
case 0:
Phs_n_pwm1 = 0;
Phs_z_pwm1 = 0;
TMR2 = 0;
IEC0 = (IEC0 | 0x0040); //разрешаем прерывание от TMR2
T2CON = (T2CON | 0x8000); //запуск TMR2
PORTD = 0x0B; //подаем «1» на IN1, SD1, SD2
Phs_p_pwm1 = 1;
break;
case 1:
if (TMR2>=Uz_pwm) //счетчик TMR2 превысил значение задания
{
PORTD = 0x0F; // подаем «1» на IN1, SD1, IN2, SD2
Phs_p_pwm1 = 2;
}
break;
case 3:
if (TMR2>=Uz_pwm) // счетчик TMR2 превысил значение задания
{
PORTD = 0x0A; // подаем «1» на SD1, SD2
Phs_p_pwm1 = 4;
}
break;
}
}
if (Uz_pwm==0) //если нет задания
{
switch (Phs_z_pwm1)
{
case 0:
Phs_n_pwm1 = 0;
Phs_p_pwm1 = 0;
PORTD = 0x00;
T2CON = (T2CON & 0x7FFF); //стоп TMR2
TMR2 = 0;
Phs_z_pwm1=1;
break;
}
}
if (Uz_pwm<0) //если задание отрицательно
{
switch (Phs_n_pwm1)
{
case 0:
Phs_p_pwm1 = 0;
Phs_z_pwm1 = 0;
TMR2 = 0;
IEC0 = (IEC0 | 0x0040); //разрешаем прерывание от TMR2
T2CON = (T2CON | 0x8000); //запуск TMR2
PORTD = 0x0E; // подаем «1» на SD1, IN2, SD2
Phs_n_pwm1 = 1;
break;
case 2:
if (TMR2>=(0-Uz_pwm)) //счетчик TMR2 превысил значение задания
{
PORTD = 0x0F; // подаем «1» на IN1, SD1, IN2, SD2
Phs_n_pwm1 = 2;
}
break;
case 3:
if (TMR2>=(0-Uz_pwm)) //счетчик TMR2 превысил значение задания
{
PORTD = 0x0A; // подаем «1» на SD1, SD2
Phs_n_pwm1 = 4;
}
break;
}
}
Обработчик прерывания по таймеру:
void __attribute__((__interrupt__)) _T2Interrupt(void)
{
if (Phs_p_pwm1==2)
{
PORTD = 0x0B; //подаем «1» на IN1, SD1, SD2
Phs_p_pwm1=3;
}
if (Phs_p_pwm1==4)
{
PORTD = 0x0B; //подаем «1» на IN1, SD1, SD2
Phs_p_pwm1=1;
}
if (Phs_n_pwm1==2)
{
PORTD = 0x0E; //подаем «1» на IN2, SD1, SD2
Phs_n_pwm1=3;
}
if (Phs_n_pwm1==4)
{
PORTD = 0x0E; //подаем «1» на IN2, SD1, SD2
Phs_n_pwm1=1;
}
IFS0bits.T2IF = 0; // сброс бита прерывания
}
Вот такой простой ШИМ-генератор из одного таймера.
© digitrode.ru