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.

100 hz tone on a PIC in C

Status
Not open for further replies.

baxterdmutt

Member
I am having a bit of trouble figuring out how to generate a 100hz tone on a PIC using C. I need it to be generated in the pic so that I can adjust it up and down programatically. I have seen a few examples using PWM and then external filters, but that won't work for me.
Any help would be greatly appreciated.
 
Last edited:
A 100-Hz square wave or sine wave? What PIC? What frequency oscillator? Why can't you use the PWM module?
 
Last edited:
The problem he is probably talking about with pwm is that 100hz is too slow at around 4MHz oscillator !
A software solution is simple though. Turn on a pin for half period, turn off pin for other half of period (Repeat).
At 4Mhz we have 1Mhz per instruction, so we need to wait (1M/100 ) 10k instructions for full period, 5k for half.
 
The problem he is probably talking about with pwm is that 100hz is too slow at around 4MHz oscillator !

The PWM module works fine at low frequencies. If he just wanted a "fixed frequency" 100-Hz sine wave tone he might do it like this;

Code:
;
;  50-Hz Sine Wave Generator using PWM module and CCP1 output
;
;  clock = 4 MHz, PWM period = 1/100(Hz)/50(steps)=200 usecs
;  setup PR2 = 199, prescaler 1
;
;  #define r08 const rom unsigned char
;
;  r08 sine = { 100,106,112,118,124,130,136,142,148,153,
;               158,163,168,172,177,180,184,187,190,192,
;               195,196,198,199,199,200,199,199,198,196,
;               195,192,190,187,184,180,177,172,168,163,
;               158,153,148,142,136,130,124,118,112,106,
;                99, 93, 87, 81, 75, 69, 63, 57, 51, 46,
;                41, 36, 31, 27, 22, 19, 15, 12,  9,  7,
;                 4,  3,  1,  0,  0,  0,  0,  0,  1,  3,
;                 4,  7,  9, 12, 15, 19, 22, 27, 31, 36,
;                41, 46, 51, 57, 63, 69, 75, 81, 87, 93 };
;
;  void interrupt();        // 200 usec interrupts
;  { pir1.TMR2IF = 0;       // clear timer 2 interrupt flag
;    ccpr1l = sine[n++];    // duty cycle for next period
;    if(n == 50) n = 0;     // reset 'n' at end-of-period
;  }
;
Since the OP wants a variable frequency he should probably consider using DDS (Direct Digital Synthesis) instead.

I have used DDS-PWM in a 12F683 Tone Generator project to produce CTCSS sine wave tones in the range of 67.00 to 254.10 Hz (0.01-Hz resolution).

The OP should tell us more about what he's trying to do.

Cheerful regards, Mike
 
Last edited:
The PWM module works fine at low frequencies. If he just wanted a "fixed frequency" 100-Hz sine wave tone he might do it like this;



I have used DDS-PWM in a 12F683 Tone Generator project to produce CTCSS sine wave tones in the range of 67.00 to 254.10 Hz (0.01-Hz resolution).

The OP should tell us more about what he's trying to do.

Cheerful regards, Mike
It is a CTCSS set of sine waves that I am after. I don't suppose you would be willing to share your Tone Generator Project with me if it is in C. I have one in Assembly, but that isn't good for me since I don't understand it very well.

Sorry I didn't explain myself better but I thought if I just found a way to do the tones I wouldn't need any more info.

Thanks
 
None of my Tone Generators were written in C. Sorry.

Some notes which may or may not be useful for more recent CTCSS versions using 12F1822 or 16F18xx devices and an 8388608-Hz xtal;

Code:
;
;  12F/16F1xxx DDS-PWM CTCSS Access Tone Generator Notes
;  =====================================================
;
;  using an 8388608 Hz crystal
;
;    Tcy = 1 / 8388608 * 4 = 476.837158203125 nsecs
;
;  using a 200 cycle PWM period provides a DDS frequency of
;
;    Fdds = 1 / (200 Tcy) = 10,485.76 Hz
;
;  frequency resolution using a 24 bit phase accumulator is
;
;    Fres = Fdds / 2^24
;    Fres = 10485.76 / 16777216 = 0.000625 Hz
;
;  dds tuning word (phase offset) can be calculated a couple
;  different ways.  since the dds frequency resolution (Fres)
;  is basically 0.01-Hz divided by 16, you can calculate the
;  phase offset by mulitplying desired Fout output frequency
;  by 1600.  the phase offset for an Fout of 254.1-Hz is;
;
;    phase = (Fout  * 100) * 16
;          = (254.1 * 100) * 16 = 406560
;
;    phase =  25410 << 4 = 406560
;
;  or you can also calculate phase offset like this (yuch!);
;
;    phase = Fout / Fres
;          = 254.1 / 0.000625 = 406560
;
;    phase = Fout * 2^24 / Fdds
;          = 254.1 * 16777216 / 10485.76 = 406560
;
;  the highest CTCSS frequency (254.1 Hz) will produce the
;  smallest number of sine wave D/A output points per cycle;
;
;    INT(10485.76 / 254.1) = 41 output points per cycle
;
Code:
;
;   CTCSS tone frequencies
;
;    67.0 Hz    69.3 Hz    71.9 Hz    74.4 Hz    77.0 Hz
;    79.7 Hz    82.5 Hz    85.4 Hz    88.5 Hz    91.5 Hz
;    94.8 Hz    97.4 Hz   100.0 Hz   103.5 Hz   107.2 Hz
;   110.9 Hz   114.8 Hz   118.8 Hz   123.0 Hz   127.3 Hz
;   131.8 Hz   136.5 Hz   141.3 Hz   146.2 Hz   151.4 Hz
;   156.7 Hz   159.8 Hz   162.2 Hz   165.5 Hz   167.9 Hz
;   171.3 Hz   173.8 Hz   177.3 Hz   179.9 Hz   183.5 Hz
;   186.2 Hz   189.9 Hz   192.8 Hz   196.6 Hz   199.5 Hz
;   203.5 Hz   206.5 Hz   210.7 Hz   218.1 Hz   225.7 Hz
;   229.1 Hz   233.6 Hz   241.8 Hz   250.3 Hz   254.1 Hz
;
Code:
;
;  r08 sine[] = { 100,102,104,107,109,112,114,117,
;                 119,121,124,126,129,131,133,135,
;                 138,140,142,144,147,149,151,153,
;                 155,157,159,161,163,165,167,168,
;                 170,172,174,175,177,178,180,181,
;                 183,184,185,187,188,189,190,191,
;                 192,193,194,194,195,196,197,197,
;                 198,198,198,199,199,199,199,199,
;                 200,199,199,199,199,199,198,198,
;                 198,197,197,196,195,194,194,193,
;                 192,191,190,189,188,187,185,184,
;                 183,181,180,178,177,175,174,172,
;                 170,168,167,165,163,161,159,157,
;                 155,153,151,149,147,144,142,140,
;                 138,135,133,131,129,126,124,121,
;                 119,117,114,112,109,107,104,102,
;                 099,097,095,092,090,087,085,082,
;                 080,078,075,073,070,068,066,064,
;                 061,059,057,055,052,050,048,046,
;                 044,042,040,038,036,034,032,031,
;                 029,027,025,024,022,021,019,018,
;                 016,015,014,012,011,010,009,008,
;                 007,006,005,005,004,003,002,002,
;                 001,001,001,000,000,000,000,000,
;                 000,000,000,000,000,000,001,001,
;                 001,002,002,003,004,005,005,006,
;                 007,008,009,010,011,012,014,015,
;                 016,018,019,021,022,024,025,027,
;                 029,031,032,034,036,038,040,042,
;                 044,046,048,050,052,055,057,059,
;                 061,064,066,068,070,073,075,078,
;                 080,082,085,087,090,092,095,097 };
;
Code:
;
;  DDS interrupt "engine"
;
;  void interrupt()             // 200-cycles (10485.76-Hz)
;  { pir1.TMR2IF = 0;           // clear TMR2 interrupt flag
;    accum += phase;            // add phase offset to accum
;    ccpr1l = sine[accum>>16];  // sine duty cycle value for
;  }                            // next PWM period
;
 
Last edited:
Hi,

I did some tone generators a while back, check this thread out.

The basic analogy of operation is to turn your port on, delay, turn your port off, and delay once again. This will give you a square wave and the frequency depends on the delay values.
 
I am new to PIC programming and don't understand how I can output a sine wave to a pin. I had already planned on putting the data in an array, but to output it to the pin has me very stumped.
 
Hi,

I did some tone generators a while back, check this thread out.

The basic analogy of operation is to turn your port on, delay, turn your port off, and delay once again. This will give you a square wave and the frequency depends on the delay values.

I need a sine wave though.
 
Mike,
Thanks. I thought the pin (whichever one I choose to output the tone on) is either on or off so that would just make a square wave, how am I getting it to gradually peak up and down. That is what I don't understand.
 
I've long back had once a Z80 program as a Function Generator, around 10 years back, if I can find it I'll post here.
 
I would use PWM and increment every time, gradually getting larger in magnitude as you increase the frequency, then lowering the magnitude as you decrease in frequency (positive cycle); do the same for the negative cycle. You can imagine it like small steps up and down a sine wave, then you can use a filter to smooth it out.
 
I would use PWM and increment every time, gradually getting larger in magnitude as you increase the frequency, then lowering the magnitude as you decrease in frequency (positive cycle); do the same for the negative cycle. You can imagine it like small steps up and down a sine wave, then you can use a filter to smooth it out.
I didn't know you could do that with pwm.
 
Perhaps you should experiment. Setup the PWM module with a period of 100 cycles (prescaler 1:1, PR2=99). Then put a simple RC filter on the CCP1 output pin. Something like 1K resistor and a 0.1-uF cap'. As you modify the PWM duty cycle in the CCPR1L register with values in the range of 0 to 100 you should be able to measure a voltage at the output of the RC filter in the range of approximately 0.0 to 5.0 volts (in 0.05 volt increments).

Have fun. Regards, Mike
 
Perhaps you should experiment. Setup the PWM module with a period of 100 cycles (prescaler 1:1, PR2=99). Then put a simple RC filter on the CCP1 output pin. Something like 1K resistor and a 0.1-uF cap'. As you modify the PWM duty cycle in the CCPR1L register with values in the range of 0 to 100 you should be able to measure a voltage at the output of the RC filter in the range of approximately 0.0 to 5.0 volts (in 0.05 volt increments).

Have fun. Regards, Mike
Well now that I have an idea of how to go (PWM) I can do that. Thanks for the help.
Roger
 
I would use PWM and increment every time, gradually getting larger in magnitude as you increase the frequency, then lowering the magnitude as you decrease in frequency (positive cycle); do the same for the negative cycle. You can imagine it like small steps up and down a sine wave, then you can use a filter to smooth it out.
Your description doesn't quite make sense. Increment what? Change the magnitude of what? Please check your terms...
 
Last edited:
Perhaps a diagram will advocate my message more clearly.
 

Attachments

  • DigitalPWMSineWaveExample.PNG
    DigitalPWMSineWaveExample.PNG
    18.6 KB · Views: 854
Mike, K8LH is right about the need to experiment. He also nailed the answer to the question.

EN I can not make much sense of your post. Why would one be increasing the PWM freq, it is the duty cycle that sets the on off ratio which is converted to a voltage by the RC filter ?
 
Last edited:
That was my point. He really needs to work on terms. He may understand the concept but he's not conveying it.

In his new graphic for example, point 'C' should be 100% duty cycle and point 'H' should be 0% duty cycle. And without a reference on the X axis one might assume his transitions are occurring at regular intervals which would produce a sawtooth wave instead of a sine wave, that is if you can imply that "pwm increment" is actually "duty cycle".

Shoddy terms followed up with a shoddy graphic which includes more shoddy terms.
 
Last edited:
Status
Not open for further replies.

Latest threads

New Articles From Microcontroller Tips

Back
Top