Continue to Site

Welcome to our site!

Electro Tech is an online community (with over 170,000 members) who enjoy talking about and building electronic circuits, projects and gadgets. To participate you need to register. Registration is free. Click here to register now.

  • Welcome to our site! Electro Tech is an online community (with over 170,000 members) who enjoy talking about and building electronic circuits, projects and gadgets. To participate you need to register. Registration is free. Click here to register now.

Achieving low PWM frequencies

Status
Not open for further replies.

PICMICRO

New Member
I am trying to make a small LED stroboscope using PIC16F72.
I am also including a display to show the frequency of flickering in RPM.
For this I am using two pots for tuning, one for adjusting frequency and the other for adjusting duty cycle.
**broken link removed**

I would love to have the PWM frequency down to 8 hz which according to this formula
**broken link removed**

requires that I use Fosc = 131 Khz at most. So, I choosed to run the pic with a 32768 Hz crystal. It would be fine, but I am not getting enough cpu speed to do the multiplexed display interrupt routine.
Any help please?

Here is my code.
Code:
#include<htc.h>
#define _XTAL_FREQ 32768

#define D0 RC7
#define D0_tris TRISC7
#define D1 RC6
#define D1_tris TRISC6
#define D2 RC5
#define D2_tris	TRISC5
#define D3 RC4
#define D3_tris TRISC4
#define CCP_tris TRISC2
#define Freq_input_tris TRISA0
#define Duty_input_tris TRISA1
#define Dutyorfreq CHS0
#define Display PORTB
#define Display_tris TRISB
const char segdata[10] = {
// 7-bits for displaying numeral 0,1,2,3...
// most be negated when used for common anode
0b01111110, // 0
0b00110000, // 1
0b01101101, // 2
0b01111001, // 3
0b00110011, // 4
0b01011011, // 5
0b01011111, // 6
0b01110000, // 7
0b01111111, // 8
0b01111011  // 9
};
// voltatile necessary for all variables used by interrupt
volatile char count0;  // counter for first display
volatile char count1;  // counter for second display
volatile char count2;  // counter for third display
volatile char count3;  // counter for 4th display

void interrupt isr(void){   // timer0 interrupt This function is automatically called everytime Timer0 Register overflows 
	static unsigned char turnof = 0;  // static necessary to retain data between sucessive call to function.
                                          // initialization is done only once 
					  // it is variable to cycle through the display slection
	switch(turnof){
			case 0:  // Turn of Display 1
			D0 = 1; //
			D1 = 1; //  Deselct all display
			D2 = 1; //
			D3 = 1;
			Display = ~segdata[count1];
			D0 = 0; // select Display1
			break;
			case 1:
			D0 = 1; //
			D1 = 1; //  Deselct all display
			D2 = 1; //
			D3 = 1;
			Display = ~segdata[count2];
			D1 = 0; // select Display1
			break;
			case 2:
			D0 = 1; //
			D1 = 1; //  Deselct all display
			D2 = 1; //
			D3 = 1;
			Display = ~segdata[count2];
			D2 = 0; // select Display1
			break;
			case 3:
			D0 = 1; //
			D1 = 1; //  Deselct all display
			D2 = 1; //
			D3 = 1;
			Display = ~segdata[count3];
			D3 = 0; // select Display1
	}
	turnof++;
	if(turnof>3) turnof = 0;
	TMR1 = 150;
	T0IF = 0;  			
}


void main(){
char i;
int sum = 0;
int rpm = 0;
int period = 0;
char desired_freq = 0;
// minimum frequency, 8 hz (480 rpm)
// maximum frequency, 158 hz (9480 rpm)
// so, ADRES = 0 corresponds to 8hz (1250 * 100 us time period)
// ADRES = 255 corresponds to 158 hz (
__delay_ms(100);
		
Display_tris = 0; // all PortB output
D0_tris = 0;
D1_tris = 0;
D2_tris = 0;
D3_tris = 0;
CCP_tris = 0;
Duty_input_tris = 1;
Freq_input_tris = 1;

char xxx;


    OPTION = 0b11010000 ;// Disable internal weak pullup,,internal clock source for T0
                             // ,, assign prescaler to TMR0,prescaler 100
	GIE = 1;
	TMR0IE = 1;// enable timer 0 interrupt

    T2CON = 0b00000101; // 1:4 prescale
	CCP1CON = 0b000011111; // pwm mode
	ADCON1 = 0b00000100; // RA0, RA1 and RA3 analog inputs
	ADCON0 = 0b11000011; // RC clock, channel 0, Done, - , ADON
count0 = 0;
count1 = 0;
count2 = 0;

while (1){

	sum = 0;
	CHS0 = 0; // frequency reading channel
	__delay_us(50);
	for(i=10;i>=1;i--){
	GODONE = 1;
	while(GODONE);
	sum+=ADRES;
	__delay_us(10);
	}
	sum /= 10;
	
	desired_freq = sum*150/255 + 8;
	
	PR2 = 32768/((int)desired_freq*4*4) - 1; // 1:4 prescale
	rpm = 32768*60/((PR2+1)*4*4);
// extract the 4 digits of rpm
	count0 = rpm % 10;
	rpm /= 10;
	count1 = rpm % 10;
	rpm /= 10;
	count2 = rpm % 10;
	rpm /= 10;
	count3 = rpm;
	
	CHS0 = 1; // duty cycle reading channel
	__delay_us(50);
	for(i=10;i>=1;i--){
	GODONE = 1;
	while(GODONE);
	sum+=ADRES;
	__delay_us(10);
	}
	sum /= 10;

	CCPR1L = sum; // duty cycle is equal to the avg of analog reading

	// wait for few second before looping
	for(i=20;i>=1;i--){
	__delay_ms(100);
	}
 }

}
 
Have a look at this thread. In it I show how to use the "Special Event Trigger" of the PWM module to generate servo signals. It should be easily modifiable to do what you require.

Edit, there's an interrupt drive version on page 2.

Mike.
 
Last edited:
Hi, Pommie
I looked at your thread.
But since this is the first time I am working with Compare Module, would you please, tell me the your algorithm there? like
1. configure Timer1 to run at ... speed
2. Initialize ..

Your comments must have explained it all, but I seem quite unable to grasp it.

I have just read the Datasheet of Compare module, and it seems plausible to me to have accurate frequencies down to 8hz.

One, quick question,
I will be using Duty-Cycle of around 5% for the LED (low duty-cycle necessary for freezing action), so it will be quite dark if I use, say a 330ohm resister for the led
Can I replace it with 1ohm resister? because even though current will tend to be huge, it will last for only brief time. Will a brief short damage the PIC?
 
Seems like I got Pommie's code expect for one point.
Don't the special event trigger automatically sets the GO bit? Why are you setting it manually?
 
I had forgotten that it starts the conversion as I originally wrote it for a 16F876 and the CCP1 module on that chip doesn't start it.

As for the LED current, the pic will probably survive unscathed but will only provide 20mA. Add a pnp and pulse the LED at the allowed pulse current.

Mike.
 
Thanks for both of the answers.
I think, Compare module is made just for this purpose, (Generating frequencies :)).

And It appears that, I should start hunting for zenon-flash tube, the LED don't appear bright enough enough at 5% duty cycle. And at 5% the stationary object (rotating fan) appears blurry. So, It seems that, I should be going to 1% Duty Cycle and Zenon Flash.
 
Here is what my project looks like.
**broken link removed**

Sorry for blurry image.
 
Last edited:
Thanks for both of the answers.
I think, Compare module is made just for this purpose, (Generating frequencies :)).

And It appears that, I should start hunting for zenon-flash tube, the LED don't appear bright enough enough at 5% duty cycle. And at 5% the stationary object (rotating fan) appears blurry. So, It seems that, I should be going to 1% Duty Cycle and Zenon Flash.

Yes, the compare module is very useful for any timing issues.

Xenon flash tubes require high voltages. I would try a super bright LED with a FET switching it.

Mike.
 
Status
Not open for further replies.

Latest threads

Back
Top