leen15:
Hey ShapeShifter, you are a wizard with code right?
Code? What is this code you are talking about? I don't understand...
How can i convert it for detect right shield (0-15) and right chip of the shield (0-3)?
The centipede function, passing a pin value of "120", detect that it need to send the command to chip 8, GPIO-B and pin 0, but i don't undestand how.. i'm not so expert with binary numbers.
In my case i should detect that is shield 1, chip 3, GPIO-B, pin 0. How can i do it?
First off, number everything with zero based numbers, it will make the math MUCH easier. You have up to 1024 logical pins, numbered 0 through 1023:
- 8 pins per port, 0 - 7
- 2 ports per chip, 0=A, 1=B
- 4 chips per board, 0 - 3
- up to 16 boards, 0 - 15
Normally, you would use a lot of division and modulo (remainder after division) arithmetic to convert a logical pin number to a physical board/chip/pin address:
- Take the logical pin number modulo 8 to get the physical pin number. Logical pin 120 becomes physical pin 0
- Divide the logical pin number by 8 (the number of pins per port) then take modulo 2 to get the port number. Logical pin 120 becomes port 1 (B)
- Divide the logical pin number by 16 (the number of pins per chip) then take modulo 4 to get the chip number. Logical pin 120 becomes chip 2
- Divide the logical pin number by 64 (the number of pins per board) and the integer portion is your board number. Logical pin 120 becomes board 1
But in this case, since all of the factors are powers of 2, it becomes much easier. The lowest 3 bits (8 values) are the pin number, the next bit (two values) is the port number, the next 2 bits (4 values) are the chip number, and the remaining 4 bits (16 values) are the board number. That's a total of 3 + 1 + 2 + 4 = 10 bits, which gives you your logical pin number range of 0 to 1023. Using B for board, C for chip, P for port, and p for physical pin, the 10 bits of a logical pin number become:
15 14 13 12 11 10 9 8 7 6 5 4 3 2 1 0
0 0 0 0 0 0 B B B B C C P p p p
You can extract those bits by shifting and masking. (If you're not familiar with them, look up the C or C++ shift and bitwise AND operators.)
unsigned logicalPin;
// The logical pin is already in the LSB position, so just mask off the rest of it.
byte pin = (logicalPin & 0x07);
// Shift the port number to the LSB, then mask off the other bits
byte port = ((logicalPin >> 3) & 0x01);
// Shift the chip number to the LSB, then mask off the other bits
byte chip = ((logicalPin >> 4) & 0x03);
// Shift the board number to the LSB, then mask off the other bits
byte board = ((logicalPin >> 6) & 0x0f);
Having everything zero based like this makes it easy to use these values as indexes into arrays to act as lookup tables. For example, you could create a constant 4 element array of I2C addresses, and then index it by the chip number to get the I2C address of the chip.
// Define a constant lookup table to convert chip number 0-3 to an I2C address
const byte I2Caddress[] = (36, 37, 38, 39};
byte address = I2Caddress[chip];
However, if you are going to use a switch statement to convert the chip number to an I2C address, then you really don't have to spend the execution time shifting the address into place, just mask it off and use the appropriate case alternative constants:
// Mask off and decode the chip number bits
switch (logicalPin & 0x30)
{
case 0x00: address = 36; break;
case 0x10: address = 37; break;
case 0x20: address = 38; break;
case 0x30: address = 39; break;
}
You could do the same thing with the port number to translate that into a device register address, as well as translate the board number into the digital I/O.
// Mask off and convert the board number bits
switch (logicalPin & 0x03c0)
case
{
case 0x0000: digitalWrite(a0Pin, low); digitalWrite(a1pin, low); digitalWrite(a2pin, low); digitalWrite(a3pin, low); break;
case 0x0040: digitalWrite(a0Pin, low); digitalWrite(a1pin, low); digitalWrite(a2pin, low); digitalWrite(a3pin, high); break;
case 0x0080: digitalWrite(a0Pin, low); digitalWrite(a1pin, low); digitalWrite(a2pin, high); digitalWrite(a3pin, low); break;
... and so on ...
case 0x03c0: digitalWrite(a0Pin, high); digitalWrite(a1pin, high); digitalWrite(a2pin, high); digitalWrite(a3pin, high); break;
But it would be tedious to write out 16 case alternatives and the appropriate four digitalWrite statements for each one. You could create an array of 16 elements, where each element is a structure for holding the values of the four output bits, but there is an even simpler way. Since the four bits that identify a board are a straight binary sequence just like the four bits that are output to select the board, the whole board selection process can come down to:
// Decode the logical pin number to address bits and set the outputs
digitalWrite(a0pin, (logicalPin & 0x0040));
digitalWrite(a1pin, (logicalPin & 0x0080));
digitalWrite(a2pin, (logicalPin & 0x0100));
digitalWrite(a3pin, (logicalPin & 0x0200));
There is a lot here. If there is anything you don't understand, I would spend some time studying it, researching it, and asking questions until the whole thing makes sense. Once you understand it all, you can decide which is the best way to decode the values, and then you can decide how to write the rest of the library.