# how to generate 50hz frequency from PIC16F84A or 877A

Status
Not open for further replies.

#### babatundeawe

##### Full Member level 5
highest period of pwm in pic16f

i am working on a project to construct an inverter using PIC16F84A or 877A. the micro is to control the whole operation of the inverter and also to generate the frequency and also using pulse width modulation regulation. pls any idea, circuit diagram and source code will be appreciated. thanks in anticipation.

#### deepu_ttc

##### Member level 5
howto generate a frequency with pic

y dont u use 2 timer( in pic ) to generate a pwm signal and generate another square wave with other timer use a ckt that have a logic such that it has 2 i/p's and 2 o/p's and the behaviour will be if square wave is 1 then o/p-1 will be pwm and o/p-2 will be 0 and when square wave is 0 then o/p-1 will be 0 and o/p-2 will be pwm then connect these 2 o/p's to 2 bjts connected in series so u get required frequency

#### VVV

how to program a servo with 877a

You can use the CCP modules in the PIC16F877A, together with TMR2. Both can be used to produce PWM pulses.
What kind of inverter are you going to design? There are newer parts that can handle the bridge. For example PIC16F690. Check the datasheet.

### babatundeawe

Points: 2

#### progart

##### Newbie level 4
how to generate 50hz ac

You can use MCU's interrupt (from TMR)function for your project and get stronger results.
Calculate your TMR prescaler values which MCU's oscillator and write basic interrupt program...

#### xorcise

##### Full Member level 2
configure ccp module as 50hz pwm output

I have written tons of 50Hz PWM code for servos. The following might be helpful for some of your own ideas. It runs 8 servos at super high resolution using mikroBasic.

SERVO8_10000 occupies less than 200 ROM and can individually position 8 servos to within 1/10000th of an 180 degree arc +/- 0.1%...if you have such a type of 50Hz servo. Add USART easily and without jitter and interruptions. This code example will work on P16's running @ 20Mhz. It is easily ported to P18's and uses NO INLINE ASSEMBLER.

Code:
Code:
program SERVO8_10000
'*********************************************************************************
' SERVO8_10000 by Warren Schroeder on October 3, 2006
' Program successfully compiled using mikroBASIC 5.0.0.0
' Tested on 16F877A @ 20MHz

' Servo8_10000 is a demonstration of managing 8 servos every 20ms with more
' than 13-bit position resolution without using inline assembler code.
' You can theoretically achieve 10,000 servo positions per servo if using
' 500us to 2500us range servos and a 20MHz oscillator. Any servo timing range
' is possible up to maximum of 2500us.
'
' Theory of operation is to give each servo an exact 2500us frame to do its
' position duty-cycle.  The servo turns ON at the start of the 2500us frame,
' completes its duty-cycle, turns OFF, and then waits for the next frame. At
' the next 2500us frame a new servo is then turned ON and the cycle is repeated.
' Each of the 8 servos occupies a 2500us slot and refreshed sequentially.  All
' 8 servos thus require 20ms to complete.  At this point, we go back to the first
' servo and repeat this whole process. This method creates exact 20ms periods
' between same servo time frames, which is required for 50Hz servos.
'
' The example below assumes using servos with a timing range of 900us to 2100us
' Timer1 is setup for 0.2us per count (no prescaler @ 20MHz).  Therefore, the min
' and max position values for this servo would be 4500 to 10,500.  To acheive 90
' degrees of motion, or 1500us, the formula is 1500 x 5 = 7500.
'
' To use RX with USART I recommend using the mB USART library commands.  These
' commands do not implement the USART Interrupts and are ideal for this program.
' Put the USART_DATA_READY and USART_READ function in the two wait loops in the
' MAIN program.  USART has a 2-byte buffer which will not fill up and is not
' affected by the Timer interrupts as long as you take advantage of reading it
' regularly.  Using the two wait loops is the best time to check the RX buffer.
'**********************************************************************************

symbol T1_Switch = T1CON.TMR1ON
symbol T1_Int_Flag = PIR1.TMR1IF
symbol T1_Int_En = PIE1.TMR1IE
symbol T0_Int_Flag = INTCON.TMR0IF
symbol T0_Int_En = INTCON.TMR0IE
const IsEnabled = 1
const IsDisabled = 0
const IsSet = 1
const IsRst = 0
const IsOn = 1
const IsOff = 0
dim intflag as boolean
dim servo as byte
dim T1 as word absolute $0E dim T0 as byte absolute$01
dim pos as word[8]

sub procedure interrupt
If T0_Int_Flag = IsSet Then      ' if Timer0 interrupt
T0 = -196                     ' load Frame 196 x 12.8us = 2508us interrupt cycle
Clearbit(PORTB, servo)        ' force servo off...in case value was wrong
servo = inc(servo) And 7      ' next servo
Setbit(PORTB, servo)          ' turn on next servo
T1 = 0 - pos[servo]           ' load servo position...each count is 0.2us
T1_Switch = IsOn              ' turn Timer1 On
T1_Int_Flag = IsRst           ' reset Timer1 Interrupt Flag
T0_Int_Flag = IsRst           ' reset Timer0 Interrupt Flag
Else                             ' if Timer1 interrupt
Clearbit(PORTB, servo)        ' turn off servo
T1_Switch = IsOff             ' turn Timer1 Off
End If
intflag = not(intflag)           ' interrupt flag status
end sub

main:
TRISB = 0
OPTION_REG = $85 ' Timer0 prescaler = 64 = 12.8us PORTB = 0 INTCON =$E4                     ' GIE, PEIE, Timer0 Enabled; Timer0 Flag Set
T1CON = 0                        ' Timer1 Off; No prescaler
For servo = 0 to 7
pos[servo] = 7500             ' set for 1500us mid-point
Next servo
intflag = False
servo = 0
T1 = 0 - 4500                    ' load Timer1
T1_Int_Flag = IsRst              ' reset Timer1 Interrupt Flag
T1_Int_En = IsEnabled            ' Timer1 Interrupt Enabled
T1_Switch = IsOn                 ' Timer1 On
T0 = -196                        ' load TMR0 for 2500us Interrupt Cycle Count
T0_Int_En = IsEnabled            ' reset Timer0 Interrupt Flag
Setbit(PORTB, 0)                 ' turn on first servo

While 1=1
While intflag = False         ' WAIT until Timer1 Interrupt
nop                          ' place USART Read routines in here
Wend
While intflag = True          ' WAIT until Timer0 Interrupt
nop                          ' place USART Read routines in here
Wend
Wend

end.

#### babatundeawe

##### Full Member level 5
pic 50 hz inverter source code

VVV said:
You can use the CCP modules in the PIC16F877A, together with TMR2. Both can be used to produce PWM pulses.
What kind of inverter are you going to design? There are newer parts that can handle the bridge. For example PIC16F690. Check the datasheet.

thanks for your post. i really appreciate the way you put it pls can you be more explanatory the way you did with the sg3525. pls i will appreciate if i can see a little source code and scematics. because i ve not tried anything on ccp and pwm with any micro. thanks in anticipation

#### xorcise

##### Full Member level 2
how to generate 50hz sine wave for 100 points

VVV said:
You can use the CCP modules in the PIC16F877A, together with TMR2. Both can be used to produce PWM pulses.
What kind of inverter are you going to design? There are newer parts that can handle the bridge. For example PIC16F690. Check the datasheet.

You cannot get 50Hz (20ms period) from the CCP PWM module, unless you run the PIC with less than 1MHz oscillator.

#### VVV

pic16f84 pwm code

xorcise is right about the oscillator frequency for 50Hz output.
But I don't think the inverter will be running at 50Hz. That is the output frequency, which is really just a modulation for the HF signal.

I will try to dig up some schematics.

#### mpopovics

##### Junior Member level 1
generate a pulse signal with pic16f84

Is there any way to generate sine wave?
Means, real sinewave.

#### VVV

servo8_10000 by warren schroeder

babatundeawe,

Can you give more details on this inverter? Input/ output voltages, power and desired waveform?

#### Mike K8LH

##### Full Member level 2
pwm pic 50hertz

xorcise said:
I have written tons of 50Hz PWM code for servos. The following might be helpful for some of your own ideas. It runs 8 servos at super high resolution using mikroBasic.

SERVO8_10000 occupies less than 200 ROM and can individually position 8 servos to within 1/10000th of an 180 degree arc +/- 0.1%...if you have such a type of 50Hz servo. Add USART easily and without jitter and interruptions. This code example will work on P16's running @ 20Mhz. It is easily ported to P18's and uses NO INLINE ASSEMBLER.
Nice example and method.

Here's another 8 channel (port b) method that uses the CCP "compare" mode with a 4 MHz clock for 1 usec pulse width resolution and 20 msec Servo period;

Code:
static unsigned char n = 0;
static unsigned int Pulse [] = { 1500, 1500, 1500, 1500,
1500, 1500, 1500, 1500,
20000 };
static unsigned char Servo = 1;

void isr_hi ()
{
/****************************************************************
*  K8LH Crazy-8 Hi-Rez Soft 8-channel (PORTB) Servo Algorithm  *
****************************************************************/

if (PIR1bits.CCP1IF == 1)     // if CCP1 "compare" interrupt
{ LATB = Servo;               // output new Servo pulse and
CCPR1 += Pulse[n];          // setup next "compare" value

PIR1bits.CCP1IF = 0;        // clear CCP1 interrupt flag

Pulse[8] -= Pulse[n++];     // adjust end-of-cycle off time
Servo <<= 1;                // and prep for next channel

if (n == 9)                 // if end of a 20-msec cycle
{ n = 0;                    // reset array index
Pulse[8] = 20000;         // reset the 20.0-msec period
Servo++;                  // reset Servo shadow to Servo 1
}
}
}

xorcise said:
VVV said:
You can use the CCP modules in the PIC16F877A, together with TMR2. Both can be used to produce PWM pulses.
What kind of inverter are you going to design? There are newer parts that can handle the bridge. For example PIC16F690. Check the datasheet.
You cannot get 50Hz (20ms period) from the CCP PWM module, unless you run the PIC with less than 1MHz oscillator.
Actually you can. Sort of (grin).

The secret is to break up the 20 msec Servo period into smaller PWM "frames" and stuff the PWM duty cycle register during the period match interrupt with the value for the next "frame".

Here's a 4-pin 8 channel example using a 4 MHz clock and a 74HC238 decoder IC which is modulated by the PWM CCP1 pin (this is not the code for the 12F683 design shown below);

Code:
unsigned char select = 0;       // Servo channel number, 0..7
unsigned char frame = 10;       //
unsigned int pulse1;

/*                                                               *
*  Servo[] array elements contain Servo pulse width values in   *
*  the range of 3000..9000 (250-nsec 'ticks') which represent   *
*  extended Servo pulse width ranges of 750 to 2250-usecs       *
*                                                               */

static unsigned int Servo [] = { 6000, 6000, 6000, 6000,
6000, 6000, 6000, 6000 };

/*****************************************************************
*  K8LH 8-Channel 74HC238 Hi-Rez 'PWM' Servo Algorithm Example  *
*****************************************************************/
#pragma interrupt isr_hi

void isr_hi ()
{ if(PIR1bits.TMR2IF)
{ PIR1bits.TMR2IF = 0;            // clear TMR2 interrupt flag

/**************************************************************
*  setup 74HC238 address lines and our work variables for    *
*  the next servo channel interval during the final (10th)   *
*  frame of the current servo channel interval (the final    *
*  frame in each interval will always have a 0% duty cycle   *
*  and all 74HC238 outputs are 'off' so it will be safe to   *
*  change the address lines)                                 *
*                                                            */
if(frame == 10)             // 10 PWM frames/Servo interval
{ frame = 0;                // reset PWM frame number
select %= 8;              // 8 Servo intervals/20-msec cycle
pulse1 = Servo[select];   // setup 'pulse' work variable

LATB = (LATB & 0b11111000) | select;  // set address lines

select++;                 // preset for next interval
}
frame++;                    // bump for next interrupt

/**************************************************************
*  setup CCP1 PWM duty cycle for next 250-usec PWM 'frame'   *
*                                                            */

if(pulse1 > 1000)           // if pulse1 > 250-usecs
{ CCPR1L = 250;             // do a 100% duty cycle frame
pulse1 -= 1000;           // subtract 250-usecs
}
else                        // do a variable or 0% frame
{ CCP1CONbits.CCP1Y = (pulse1 & 1);
CCP1CONbits.CCP1X = (pulse1 & 2);
CCPR1L = (pulse1 >>= 2);
pulse1 = 0;               // remaining frames are %0
}
}
}

#### xorcise

##### Full Member level 2
pic16f84a frequency tmr0

You certainly have a talent for this. I hadn't considered the CCP module in the first application... very nice. I've been programming PIC's for a couple years now and still learn something new every day.

#### ldanielrosa

##### Member level 4
pic16f84 square wave

I suppose I jumped in a bit late.

My approach would be similar to what progart said. Whatever the crystal frequency (I will assume 20MHz), I would assign a timed interrupt for 1024 Tosc (256 Tins) which is the highest frequency that would allow the full resolution of the PWM. This would give me 390.625 PWM periods (51.2 uS) per AC output cycle.

The '877 has two PWM outputs that share the same period, but have independent duty cycles. I would use them in tandem- one controlling the positive half cycles and the other for the negative, only one would be active at a time.

The means of determining the instantaneous period would be by adding a constant to a rolling sum. In this case a 24 bit sum should be accurate to about 0.001Hz. At each timed interrupt I would add 42,950 (0x00A7C6) to the sum, use the most significant 9-11 bits (depending on the resolution you want) to determine which phase (PWM output) and fetch a value from a lookup table for the PWM period.

MUSTAFA19

Points: 2