Software PWM

Thats actually something I
Thats actually something I wanted to know. you can feel free to add as much detail as you want (within reason). I’m an Electrical Engineering student so I shouldn’t get lost too easily.

by experience I can say
by experience I can say that, on a pic, if your clock is 8MHz your timer will run at 2Mhz

just a small problem…once
just a small problem…

once count gets to zero do I continue to decrement it (so it becomes 0xFF then 0xFE …) or do I reset it to 16 again?

EDIT: I’m not sure whats wrong. at first I had a frequency of 1Hz and then realized that I wasnt clearing the interrupt flag. now that I’m clearing the flag it doesnt appear to work at all. I’ve followed your instructions, the only difference is that I have an 8Mhz clock so i’d expect the frequency to be doubble.

unexpected results

It’s not doing what I want it to. I’'ve followed BOA’s instructions but currently its creating a 7Hz frequency and my DMM reads 0% duty cycle. It seems odd that it can measure a frequency but no duty. anyways something isn’t working.

I dont think this is the best way but this is the interrupt routine i’ve put together


highpriorityint:
bcf PIR2,TMR3IF ;clear the interrupt flag
movff Demand,W ;move demand into the working register
cpfsgt Count ;compair if greater than
bcf PORTB, RB3 ;if false then set pin low
cpfslt Count ;compair if less than
bsf PORTB, RB3 ;if false then set pin high
decfsz Count,F
retfie ;if count is not zero go back
call setcount ;reset count when reaches zero
retfie

the roiutine should be

the roiutine should be fine, but i just read the comments, i am not familiar with pic mnemonics.

what kind of driver do you use?

Get Lost
Get as lost as you want right here.

Looks Good

I’m not so familiar with the extended instruction set (the 8-bit chips don’t have cpfsgt, cpfslt and movff) but it looks pretty good. (I didn’t read the comments!!)

I think you need to set TMR3IF before exiting.

I thougth TMR3IF was the
I thougth TMR3IF was the interrupt flag. If I set it (or dont clear it) wont it go right back to my interrupt routine?

currently I’m just using a
currently I’m just using a led and my DMM to meauser the frequency and duty cycle. eventually i’ll be using the L293D motor driver

Correct

Yes. I got that mixed up with TMR3IE. Hmmm…

Try clearing it LAST thing before RETFIE rather than the first thing. I know two cycles have passed due to the jump and this shouldn’t really have any effect,but you never know. Any examples I recall cleared the bit last.

I put some work into

I put some work into figuring out what was going on and I figured out that when I thought I was setting timer 3 as a 8-bit timer I actually set the way you read the value of timer 3 as two 8-bit values. I’m not sure how to change timer 3 to an 8 bit timer. so I have a 16 bit timer and the highest frequency I could get while using it was 7.89Hz. somehow I need to figure out how to set it as an 8-bit timer.

 

EDIT: my options look to be

1)use tmr2 which is an 8 bit timer. the only problem is it doesnt have an option to interrupt on overflow although it can set an interrupt when it matches a value in a certain register.

2)load a value into timer 3 so that it interrupts sooner. the down side would be a longer interrupt routine.

I think i’ll go with option 2 since i alredy have timer 3 configured. i’ll load in 2^16 - 2^8 after it overflows and it should act like an 8 bit timer

Bit and Bobs

You could just use an 8-bit timer (TMR2) OR, each time TMR 3 overflows, the first thing you do is set it so it will interrupt 256 ticks later.

Or, you could switch off the prescaler and ignore the least significant byte of the timer. That’s the same as having a 256:1 prescaler!!!

 

so, I’ve got it working a
so, I’ve got it working a little better now. now my problem is to have 4 pwm output’s my interrrupt routine is nearly 4X as long as it was before. I think that it is spending too much time dealing with the interrupt.

4x? try 16x!

I know. It’s a nightmare. Your interrupt can only be as long as the smallest PWM step. My servo controller has 16 outputs and it’s … flaky at best!

Have you looked at macros? You should be able to write a macro which does the compare and modifies the output bit in under 10 cycles. (Times 4 for 4 outputs!!)

Macros might impress your professor. Specially if you can write a chapter discussing the pros and cons of macros versus subroutine calls.

I’ve always been a little

I’ve always been a little confused as to how macro’s acutally work. when you use a macro does the assembler stick the code of the macro into the program or does the pic microcontroller acutally deal with the macro? currently there are 4 subroutines (1 for each pwm). I’ve made a bunch of changes now and in theory it should work but there must be a typo or mistake somewhere since it doesn’t appear to be working. I’ve fallen back to my old code for now.

 

I have a feeling by the way you brough up macro’s they could save me a few clock cycles.

Yep

Like evereything, there are upsides and downsides.

The assembler expands the macro so as to inclulde another instance of the code chunk. Your assumptions are correct: four "calls" to the macro will cause the same code to be in your program four times over, which is inefecient from a memory perspective, but it does save you on subroutine calls. (2 operations to jump into a sub and 2 operations to return from it).

If you open up the source code window (assember listing view) you can step through the marco in the IDE.

works in sim not on pic

as far as I can tell ,in simulation, my program is doing what I want it to. when it gets programmed to the pic it starts doing odd things. I’m using port b pins 4-7 as my 4 pwm outputs and all the other pins should remain low. when the program is running on the pic pins in port A randomly toggle, the pwm remains stabel for a while then goes out of control and then becomes stable again.

 

I’ve been stepping line by line through the code and seeing that all the registers are changing correctly. then i have it run through the program and the registers appear to be correct after onece through. It seems like the program is written correctly but yet it doesnt work.


EDIT: Solved

problem 1) I was forgetting to reset the timer to 0xFF00

problem 2) somehow I have 2 dead pins. they just happened to be the ones that I was testing!

PWM doesnt play nice with SRF05
I think the pwm interrupt routine is messing with my routine for getting the distance from an object witht the SRF05. Either it is messing with it becaue its taking up clock cylces or it interfears with the value in the working register.

i’m trying to rewrite the

i’m trying to rewrite the routine to measure the return pulse from the srf05 but its not working. I currently have it coppy the 8bit range value to the hardware pwm and thats connected to a led. the problem is that the led is always bright representing a number close to 256 in range. occasionally it will pick up on my hand or something and go dim but it goes bright right away after that.

 

my original routine just incremented a register every 120 micro seconds untill the pin went low. now i’m trying to set up a timer to measure the pulse. the maximum time the pin will be high is 30ms which I think is 60,000 clock cycles when using the internal oscillator set at 8MHz (fosc/4)=2Mhz. using a prescaler of 256 I figured the maximum value in the timer low byte should be 60,000/256=~235 meaning that the high byte of the 16 bit timer should be zero. once I have the timer set up i go into a loop where it checks if the pin has fallen low. If it has the timer value is stored in memory. since the value in timer0 is only 8bits I only need one memory location and it makes using the range value much easier.

It appears (by looking at the pwm led) that there is always a value near 256 (since the led is very bright) being moved into range each time the routine is called.

SRF_measure:
movlw 0x8F ; enable TMR0 with prescaler set to 1:256
movwf T0CON
clrf TMR0H ; clear the timer
clrf TMR0L
bcf INTCON,TMR0IF ;clear the overflow flag
waitalow:
btfsc PORTA,1
goto waitalow
movff TMR0L,range

Another PWM method

The method I use for PWM is the following,

Create an 8 bit "Accumulator" and a "PWM". The PWM will hold your "speed" or "brightness" from 0 to 255.

Setup a timer interrupt, and in the interrupt routine …

movf PWM, W

addwf ACC, F

btfss STATUS,C

bcf PORT, BIT

btfsc STATUS, C

bsf PORT, BIT

retfie FAST

Basically, every time you enter the ISR, you simply add your PWM value to the accumulator. Every time the accumulator overflows, the carry flag is set. You simply copy the carry flag to the output pin. I have used this to control motor speed and LED brightness. If PWM is 255, the carry flag will be set almost every time the ISR runs (255 out of 256 times). If PWM is 0, you will never set the carry flag.

If you need to drive 2 motors, create ACC1, ACC2, PWM1, and PWM2. Then do the same 6 instructions for each set of ACC and PWM.