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.

PWM 16F628A - Need a bit of guidance

Status
Not open for further replies.

Tipp

New Member
Hey all, first post on your forum, and I must say it looks pretty good :D

Alright, well, a bit about my situation. I've just started working with PIC microcontrollers and it's a ton of fun! I've written a few small programs already to blink and sequence LED's. It's pretty sweet knowing what all that jibberish assembly code means :D Anyway, I've been researching how to fade LED's on one of my 16F628A's. Obviously a pin can only be a 1 or 0, so I did some poking around and came across PWM. Ok, well I know my 628A's have a PWM module somewhere, so how do I use it? Again, more info brought me to many sites, including Nigel's tutorials and suddenly it was right over my head! Whats all this about writing to specific registers? Whats this capture/compare equipment? Here's what I've figured out so far:

-PWM output is pin RB3

So, now you know what I want to do, and how much I currently know. I ask that if you provide any kind of example code, don't give me a whole program, just what I can use to play around with and learn. I want to learn this step-by-step instead of having it handed to me. What I want to know is how to go about setting up the PWM to control the brightness of a single LED. What should I write to specific registers, and what do they mean?

I read somewhere that, to make it fade in or out, I can add or subtract something from a register to control duty cycle, but that'll come later.

Thanks for your time, it's really appreciated :D

Edit - mis-spelled title :p
 
Hi Tipp,

Welcome to the forum and a wonderful and exciting new adventure...

Please tell us what you're using for the '628A oscillator and we'll provide you with some code snippets and explanations...

Kind regards, Mike
 
Oh, sorry, of course! I'm running 4 MHz external crystal :)
 
Ah, most excellent! I'll play around with this tonight and see if I can get something started. Thanks very much! :D
 
Congratulations on your efforts so far, let's see if we can jumpstart the next phase.

PWM & Register Basics.

Some of the places in the data address space that you can write to and read from are just ordinary memory. You read back exactly what you wrote. There are other places in the data address space that have a bit more under the hood. Bits in those locations control actual pieces of hardware, AND you may or may not get back what you wrote. It all depends on the specific register in the register file(data memory).

To get started with PWM you need to get your arms around the concept of a fixed frequency. You get to choose from some number of alternatives, but your choice of frequency is restricted to those alternatives. In the datasheet for the PIC16F628A this is Table 9-3 on page 59. It shows what frequencies the PWM signal will have for an oscillator of 20 MHz and various prescaler values. Notice also that the table tells you how many bits will cover the range from a duty cycle of 0% to a duty cycle of 100%

To successfully use the peripheral devices in the PIC there will need to be some initialization code which is executed one time ONLY, and some code which reacts to events as they happen. If you look carefully at the tables and figures in the datasheet you will find helpful hints on the set of registers you need to understand and provide for.

Your homework problem is to read section 9.3 of the datasheet, multiple times if necessary, and create a revised Table 9-3 assuming a 4 MHz. oscillator. Post a corrected Table 9-3 and we'll have another installment of the discussion.
 
*Shuffles into class the next day*

Alright, well I played around with some of that sample code last night and made quite a bit of progress. First thing I did was study the code and figured out what everything did. I think I have it under control...but I have a question...

~Code quote from given example~
Code:
InitPWM
	bsf	STATUS,RP0	;				  |B1
	movlw	b'00000010'	;				  |B0
	movwf	T2CON		; prescale:16 (3.2-usec ticks)	  |B0
	movlw	d'40'		; 40 3.2-usec 'ticks'		  |B0
	movwf	CCPR1L		; 80% duty cycle		  |B0
	bsf	STATUS,RP0	; select bank 1			  |B1
	movlw	d'50'-1		; 50 3.2-usec 'ticks'		  |B1
	movwf	PR2		; Period:160-usecs (6.25 KHz)	  |B1
	bcf	TRISB,3		; make RB3/CCP1 pin output	  |B1
	bcf	STATUS,RP0	; select bank 0			  |B0
	movlw	b'00001100'	;				  |B0
	movwf	CCP1CON		; put CCP module in PWM mode	  |B0
	bsf	T2CON,TMR2ON	; turn on TMR2			  |B0

When you move the d'50'-1 into the PR2 register, what is the -1 for? I've never seen that done before :D

I set up the registers the way shown in the example, and then wrote some code to change the value of the CCPR1L register on a button push. It would change from a '40' <push button> to a '20' <push button> and back. I compiled my code, stuck a blue LED on RB3 and watched it work! I was extremely happy! But this was a bit simple, so I moved on to this:

Setting up the registers the same as before, but I loaded the number 200 into CCPR1L. I created code to decrease the CCPR1L register by 1, check if the result was 0, and call a delay. When the register reached 0, it would call a larger delay and reset the CCPR1L register back to 200, beginning the cycle again. This quite visually faded the LED down to 0. Ok, so I'm slowly getting the hang on this thing...

Now, the LED fades down to zero, which is fine and good, but how can I make it fade back up? It's easy to control when it hit's 0, but is there any way to specify a number to stop at when increasing the register? Hmm...my poor brain! <grin> 8)

Thanks for all your help so far guys! I'm quite pleased with the progress I've made :D

Oh, and noticing the post above this, I will get on that right away :D
 
I'm happy to see that you dove in and solved the problem with just a small push. It restores my faith in young and old alike.
 
Ugh, beleive me, I know what you mean. Many people today want things handed to them on silver platters with no work on their part, which really makes me wonder where this world will be heading over the generations to come.

[FYI: I'm 16, so the 'young and old alike' part really suits this particular situation :) ]
 
Tipp said:
Code:
InitPWM
	movlw	d'50'-1		; 50 3.2-usec 'ticks'		  |B1
	movwf	PR2		; Period:160-usecs (6.25 KHz)	  |B1
When you move the d'50'-1 into the PR2 register, what is the -1 for? I've never seen that done before :D

This is done as a reminder that the count is actually 50 even though the register is loaded with 49. The count goes 49,48 ..... 2,1,0 - the zero being the 50th value.

Mike.
 
A Picky Point

This is such a picky point I almost hate to bring it up. The previous poster is correct about the intention of the expression d'50'-1 to remind us that there are actually 50 distinct states in the range [0..49]. The incredibly picky point is that the PR2 register does not decrement to zero, rather TMR2 increments until it is equal to PR2 and then it is syncronously RESET to zero.

When PR2 is set to 0xFF, it's like it isn't even there.
 
Tipp said:
Now, the LED fades down to zero, which is fine and good, but how can I make it fade back up? It's easy to control when it hit's 0, but is there any way to specify a number to stop at when increasing the register? Hmm...my poor brain! <grin>
I suspect you've already figured this out, but just in case (just one of many many different ways to check for the upper limit)...
Code:
Inc_PWM movf    CCPR1L,W        ;                                |B0
        xorlw   d'50'           ; upper limit?                   |B0
        skpz                    ; yes, skip                      |B0
        incf    CCPR1L,f        ; else increment                 |B0
        return                  ;                                |B0
If PR2 is set to 200-1 then your upper limit for the 8-bit CCPR1L would be 200... If PR2 is set to 128-1 then your upper limit for CCPR1L would be 128, etc., etc.....

Have fun... Regards, Mike

<added>

Very happy to see a young person interested in electronics/microcontrollers...

Good luck in your studies...
 
Re: A Picky Point

Papabravo said:
When PR2 is set to 0xFF, it's like it isn't even there.

It is still there. In fact it gives the longest period on the PIC PWM output at the current clock speed & prescaler.
 

Attachments

  • pr2_max.gif
    pr2_max.gif
    8.8 KB · Views: 639
Re: A Picky Point

Papabravo said:
The incredibly picky point is that the PR2 register does not decrement to zero, rather TMR2 increments until it is equal to PR2 and then it is syncronously RESET to zero.

Quite right. If it decremented then it wouldn't know to set itself back to 49. :lol:

Don't worry about being picky, it's better not to confuse people.

Mike.
 
eblc1388

I did not say PR2 wasn't there I said it's like PR2 wasn't there because there is no essential difference between letting TMR2 roll over to zero by incrementing from 0xFF, and reseting it to zero because it equals 0xFF. If you can only look at the value of TMR2 you can't tell the difference between these two cases.

The difference only becomes obvious when a value other than 0xFF is placed in PR2.
 
Papabravo said:
eblc1388

I did not say PR2 wasn't there I said it's like PR2 wasn't there because there is no essential difference between letting TMR2 roll over to zero by incrementing from 0xFF, and reseting it to zero because it equals 0xFF. If you can only look at the value of TMR2 you can't tell the difference between these two cases.

The difference only becomes obvious when a value other than 0xFF is placed in PR2.

I have read your explanation several times but still I'm lost as what you really meant by "like it wasn't there".

When PR2=0xFF, TMR2 only reset after 256 more increment. This led me to believe "it is there".
 
With PR2 set to 0xFF consider what happens as TMR2 increments. TMR2 increments from 0xFE to 0xFF. Now TMR2 == PR2 = 0xFF. On the next clock pulse TMR2 is cleared by having eight zeros jamed into TMR2.

Now suppose we take PR2 away from the circuit. Now TMR2 would increment from 0xFE to 0xFF just like in the previous case. On the next clock pulse instrad of clearing TMR2 we let it increment. It goes from 0xFF to 0x00. This is the same result as in the previous case.

TMR2 goes throught the identical set of states regardless of weather we clear it when it reaches 0xFF or we increment it and let it roll over. PR2 can be there or not TMR2 will behave the same way and looking at the value of TMR2 you can't tell what the PIC hardware is doing under the hood when PR2 has the value 0xFF. This statement is true for this value ONLY.
 
Hi Papabravo,

You are of course, totally correct. I realise my mistake in my previous postings.

I have finally figured out what you meant. Sorry my mind was so fixated on the relationship between value of PR2 and PWM output.

Normally TMR2 counts from 0,1..254,255,0....in counter mode.

When it is used in PWM, TMR2 will count from 0,1,...N,0, where N=value in PR2.

However, when PR2=0xFF, TMR2 will count from 0,1,...254,255,0...as if PR2 isn't there.
 
I apologize for any upset that you may have felt. I need to be mindful that my English may not be your English. When simple sentences deviate from simple structures, meanings can and do get lost. I'm glad we are now on the same page. You know the hardware. I knew that.
 
I suspect you've already figured this out, but just in case (just one of many many different ways to check for the upper limit)...

Nope, actually I didn't have a clue :p Thanks for the tip! I'll mess around with that for a while and figure something out :D Just out of curosity, just how many different techniques are there? I'm afraid that this specific one will work here, but not in another situation :shock: :D

Very happy to see a young person interested in electronics/microcontrollers...

I've been into this kind of thing for about a year and a half now. I've done coilguns, tesla coils, flyback drivers, DC/DC converters, work with logic gates, short range FM transmitters etc and I love it all :D

Microcontrollers are a whole different league then all that other stuff. You can't just whip up a circuit, stick everything in place and have it work. It takes patience, skill and practice. And besides that, I love a good challenge :D My parents are completely blown away by some of the stuff I turn out :wink: Alright...'nuff of my rambling :D

This is done as a reminder that the count is actually 50 even though the register is loaded with 49. The count goes 49,48 ..... 2,1,0 - the zero being the 50th value.

Ah, I got it. It's like how PORTA is numbered up to RA7 even though there are 8 pins. They count RA0. :D

Thanks everyone!
 
Status
Not open for further replies.

Latest threads

New Articles From Microcontroller Tips

Back
Top