2

This is my first post here so please forgive anything I do wrong :) This is my situation. I am writing a simple data transfer operation for a PIC16F876 using MPLAB and the HI-Tech C compiler.

I have a char called data, I wanted to access the bits in data and send them to portB0, starting with the MSB.

In assembly I would simply do:

PORTB,0 = data,7 // to get the MSB and put it on port B0, I would then do this for all bits.

However in C this seems to be more complicated. I have done some research and have found a function which works:

getBit(char data, int bitNumber)
{
     return (data & (1 << bitNumber-1)) != 0;
}

Then I just use:

PORTBbits.RB0 = getBit(data,7);

This is OK, but messy and seems to take longer, I dont know why I need an extra function... So my question is: Is there not a simple method to access a bit in a register? like:

PORTBbits.RB0 = data,7

I cant understand why there would not be as the complier converts it in to assembly anyway??!!!!

Thanks in advance. Regards, Tim.

Fred Foo
  • 355,277
  • 75
  • 744
  • 836
Tim M
  • 479
  • 1
  • 8
  • 21
  • 1
    you can use bitfields in struct. but this will be probably worse. – Elazar Apr 26 '13 at 15:19
  • http://stackoverflow.com/a/8584614/193892 – Prof. Falken Apr 26 '13 at 15:24
  • possible duplicate of [Access bits in a char in C](http://stackoverflow.com/questions/8584577/access-bits-in-a-char-in-c) – Prof. Falken Apr 26 '13 at 15:25
  • Hi there, thanks for your quick replies, Elazar, I did try that, but seeing as I want, in the end, to write a loop for the data send this doesn't work because I cant loop on a name. Amigable: I have looked at those (and other) topics, the ones I read seemed to be for the C language. Also, part of the question was why isn't there a simple solution, seeing as the language is based on ASM. – Tim M Apr 26 '13 at 15:44
  • Most C compilers will let you use inline assembly. For your multiple bits operation, you probably want a repeated shift, and to take your output from the MSB or LSB (depending on the order you want). – Chris Stratton Apr 26 '13 at 17:03

4 Answers4

12

Another way to accomplish what you looking for is something like this:

PORTBbits.RB0 = (data >> 7) & 1;

Or more generically:

#define BIT(x,n) (((x) >> (n)) & 1)
PORTBbits.RB0 = BIT(data, 7);
Remy Lebeau
  • 555,201
  • 31
  • 458
  • 770
  • This looks good, I'll try it, thanks. Still don't know why there isn't a simple option to directly access an element in a register, I thought C for PIC was meant to simplify things.... – Tim M Apr 26 '13 at 15:45
  • Worked like a charm, and I suppose data,7 Vs. (data >> 7) & 1 is a fairly close match in typing terms. I still don't see why its needed though... Many thanks for your help, I wasn't allowed to vote up as I have no rep, but this was my chosen answer :). – Tim M Apr 26 '13 at 15:55
3

Bear in mind that when you use a function, such as this, that means that you're going to push two values on the stack, perform a jump, execute operations, pop the stack and return a value.

You could get around it via a MACRO which would inline the code

#define GETBIT(x,n) ((x >> (n-1)) & 1)

Option #2 is the use of inline ASM if you're given to masochism and screaming to save cycles. ~smile~

K Scott Piel
  • 4,320
  • 14
  • 19
2

If you just need the bit, you can get it by ( data & (1 << (bitNumber-1)) ) != 0. Or you could define a macro to make it more readable as

#define getBit(x,y) ((x) & (1 << ((y)-1))) != 0

and call it by getBit(data,bitNumber)

The macro will remove the function overhead. But there is no operator to give you the bit value the way you wanted.

unxnut
  • 8,509
  • 3
  • 27
  • 41
0

Some (most?) micros have several registers for the pins - if you know what you are going to do then (f'rexample) writing to the SET or CLEAR pin registers saves the whole read-modify-write/masking kerfuffle.

You probably know, but for the sake of clarence - SET/CLEAR registers work by only setting or clearing the pin if the bit written is 1, if 0 is written the pin state is not changed, which means the hardware is doing the work for you. To set pin 3 of a port you just write 0x04 to the port_SET register. To clear it, you write 0x04 to the port_CLEAR register.

It's not always possible to use these, but it shaves a lot of CPU cycles off if you can.

John U
  • 2,886
  • 3
  • 27
  • 39