Jump to content
Sign in to follow this  
ra68gi

Pwm Pin & Simulator?

Recommended Posts

Hi guys,

 

Is it possible to view or see the state of pwm pin( RC2) on the source boost simulator? I have a sample code written for PIC16F72 at 1Mhz. When i built the code i didn't see the the change on the simulator. Have i missed any thing in the code?

 

#include <system.h>

// Set clock frequency to 1MHz.

#pragma CLOCK_FREQ 1000000

//set configuration fuse.
#pragma DATA _CONFIG, _XT_OSC & _WDT_OFF & _CP_OFF & _PWRTE_OFF



/*Interrupt service routine (ISR).On timer2 interrupt, program 
 will jump to this code location.  */	
void interrupt( void )
{
   char pulse;
/*generate two 50hz 180 degree out of phase pulses & externally
AND it with the 100Hz pwm pin to get a modulated 50Hz to drive
mosfets connected to a transformer in a push-pull configuration.
A/D conversion of the the output voltage can act as feed back to
adjust the duty-cycle ( not yet implemented in this code).
*/
   pulse = portb;  
   pulse.0 = ~ pulse.0;
   pulse.1 = ~ pulse.1;  
   portb = pulse;
   
pir1.1=0;  //clear TMR2 to pr2 match interrupt flag
}
// The main code configures the pwm registers
void main()
{
   trisa = 255;
  	trisb = 0;         //configure port B as output
  	trisc = 0;         // portc as out put
portb = 1;       //set port B to 1
portc = 0;       //clear portc



// enable interrupts
intcon.6=1;     //enable peripheral interrupt     
intcon.7=1;     //enable global interrupt

pie1.1=1;       //tmr2 to pr2 match interrupt


//PWM period=[(PR2)+1]*4*Tosc*(TMR2 prescaler value)

/*our pmw period is 10ms(100Hz),Tosc is 1/1000,000Hz & prescaler 
is 16.For which PR2+1 works out to 156.25. Lets round it to 156 &
make PR2 to 155. 
*/

//load the period value into pr2 register.
   pr2 = 155;

/*PWM duty cycle = (ccpr1l:ccp1con<5:4>)*Tosc*(TMR2 prescaler value)
Here i have taken 2ms as an example value for duty cycle, Tosc & pre-
scaler are same as above.We will get 10 bit values when we work with
larger duty cycle but for our example we get the value as 125.
*/ 
  
//load the duty cycle value

   int duty_cycle;
   duty_cycle = 125;          //duty cycle is for 2ms
   
   ccpr1l.7 = duty_cycle.9;  
   ccpr1l.6 = duty_cycle.8;           
   ccpr1l.5 = duty_cycle.7;  
   ccpr1l.4 = duty_cycle.6;  
   ccpr1l.3 = duty_cycle.5; 
   ccpr1l.2 = duty_cycle.4;  
   ccpr1l.1 = duty_cycle.3;  
   ccpr1l.0 = duty_cycle.2;  
   ccp1con.5 = duty_cycle.1;  
   ccp1con.4 = duty_cycle.0;  
 
   
     
/*timer2 control register
we have selected
bit6-3...(0000) 1:1 for post scaler
bit2.....(1) timer2 on
bit1-0...(11) prescaler is 16
*/

   t2con = 0b00000111;  




while( 1 ); //do nothing & wait for tmr2 interrupt.
}

 

Raghunathan.

Share this post


Link to post
Share on other sites

Hi guys,

Its working!

 

I forgot to configure the ccp1con register to PWM mode. The modified code is written below.

The ccp module is a superb hardware function with which we can obtain true multi tasking feature or call it parallel processing. With built-in adc & PWM modules one can construct wonderful automatic feed back control systems.

 

This project is a design of an inverter which will convert 12v dc to 230v, 50Hz ac using iron core transformer similar to the APC UPS( uninterrupted power supply) that powers the computers. Now i have successfully produced the 50Hz 180 degree out of phase pulses on portb.0 & portb.1 in the interrupt service routine. We will then AND the 50Hz pulses with the 100hz PWM pulse generated on pin RC2(pwm pin).

The ANDing is done externally using simple transistor circuits to keep cost low.

The ANDed output will drive the mosfet connected to a iron core tx in a push pull configuration. By sensing the voltage from the tx & using the built-in adc of the PIC we can cange the duty cycle value to give a constant voltage at the output of the tx.

 

This is in a nut shell. But there is more to it, like checking battery voltage short circuit protection, annunciations etc. This product is nothing new, but will be a wonderful project for my thread "pic micro programming in Boostc for begginners".

 

One more thing with regards to the clock. To genrate a PWM for 100Hz you need to use oscillators less then 1.5Mhz. I have used an RC oscillator & the R value is around 10K & the capacitor value is 68pf. This value generates around 1MHz. For our project RC will do the job( the cost of 1Mhz crystal is 4 times the cost of the micro in my place).

 

#include <system.h>

// Set clock frequency to 1MHz.

#pragma CLOCK_FREQ 1000000

//set configuration fuse.
#pragma DATA _CONFIG, _RC_OSC & _WDT_OFF & _CP_OFF & _PWRTE_OFF



/*Interrupt service routine (ISR).On timer2 interrupt, program 
 will jump to this code location.  */    
void interrupt( void )
{
   char pulse;
/*generate two 50hz 180 degree out of phase pulses & externally
AND it with the 100Hz pwm pin to get a modulated 50Hz to drive
mosfets connected to a transformer in a push-pull configuration.
A/D conversion of the the output voltage can act as feed back to
adjust the duty-cycle ( not yet implemented in this code).
*/
   pulse = portb;  
   pulse.0 = ~ pulse.0;
   pulse.1 = ~ pulse.1;  
   portb = pulse;
   
    pir1.1=0;  //clear TMR2 to pr2 match interrupt flag
}
// The main code configures the pwm registers
void main()
{
   trisa = 255;
      trisb = 0;         //configure port B as output
      trisc = 0;       // portc as out put
    portb = 1;         //set port B to 1
    portc = 0;       //clear portc

    
    
// enable interrupts
    intcon.6=1;     //enable peripheral interrupt     
    intcon.7=1;     //enable global interrupt
    
    pie1.1=1;       //tmr2 to pr2 match interrupt

//configure the ccp1con register to enable PWM module.

/*ccpxm3:ccpxm0: mode select bits<3:0>
   11xx = for PWM mode.  
*/
   ccp1con=0b00001100;    //pwm mode
   

//PWM period=[(PR2)+1]*4*Tosc*(TMR2 prescaler value)

/*our pmw period is 10ms(100Hz),Tosc is 1/1000,000Hz & prescaler 
is 16.For which PR2+1 works out to 156.25. Lets round it to 156 &
make PR2 to 155. 
*/

//load the period value into pr2 register.
   pr2 = 155;

/*PWM duty cycle = (ccpr1l:ccp1con<5:4>)*Tosc*(TMR2 prescaler value)
Here i have taken 2ms as an example value for duty cycle, Tosc & pre-
scaler are same as above.We will get 10 bit values when we work with
larger duty cycle but for our example we get the value as 125.
*/    
//load the duty cycle value
   int duty_cycle;
   duty_cycle = 125; //duty cycle is for 2ms
   
   ccpr1l.7 = duty_cycle.9;  
   ccpr1l.6 = duty_cycle.8;           
   ccpr1l.5 = duty_cycle.7;  
   ccpr1l.4 = duty_cycle.6;  
   ccpr1l.3 = duty_cycle.5; 
   ccpr1l.2 = duty_cycle.4;  
   ccpr1l.1 = duty_cycle.3;  
   ccpr1l.0 = duty_cycle.2;  
   ccp1con.5 = duty_cycle.1;  
   ccp1con.4 = duty_cycle.0;  
 
   
     
/*timer2 control register
we have selected
bit6-3...(0000) 1:1 for post scaler
bit2.....(1) timer2 on
bit1-0...(11) prescaler is 16
*/

   t2con = 0b00000111;  
    



    while( 1 ); //do nothing & wait for tmr2 interrupt.
}

 

Regards

Raghunathan.

Edited by ra68gi

Share this post


Link to post
Share on other sites

You sure helping beginners electrocute themselves is a good idea?

Edited by emte

Share this post


Link to post
Share on other sites
You sure helping beginners electrocute themselves is a good idea?

 

Only after testing it fully will i post it. When i post my project i definitely will warn them of dangerous voltages and precaution they need to take.

 

Regards

Raghunathan.

Share this post


Link to post
Share on other sites

Hi guys,

Some more progress in the inverter project. I have included the adc module, adc is performed on the battery supply, the adc value is checked for low battery, annunciation is done by switching portb pins. If the the battery voltage gets too low, the inverter is switched off & a trip flag is set, which gets cleared only on resetting the micro. adc is also done on inverter feed back voltage. The initial (minimum) pulse width is made 3ms. As the inverter feed back voltage drops( due to loading or drop in battery voltage) the adc value will also drop. The difference in the drop between NO-load (255 -adc) and with load (x-adc) is the error feed back, which we multiply by 44/10( determined from the 10 bit duty cycle formula). This error is added to 188( which is the duty_cycle value for 3ms). The duty_cycle is controlled in the range of 3ms to 9ms, giving a dead band of about 1ms, which is safe for the mosfets commutation.

Some more test need to be performed.

#include <system.h>

// Set clock frequency to 1MHz.

#pragma CLOCK_FREQ 1000000

//set configuration fuse.
#pragma DATA _CONFIG, _RC_OSC & _WDT_OFF & _CP_OFF & _PWRTE_OFF

int duty_cycle;    //global variable
unsigned char adc;

/*Interrupt service routine (ISR).On timer2 interrupt, program 
 will jump to this code location.  */    
void interrupt( void )
{
   char pulse;
/*generate two 50hz 180 degree out of phase pulses & externally
AND it with the 100Hz pwm pin to get a modulated 50Hz to drive
mosfets connected to a transformer in a push-pull configuration.
A/D conversion of the the output voltage can act as feed back to
adjust the duty-cycle ( not yet implemented in this code).
*/
   pulse = portb;  
   pulse.0 = ~ pulse.0;
   pulse.1 = ~ pulse.1;  
   portb = pulse;
   
    pir1.1=0;  //clear TMR2 to pr2 match interrupt flag
}

void load_duty_cycle(void)   
{    
   ccpr1l.7 = duty_cycle.9;  
   ccpr1l.6 = duty_cycle.8;           
   ccpr1l.5 = duty_cycle.7;  
   ccpr1l.4 = duty_cycle.6;  
   ccpr1l.3 = duty_cycle.5; 
   ccpr1l.2 = duty_cycle.4;  
   ccpr1l.1 = duty_cycle.3;  
   ccpr1l.0 = duty_cycle.2;  
   ccp1con.5 = duty_cycle.1;  
   ccp1con.4 = duty_cycle.0; 
   }

void a_d(void)  //adc routine.
{ 
 adc=0; 
 adcon0.2=1;           //start ad conversion.
 while(adcon0.2==1)     //check if conversion is complete.
 {
 
 }
 adc=adres;           //if conversion is over, load adc value.
}    



// The main code configures the pwm registers
void main()
{
   trisa = 255;
      trisb = 0;         //configure port B as output
      trisc = 0;       // portc as out put
    portb = 1;         //set port B to 1
    portc = 0;       //clear portc

/* make RA0,RA1,RA2 pins as analog inputs & RA3 as +ref.*/
 adcon1=1;       
/*choose Fosc/2,RA0/AN0 as channel(0),go/done=0,adon=1.*/
 adcon0=0b00000001;  //we use Fosc/2 bec' we have chosen 1Mhz clk.    
    
// enable interrupts
    intcon.6=1;     //enable peripheral interrupt     
    intcon.7=1;     //enable global interrupt
    
    pie1.1=1;       //tmr2 to pr2 match interrupt

//configure the ccp1con register to enable PWM module.

/*ccpxm3:ccpxm0: mode select bits<3:0>
   11xx = for PWM mode.  
*/
   ccp1con=0b00001100; //
   

//PWM period=[(PR2)+1]*4*Tosc*(TMR2 prescaler value)

/*our pmw period is 10ms(100Hz),Tosc is 1/1000,000Hz & prescaler 
is 16.For which PR2+1 works out to 156.25. Lets round it to 156 &
make PR2 to 155. 
*/

//load the period value into pr2 register.
   pr2 = 155;
   
   
/*timer2 control register
we have selected
bit6-3...(0000) 1:1 for post scaler
bit2.....(1) timer2 on
bit1-0...(11) prescaler is 16
*/

   t2con = 0b00000111;  
    
/*PWM duty cycle = (ccpr1l:ccp1con<5:4>)*Tosc*(TMR2 prescaler value)
Here i have taken 2ms as an example value for duty cycle, Tosc & pre-
scaler are same as above.We will get 10 bit values when we work with
larger duty cycle but for our example we get the value as 125.
*/

//load the duty cycle values 
 duty_cycle = 188;
 load_duty_cycle();
 
 unsigned int sample;  //sample var holds the adc sample value.
 unsigned char b0;     //for loop var.
 unsigned char battery_adc;
 unsigned char inverter_adc;
 unsigned char error_adc;
 bit low_bat_flag;
 bit low_bat_trip_flag;
  
    while( 1 )
{
 
 adcon0=0b00000001;   //choose channel 0
 
check_battery:
 
 sample=0;             //initialize the sample to zero.
 for(b0=0;b0<10;b0++)  //take 10 adc samples.
 {
 a_d();                //call function a_d().
 sample += adc;        
 }
 battery_adc=sample/10;  //take average of 10 samples.
 
 if((battery_adc<202)&&(low_bat_flag == 0))
 {
 portb.3=1;
 low_bat_flag=1;
 }
 else
 if((battery_adc>219)&&(low_bat_flag == 1))
 {
 portb.3=0;
 low_bat_flag=0;
 }
 if((battery_adc<192)&&(low_bat_trip_flag == 0))
 {
 portb.2=1;                //shut down the mosfets/inverter
 low_bat_trip_flag=1;
 }
 
 while(low_bat_trip_flag == 1);  //do nothing until reset.
 
 
check_inverter:
 
 adcon0=0b00001001;   //choose channel 1(RA1)
 sample=0;             //initialize the sample to zero.
 for(b0=0;b0<10;b0++)  //take 10 adc samples.
 {
 a_d();                //call function a_d().
 sample += adc;        
 }
 inverter_adc=sample/10;  //take average of 10 samples.
 
 if(inverter_adc < 255)
 {
 error_adc = 255 - inverter_adc;    //error feed back value
 
 duty_cycle = (error_adc*44)/10 + 188;
 
 load_duty_cycle();       //load the new duty cycle value
 }
 
}
}

 

Any suggestion is appreciated.

 

Regards

Raghunathan

Edited by ra68gi

Share this post


Link to post
Share on other sites

Making it non-blocking would vastly increase its usefulness.

 

Stuck in while states when you can be doing other things is not super useful,

altho since this code does not do anything else, not a bad thing either.

 

Maybe cleaning up your if-else if block since part of the test is duplicated.

 

i take it your only using an 8bit adc? "unsigned char adc;"

 

Other than those, your code looks fine, could be a bit more modular but

is decent.

Share this post


Link to post
Share on other sites

Join the conversation

You are posting as a guest. If you have an account, sign in now to post with your account.
Note: Your post will require moderator approval before it will be visible.

Guest
Reply to this topic...

×   Pasted as rich text.   Paste as plain text instead

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.

Loading...
Sign in to follow this  

×
×
  • Create New...