Continue to Site

Welcome to EDAboard.com

Welcome to our site! EDAboard.com is an international Electronics Discussion Forum focused on EDA software, circuits, schematics, books, theory, papers, asic, pld, 8051, DSP, Network, RF, Analog Design, PCB, Service Manuals... and a whole lot more! To participate you need to register. Registration is free. Click here to register now.

precise 2us square wave generation not possible ?

Status
Not open for further replies.

vinayakdabholkar

Advanced Member level 4
Full Member level 1
Joined
Nov 29, 2009
Messages
114
Helped
0
Reputation
0
Reaction score
0
Trophy points
1,296
Location
goa
Visit site
Activity points
2,195
i tried generating a 2us square wave.
what i did is seRC0 high initially and then make it low when interrupt occurs and after exiting the ISR again set it high
so i get a 2us pulse but there is a undesired off time between two periods. Is is possible to get rid of it ?
Code:
 /*Example Source Code For PIC Timers
*   THis blinks LEDs on PORTB to show interrupt rates
*
* Barton Dring
* Dring Engineering Services
* www.eng-serve.com
*
* Example only!  Use any code at your own risk.
*/

// Interrupt Handler
void interrupt()
{

  // Timer0 Interrupt - Freq = 500000.00 Hz - Period = 0.000002 seconds
  if (INTCON.TMR0IF ==1) // timer 0 interrupt flag
  {
    LATC.RC0 = 0;      // Toggle PORTB bit0 LED
    INTCON.TMR0IF = 0;         // clear the flag
    INTCON.TMR0IE = 1;         // reenable the interrupt
    TMR0L = 250; 
              // reset the timer preset count
  }
}



// code starts here...
void main()
{

  // setup portb to show the interrupts by blibking LEDs
  TRISC = 0x00;    // PORT is all output...to show the interrupts
  PORTC = 0;       // start with all outputs low

//Timer0 Registers Prescaler= 1 - TMR0 Preset = 246 - Freq = 500000.00 Hz - Period = 0.000002 seconds
T0CON.T0CS = 0;  // bit 5  TMR0 Clock Source Select bit...0 = Internal Clock (CLKO) 1 = Transition on T0CKI pin
T0CON.T0SE = 0;  // bit 4 TMR0 Source Edge Select bit 0 = low/high 1 = high/low
T0CON.PSA = 1;   // bit 3  Prescaler Assignment bit...0 = Prescaler is assigned to the WDT
T0CON.T0PS2 = 0;   // bits 2-0  PS2:PS0: Prescaler Rate Select bits
T0CON.T0PS1 = 0;
T0CON.T0PS0 = 0;
T0CON.T08bit = 1;
TMR0L = 246;             // preset for timer register


// Interrupt Registers
  INTCON = 0;           // clear the interrpt control register
  INTCON.TMR0IE = 1;        // bit5 TMR0 Overflow Interrupt Enable bit...1 = Enables the TMR0 interrupt
  INTCON.TMR0IF = 0;        // bit2 clear timer 0 interrupt flag
  INTCON.GIE = 1; 
  LATC.RC0=1;          // bit7 global interrupt enable
  T0CON.TMR0ON=1;


  while(1)  //endless loop
  {
  
  LATC.RC0=1;
  }
}

- - - Updated - - -

The controller is PIC18F4520 at 20M crystal and compiler is MIkroC
 

Attachments

  • proteus_square_wave.png
    proteus_square_wave.png
    237.3 KB · Views: 115

The problem isn't clear at all. If you want to set the output permanently high, this can be achieved more easily. :smile:

In fact also the 2 us pulse width can't be exact as long as it's generated in software. Programming timer CCP outputs is the only way to get cycle accurate timing.
 
The problem isn't clear at all. If you want to set the output permanently high, this can be achieved more easily. :smile:

In fact also the 2 us pulse width can't be exact as long as it's generated in software. Programming timer CCP outputs is the only way to get cycle accurate timing.

yes you were right. so i gave up the idea of soft_PWM and used the ccp module to generate two pwms of same frequency and same duty.
i want to introduce delays in starting this pwms i.e
first pwm starts at 0s point
second starts at 0.5us
3rd at 1us and 4th at 1.5us where the period is 2us. I used the delay function of mikroC and got the 1us delay. How can i get the remaining delays ?
should i use a Dflip flops with clocks of 1/0.5us and 1/1.5us to delay the pwms ? or is there any other way in code ?
 

Need help here. Please some one point the error in the code.This is the code
Code:
//Definations of different variables used in the code
#define BOOL unsigned char
#define TRUE 1
#define FALSE 0
//PID definations
float PID_Kp, PID_Ki, PID_Kd;
float PID_Integrated;
float PID_Prev_Input;
float PID_MinOutput, PID_MaxOutput;
BOOL PID_First_Time;
float control;
float setpoint=246;
//PWM definations
unsigned short current_duty, old_duty, current_duty1, old_duty1;
float InputValue;

//function declarations
float PID_Calculate(float Setpoint, float InputValue);
void Reset_PID();
void Init_PID(float Kp, float Ki, float Kd, float MinOutput, float MaxOutput);
void ADCInit();
unsigned int ADCRead(unsigned char ch);

void main() 
{
TRISC=0;
PORTC=0;
AN0_bit=1;
ADCInit();                             //TRISD=0x00;
PWM1_Init(5000000);                    // Initialize PWM1 module at 500KHz
PWM2_Init(5000000);                    // Initialize PWM2 module at 500KHz

Reset_PID();
init_PID(10,10,10,225,276); // just inserted values for understanding. Here Kp=10,Ki=10,Kd=10, min_output and max_output also defined
while(1)                       // voltage ripple of 10% has been considered which comes to 120m. Max_out=1.32(26.4%) and Min_out=1.08(21.6%)
      {                         //so for simplicity 22 and 27 percent of 5V is considerd which results in Max_out=1.35 and Min_out=1.1
                              //need to call this function after definate period for simplicity
      InputValue=ADCRead(0); // call this function to get the feed back voltage value
      control=PID_Calculate(setpoint,InputValue);
      current_duty  = control;                 // initial value for current_duty
      current_duty1 = control;
      PWM1_Set_Duty(current_duty);        // Set current duty for PWM1
      PWM2_Set_Duty(current_duty1);         // Set current duty for PWM2
      PWM1_Start();                     // start PWM1
      Delay_us(1);
      PWM2_Start(); 

      //LATD=val;
      //LATC=(val>>8);

                          // start PWM2
      }
}

//function definations

float PID_Calculate(float Setpoint, float InputValue)
{
  float Err, ErrValue, DiffValue, Result;


  Err = SetPoint - InputValue;

  // --- calculate proportional value ---
  ErrValue  = Err * PID_Kp;

  // --- Calculate integrated value ---
  PID_Integrated = PID_Integrated + (Err * PID_Ki);
  // limit it to output minimum and maximum
  if (PID_Integrated < PID_MinOutput)
    PID_Integrated = PID_MinOutput;
  if (PID_Integrated > PID_MaxOutput)
    PID_Integrated = PID_MaxOutput;

  // --- calculate derivative value ---
  if (PID_First_Time)
  {
    // to avoid a huge DiffValue the first time (PID_Prev_Input = 0)
    PID_First_Time = FALSE;
    PID_Prev_Input = InputValue;
  }
  DiffValue = (InputValue - PID_Prev_Input) * PID_Kd;
  PID_Prev_Input = InputValue;

  // --- calculate total ---
  Result = ErrValue + PID_Integrated - DiffValue; // mind the minus sign!!!
  // limit it to output minimum and maximum
  if (Result < PID_MinOutput)
    Result = PID_MinOutput;
  if (Result > PID_MaxOutput)
    Result = PID_MaxOutput;
  return (Result);
}


void Reset_PID()
{
  PID_Integrated = 0.0;        //
  PID_Prev_Input = 0.0;
  PID_First_Time = TRUE;       //after reset PID being called will be first time and first_time has been defined as a boolean and 1 means TRUE
}

void Init_PID(float Kp, float Ki, float Kd, float MinOutput, float MaxOutput)
{
  PID_Kp         = Kp;
  PID_Ki         = Ki;
  PID_Kd         = Kd;
  PID_MinOutput  = MinOutput;
  PID_MaxOutput  = MaxOutput;
  PID_Integrated = 0.0;
  PID_Prev_Input = 0.0;
  PID_First_Time = TRUE;
}
//initialize ADC
void ADCInit()
{
 CMCON =CMCON | 0x07;             // Disable comparators
// ADCON0= 0x00;                 // ADC off Channel 0
 ADCON1= 0x30;
 ADCON2= 0x92;
}
//Read ADC value
unsigned int ADCRead(unsigned char ch)
  {
  ADCON0=0x00;
  if (ch>13) return 0;
  ADCON0= (ch<<2);
  ADON_bit=1;
  GO_DONE_bit=1;
  while(GO_DONE_bit);
  ADON_bit=0;
  return ADRES;
  }


What this code basically does is act as a PID controller and generates PWM
I am taking a input from ADC comparing it with a setpoint of 1.2V and running the PID algorithm on it and varing the duty cycle of my pwm. I am generating a PWM of 500K, but i am not getting a frequency of 500K now. What is the problem ? As a standalone 500K pwm generation code works fine, but now its not giving 500K frequency i.e(2us period).
 

Attachments

  • sch.png
    sch.png
    245.1 KB · Views: 84
  • Desktop.rar
    20.2 KB · Views: 56

Code:
PWM1_Init(5000000);                    // Initialize PWM1 module at 500KHz
PWM2_Init(5000000);                    // Initialize PWM2 module at 500KHz
Sets PWM frequency of 5MHz.

I'm not familiar with mikroC, how do you specify the clock frequency in your application?
 
Code:
PWM1_Init(5000000);                    // Initialize PWM1 module at 500KHz
PWM2_Init(5000000);                    // Initialize PWM2 module at 500KHz
Sets PWM frequency of 5MHz.
Thanks for correcting me there. changed the frequency to 500k, but still its not what i am expecting
I'm not familiar with mikroC, how do you specify the clock frequency in your application?
If i got you right , in mikroC it takes the frequency when making the project(new project wizard, which in my case is 20M). In code there is no need to specify
 

Attachments

  • sch.png
    sch.png
    244.2 KB · Views: 77

If i got you right , in mikroC it takes the frequency when making the project(new project wizard, which in my case is 20M). In code there is no need to specify
It hasn't been set correctly for simulation in your previously supplied *.dsn file, however.

It's no problem to find out in a PIC datasheet how the pwn-related registers have to be set, and you can check if mikroC does this correctly, e.g. in the debugger. If the result is correctly displayed in Proteus is a different question. In so far I think, it's a MikroC or Proteus problem which is neither my business.
 
void interrupt()
{

// Timer0 Interrupt - Freq = 500000.00 Hz - Period = 0.000002 seconds
if (INTCON.TMR0IF ==1) // timer 0 interrupt flag
{
LATC.RC0 = 0; // Toggle PORTB bit0 LED
INTCON.TMR0IF = 0; // clear the flag
INTCON.TMR0IE = 1; // reenable the interrupt
TMR0L = 250;
// reset the timer preset count
}
}

when timer 0 will overflow then it must be reloaded with 246 ,think.why 250?
 

I don't see the point of reloading timer0. Hardware PWM should work without reloading a timer. Realistically, you can never keep up with 500 kHz in software.
 

void interrupt()
{

// Timer0 Interrupt - Freq = 500000.00 Hz - Period = 0.000002 seconds
if (INTCON.TMR0IF ==1) // timer 0 interrupt flag
{
LATC.RC0 = 0; // Toggle PORTB bit0 LED
INTCON.TMR0IF = 0; // clear the flag
INTCON.TMR0IE = 1; // reenable the interrupt
TMR0L = 250;
// reset the timer preset count
}
}

when timer 0 will overflow then it must be reloaded with 246 ,think.why 250?


yes it was supposed to be 246. But as Fvm says its not possible to maintain 500K in software. What was trying there is
after loading the count 246,the statement T0CON.TMR0ON=1 starts the counter and at the end of this statement count becomes F7, and then in an infinite while it goes FF+1 and a interrupt occurs and the control goes to interrupt service routine.Here is the main problem
When the control goes to interrupt service routine as per the stopwatch in MPLAB 12 instruction cycles pass, i.e 200ns*12
So if it was less instruction cycles passing then you could have compensated for it by loading a higher count into timer when you reload it
But in my case 12 cycles cannot be compensated for.

- - - Updated - - -

In so far I think, it's a MikroC or Proteus problem which is neither my business.

I think its not coming proper because the simulation in proteus is not running in real time.I would have to check the outputs on an oscilloscope
 

#include<p18f4520.h>
#include <pwm.h>
#include<timers.h>
#include<delays.h>


//configuration bits being set
//_CONFIG(FOSC_HS & WDTE_OFF & PWRTE_ON & CP_OFF & BOREN_ON & LVP_OFF & CPD_OFF & WRT_ON & DEBUG_OFF);
#pragma config OSC=HS, FCMEN=ON, WDT=OFF, IESO=ON, XINST=OFF, LVP=OFF
//function declarations


//Main function body
void main(void)
{


char period=0x00;
//unsigned char outputconfig=0,outputmode=0,config=0;
unsigned int duty_cycle=0;
OpenTimer2(TIMER_INT_OFF & T2_PS_1_1 & T2_POST_1_1);

//------------------Configure pwm ----------------------------------------
period = 9;
OpenPWM1( period); //Configure PWM module and initialize PWM period



//---------------------set duty cycle---------------------------------------------------------
duty_cycle = 0x00F0;
SetDCPWM1(duty_cycle); //set the duty cycle
//-------------------set pwm output---------------------------------------------------------.
//outputconfig = FULL_OUT_FWD ;
//outputmode = PWM_MODE_1;
//SetOutputPWM1( outputconfig, outputmode); //output PWM in respective modes

while(1); //observe output on CCP1 pin

//--------------------------close pwm----------------------------------------
//ClosePWM1();
}


can some one look at this code ? Please tell me why its not generating for a period of 9, since for my calculations
2u=(10+1)*4*TOSC*1, PR2 is 9 but nothing comes
Its compiled in mplab 20M fosc
 

Code:
#include<p18f4520.h>
#include<timers.h>
#include<delays.h>
void init_PWM();
//unsigned short control=0x0003;
//--------------------------------------------------------------------------------------------------
//VARIABLE DEFINITIONS
unsigned short control;
#define BOOL unsigned char
#define TRUE 1
#define FALSE 0
//PID definations
float PID_Kp, PID_Ki, PID_Kd;
float PID_Integrated;
float PID_Prev_Input;
float PID_MinOutput, PID_MaxOutput;
BOOL PID_First_Time;
unsigned short control;
float mapped_value;
float Setpoint=246;
//PWM definations
unsigned short current_duty, old_duty, current_duty1, old_duty1;
float InputValue;
float resultmap;
float MinOutput=225; 
float MaxOutput=275;
float Kp=1;
float Ki=1;
float Kd=1;



//----------------------------------------------------------------------------------------------------
//FUNCTION DECLARATIONS
void init_PWM();
void set_dutycycle(unsigned short control);
unsigned short mapping_control(float result);
int round(float Du);
float PID_Calculate(float Setpoint, float InputValue);
void Reset_PID();
void Init_PID(float Kp, float Ki, float Kd, float MinOutput, float MaxOutput);
void ADCInit();
unsigned int ADCRead(unsigned char ch);
//---------------------------------------------------------------------------------------------------


void main(void)
{
TRISC=0;
PORTC=0;
TRISA=0xFF;
void Reset_PID();
void Init_PID(float Kp,float Ki,float Kd,float MinOutput,float MaxOutput);
void init_PWM();
void ADCInit();
InputValue=ADCRead(0);
resultmap=PID_Calculate(Setpoint,InputValue);
control=mapping_control(resultmap);
set_dutycycle(control);
//while(1);
}

void init_PWM()
{
PR2=0x09;
T2CON=0b00000100;
CCP1CON=0b00001100;
//void set_dutycycle( unsigned short control);
}

void set_dutycycle(unsigned short control)
{
//CCPR1L=0b00000000;
//CCP1CON=0b00111100;
CCPR1L=(control>>2);
CCP1CON |=(control<<4);
}

//-----------------------------------------------------------------------------------------------------
// this function is designed to map the output of PID calculate to the range between 0-39 of duty cycle
unsigned short mapping_control(float resultmap)
{
float Du;
unsigned short mapped_value;
if(resultmap>=275)
   Du=39;
else if (resultmap>=225)
   Du=(resultmap-225)*39/50;
else
   Du=0;
mapped_value=round(Du);
return mapped_value;
} 

int round(float Du)
{
float a;
int R,b;
a=Du;
b=(int)a;
if(Du-b >=0.5)
  R=b+1;
else
  R=b;
return R;
}
//-------------------------------------------------------------------------------------------------------
//-------------------------------------------------------------------------------------------------------
float PID_Calculate(float Setpoint, float InputValue)
{
  float Err, ErrValue, DiffValue, Result;


  Err = Setpoint - InputValue;

  // --- calculate proportional value ---
  ErrValue  = Err * PID_Kp;

  // --- Calculate integrated value ---
  PID_Integrated = PID_Integrated + (Err * PID_Ki);
  // limit it to output minimum and maximum
  if (PID_Integrated < PID_MinOutput)
    PID_Integrated = PID_MinOutput;
  if (PID_Integrated > PID_MaxOutput)
    PID_Integrated = PID_MaxOutput;

  // --- calculate derivative value ---
  if (PID_First_Time)
  {
    // to avoid a huge DiffValue the first time (PID_Prev_Input = 0)
    PID_First_Time = FALSE;
    PID_Prev_Input = InputValue;
  }
  DiffValue = (InputValue - PID_Prev_Input) * PID_Kd;
  PID_Prev_Input = InputValue;

  // --- calculate total ---
  Result = ErrValue + PID_Integrated - DiffValue; // mind the minus sign!!!
  // limit it to output minimum and maximum
  if (Result < PID_MinOutput)
    Result = PID_MinOutput;
  if (Result > PID_MaxOutput)
    Result = PID_MaxOutput;
  return (Result);
}
//---------------------------------------------------------------------------------------------------------------------------------------------

void Reset_PID()
{
  PID_Integrated = 0.0;        //
  PID_Prev_Input = 0.0;
  PID_First_Time = TRUE;       //after reset PID being called will be first time and first_time has been defined as a boolean and 1 means TRUE
}
//----------------------------------------------------------------------------------------------------------------------------------------------
void Init_PID(float Kp, float Ki, float Kd, float MinOutput, float MaxOutput)
{
  PID_Kp         = Kp;
  PID_Ki         = Ki;
  PID_Kd         = Kd;
  PID_MinOutput  = MinOutput;
  PID_MaxOutput  = MaxOutput;
  PID_Integrated = 0.0;
  PID_Prev_Input = 0.0;
  PID_First_Time = TRUE;
}
//------------------------------------------------------------------------------------------------------------------------------------------------
//initialize ADC
void ADCInit()
{
 CMCON =CMCON | 0x07;             // Disable comparators
// ADCON0= 0x00;                 // ADC off Channel 0
 ADCON1= 0x30;
 ADCON2= 0x92;
}
//------------------------------------------------------------------------------------------------------------------------------------------------
//Read ADC value
unsigned int ADCRead(unsigned char ch)
  {
  ADCON0=0x00;
  if (ch>13) return 0;
  ADCON0= (ch<<2);
  ADCON0bits.ADON=1;
  ADCON0bits.GO_DONE=1;
  while( ADCON0bits.GO_DONE);
  ADCON0bits.ADON=0;
  return ADRES;
  }


I get a error "ADC conversion clock period (5e07) violates the minimum required Tad time "
Please help
 

Status
Not open for further replies.

Similar threads

Part and Inventory Search

Welcome to EDABoard.com

Sponsor

Back
Top