Академический Документы
Профессиональный Документы
Культура Документы
Group # 7
Submitted to: Sir Nauman Masud
Submitted by: Kamran Iftikhar-51997 Moazzam Nazir-50481 Muhammad Ahmed-50996 Muhammad Aqeel Abassi Muhammad Awais Tayyab-52251
Introduction
3-phase AC Induction Motor Drives
The AC induction motor is said to be a workhorse with adjustable speed drive systems. The most popular type is the 3-phase, squirrel-cage AC induction motor. It is a maintenance-free, less noisy and efficient motor. The stator is supplied by a balanced 3-phase AC power source. The synchronous speed ns of the motor is calculated by:
where fs is the synchronous stator frequency in Hz, and p is the number of stator poles. The load torque is produced by slip frequency. [1] It is obvious that in order to control the speed of Induction Motor, an efficient way would be to control its synchronous frequency. The finest way to achieve this is by use of inverter and sinusoidal PWM. This is the strategy used in this lab work.
Control Card
The Input Signal shown in Figure 2 has to come from the control card and the Fault Output has to go back to the Control Card. The Input Signals are Sinusoidal PWM signals which allow us to control the Voltage and Frequency applied to motors stator windings.
Lab Objective
In this lab, we were assigned the task design the control card which generates suitable PWM Signals based on the inputs and feedback signals. The details of implementation are given in coming sections.
Other than the variation in speed, the torque-speed characteristics of the VF control reveal the following: The starting current requirement is lower The stable operating region of the motor is increased. Instead of simply running at its base rated speed (NB), the motor can be run typically from 5% of the synchronous speed (NS) up to the base speed. The torque generated by the motor can be kept constant throughout this region At base speed, the voltage and frequency reach the rated values. We can drive the motor beyond the base speed by increasing the frequency further. However, the applied voltage cannot be increased beyond the rated voltage. Therefore, only the frequency can be increased, which results in the reduction of torque [2]
Implementation
For implementation of Control Card, we selected PIC18F4431 due to its excellent peripherals including the Power Control PWM Module, High Speed 10-bit ADC and various features of timers, serial and parallel communication.
The Power Control PWM module supports four PWM generators and eight output channels on PIC18F4X31 devices. Block Diagram is shown in Figure 6. Figure 7 shows one PWM pair in complementary mode.
Figure 8 DEAD TIME CONTROL UNIT BLOCK DIAGRAM FOR ONE PWM OUTPUT PAIR
PWM output signals and drive them into an inactive state. The action of the fault inputs is performed directly in hardware so that when a fault occurs, it can be managed quickly and the PWMs outputs are put into an inactive state to save the power devices connected to the PWMs. The PWM fault inputs are FLTA and FLTB, which can come from I/O pins, the CPU or another module. The FLTA and FLTB pins are active-low inputs so it is easy to OR many sources to the same input.
These features lend themselves to many applications including motor control, sensor interfacing, data acquisition and process control. In many cases, these features will reduce the software overhead associated with standard A/D modules.
10
Main.c
#include <htc.h> #include "sine.h" #include "misc.h" uint16 fv = fa2fv(160); #define fv_min fa2fv(10) #define fv_max fa2fv(160) uint8 Amplitude = (uint8)(fa2fv(160)>>2); //Desired Amplitude //"virtual" frequency, a 10-bit variable //proportional to the desired frequency
void InitPeripherals(void) { #if (USE_EXTERNAL_DAC) //Initializes SSP module to do SPI communication with DACs CKP = 0; //Idle state for clk is low CKE = 1; //Tx on rising edge SMP = 0; //Suitable for Daisy Chaining //SSPM=0; //Master Mode, Clock = Fosc/4 TRISC7 = 0; //Make SDO output TRISC5 = 0; //Make SCK output SSPIF = 0; //Initialize Flag SSPEN = 1; //SSP Enable TRISC6 = 0; //LDAC output TRISE &= 0xF8; #endif #if (USE_INTERNAL_PWM_MODULE) //Initialize Power Control PWM Module OVDCOND = 0xFF; //Override none of the PWM pins OVDCONS = 0x00; //Doesn't matter due to 1's in OCDCOND PTCON0 = 0x03; //Prescale=1:1, Postscale=1:1, //Count up/down with double update PWMCON0 = 0x40; //Six PWM channels enabled, //All six in complementary mode PWMCON1 = 0x00; //Asynchronous output overrides,
11
PTPERL = 0xFE; PTPERH = 0x01; DTCON = (0b10)<<6; DTCON |= 0x32; PTEN #endif = 1;
//PWM duty update not disabled //At Fosc=40MHz, timer will count up for 50usec //and then it will count down //Dead Time Prescale: Fosc/8; //Counts = 0x32 => 0x32/(Fosc/8) = 10uSec @ 40MHz //Timer On
//Initialize CCP1 module to get periodic interrupts to update DutyCycle CCP1CON = 0x0B; //Compare mode; Triggers //special event (CCPIF bit is also set) SetWaveUpdateInterval(fv); T1CON = 0b00000001; //8bit RW, 1:1 prescale; //Internal clock; Timer1 ON CCP1IP = 1; //interrupt Priority high CCP1IE = 1; //interrupt enable //initialize adc ADCON0 = 0x00; ADCON1 = 0x00; disabled, ADCON2 = 0x8A; ADCON3 = 0x00; ADCHS = 0x00; ANSEL0 = 0x3F; TRISA = 0x3F; ADON = 1; } //single-shot, single-ch, Group A, ADC yet OFF //VREF+ = AVDD & VREF- = AVSS, FIFO buffer //Right-Justify, Acquisition = 2TAD, Fosc/32 //No External Trigger //AN0 selected in GroupA //AN0-AN5 inputs Analog //Make analog pins of RA Input //Now Turn ON the ADC
void main(void) { uint16 temp_fv; uint8 temp_Ampl; InitPeripherals(); IPEN = 1; //interrupt priority system enabled GIEL = 0; //low-priority interrupts disabled GIEH = 1; //high-priority interrupts enabled while(1) { GO = 1; while(GO == 1); temp_fv = ADRESH << 8; temp_fv |= ADRESL; if(temp_fv < fv_min) temp_fv = fv_min; if(temp_fv > fv_max) temp_fv = fv_max; temp_Ampl = fv2Ampl(fv); GIEH = 0; //Critical task, disable interrupts fv = temp_fv; Amplitude = temp_Ampl; GIEH = 1; SetWaveUpdateInterval(fv); } } void interrupt HighPriorityISR(void) {
12
if((CCP1IE) && (CCP1IF)) //if interrupt is from CCP1 module, the periodic interrupt { static uint8 n = 0; uint8 dummy=0xaa, dummy2=0; STRUCT_3PH_SINE SineValues; //This struct holds current values //of the three phases of sine CCP1IF = 0; //clear interrupt flag //calculate current values of the three phases SineValues = sine(Amplitude,n++); #if(USE_INTERNAL_PWM_MODULE) UDIS = 1; //Duty cycle update disabled //update all DutyCycles before change takes effect PDC0H = SineValues.ph1 >> 8; PDC0L = SineValues.ph1; PDC1H = SineValues.ph2 >> 8; PDC1L = SineValues.ph2; PDC2H = SineValues.ph3 >> 8; PDC2L = SineValues.ph3; UDIS = 0; #endif #if (USE_EXTERNAL_DAC) RE0 = 0; SSPBUF = (uint8) (SineValues.ph1>>8)|0b01010000; while(SSPIF == 0); SSPIF = 0; SSPBUF = (uint8) (SineValues.ph1); while(SSPIF == 0); SSPIF = 0; RE0 = 1; RE6 = 0; dummy>>=1; RE6 = 1; RE1 = 0; SSPBUF = (uint8) (SineValues.ph2>>8)|0b01010000; while(SSPIF == 0); SSPIF = 0; SSPBUF = (uint8) (SineValues.ph2); while(SSPIF == 0); SSPIF = 0; RE1 = 1; RE6 = 0; dummy>>=1; RE6 = 1; RE2 = 0; SSPBUF = (uint8) (SineValues.ph3>>8)|0b01010000; while(SSPIF == 0); SSPIF = 0; SSPBUF = (uint8) (SineValues.ph3); while(SSPIF == 0); SSPIF = 0; RE2 = 1; RE6 = 0; dummy>>=1; RE6 = 1; dummy2 = dummy; dummy = dummy2; #endif } }
13
MISC.h
#ifndef #define typedef typedef MISC_H MISC_H unsigned short uint16; unsigned char uint8;
#define USE_EXTERNAL_DAC 1 #define USE_INTERNAL_PWM_MODULE 0 // Config Bytes of the Microcontroller #pragma config OSC=HSPLL, IESO=OFF, FCMEN = OFF #pragma config BOREN=OFF, PWRTEN=ON #pragma config WDTEN=OFF #pragma config T1OSCMX=OFF, PWMPIN=OFF, HPOL=HIGH, LPOL=HIGH #pragma config MCLRE=ON, SSPMX=RC7 #pragma config DEBUG=OFF, STVREN=OFF, LVP=OFF #pragma config CP0=OFF, CP1=OFF, CP2=OFF, CP3=OFF #pragma config CPD=OFF, CPB=OFF #pragma config WRT0=OFF, WRT1=OFF, WRT2=OFF, WRT3=OFF #pragma config WRTB=OFF, WRTC=OFF, WRTD=OFF #pragma config EBTR0=OFF, EBTR1=OFF, EBTR2=OFF, EBTR3=OFF #pragma config EBTRB=OFF #endif//#ifndef MISC_H //Config1H //Config2L //Config2H //Config3L //Config3H //Config4L //Config5L //Config5H //Config6L //Config6H //Config7L //Config7H
Sine.h
#ifndef SINE_H #define SINE_H #define fa2fv(fa) (uint16)(1023*(unsigned long)fa/200) #define fv2Ampl(fv) (uint8)(fv>>2) typedef unsigned short uint16; typedef unsigned char uint8; typedef struct { uint16 ph1; uint16 ph2; uint16 ph3; }STRUCT_3PH_SINE; void SetWaveUpdateInterval(uint16 fv); STRUCT_3PH_SINE sine(uint8 A, uint8 n); #endif //#ifndef SINE_H
Sine.c
#include <htc.h> #include "sine.h" #include "misc.h" uint8 mul8_arg1,mul8_arg2; //Global variables used in multiplication //using in-line assembly. In-line assembly
14
//can directly work with Global variables ///////////////////////////////// SineTable ////////////////////////////// // This is a lookup table containing the values for positive half cycle // of sine wave // Horizontal Resolution: 64 points // Vertical Resolution: 8-bits ////////////////////////////////////////////////////////////////////////// const uint8 SineTable[] = { 0, 13, 25, 37, 50, 62, 74, 86, 98, 109, 120, 131, 142, 152, 162, 171, 180, 189, 197, 205, 212, 219, 225, 231, 236, 240, 244, 247, 250, 252, 254, 255, 255, 255, 254, 252, 250, 247, 244, 240, 236, 231, 225, 219, 212, 205, 197, 189, 180, 171, 162, 152, 142, 131, 120, 109, 98, 86, 74, 62, 50, 37, 25, 13, 0 }; ////////////////////////////////// sine ////////////////////////////////// // ARGUMENTS: // ---------// A: Indicates Desired Amplitude // n: Indicates time/phase // // RETURN: // ------// Structure containing three 16-bit numbers related to the three phases ////////////////////////////////////////////////////////////////////////// STRUCT_3PH_SINE sine(uint8 A, uint8 n) { uint8 n1,n2,n3; //Indices to SineTable for the three phases STRUCT_3PH_SINE ret; //Structure to be returned n1 n1 n2 n2 n3 n3 = n; &= 0x7F; //max allowed value is 127. This is same as "n MODULO 128" = n+43; //(128/3) = 43 &= 0x7F; = n+85; //(2*128/3) = 85 &= 0x7F;
//STRATEGY: //--------//The values held in SineTable are 8-bit and we have to multiply //them by A, another 8-bit number. The product will be at most //16-bit. If we use 12-bit DAC, we left shift the product by 5 //to get 11-bit result and then add offset of 0x7FF // To use H/W multiplier, we use assembly instructions which //place the result in PROD register #if(USE_INTERNAL_PWM_MODULE) #define L_SHIFT (uint8)6 //amount of left shift needed to //adjust the number of bits in outputs #define OFFSET (uint16) 0x3FF //Corresponding offset #endif #if(USE_EXTERNAL_DAC) #define L_SHIFT (uint8)5 #define OFFSET (uint16)0x7FF #endif
15
mul8_arg2 = A;
if(n1 < 64) //Phase1, positive cycle { //overall operation: ret.ph1 = OFFSET +((SineTable[n1]*fv)>>L_SHIFT); mul8_arg1 = SineTable[n1]; //Place the value in global variable //to be able to access it in assembly asm("movf _mul8_arg1,w"); //in-line assembly asm("mulwf _mul8_arg2"); ret.ph1 = OFFSET + (PROD>>L_SHIFT); } else //Phase1, negative cycle { //ret.ph1 = OFFSET - ((SineTable[n1-64]*fv)>>L_SHIFT); mul8_arg1 = SineTable[n1-64]; asm("movf _mul8_arg1,w"); asm("mulwf _mul8_arg2"); ret.ph1 = OFFSET - (PROD>>L_SHIFT); } if(n2 < 64) //Phase2, positive cycle { //ret.ph2 = OFFSET + ((SineTable[n2]*fv)>>L_SHIFT); mul8_arg1 = SineTable[n2]; asm("movf _mul8_arg1,w"); asm("mulwf _mul8_arg2"); ret.ph2 = OFFSET + (PROD>>L_SHIFT); } else //Phase2, negative cycle { //ret.ph2 = OFFSET - ((SineTable[n2-64]*fv)>>L_SHIFT); mul8_arg1 = SineTable[n2-64]; asm("movf _mul8_arg1,w"); asm("mulwf _mul8_arg2"); ret.ph2 = OFFSET - (PROD>>L_SHIFT); } if(n3 < 64) //Phase3, positive cycle { //ret.ph3 = OFFSET + ((SineTable[n3]*fv)>>L_SHIFT); mul8_arg1 = SineTable[n3]; asm("movf _mul8_arg1,w"); asm("mulwf _mul8_arg2"); ret.ph3 = OFFSET + (PROD>>L_SHIFT); } else //Phase3, negative cycle { //ret.ph3 = OFFSET - ((SineTable[n3-64]*fv)>>L_SHIFT); mul8_arg1 = SineTable[n3-64]; asm("movf _mul8_arg1,w"); asm("mulwf _mul8_arg2"); ret.ph3 = OFFSET - (PROD>>L_SHIFT); } return ret; } //////////////////////// SetWaveUpdateInterval /////////////////////////// // Sets the time between successive interrupts. At interrupt, the values // of all three phases are updated according to next index in SineTable // ARGUMENT: // --------// fv: "virtual frequency", indicates the desired frequency
16
////////////////////////////////////////////////////////////////////////// void SetWaveUpdateInterval(uint16 fv) { //left and right shift by 3 are just to fit the division //to 16 bit operation CCPR1 = ((uint16)((10000000>>3)*1023/(128*200))/fv)<<3; }
Performance Analysis
The heaviest task currently being performed by the microcontroller is waveform generation. A timer interrupt is being used to update the duty cycle of each PWM channel at each sampling time, according to VF control law. As the number of samples in the lookup table is fixed, we change the sampling time (the time between two consecutive timer interrupts) to control the frequency of the generated Sine wave. Obviously, the time needed to execute the ISR, is very crucial for overall system performance. It has been found for current source code implementation that:
This is found by observing the value of timer after the ISR finishes execution. Currently, each cycle of sine wave is made up of 128 samples. So at 50Hz, the sampling time becomes:
Works Cited
[1] AN1958, Freescale. [Online]. http://cache.freescale.com/files/dsp/doc/app_note/AN1958.pdf [2] Rakesh Parekh. Microchip Inc. AN889. [Online]. http://ww1.microchip.com/downloads/en/AppNotes/00889b.pdf
18