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!

coolestDisplayName
  • 161
  • 1
  • 2
  • 9
  • 1
    `char pins[4]` should be `char pins[5]`... – Sourav Ghosh Dec 30 '15 at 21:47
  • 1
    also, `000000` is not a 6-bit value.... – Sourav Ghosh Dec 30 '15 at 21:47
  • Ah, thanks for that! Aside from that, is that an okay strategy for what I'm trying to do? – coolestDisplayName Dec 30 '15 at 21:53
  • I am pretty sure you can write the port as a byte/word rather than individual bits..Like `LATB=0x5A` – Eugene Sh. Dec 30 '15 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 `>>`). – kaylum Dec 30 '15 at 22:04
  • @kaylum There is a bit-field option as well... – Eugene Sh. Dec 30 '15 at 22:06
  • @EugeneSh.Yes, agreed. Good point. – kaylum Dec 30 '15 at 22:10
  • Are you trying to create an array where each element has the same value as its index? (That's not what you actually did but it seems like that was your intention.) If that's true then wouldn't it be simpler to just use the index value directly, rather than as an index into an array? – kkrambo Dec 30 '15 at 22:37
  • Should the "Set 3" command set bits 4 and 5, as you have shown? Or should it really set bits 0 and 1, as I would expect. In other words, is LATB0 the least significant bit or is LATB5 the least significant bit? Or, are you trying to reverse the order of the bits for some reason? – kkrambo Dec 30 '15 at 22:41
  • I suspect your pseudo code could be as simple as: `if command="Set 3" then LATBbits = 3;`. Why do you think it needs to be more complicated than that? – kkrambo Dec 30 '15 at 22:52
  • @kkrambo Interesting. Thanks for this tip! I think I am overcomplicating it. So, I could do something like `if command="Set 3" then LATBbits = pins[3];` ? Does pins[3] need to be something like 0b000011 rather than just 000011? Thanks guys! Still learning but this is certainly fun stuff! – coolestDisplayName Dec 31 '15 at 03:23
  • Why do you need the array? Just set LATBbits = 3. – kkrambo Dec 31 '15 at 04:09
  • I solved such an issue for the 16-bit range (pic24/dspic33) series once. Maybe it helps: http://www.microchip.com/forums/m794597.aspx – Marco van de Voort Jan 01 '16 at 17:26

1 Answers1

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];
kkrambo
  • 6,643
  • 1
  • 17
  • 30
  • 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. – kkrambo Dec 31 '15 at 19:04
  • 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. – Marco van de Voort Jan 01 '16 at 17:28
  • 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 – old_timer Jan 02 '16 at 02:58
  • 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. – user1582568 Jan 02 '16 at 23:53