PIC18f4431 PWM Generation

Thread Starter

bilal sheikh

Joined Jan 21, 2015
22
hello all, recently i am working on a project that is variable frequency drive. i have to control the speed of a single phase AC induction motor. inverter design which i am following in a full H-bridge circuit containing power mosfets. now i have to generate variable frequency PWM signles using MCU, for that purpose i am using pic18f4431. here is the result of simulation which i am also getting on hardware.
Screenshot (46).png

now, have a look at the 10ms delay, during which both the channels are off (which i cant bear when actually driving a motor). the 10ms delay is due to the fact that i am checking adc value every now and than to varry the frequency, if the user wants.
any solutions ? so that i am unable to check the adc value as well as both the pwm channels operate without delay (continuesly) . comments are appreciated :)
 

Papabravo

Joined Feb 24, 2006
21,225
Why did you code it that way?
You should be able to write the code in such a way that the operation of the PWM signals is overlapped with the A2D conversion. It would help if you could post your code, and remember to use the code tags.
 

atferrari

Joined Jan 6, 2004
4,766
In that particular micro you have two peripherics that can generate PWM signals without compromising the micro in charge of more generic tasks.

One is the same as in most micros of the 18F family and the other is oriented to power control. Maybe you could need this last. There is a vast list of options.

Read the datasheet with that in mind.
 

Papabravo

Joined Feb 24, 2006
21,225
Please tell me that you did not write your code to "START CONVERSION" and then wait for the "END OF CONVERSION" flag in a tight loop with interrupts disabled.

The proper way to do it is to START CONVERSION, then use an END of CONVERSION interrupt or periodically check the END OF CONVERSION flag, whil maintaining the PWM.
 
Last edited:

Thread Starter

bilal sheikh

Joined Jan 21, 2015
22
Please tell me that you did not write your code to "START CONVERSION" and then wait for the "END OF CONVERSION" flag in a tight loop with interrupts disabled.

The proper way to do it is to START CONVERSION, then use an END of CONVERSION interrupt or periodically check the END OF CONVERSION flag, whil maintaining the PWM.
sir, i am trying to obtain sine pwm using sine look up table. for each and every frequency, sine look up table is generated during runtime. my code is given. i have checked it on hardware, its not continuously running.

Code:
#include<p18f4431.h>
#include <math.h>
#pragma config LVP =OFF
#pragma config WDTEN = OFF
#pragma config OSC=HS
#include <math.h>
unsigned char p=0;
unsigned char q=0;
unsigned char r=0;
unsigned char x=0;
float f1=96.66;
unsigned char sinee [64];
float factor;
float frequency,val,pr2;
unsigned char sine [64]={0, 4, 8, 13, 17, 21, 25, 29, 33, 37, 41, 44, 48, 51, 55, 58, 61, 64, 66, 69, 72, 74, 76, 78, 79, 81, 82, 83, 84, 85, 86, 86, 86, 86, 86, 85, 84, 83, 82, 81, 79, 78, 76, 74, 72, 69, 66, 64, 61, 58, 55, 51, 48, 44, 41, 37, 33, 29, 25, 21, 17, 13, 8, 4};
float factor;
void deadtime (unsigned char d)               // function for dead time
{
unsigned char t=0;
while(t<d)
    {
        t=t+1;
    }
}
void pwm (void)
{
for( p=0; p<64; p=p+1)                        //loop for implementing look-up table, writing duty cycle value to CCPR1L register which is copied in CCPR1H on each interupt
                                            //i.e when a match between TMR2 & PR2 occura
        {
            CCPR1L=sinee[p];
            PIR1bits.TMR2IF=0;
            while(PIR1bits.TMR2IF==0);                    //when interupt occurs TMR2IF bit sets to 1, showing that inerupt has occured
        }
        //CCPR1L=0;                           //after the above loop executed 64 times i.e for 10ms, square waves are inverted
        //deadtime(50);                                  // insertion of dead time between two PWM channels
  
        for( q=0; q<64; q=q+1)                       //loop for implementing look-up table, writing duty cycle value to CCPR1L register which is copied in CCPR1H on each interupt
        {                                     //i.e when a match between TMR2 & PR2 occur
            CCPR2L=sinee[q];
            PIR1bits.TMR2IF=0;
            while(    PIR1bits.TMR2IF==0);
    }

}
void setup(void)                                //function for adc setup
{

    //ADCON0bits.ACONV=1;               // contineous mode
    ADCON0bits.ACONV=0;             // single shoot mode
    ADCON0bits.ACSCH=0;       
    ADCON0bits.ACMOD0=0;             //sequential mode
    ADCON0bits.ACMOD1=0;
    //ADCON0bits.ACMOD0=0;             //contineous mode single channel mode
    //ADCON0bits.ACMOD1=0;
    ADCON1bits.VCFG0=0;
    ADCON1bits.VCFG1=0;
    ADCON2bits.ADFM=0;             // left justified
    ADCON2bits.ACQT0=1;               // aquction time=2*tad
    ADCON2bits.ACQT1=0;
    ADCON2bits.ACQT2=0;
    ADCON2bits.ACQT3=0;
    ADCON2bits.ADCS0=0;              // tad=32tosc
    ADCON2bits.ADCS1=1;
    ADCON2bits.ADCS2=0;
    ADCHSbits.GASEL0=0;
    ADCHSbits.GASEL1=0;
    ANSEL0=1;

    TRISC=0x00;            //pwm setup
    CCP1CON=0x00;                                     
    CCP2CON=0x00;   
    CCPR1L=0; 
    //    CCPR2L=0;                                  /                                 
    CCP1CON=0xC;
    CCP2CON=0xC;   
    T2CON=6;   
}
int ADCRead(unsigned char ch)
{

    ADCON0bits.ADON=1;                 //switch on the adc module
    ADCON0bits.GO=1;                 //Start conversion
    while(ADCON0bits.GO);                 //wait for the conversion to finish
    ADCON0bits.ADON=0;                 //switch off adc
    frequency=0.1953125*ADRESH;             //0-5Volts of adc ----> 0---->50Hz output, using 8 MSB's of adc
  
pr2  =( 2456 *(pow(frequency,-1.002)))-0.888;         // period register calculation formula
                                                          
    factor=pr2/f1;                                  //contant factor that should be multiplied with basic sine lookup table to get the table for desired frequency
    PR2=pr2;
    for (r=0;r<64;r=r+1)
      {
          sinee[r]=factor*sine[r];

      }
return PR2;
}

void main()
{
    setup();   
    ADCRead(0);
    pwm();
    deadtime(50000000);
  
  
}
kindly help if u can.

Moderators note : Please use code tags for pieces of code
 
Last edited by a moderator:

Papabravo

Joined Feb 24, 2006
21,225
It is as I feared. Each of your processes has what is called "busy waiting" in it.
  1. while(ADCON0bits.GO); //wait for the conversion to finish
  2. t=t+1;
  3. while( PIR1bits.TMR2IF==0);
You need to stop doing things this way.

Also, Why are you calling setup each time around the main() loop?

The smart way to do things is to start the various processes and do them all in parallel. Do the high priority tasks first and the low priority tasks last. Your deadtime routine is ridiculous, you don't know for certain how long it takes except by empirical measurement and that is no way to to do things.

Code:
main()
{
  setup()
  while(1)
  {
    if(ADCON0bits.GO == 0) processConversion() ;
    if(deadTime) processDeadtimeIncrement() ;
    else nextSineWaveSection() ;
  }
}
Of course you will need to work out the details. The main principle is:
Never create an infinite loop with a single exit condition.
 
Top