3

Just trying to make sure I'm on the correct track here. I'm trying to store lots of 6-bit bytes into an array to control a parallel device with my PIC18F2550.

My array:

char pins[4] = {
        000000, //0
        000001, //1
        000010, //2
        000011, //3
        000100 //4
}

Later in my code, I want to be able to enter a command such as "Set 3" which will set pins RB0-RB5 to 000011 respectively.

PSEUDO CODE:

if command="Set 3" then find pins[3]{
LATBbits.LATB0 = pins[3][0];
LATBbits.LATB1 = pins[3][1];
LATBbits.LATB2 = pins[3][2];
LATBbits.LATB3 = pins[3][3];
LATBbits.LATB4 = pins[3][4];
LATBbits.LATB5 = pins[3][5];
}

which will give:

{
 LATBbits.LATB0 = 0;
 LATBbits.LATB1 = 0;
 LATBbits.LATB2 = 0;
 LATBbits.LATB3 = 0;
 LATBbits.LATB4 = 1;
 LATBbits.LATB5 = 1;
}

Is this an appropriate way to create this? Am I on the right track? Do you have suggestions on a better way to create an efficient array to control a 6bit parallel device with many settings?

Thanks everyone!

13
  • 1
    char pins[4] should be char pins[5]... Commented Dec 30, 2015 at 21:47
  • 1
    also, 000000 is not a 6-bit value.... Commented Dec 30, 2015 at 21:47
  • Ah, thanks for that! Aside from that, is that an okay strategy for what I'm trying to do? Commented Dec 30, 2015 at 21:53
  • I am pretty sure you can write the port as a byte/word rather than individual bits..Like LATB=0x5A Commented Dec 30, 2015 at 22:00
  • Your approach is ok in general. But the shown code will not quite work for a number of reasons.1. Those are not binary literals that you have shown in the pins array definition. The C standard does not define binary literals at all. gcc does have an extension for that (but not sure if that is your compiler). 2. You cannot access bits in a char with array notation. You need to use masking (&) and optionally shifting (<< and >>). Commented Dec 30, 2015 at 22:04

1 Answer 1

3

You are on the wrong track for many reasons.

Wrong track #1: In your array definition, the C compiler will not interpret values like 000011 as binary. It will interpret that as octal because of the leading zeroes. So 000011 is octal which is decimal 9. So your array contains the values zero, one, eight, nine, and sixty-four.

You might be able to write the value like 0b000011 to tell the compiler that the value is binary. But that is not standard C and many C compilers do not support that. You'll have to check whether your compiler supports that convention.

Wrong track #2: Your intention was to create an array containing the values 0, 1, 2, 3, 4. Notice that the value of each member of the array is equal to the index of that member. This array is pointless. Just use the index value directly rather than as an index into an array which simply returns the original index value.

Wrong track #3: When you set LATBbits.LATB0 = pins[3][0]; you are trying to reference a one-dimensional array as if it were a two-dimensional array. You can't do that. You cannot use an extra array dimension specifier on a value to pull out a bit from that value. The C language doesn't work that way.

Wrong track #4: Just because LATBbits has bitfields defined, it doesn't mean that you cannot set LATBbits directly. In other words, you don't have to set the bits individually. You can set all the bits at once simply by setting LATBbits directly.

Wrong track #5: You wrote that LATB4 and LATB5 will be set to 1. But those are not the least significant bits of LATBbits. LATB0 and LATB1 are the least significant bits and those are the ones that will be set when you set LATBBits = 0b000011.

The right track: Take a look at the definition of LATBbits. I found this online, make sure it matches the definition in your header file.

//==============================================================================
//        LATB Bits

extern __at(0x0F8A) __sfr LATB;

typedef struct
  {
  unsigned LATB0                : 1;
  unsigned LATB1                : 1;
  unsigned LATB2                : 1;
  unsigned LATB3                : 1;
  unsigned LATB4                : 1;
  unsigned LATB5                : 1;
  unsigned LATB6                : 1;
  unsigned LATB7                : 1;
  } __LATBbits_t;

extern __at(0x0F8A) volatile __LATBbits_t LATBbits;

#define _LATB0                  0x01
#define _LATB1                  0x02
#define _LATB2                  0x04
#define _LATB3                  0x08
#define _LATB4                  0x10
#define _LATB5                  0x20
#define _LATB6                  0x40
#define _LATB7                  0x80

I'm pretty sure that your entire example pseudo code can be reduced to this.

if command="Set 3" then {
    LATB = 3;
}

There is no need for the array and there is no need to set the bits individually. You could set either LATB or LATBbits (They're two different names for the same memory mapped register). Setting LATB (or LATBbits) = 3 will result in LATB0 and LATB1 being set and the other bits being cleared.

If the LATB value did not match the command value then it might be useful to use an array to lookup the LATB value. For example, suppose you really do want LATB4 and LATB5 set when command is 3. In that case, you should use the _LATBx definitions to define the array like this:

char pins[] = {
    0,                  // All bits clear
    (_LATB0),           // Bit 0 set
    (_LATB1),           // Bit 1 set
    (_LATB4 | _LATB5),  // Bit 4 and Bit 5 set
    (_LATB2)            // Bit 2 set
}

Then you could set LATB from the array like this.

LATB = pins[3];
Sign up to request clarification or add additional context in comments.

4 Comments

Thanks @casey. I've updated my answer. I've probably never used octal literals and had forgotten that the leading zeroes are interpreted that way.
This requires that you always program all bits of the LAT at once, and their old state is never important. One needs a form of atomic XOR for the better solution. That exists for the pic24/33f range, but I don't know if it exists for 8-bit too.
bitfields are evil and should never be used. there is no guarantee of ordering or alignment, it is implementation defined, not assumed to port from one compiler to another nor from one version of the same compiler to another. for the same reason you should never use structs across compile domains. using an approach like this carries the baggage of maybe having to re-write it from time to time. So you are gambling with an approach like this, maybe it works long enough or maybe you have to keep re-doing it. Understand this and what your other choices are. When it goes bad it goes really bad
Bitfields are the only good way to set individual port pins on the 8 bit devices. Also be aware that some 8 bit devices have only the port register, which can lead to problems when writing one bit and getting spurious changes on other bits (due to the read modify write sequence). This is not a problem on your micro though as long as you always read the port and write to the latch register.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.