I realized my original code was delaying the PWM loop some because it was waiting on a ADC read before finishing the loop. In the code below, the ADC read is started and read the next time around. Then the next time is started again, this eliminates the delay of waiting on the ADC.
#define ADCStart ADCON0.b1 = 1 //set this bit to begin ADC conversion
//////////////////////////////////////////////////////////////////////////////
const unsigned char sine[256] =
{// sine wave 8 bit resolution scaled to 90% max val
131,132,135,137,140,143,146,149,152,155,157,160,163,166,168,171,
174,176,179,181,184,186,189,191,194,196,198,200,202,205,207,209,
211,212,214,216,218,219,221,223,224,226,227,228,229,231,232,233,
234,234,235,236,237,237,238,238,239,239,239,239,240,240,240,239,
239,239,239,238,238,237,237,236,236,235,234,233,232,231,230,229,
227,226,225,223,222,220,219,217,216,214,212,210,208,206,204,202,
200,198,196,194,192,189,187,185,182,180,177,175,173,170,167,165,
162,160,157,154,152,149,146,144,141,138,135,133,130,127,124,122,
119,116,113,111,108,105,103,100, 97, 95, 92, 89, 87, 84, 82, 79,
77, 74, 72, 69, 67, 64, 62, 60, 58, 55, 53, 51, 49, 47, 45, 43,
41, 39, 37, 36, 34, 32, 31, 29, 28, 26, 25, 24, 22, 21, 20, 19,
18, 17, 16, 15, 15, 14, 13, 13, 12, 12, 12, 11, 11, 11, 11, 11,
11, 11, 11, 12, 12, 12, 13, 14, 14, 15, 16, 16, 17, 18, 19, 21,
22, 23, 24, 26, 27, 29, 30, 32, 33, 35, 37, 39, 41, 43, 45, 47,
49, 51, 53, 56, 58, 60, 63, 65, 68, 70, 73, 75, 78, 81, 83, 86,
89, 92, 94, 97, 100,103,106,108,111,114,117,120,123,126,129,130};
////////////////////////////////Global variable here//////////////////////////////////////////////
long PhaseAccum;//phase accumilator generates the cycle rate for lookup table
//loading therby changing frequency. The MSbyte is used to provide the byte address
//of the look up table value to be used.
long PhaseShift;//value added to PhaseAccum every PWM cycle. This makes the waveform
//lookup faster or slower – which changes frequency.
////////////////////////////////////////////////////////////////////////////////////////////
////////////////////////////////PIC Config routine here////////////////////////////////////
void Init_Main(){
//PIC12F1822 specific config
OPTION_REG = 0b10000000; // disable internal pull ups
OSCCON = 0b11110000; //8MHz clk //32Mhz pll
TRISA = 0b00011000; // configure IO/a2d(gpio0) and mclr set as inputs
T2CON = 0b00000100;// TMR2 ON, postscale 1:1, prescale 1:1
PR2 = (0x50);// sets PWM rate to approx 98.5KHz with 32Mhz internal oscillator
CCP1CON = 0b00001111;// CCP1 ON, and set to simple PWM mode
PhaseShift = 0x00FFFFFF;//frequency values loaded into
ANSELA = 0b00010000; //select RA4 as A2D input 32Mhz clk
ADCON0 = 0b00001101; // configure ADC
ADCON1 = 0b00100000; // configure ADC
}
////////////////////////////main program loop here/////////////////////////////////
void main() {
Init_Main();//configue part
while(1){ //alway do this
while(!PIR1.TMR2IF);// wait for TMR2 cycle to restart
CCPR1L = (sine[((char *)&PhaseAccum)[3]]) >> 2;// load MSbits 7-2 duty cycle value into CCPRIL
CCP1CON ^=((sine[((char *)&PhaseAccum)[3]]) & 0x03) << 4;// load in bits 1-0 into 5 and 4 of CCP1CON
//////duty cycle value byte is now loaded for next cycle comming//////
if(PIR1.ADIF == 0)ADCStart; //start ADC here to get value into PhaseShift to change Freq
//will have to go around the loop one time before ready flag is high
if(PIR1.ADIF){ //if ADC read complete load values and clear flag
((char *)&PhaseShift)[1] = ADRESL; //load ADRESL into PhaseShift
((char *)&PhaseShift)[2] = ADRESH; //load ADRESH into PhaseShift
PIR1.ADIF = 0;//clear flag so next time ADC canΒ run
}
PhaseAccum = PhaseAccum + ((PhaseShift << 5) + 1); //move PhaseAccum through waveform values
//”<<5″ can be more or less and sets the frequency sweep range
// the +1 is just so there is never 0;
porta.b0 = ((char *)&PhaseAccum)[3].b7;
PIR1.TMR2IF = 0; // clear TMR2 int flag
}
}
I would like to put my own values into a variable that I can set for specific frequencies. This would be in place of the value of the ADC. I would like to program in 7.83Hz exactly.
I imagine that typing in a distinct value for ADRESL and ADRESH would do the trick?
What value would I use in this code:
((char *)&PhaseShift)[1] = ADRESL; //load ADRESL into PhaseShift
((char *)&PhaseShift)[2] = ADRESH; //load ADRESH into PhaseShift
Thanks for your help!
Russ π
the best thing would be to comment out all of the ADC related lines of code:
then use something like this:
PhaseAccum = PhaseAccum + PhaseShift //move PhaseAccum through waveform value
this line already exists but you can modify to make Phaseshift a long (4 byte) constant just load in whatever value you want in your initialization
I think the value you will want in Phaseshift will roughly 269037 for 7.83 Hz ……7.83Hz/(1/(.000008 * 2^32)) -> where 8 uSec is the period of the PR2 time of 125KHz
also in the init_main() make PR2 = 40 not 50 the cycle rate will be 125Khz…it will perform better.
Wow!!! Thanks for your help!
I will do just that and test it out. π
I need to find a C compiler as I have never worked in C. Can you recommend one?
I use MELABs PIC Basic Pro and there USB PIC Programmer. So, I can easily flash a HEX code to the PIC.
Thanks for the speedy response and THANK-YOU for this great circuit!!!!!
MikroC its freeware up to 2K (program size) so my program will fit…It is what I used originally
Brilliant!!! I thought I saw you mention the link. Downloaded it and installed it perfectly!! Thanks!!!!!!!
Just ordered the PIC from Digikey. Hope to get it all up and running in a week or so!
cool if you have trouble compiling let me know
UPDATE: Just playing around with values and this one gets me almost exactly 7.83Hz:
PhaseShift = 1094733;//Set for 7.83Hz
your code is fine..not sure where I went wrong with the calculation but it sounds like you have it working.
Thanks so much for your circuit and code. I am stocked! It is brilliantly simple and performs perfectly!!!
I am now thinking about adding a push-button interface where I can scroll through a pre-set frequencies. So, I can see using one Port for the pushbutton, and the remaining 4 Ports outputting a 4-bit word that I can then decode to 1 of 16 states using 16 LEDs to indicate what frequency I have selected. That type of thing.
Problem is I no nothing about C language!
π
Should be easy to do what you are describing. Just add complexity slowly and look at the mikroC tutorials!
Yes! I will check out the tutorials. Good call!!
π
Oh, one small typo on your schematic here: https://circuitsaladdotcom.files.wordpress.com/2014/06/pic_dds.gif
The regulator is described as a 5V down to 3V, whereas it is 9V down to 5V.
π
its not a typo …just poorly worded. I am trying to indicate it can be a 5v or 3v regulator… the 9V can be any input Voltage the regulator can tolerate
π
Would it be possible to rewrite the code to be uploaded to a ATTiny85?
Are you asking me rewrite the code? I don’t have a dev board or the compiler tools to do that. For ATTiny micros that support pwm(not sure about the 85?) the PWM is handled differently so the code would have to be changed with regard to the PWM config registers and how you actually load the PWM value register but those parts will work fine. Of course the IO definitions also have to change but it should only take a few hours to get working.
great! yes the ATTiny85 has PWM and analog inputs. Thanks. I actually found an other program that was easily rewritten to accept frequency control. I’ stuck with a triangle wave (cycling through a sine waveform takes to long), but I think it sounds ok.
http://www.technoblogy.com/show?QVN
Hi this is great project, thank you for it. I try compile source but many errors, can someone upload hex file?
Thank you