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.

Writing 10bit duty cycle to CCP1CON?

Status
Not open for further replies.

Rogue

New Member
Hopefully this is just a matter of me being daft and can be easily cleared up.

I'm working on hardware PWM using a PIC16F627A. I intend to use a 10bit duty cycle, or at least develop a function for handling a 10bit cycle even if I later move to 8bit.

According to the datasheet, the 8 MSB should get written to CCPR1L while the 2 LSB should be written to bytes 5 and 4 of CCP1CON.

Ok, sounds a little awkward but understandable. Any pointers on efficient ways to do that in C would be appreciated. :D

What confuses me is that in the examples I've seen, people just write their duty cycle to CCPR1L. I've not come across an example where someone is splitting it. Are they simply discarding the LSBs and assuming everyone wants 8bit, or is there some magic happening in the background that I don't know about here that drop the LSB into the right place? :confused:

My suspicion is that the others are simply using 8bit...
 
They are loosing the LSBs.
PIC built a 8 bit PWM and people wanted more bits so at the last minute PIC added two more bits in a clumsy way. Maybe not really what happened but it looks that way.
 
I need to work on my bit operations, I'm hitting a rather silly mental block :(

8 MSBs:

if I just assign the 10bit number to an 8 bit register, ie CCPR1L = MyTenBitNumber, do the last 2 bits get safely dropped or do they overflow somewhere?

2 LSBs:

Consider the following code:

unsigned int uiLSB;

uiLSB = MyTenBitNumber; // uiLSB = 1000110011 for example
uiLSB &= 512; // uiLSB now equals b'1000000000', only keeping the 2 LSBs.
uiLSB = uiLSB >> 4; // uiLSB now equals b'0000100000', aka 32

This should leave me with either 16, 32 or 48, reflecting the three possible combinations for bits 4 & 5 - it is 32 in the example above.

The reason I did this was to give myself an 8 bit number with the original LSBs now lined up with bits 4 & 5 in CCP1CON, as in the back of my mind I was thinking that XOR would let me add these into the target register. I then remembered how XOR works and realised this wasn't going to happen :eek:

If CCP1CON = 00011100, how do I neatly change this to 00101100, other than checking and changing the two bits individually?
 
Wait a second...

...bits 0-3 of CCP1CON are always b'1100' (decimal 12) in this case, as that is what enables PWM mode. Also, bits 6 and 7 an unimplemented so I do not need to be concerned about them.

So I just need to add the 16, 32 or 48 given by the calculation to 12!

uiLSB = MyTenBitNumber; // uiLSB = 1000110011 for example
uiLSB &= 512; // uiLSB now equals b'1000000000', only keeping the 2 LSBs
uiLSB = uiLSB >> 4; // uiLSB now equals b'0000100000', aka 32
CCP1CON = uiLSB + 12; // CCP1CON now equals 42, which is... b'00101100'.


So, assuming the code does what I think it should be doing, that should be the LSB sorted at least!

Edit to add: My normal "trial and error" method is unavailable until later, which is why I'm approaching this as a paper exercise rather than just trying it and seeing if I get the expected outcome :D
 
Last edited:
I think you might have your notion of LSB and MSB mixed up. In your example number, MyTenBitNumber, the two one's on the right are the LSBs: 1000110011.

So, to follow your technique:
uiLSB = MyTenBitNumber; // uiLSB = 0b1000110011 for example
uiLSB &= 0b00000011; // I always prefer to use binary or hex when masking
uiLSB <<= 4; // uiLSB now equals 0b00110000
CCP1CON = uiLSB + 12; // CCP1CON now equals 60, which is 0b00111100
 
Last edited:
Here's an example (the last few instructions);

Code:
;
;  //  setup a 1000 usec PWM period with PR2 = 249 and prescaler
;  //  16:1 (16 MHz clock) or 4:1 (4 MHz clock) and then link 20
;  //  of these 1000 usec PWM "frames" together to form the much
;  //  longer 20-msec servo period.
;
;  int servo = 1500;            // 0..20000 in 1 usec steps
;  int frame = 1;               // frame number 1..20
;
;  void interrupt()             // 
;  { int width;                 // work variable
;    pir1.TMR2IF = 0;           // clear Timer 2 interrupt flag
;    frame--;                   //
;    if (frame == 0)            // if end of the 20 msec period
;    { frame = 20;              // reset for new 20 msec period
;      width = servo;           // reset 'width' work variable
;    }
;    if ((width > 1000)         // if width > 1000 usecs
;    { ccpr1l = 250;            // do a 100% duty cycle frame
;      ccp1con.CCP1Y = 0;       //
;      ccp1con.CCP1X = 0;       //
;      width -= 1000;           // subtract 1000 usecs
;    }
;    else
;    { ccp1con.CCP1Y = (width & 1);
;      ccp1con.CCP1X = (width & 2);
;      ccpr1l = (width >> 2);   // 0..250 (0..1000 usecs)
;      width = 0;               // force remaining frames to 0%
;    }
;  }
;
 
Last edited:
Thanks for all the replies! It was pointed out to me that I was working on the wrong endianess - I feel a little sheepish now, baaaah...

Mike, thanks for the example. I'll go back and play with my code later.

Again, many thanks for all your help.
 
Status
Not open for further replies.

Latest threads

Back
Top