Pull to refresh

Работа с трехфазным синхронным двигателем

Reading time5 min
Views62K
Довелось мне, по роду своей деятельности, писать программу для разгона раскрутки и управления трехфазным синхронным двигателем. Далее я постараюсь подробно описать как я это реализовал.

График раскрутки двигателя выглядит таким образом:

image

Как видно, что необходимо не только увеличивать частоту, но и амплитуду, причем она растет не с нуля, а с 4-х вольт и при частоте в 80 Гц, должна достигать своего максимума. Ну и т.к. это трехфазный двигатель, то должно быть 3 синусоиды, причем сдвинутые относительно друг друга на 120 градусов. Также дополнительным условием было, чтобы на 80 Гц двигатель выходил не меньше чем через 30с, поэтому я решил использовать секунду на герц (100 Гц достигается за 100с).

В контроллере с которым я работаю имеется как раз 3 ШИМ’а и я решил использовать их, а не заморачиваться возиться с внешними ЦАП’ами.

Первая проблема с которой я столкнулся это то, что сигнал с выхода ШИМ будет только положительный, т.е. синусоида будет выше нуля, для этого пришлось разбить ее на полуволны и строить их отдельно. Вот так будет выглядеть синусоида при минимальной амплитуде.

image
image

А вот так при максимальной.

image
image

чтобы получить положительную полуволну:
DCH = sin[ptrA];
DCH = DCH + 128;

отрицательную:
DCH = sin[ptrA];
DCH = 128 - DCH;

Как видно из следующего рисунка теперь у меня синусоида крутится возле значения 128, теперь достаточно аппаратно сдвинуть сигнал и установить ноль на значении 128 и она станет биполярной.

image

Синусоида состоит из 128 точек, этого более чем достаточно. После низкочастотного фильтра получается практически идеально гладкая. Амплитуда растет тоже довольно плавно (таблица коэффициентов состоит из 80 значений), умножаем на значение из таблицы и отбрасываем младший байт:

ampS = amp[fctr];
DCH = DCH*ampS;
DCH = DCH>>8;

Для увеличения частоты я использовал 16 разрядный таймер TMR0, значение его периода берется из таблицы, которая состоит из 100 значений (от 1 до 100 Гц). Формула для вычисления выглядит следующим образом: 65535-sec/clk/smpl/Hz, где Hz меняется от 1 до 100.
  • 65535 — максимальное значение 16 разрядного таймера
  • sec — 1с в наносекундах, значение 1000000000
  • clk — длительность 1 такта в наносекундах, при кварце в 32 Мгц равна 125
  • smpl — количество точек на период, значение 128

Программа разрабатывалась для микроконтроллера PIC17 с использованием компилятора CC7A норвежской компании B Knudsen Data.

Вот, собственно, таблица значений для таймера.

    #define     CDATA_START  0x300
    #pragma     cdata[CDATA_START]
    #pragma     cdata[] = 0x153B, 0x8A9D, 0xB1BE, 0xC54E, 0xD10B, 0xD8DE, 0xDE75, 0xE2A7, 0xE5E9, 0xE885, 0xEAA7, 0xEC6F, 0xEDF0, 0xEF3A, 0xF058, 0xF153, 0xF230, 0xF2F4, 0xF3A4, 0xF442, 0xF4D1, 0xF553, 0xF5CA, 0xF637, 0xF69B, 0xF6F7, 0xF74D, 0xF79D, 0xF7E7, 0xF82C, 0xF86C, 0xF8A9, 0xF8E2, 0xF917, 0xF94A, 0xF97A, 0xF9A7, 0xF9D1, 0xF9FA, 0xFA21, 0xFA45, 0xFA68, 0xFA89, 0xFAA9, 0xFAC7, 0xFAE4, 0xFB00, 0xFB1B, 0xFB34, 0xFB4D, 0xFB65, 0xFB7B, 0xFB91, 0xFBA6, 0xFBBA, 0xFBCE, 0xFBE1, 0xFBF3, 0xFC04, 0xFC15, 0xFC26, 0xFC36, 0xFC45, 0xFC54, 0xFC62, 0xFC70, 0xFC7E, 0xFC8B, 0xFC98, 0xFCA4, 0xFCB1, 0xFCBC, 0xFCC8, 0xFCD3, 0xFCDE, 0xFCE8, 0xFCF2, 0xFCFC, 0xFD06, 0xFD10, 0xFD19, 0xFD22, 0xFD2B, 0xFD34, 0xFD3C, 0xFD44, 0xFD4C, 0xFD54, 0xFD5C, 0xFD63, 0xFD6B, 0xFD72, 0xFD79, 0xFD80, 0xFD86, 0xFD8D, 0xFD93, 0xFD9A, 0xFDA0, 0xFDA6


Еще 2 таблицы со значениями синуса и коэффициентами амплитуды соответственно.

const unsigned char sin[128]=
     {
     0, 7, 13, 18, 24, 31, 37, 43, 50, 54, 60, 65, 71, 76, 80, 85, 90, 94, 99, 101, 105, 109, 112, 115, 118, 119, 121, 123, 125, 126, 126, 127, 127, 127, 126, 126, 125, 123, 121, 119, 117, 115, 112, 109, 105, 101, 99, 94, 90, 85, 80, 76, 71, 65, 60, 54, 48, 43, 37, 31, 24, 18, 13, 7, 0, 7, 13, 18, 24, 31, 37, 43, 50, 54, 60, 65, 71, 76, 80, 85, 90, 94, 99, 101, 105, 109, 112, 115, 118, 119, 121, 123, 125, 126, 126, 127, 127, 127, 126, 126, 125, 123, 121, 119, 117, 115, 112, 109, 105, 101, 99, 94, 90, 85, 80, 76, 71, 65, 60, 54, 48, 43, 37, 31, 24, 18, 13, 7
     };
     
const unsigned char amp[80]=
     {
     86, 88, 90, 93, 95, 97, 99, 101, 103, 105, 108, 110, 112, 114, 116, 118, 121, 123, 125, 127, 129, 131, 133, 136, 138, 140, 142, 144, 146, 148, 151, 153, 155, 157, 159, 161, 164, 166, 168, 170, 172, 174, 176, 179, 181, 183, 185, 187, 189, 192, 194, 196, 198, 200, 202, 204, 207, 209, 211, 213, 215, 217, 220, 222, 224, 226, 228, 230, 232, 235, 237, 239, 241, 243, 245, 247, 250, 252, 254, 255
     };


Обработчик прерывания таймера, выглядит следующим образом.

TMR0_service:
        {
        T0IF = 0;					// сброс флага прерывания
        
		sPRODL = PRODL;
		sPRODH = PRODH;
		sTBLPTRH = TBLPTRH;
		sTBLPTRL = TBLPTRL;
		sFSR0 = FSR0;
		sFSR1 = FSR1;
        
        if (herz < 100)
            {
            if (ptrA == 127)
               TMR0_inc();
            }

        TMR0_set();
        
        if (ptrA == 127)
            ptrA = 0;
        
        if (ptrB == 127)
            ptrB = 0;
           
        if (ptrC == 127)
            ptrC = 0;
            
        ptrA++;						// переход к след. точке 1-й синусоиды
        ptrB++;						// переход к след. точке 2-й синусоиды
        ptrC++;						// переход к след. точке 3-й синусоиды
        
        if (herz>=79)
            {
            if (ptrA < 64)
                {
                DCH = sin[ptrA];	// положительная полуволна
                DCH = DCH + 128;
                }
            else
                {
                DCH = sin[ptrA];	// отрицательная полуволна
                DCH = 128 - DCH;
                }
            PW1DCH = DCH;
        
            if (ptrB < 64)
                {
                DCH = sin[ptrB];	// положительная полуволна
                DCH = DCH + 128;
                }
            else
                {
                DCH = sin[ptrB];	// отрицательная полуволна
                DCH = 128 - DCH;
                }
            PW2DCH = DCH;
        
            if (ptrC < 64)
                {
                DCH = sin[ptrC];	// положительная полуволна
                DCH = DCH + 128;
                }
            else
                {
                DCH = sin[ptrC];	// отрицательная полуволна
                DCH = 128 - DCH;
                }
            PW3DCH = DCH;
            }
        else
            {
            fctr = herz-1;			// вычисление индекса
            ampS = amp[fctr];		// выборка коэффициента
            if (ptrA < 64)
                {
                DCH = sin[ptrA];	// положительная полуволна
                DCH = DCH*ampS;
                DCH = DCH>>8;
                DCH = DCH + 128;
                }
            else
                {
                DCH = sin[ptrA];	// отрицательная полуволна
                DCH = DCH*ampS;
                DCH = DCH>>8;
                DCH = 128 - DCH;
                }
            PW1DCH = DCH;
        
            if (ptrB < 64)
                {
                DCH = sin[ptrB];	// положительная полуволна
                DCH = DCH*ampS;
                DCH = DCH>>8;
                DCH = DCH + 128;
                }
            else
                {
                DCH = sin[ptrB];	// отрицательная полуволна
                DCH = DCH*ampS;
                DCH = DCH>>8;
                DCH = 128 - DCH;
                }
            PW2DCH = DCH;
        
            if (ptrC < 64)
                {
                DCH = sin[ptrC];	// положительная полуволна
                DCH = DCH*ampS;
                DCH = DCH>>8;
                DCH = DCH + 128;
                }
            else
                {
                DCH = sin[ptrC];	// отрицательная полуволна
                DCH = DCH*ampS;
                DCH = DCH>>8;
                DCH = 128 - DCH;
                }
            PW3DCH = DCH;
            }
        
		TBLPTRH = sTBLPTRH;
		TBLPTRL = sTBLPTRL;
		PRODL = sPRODL;
		PRODH = sPRODH;
		FSR0 = sFSR0;
		FSR1 = sFSR1;
        }

Основная программа.

void main()
     {
     GLINTD = 1;				// запрещение прерываний
     
     // -- загрузка адреса таблицы -->
     TBLPTRL = 0;
     TBLPTRH = 3;				// 0x300
     #asm
	TABLRD		0,1,WREG		; пустое чтение из табличной защелки
	TLRD		1,sTMR0H		; чтение старшего байта из табличной защелки
	TABLRD		0,1,sTMR0L		; чтение младшего байта из табличной защелки
     #endasm
     // <--
    
     // -- настройка TMR0 -->
     T0IE = 1;					// разрешение прерывания по переполнению TMR0
     T0STA = 32;				// внутренняя тактовая частота, 1:1
     // <--
    
     // -- настройка ШИМ -->
     PR1 = 253;					// Частота ШИМ = 32000000 / 4 / 253 = 31620 Гц
     PW1DCL = PW2DCL = PW3DCL = 0;
     PW1DCH = 64;				// начальное значение 1-й синусоиды
     PW2DCH = 46;				// начальное значение 2-й синусоиды
     PW3DCH = 83;				// начальное значение 3-й синусоиды
     // <--
    
     // -- начальная инициализация -->
     rtc = 0;
     herz = 1;					// начинаем с 1 Гц
     ptrA = 0;					// стартовое смещение 1-й синусоиды
     ptrB = 85;					// стартовое смещение 2-й синусоиды
     ptrC = 42;					// стартовое смещение 3-й синусоиды
     
     TMR1ON = 1;				// запуск TMR1
     PWM1ON = PWM2ON = PWM3ON = 1;		// запуск ШИМ
     TMR0_set();				// запуск TMR0
     // <--
    
     GLINTD = 0;				// разрешение прерываний
     
     while(1);
     }


Две подпрограммы по работе с таймером.

void TMR0_set()
     {
     TMR0L = sTMR0L;
     TMR0H = sTMR0H;
     }

void TMR0_inc()
    {
    rtc++;						// счетчик реального времени
    if (rtc == herz)
       {
       rtc = 0;
       herz++;
       TBLPTRL = TBLPTRL - 1;
       #asm
	TABLRD		0,1,WREG	; пустое чтение из табличной защелки
	TLRD		1,sTMR0H	; чтение старшего байта из табличной защелки
	TABLRD		0,1,sTMR0L	; чтение младшего байта из табличной защелки
       #endasm
       sTBLPTRH = TBLPTRH;
       sTBLPTRL = TBLPTRL;
       }           
    }
Tags:
Hubs:
+18
Comments25

Articles

Change theme settings