Three phase AC with frequency adjustment via a potentiometer in ADC Mode with PIC16F1937

Thread Starter

jean120

Joined Jan 24, 2016
75
Hello everybody,I would like to control the frequency of my Three Phase DC-AC Inverter with the variable frequency so that the VFD can be implemented using PIC16F1937,I have the codes here in attachment I tried to implement the adc reading capability with interrupts but I am not coming at the stage where the frequency can be variable,I want it to be adjustable with the voltage at the output of the three phase DC-AC Inverter.Please could you help?so that the frequency and amplitude changes proportionally with my PIC here,I am using the IR21362 so that I need the output at P1A,P2A and P3A of the PIC which through the driver IR21362 gives the complete cycle (360degrees for each phase).

Codes
C:
#define NUMBER_OF_TABLE_ENTRIES_FOR_180_DEGREES 64
#define FACTOR_TO_GET_360_DEGREES

char i = 0;
double value_adc;

unsigned int sin_table[64] = {125,137,149,161,173,184,194,204,
                              213,222,229,235,240,245,248,249,
                              250,249,248,245,240,235,229,222,
                              213,204,194,184,173,161,149,137,
                              125,113,101,89,77,66,56,46,
                              37,28,21,15,10,5,2,1,
                              0,1,2,5,10,15,21,28,
                              37,46,56,66,77,89,101,113
                             };

unsigned int TBL_POINTER_NEW[3], TBL_POINTER_OLD[3], TBL_POINTER_SHIFT[3], SET_FREQ = 0;
unsigned int ADC_VAL = 0, PREV_ADC_VAL = 0;
char DUTY_CYCLE[3];
//Timer2
//Prescaler 1:1; Postscaler 1:2; TMR2 Preload = 249; Actual Interrupt Time : 100 us
//Place/Copy this part in declaration section
void InitTimer2() {
    T2CON = 0x0C;
    PR2 = 249;
    TMR2IE_bit = 1;
    INTCON = 0xC0;
}

void interrupt()
                {
    if(TMR2IF_bit==1) {
  
        TBL_POINTER_NEW[0] = TBL_POINTER_OLD[0] + SET_FREQ;
        if (TBL_POINTER_NEW[0] < TBL_POINTER_OLD[0]) {
           CCP1CON.P1M1 = ~CCP1CON.P1M1;
        }
        TBL_POINTER_SHIFT[0] = TBL_POINTER_NEW[0] >> 10;
        DUTY_CYCLE[0] = TBL_POINTER_SHIFT[0]*value_adc;  //check this for multiplicity of value with read data from potentiometet
        CCPR1L = sin_table[DUTY_CYCLE[0]];
        TBL_POINTER_OLD[0] = TBL_POINTER_NEW[0];
      
       // Phase2
        TBL_POINTER_NEW[1] = TBL_POINTER_OLD[1] + SET_FREQ;
        if (TBL_POINTER_NEW[1] < TBL_POINTER_OLD[1]){
           CCP2CON.P2M1 = ~CCP2CON.P2M1;
        }
        TBL_POINTER_SHIFT[1] = TBL_POINTER_NEW[1] >> 10;
        DUTY_CYCLE[1] = TBL_POINTER_SHIFT[1]*value_adc;
        if((DUTY_CYCLE[1] + 42) < 64)DUTY_CYCLE[1] += 42;
        else DUTY_CYCLE[1] -= 22;
        CCPR2L = sin_table[DUTY_CYCLE[1]];
        TBL_POINTER_OLD[1] = TBL_POINTER_NEW[1];
        //Phase 3
         TBL_POINTER_NEW[2] = TBL_POINTER_OLD[2] + SET_FREQ;
        if (TBL_POINTER_NEW[2] < TBL_POINTER_OLD[2]) {
           CCP3CON.P3M1 = ~CCP3CON.P3M1;
        }
        TBL_POINTER_SHIFT[2] = TBL_POINTER_NEW[2] >> 10;
        DUTY_CYCLE[2] = TBL_POINTER_SHIFT[2]*value_adc;
        if((DUTY_CYCLE[2] + 21) < 64)DUTY_CYCLE[2] += 21;
        else DUTY_CYCLE[2] -= 43;
        CCPR3L = sin_table[DUTY_CYCLE[2]];
        TBL_POINTER_OLD[2] = TBL_POINTER_NEW[2];
        TMR2IF_bit = 0;
    }
}
     //Interrupt for ADC Value recording  ,reading the
     void interrupt_ADC()
          {
   
      if(ADIF_bit==1)
      {
      value_adc=ADRESH;
      //value_adc=ADRESL;
      ADIF_bit=0;
      }
           }

void main() {

    Delay_ms(2);
     APFCON = 0x00;
     ADCON1 = 0X20;
     ADCON0=0X19;
     delay_ms(2);
     ADCON0.GO=1;
     FVRCON = 0x00;
     ANSELA =0X3F;
     LATA=0X00;
     CM1CON0 = 0x00;
     CM2CON0 = 0x00;
     TRISA = 0x01;
     TRISB = 0xDF;
     TRISC = 0xF9;
     PORTB = 0x00;
     PORTC = 0x00;
     LATA = 0x00;
    //Initiailization ADC reading modules
     ADIF_bit=0;
     while(ADIF==0)
     ADIF_bit=0;
     ADIE_bIT=1;
     GIE_bit=1;
     PEIE_bit=1;
     ADC_Init();
     //loop for cycles repeating
     for(i = 0; i < 3; i++)
            {
         TBL_POINTER_SHIFT[I] = 0;
         TBL_POINTER_NEW[I] = 0;
         TBL_POINTER_OLD[I] = 0;
         DUTY_CYCLE[I] = 0;
             }
     PWM1_Init(10000);
     PWM2_Init(10000);
     PWM3_Init(10000);

     PWM1_Set_Duty(0);
     PWM2_Set_Duty(0);
     PWM3_Set_Duty(0);

     PWM1_Start();
     PWM2_Start();
     PWM3_Start();
     InitTimer2();
     while(1)
              {
    
              ADC_VAL=value_adc;
              SET_FREQ=171;

          }
     }

Thanks

Moderators note: please use code tags for pices of code
 
Last edited by a moderator:

dannyf

Joined Sep 13, 2015
2,197
Please could you help?
you have made it very difficult for others to help you.

For example, your code is poorly documented so that it is hard for others, as well as you, to follow....

There are a lot of things that you can do to help you identify where it is.

I would suggest the following:

1) can you generate a fixed frequency 3-phase signal?
2) can you adc a pot reliably?
3) can you combine the two together?

Forget about the fancy things you are trying to do for a moment. Learn to crawl before attempting to run.
 

Thread Starter

jean120

Joined Jan 24, 2016
75
Hello,
1)I can generate a fixed frequency three phase signal
2)I can make an A/D reading reliably of an analog input signal
3)The problem comes on the combination of the two because here the values is read from the look up table and then multiplied with the ADC Value read from the potentiometer (variable resistor) and then the result is sent to the port for PWM parameters like duty cycle,etc.

Please help.

Thanks
 

dannyf

Joined Sep 13, 2015
2,197
Maybe you can help others help you by posting the pictures here as well?

You will need to understand how the code works. It is a DDS algorithm. To change the output frequency, you will need to change its stepping, which the code is attempting to do in a convoluted way.

Fix that and we can talk about your adc.
 

dannyf

Joined Sep 13, 2015
2,197
This may help get you going in the right direction.

5-ch pwm output implemented over a 16f1936, with variable frequency output, perfectly aligned. The code utilizes your sine table, as well.

The isr is as follows, in its entirety:

Code:
    if (TMR2IF) {
        TMR2IF = 0;                            //clear the flag
        //IO_FLP(LED_PORT, LED);                //flip the led - debugging only
        _dds_phase+=_dds_step;                //increment the dds phase accumulator
        _dds_index=_dds_phase >> 10;        //index is top 6 bits (2^6=64)
        CCPR1L = dc_table[(_dds_index+=PWM_STEP*1/5) & 0b00111111];        //update pwm1
        CCPR2L = dc_table[(_dds_index+=PWM_STEP*1/5) & 0b00111111];        //update pwm2
        CCPR3L = dc_table[(_dds_index+=PWM_STEP*1/5) & 0b00111111];        //update pwm3
        CCPR4L = dc_table[(_dds_index+=PWM_STEP*1/5) & 0b00111111];        //update pwm4
        CCPR5L = dc_table[(_dds_index+=PWM_STEP*1/5) & 0b00111111];        //update pwm5
    }
The right shift can be simplified too.
 

Attachments

Thread Starter

jean120

Joined Jan 24, 2016
75
Dear dannyf,could you please upload the complete codes?I think it could be better if you make the codes for giving 3 half wave sine signals each 0-180degres,because I have a MOSFET Driver IR21362 which need 3 signals and internally it inverse each for getting a complete signal of 0-360 degrees.And also with the above posted codes no A/D with potentiometer which seems to be very difficult for me.

With the DDS algorithm how will the stepping be changed?

Thank you very much.
 
Top