![]() | ![]() | ![]() |
| | |||||||
| Micro Controllers Discuss all aspects of micro controllers - building them, coding them, etc. All controllers are welcome - PIC, BASIC, Z8 Encore!, etc. |
| | LinkBack | Thread Tools | Display Modes |
| | (permalink) |
| Hi, I'm building a power inverter that needs a high frequency clock at about 25Khz and a low frequency one at 50Hz. I have access to various crystal speeds, and as the choice of high frequency is not vital I can see how by choosing prescaler values I can use TMR0 to give me a suitable square wave to control my bridge. However, the 50Hz output is causing more problems - it needs to be exact, but crystal speed divided by 4 divided by 256 divided by prescaler doesnt equal 50 for any crystal/prescaler combination! I realise I could use a simple op-amp and cap/resistor network to get a 50Hz square wave, but I'm hoping to be able eventually to get the PIC to give me a nice quasi sine wave (square wave with deadtime). However, If I can't get the frequency right this is a non-starter!As is probably evident, I am very innexperienced with the PIC, so any advice would be very welcome. | |
| |
| | (permalink) |
| I don't think you really need to get exactly 50hz. An output within 1% would be good enough. A crystal controlled PIC will give a closer frequency match than any op-amp based RC oscillator. Nevertheless, it is possible to get exactly 50Hz. Using the low cost PIC16F627: First, initialize timer 2 control register T2CON, to 1:1 prescale and 1:2 postscale+TMR2ON = b'00001100'. Second, setup PIC to generate a 25Khz PWM signal. Assuming, you use a 4Mhz PIC16F627, initialize the period register PR2 with the value D'39'. The period is therefore equal to (39+1)*4*250nsec=40usec. Configure the CCP1 module for PWM operation. Follow the steps outlined in section 10.3.3 of the PIC16F627 datasheet. Third, enable timer2 interrupts by setting TMR2IE bit in PIE1 as well as GIE and PEIE in INTCON. Interrupts will be generated every 80usec because of the 1:2 postscale. In the interrupt service routine (ISR), toggle any desired output pin every 125 interrupts to generate the 50Hz signal. The PWM duty cycle can also be modulated during the ISR. The interrupt service routine is limited to 80 instructions when using a 4Mhz crystal but this may be sufficient. Or you can use a faster crystal up to 20Mhz. A faster PIC will also give a finer resolution PWM signal.
__________________ "Having to do with Motion Control" | |
| |
| | (permalink) |
| was just thinking of something. Say I want a 100hz signal purely based on tmr0. Say I scale tmr0 this way: 4Mhz/4/256 = 3906hz. So if I count tmr0 a hundred times. that would be 100hz? or 3906/100 = 39 tmr0 pulses. Edit: 1/3906 = 256µs - this makes sense as one instruction = 1µs and prescaler is 256 and it takes this long for a timer overflow. So, 1/100 = 0.01s (period) of 100hz, and 0.01/256x10^-6 = 39.06. Sweetness..... So what I've been doing so far is taking 105(pulses) too = 105hz >> WRONG 1/(105*256x10^-6) = 39hz, :lol: :lol: This solves my problem
__________________ "Ambition is the last refuge of failure..." --Oscar Wilde "Success is not final, failure is not fatal: it is the courage to continue that counts." -- Winston Churchill | |
| |
| | (permalink) |
| Thanks for that. One quick question though: Interrupts are generated every 80 uS, and the interrupt routine can be used to send whatever pins wanted to high or low as needed. While the interrupt routine is being processed, is the counter still counting ready for the next interrupt, or does the interrupt routine stop this. If the counting stops when the interrupt is being processed, then presumably the length of the interrupt code will affect the frequency...? Sorry to be so slow, your help is much appreciated. Cheers, Ben | |
| |
| | (permalink) | |
| Quote:
Here's the line from a timer2 routine which resets the flag: Code: BCF PIR1,TMR2IF ; Clear flag and continue. | ||
| |
| | (permalink) | |
| Quote:
TMR2IE is not disabled (cleared) by the interrupts. GIE is cleared during interrupts but is restored automatically with the RETFIE instruction. You only have to clear TMR2IF in the ISR as Nigel has suggested. This is a more accurate way of generating periodic interrupts rather than using timer0 and reloading timer0 in the ISR. Writing to timer0 to set the delay clears the prescale registers and this results in small errors in timing. This old technique applies to the PIC16F84 because it's the only timer available.
__________________ "Having to do with Motion Control" | ||
| |
| | (permalink) |
| Unfortunately I only have access to a PIC16F84A, Maplins seem to be out of any others for the moment. I am fiddling with a piece of code, but have a question. I want to, if possible, generate a number of signals: a high frequency square wave (exact f not important, but 20-30Khz) and its inverse (although could invert outside the pic) 2 50Hz square waves with duty cycles and phase shifts such that subtracting the two gives a quasi sine wave (a 50Hz square wave with deadtime) Am I right in thinking that I can't, for instance, set pin 6 high, but have to set the entire port to a value? This seems to complicate things, as to change just one pin I have to take a copy of current outputs, modify the desired bit, then set the new outputs... | |
| |
| | (permalink) | |
| Quote:
BSF PORTB,6 You may need to modify that for whatever pin 6 is on your PIC.
__________________ Dave Pusey. PIC Programming Tutorials: http://www.mstracey.btinternet.co.uk...al/picmain.htm Brilliant PIC Simulator: http://www.oshonsoft.com/pic.html | ||
| |
| | (permalink) | |
| Quote:
Code: BSF PORTB, 6 BCF PORTB, 5 . . ;and later on, for the other change. . . BCF PORTB, 6 BSF PORTB, 5 | ||
| |
| | (permalink) |
| Sorry about this - thanks for being so helpful. I've been trying to calculate the values to put into the PWM duty cycle registers, and getting in a bit of a mess. I am looking for 50% duty cycle, and have to fill the whole of CCPR1L and bits 4 and 5 of CCP1CON. Duty_cycle = registervalue * Tosc * TMR2_prescale registervalue= Duty_cycle/(Tosc * TMR2_prescale) registervalue=(1/2*(1/25,000))/(4,000,000 * 39) =1.28 * 10^-13 Somethings gone wrong somewhere ...! | |
| |
| | (permalink) |
| Hello again. I've put together a piece of code that I hope will make my PIC output two square waves, at 50Hz and at 25Khz - thanks to Nigel for advice on that! The only thing I can't work out as yet is what to initialise the duty cycle registers to. I won't have a chance to try out the code until Monday, but if any kind hearted person wants to have a look at my handiwork, it is up at: http://www.srcf.ucam.org/~dbrb2/oscillator This is my first PIC program, so I am slightly worried it might be completely wrong, and any critiscism would be very welcome! Cheers, Ben | |
| |
| | (permalink) |
| If: PWM duty cycle = (register value) * Tosc * (TMR2 prescale value) At 25Khz, duty cycle = T/2 = (25000*2)^-1 Tosc = 1/(4,000,000) TMR2 prescale = 39 thus register value = 200 200=b'11001000' So bits 4 and 5 of CCP1CON = 0 and the rest of the sequence fills CCPR1L | |
| |
| | (permalink) |
| I had a quick glance at your code and I would like to recommend a few optimizations: Code: isr decfsz interrupt_count, F goto end_isr ; movlw d'125' movwf interrupt_count ; movlw slow_toggle ;slow_toggle is defined under 'constants' xorwf PORT_B,W ; get the inverse of the slow toggle pins and save in W reg andwf PORTB,F ; First turn OFF the pins with "0" bits nop ; insert as many dead instructions as necessary iorwf PORTB,F ; Then turn ON the pins with "1" bits end_isr bcf PIR1,TMR2IF ;end isr, resetting interrupts retfie
__________________ "Having to do with Motion Control" | |
| |
| | (permalink) |
| Thanks I couldn't use the nop methid to get my phaseshift as I would need to many to fi in my interrupt (about 3000). However, by using another variable initialised at startup to a positive value, but decremented just like my interrupt counter, I can arrange for them to reach 0 at different times, and so produce my out of phase signals. The modified code is up at: http://www.srcf.ucam.org/~dbrb2/oscillator Thanks for all your help - hopefully when I get this code to a PIC it will work... in the end! Cheers, Ben | |
| |
| | (permalink) |
| I ran the code through a simulator, and for some reason interrupts never seem to occur. I cant work out what is going wrong... (hair pulling time)! | |
| |