So why do you not use the centipede library with your own project? Then you would not have to rewrite anything.
As for the reset pin I connect it to an arduino output and toggle it on start up.
if(w != x)
{ // something has changed
// write the value of x to your LED port expander interface here
y = 1;
some have resistors on pins 4 and 5 other don't,
The ones without pull up resistors on pins 4 & 5 are wrong, no debate about it, it is just wrong.
OK lets spell it out. Use the Centipede library and change your code to write out all 16 bits at once to light your LEDs:-
if(w != x)
{ // something has changed
// write the value of x to your LED port expander interface here
myInstance.portWrite(0, x);
y = 1;
Having first made an instance ( I called it myInstance ) like you did in the knightrider program, and setting all the bits to outputs like you did in the knightrider program.
add
#include <Centipede.h>
and change
if(w != x)
{ // something has changed
// write the value of x to your LED port expander interface here
y = 1;
to
if(w != x)
{ // something has changed
// write the value of x to your LED port expander interface here
myInstance.portWrite(0, x);
y = 1;
Add:-
#include <Centipede.h>
Centipede myInstance; // create Centipede object
Then inside the setup() function add:-
myInstance.initialize(); // set all registers to default
myInstance.portMode(0, 0); // set all pins on chip 0 to output
then what I said before:-
if(w != x)
{ // something has changed
// write the value of x to your LED port expander interface here
myInstance.portWrite(0, x);
y = 1;
But this is totally different code to what you posted earlier. I can't even see the variable x mentioned in this code you have just posted. Do you understand what you are trying to do?
You need to send to the LEDs a 16 bit value, an integer. Each bit in the integer represents an LED that will turn on or off. When you scan through all the sensors that other code was putting a bit in an integer that represented the state of that sensor.
What is that code you posted? Have you missed things out of it?
Mike Thanks for the info I checked and now my running v1.0. So I'll Try to leave the whole thing intact including the qtrSensors, and see how far I get. I understand what I'm trying to do but not how to do it. And marco_c I've made note of your update to the mux section. So my focus is still on the LEDs
and trying to turn them on/off based on whats happening here
void checkSensors(int analogPin){
for(int pin=0; pin < 16; pin++){
//hitavg = analogRead(pin); // read the input pin
//hitavg = muxArray[pin]; // read the input pin
if(analogPin==0){
hitavg = mux0array[pin];
pad=pin;
}
else if(analogPin==1){
hitavg = mux1array[pin];
pad=pin+16;
}
else if(analogPin==2){
hitavg = mux2array[pin];
pad=pin+32;
}
if((hitavg > PadCutOff[pin])){
//Serial.write("hitavg > PadCutOff[pin])");
//Serial.write(' ');
if((activePad[pad] == false)){
if(VelocityFlag == true){
//hitavg = 127 / ((1023 - PadCutOff[pin]) / (hitavg - PadCutOff[pin])); // With full range (Too sensitive ?)
hitavg = (hitavg / 8) -1 ; // Upper range
}
else{
hitavg = 127;
}
if (analogPin==0 && PadNote[pad]==42){ // array position = 7 , Hihat is handeld in a special way
qtra.readCalibrated(sensorValues);
unsigned char i;
for (i = 0; i < NUM_SENSORS; i++){
//Serial.write(sensorValues[i] * 10 / 1001);
//Serial.write(' ');
hihatPos = sensorValues[i] * 10 / 1001;
if (hihatPos==0){
MIDI_TX(144,42,hitavg);
PinPlayTime[7] = 0;
activePad[7] = true;
// hihatWasTriggered=false;
}
else if (hihatPos >0 && hihatPos <= 6){
MIDI_TX(144,44,hitavg);
PinPlayTime[9] = 0;
activePad[9] = true;
// hihatWasTriggered = true;
}
else{
MIDI_TX(144,46,hitavg);
PinPlayTime[11] = 0;
activePad[11] = true;
// hihatWasTriggered = true;
}
}
}
else{
MIDI_TX(144,PadNote[pad],hitavg);
PinPlayTime[pad] = 0;
activePad[pad] = true;
}
}
else{
PinPlayTime[pad] = PinPlayTime[pad] + 1;
}
}
else if((activePad[pad] == true)){
PinPlayTime[pad] = PinPlayTime[pad] + 1;
if(PinPlayTime[pad] > MaxPlayTime[pad]){
activePad[pad] = false;
MIDI_TX(128,PadNote[pad],127);
}
}
}
}
You really need to understand what you are trying to achieve rather than just copying code, because your data mapping may/will be different from what others have done. Discipline is required!
Here's what I suggest as an approach:
-
Understand the commands you need to send to the MCP chip and how tio interact with it. As you had your knightrider thing going I am going to assume that you have some idea on how this needs to be done. Add the code to initialise the MCP thru the I2C in the setup function.
-
You need to work out how the data in your arrays (activePad?) maps to the bits for the MCP. Actually do this on a bit of paper - which element goes to which output bit - if is not clear. Hopefully you have a design that is linear and all the bits are consecutive which makes it easier as you can use loops.
-
Once the mapping is done, you then construct the 16 bit words using the ORing function we discussed at the start of this thread.
-
Then send those bytes to the MCP using the right address on the I2C interface.
Thanks for the suggestion!
working on the steps.........
#include <Wire.h>
#include <Centipede.h>
/* Available commands
.digitalWrite([0...127], [LOW...HIGH]) - Acts like normal digitalWrite
.digitalRead([0...127]) - Acts like normal digitalRead
.pinMode([0...127], [INPUT...OUTPUT]) - Acts like normal pinMode
.portWrite([0...7], [0...65535]) - Writes 16-bit value to one port (chip)
.portRead([0...7]) - Reads 16-bit value from one port (chip)
.portMode([0...7], [0...65535]) - Write I/O mask to one port (chip)
.pinPullup([0...127], [LOW...HIGH]) - Sets pullup on input pin
.portPullup([0...7], [0...65535]) - Sets pullups on one port (chip)
.init() - Sets all registers to initial values
Examples
CS.init();
CS.pinMode(0,OUTPUT);
CS.digitalWrite(0, HIGH);
int recpin = CS.digitalRead(0);
CS.portMode(0, 0b0111111001111110); // 0 = output, 1 = input
CS.portWrite(0, 0b1000000110000001); // 0 = LOW, 1 = HIGH
int recport = CS.portRead(0);
CS.pinPullup(1,HIGH);
CS.portPullup(0, 0b0111111001111110); // 0 = no pullup, 1 = pullup
*/
[ Two's complement ]
doing the steps
TABLE 1-2:
REGISTER ADDRESSES
Address
IOCON.BANK = 1
00h 10h 01h 11h 02h 12h 03h 13h 04h 14h 05h 15h 06h 16h 07h 17h 08h 18h 09h 19h 0Ah 1Ah
Address
IOCON.BANK = 0
00h 01h 02h 03h 04h 05h 06h 07h 08h 09h 0Ah 0Bh 0Ch 0Dh 0Eh 0Fh 10h 11h 12h 13h 14h 15hAccess to:
IODIRA IPOLA GPINTENA DEFVALA INTCONA IOCON GPPUA INTFA INTCAPA GPIOA OLATA
IODIRB IPOLB GPINTENB DEFVALB INTCONB IOCON GPPUB INTFB INTCAPB GPIOB OLATB
my muX bits
LSB MSB
0 1 2 4 5 6 7 8 9 10 11 12 13 14 15
The default mode of the mcp2317 is the sequential mode which is more like the knightrider example, however what I need is BYTE mode....
You are tying yourself in knots.
You have the centipede library so that removes one big problem for you, so stop worrying about the chip and how to drive it. You have that bit nailed.
What you need to do is to see how you can get from a MIDI note number to an LED number.
Supposed you used all the MIDI notes from 48 to 64 to output, that is 16 values. Then when you sent the MIDI note number all you would have to do is to do a .digitalWrite() to the MIDI note number minus 48.
However if your MIDI note numbers are not contiguous then you have to do something else. In that case it would make sense to do it when you read the sensors because there is a contiguous relationship between LED and sensor.
can the pitches and LED addresses be defined at the same time ?
Grumpy_Mike:
You send two bytes to the I2C port expander, each bit in those bytes will correspond to one of the LEDs. If you hold the current state of the lights in an int variable ( that is 16 bits ) then all you need to do is to set or clear the appropriate bit and then write it out to the port expander.The MIDI will have a note number associated with the note, and the LED will have a bit number associated with its control. You have to make sure you set the right bit for the right note. There are many ways to do this, the best being a look up table. This is implemented with an array whose index represents the MIDI note and the contents represent the bit to set.
So if you are sending MIDI note 64 then you fine the bit to set in the look up array position 64.//find it easier to use a bunch of if statements:-
if(midiNote == 64) ledBits |= 0x1;
if(midiNote == 65) ledBits |= 0x2;
if(midiNote == 66) ledBits |= 0x4;
if(midiNote == 67) ledBits |= 0x8;
if(midiNote == 68) ledBits |= 0x10;
> ```
>
>
> the same goes for turning the LED off:-
>
>
> ```
> if(midiNote == 64) ledBits &= ~0x1;
if(midiNote == 65) ledBits &= ~0x2;
if(midiNote == 66) ledBits &= ~0x4;
if(midiNote == 67) ledBits &= ~0x8;
if(midiNote == 68) ledBits &= ~0x10;
> ```
>
>
> Note here that ~0x10 is tilda 0x10 not minus.
I don't know why you are just posting lumps of the data sheet for the MCP23X17 chip. I can read the original and so can you.
Forget the data sheet about the chip. It is way too complicated for you to understand. The Centipede library offers you easy access to the hardware.
Let me try again to tell you about this.
There are TWO ways of turning the lights on, you only need to use one of them:-
- Work out the number to use with a .digitalRead()
- Set and clear bits in an int variable and use .portWrite()
Method 1 is easier to do when you are actually sending the MIDI data.
Method 2 is easier to do when you are reading the sensors in.
pondering 48*2 'if' statements
TWO ways of turning the lights on, you only need to use one of them:-
- Set and clear bits in an int variable and use .portWrite() //Write XOR 230x17 Expander Pins
So if you are sending MIDI note 64 then you fine the bit to set in the look up array position 64.
//I find it easier to use a bunch of if statements:-
if(midiNote == 64) ledBits |= 0x1;
if(midiNote == 65) ledBits |= 0x2;
if(midiNote == 66) ledBits |= 0x4;
if(midiNote == 67) ledBits |= 0x8;
if(midiNote == 68) ledBits |= 0x10;
the same goes for turning the LED off:-
if(midiNote == 64) ledBits &= ~0x1;
if(midiNote == 65) ledBits &= ~0x2;
if(midiNote == 66) ledBits &= ~0x4;
if(midiNote == 67) ledBits &= ~0x8;
if(midiNote == 68) ledBits &= ~0x10;
There is no difference between an LED and a solenoid. I did not know that.
Good to know :%
I now understand it it's matter of both Bitwise AND as well as Bitwise XOR.
There is no difference between an LED and a solenoid.
Now if you are going to be silly and take things out of context like that I won't play with you any more.
That statement was made in the context of you saying that the code only turned on solenoids and not LEDs. In the context of the code needed to turn a device on the is indeed no difference between an LED and a solenoid.
pondering 48*2 'if' statements
Well that is just silly, you don't need 96 if statements to control just 16 LEDs do you?
]Alternative conversion process | Just a reminder]
A shortcut to manually convert a binary number into its two's complement is to start at the least significant bit (LSB), and copy all the zeros (working from LSB toward the most significant bit) until the first 1 is reached; then copy that 1, and flip all the remaining bits. This shortcut allows a person to convert a number to its two's complement without first forming its ones' complement. For example: the two's complement of "0011 1100" is "1100 0100", where the underlined digits were unchanged by the copying operation (while the rest of the digits were flipped).
In computer circuitry, this method is no faster than the "complement and add one" method; both methods require working sequentially from right to left, propagating logic changes. The method of complementing and adding one can be sped up by a standard carry look-ahead adder circuit; the alternative method can be sped up by a similar logic transformation.
source: Two's complement - Wikipedia
I said 48 because I have 48 inputs. at the moment only 24 piezos and 16 LEDs but I hope go to 48 piezos and perhaps buy a centipede shield and use 48 LED although at the moment twelve or 16 LED would be enough. Just extrapolating for the entire mux-shield;
Lol about the solenoid! ![]()
guess I'm NOT 'doing the steps'
You have the centipede library so that removes one big problem for you, so stop worrying about the chip and how to drive it. You have that bit nailed.
CS.portMode(0, 0b0111111001111110); // 0 = output, 1 = input
CS.portWrite(0, 0b1000000110000001); // 0 = LOW, 1 = HIGH
marco_c writing it out on paper really helps. so I'm doing the steps..Thanks mate!
Back to the data sheet for a moment and doing the steps
is this any good for first 12 LEDs?, there maybe errors here.
pondering.........
table 6 (IOCON=0)
Address
(hex)
00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F 10 11 12 13 14 15
table 5 (IOCON=1)
Address
(hex)
00 01 02 03 04 05 06 07 08 09 0A 10 11 12 13 14 15 16 17 18 19 1A
| | | | | | | | | | | | | | | | | | | | |
C C# D D# E F F# G G# A A# B C OFF______________
60 61 62 63 64 65 66 67 68 69 70 71 72 Note numbers
Table 1-5
(iocon=1) | Table 1-6 (iocon=0)
A | B
ALL OFF 00 10 | 00 01 C4
C# 01 11 | 02 03 D
D# 02 10 | 04 05 E
F 03 13 | 06 07 F#
G 04 14 | 08 09 G#
A 05 15 | 0A 0B A#
B 06 16 | 0C OD C5
NULL 07 17 | 0E OF NULL or OFF
NULL 08 18 | 10 11 NULL
NULL 09 19 | 12 13 NULL
NULL A0 1A | 14 16 NUL
Table #
a 00 01 02 03 04 05 06 07 08 09 0A //bank A
b 10 11 12 13 14 15 16 17 18 19 1A //bank B
a 00 02 04 06 08 0A 0C 0E 10 12 14 //bank A
b 01 03 05 07 09 0B 0D 0F 11 13 15 //bank B
Table #
1.3.1
BYTE MODE AND SEQUENTIAL
MODE
The MCP23X17 family has the ability to operate in Byte
mode or Sequential mode (IOCON.SEQOP).
Byte Mode..............A special mode (Byte mode with IOCON.BANK = 0)
causes the address pointer to toggle between
associated A/B register pairs. For example, if the BANK
bit is cleared and the Address Pointer is initially set to
address 12h (GPIOA) or 13h (GPIOB), the pointer will
toggle between GPIOA and GPIOB. Note that the
Address Pointer can initially point to either address in
the register pair.
Sequential mode...............These two modes are not to be confused with single
writes/reads and continuous writes/reads that are
serial protocol sequences.
*CS.portMode(0, 0b0111111001111110); // 0 = output, 1 = input
*CS.portWrite(0, 0b1000000110000001); // 0 = LOW, 1 = HIGH
I also find this very helpful:
A left arithmetic shift of a binary number by 1. The empty position in the least significant bit is filled with a zero. Note that arithmetic left shift may cause an overflow; this is the only way it differs from logical left shift.
A right arithmetic shift of a binary number by 1. The empty position in the most significant bit is filled with a copy of the original MSB.
Source: Arithmetic shift - Wikipedia
If you are using the Centipede library then your mapping should be easier.
As Grumpy_Mike says, you can pretty much forget that you have the hardware there and just turn on the output you need using the correct functions in the CS library, so you really need to read the library documentation and code examples.
As I don't have experience with the libraries I'll watch from the sidelines and learn (He's probably in a better time zone anyway).
Not a bad tutorial- [using just the wire library] [ Two's complement ] the 23017 data sheet again http://ww1.microchip.com/downloads/en/DeviceDoc/21952b.pdf
tronixstuff 230x1 tutorial revisited:
Tutorial: Maximising your Arduino’s I/O ports with MCP23017 | tronixstuff.com
Now to examine how to use the IC in our sketches. As you should know by now most I2C devices have several registers that can be addressed. Each address holds one byte of data that determines various options. With the MCP23017 the registers can be ordered in one of two ways – see tables 1.3 and 1.4 on page nine of the data sheet. In our examples we will use the addresses listed on table 1.4. So the first command to use in void setup() is:
Wire.beginTransmission(0x20);
Wire.send(0x12);
Wire.send(0x20); // use table 1.4 addressing
Wire.endTransmission();
The next is to set the I/O ports as inputs or outputs. First we will work with outputs. When the MCP23017 is turned on or reset, it defaults to inputs so we need to change them. So we use:
Wire.beginTransmission(0x20);
Wire.send(0x00); // IODIRA register
Wire.send(0x00); // set all of bank A to outputs
Wire.send(0x00); // set all of bank B to outputs
Wire.endTransmission();
Go back to the data sheet and see table 1.4. Notice how we started with the IODIRA (“I/O direction, bank A”) register at 0×00 and sent two bytes? You can do this without having to separate address the second register. This only works when the registers have sequential addresses, as in this example we wanted a byte to go to 0×00 then 0×01. We sent zero which in binary is 00000000 – each bit refers to one output of the bank and refers to I/O pins 7~0.
So now we are in void loop() or a function of your own creation and want to control some output pins. To control bank A, we use:
Wire.beginTransmission(0x20);
Wire.send(0x12); // address bank A
Wire.send(??); // value to send
Wire.endTransmission();
… replacing ?? with the binary or equivalent hexadecimal or decimal value to send to the register. To calculate the required number, consider each I/O pin from 7 to 0 matches one bit of a binary number – 1 for on, 0 for off. So you can insert a binary number representing the output levels. Or if binary does your head in, convert it to hexadecimal. So for example, you want pins 7 and 1 on. In binary that would be 10000010, in hexadecimal that is 0×82, or 130 decimal. (Using decimals is convenient if you want to display values from an incrementing value or function result).
If you had some LEDs via resistors connected to the outputs, you would have this as a result of sending 0×82:
Now if you want to address all the outputs at once, just send the byte for bank B after bank A. For example, we want bank A to be 11001100 and bank B to be 10001000 – so we send the following:
Wire.beginTransmission(0x20);
Wire.send(0xCC); // address bank A
Wire.send(0x88); // address bank B
Wire.endTransmission();
… with the results as such (bank B on the left, bank A on the right):
You can also just address bank B, if so bank A does not change. Now let’s put all of this output knowledge into a more detailed example. From a hardware perspective we are using a circuit as described above, with the addition of a 560 ohm resistor followed by an LED thence to ground from on each of the sixteen outputs. Here is the sketch (download):
Example 41.1
/*
Example 41.1 - Microchip MCP23017 with Arduino
http://tronixstuff.wordpress.com/tutorials > chapter 41
John Boxall | CC by-sa-nc
*/
// pins 15~17 to GND, I2C bus address is 0x20
#include "Wire.h"
void setup()
{
Wire.begin(); // wake up I2C bus
// setup addressing style
Wire.beginTransmission(0x20);
Wire.send(0x12);
Wire.send(0x20); // use table 1.4 addressing
Wire.endTransmission();
// set I/O pins to outputs
Wire.beginTransmission(0x20);
Wire.send(0x00); // IODIRA register
Wire.send(0x00); // set all of bank A to outputs
Wire.send(0x00); // set all of bank B to outputs
Wire.endTransmission();
}
void binaryCount()
{
for (byte a=0; a<256; a++)
{
Wire.beginTransmission(0x20);
Wire.send(0x12); // GPIOA
Wire.send(a); // bank A
Wire.send(a); // bank B
Wire.endTransmission();
delay(100);
}
}
void loop()
{
binaryCount();
delay(500);
}
And here is the example blinking away:
Although that may have seemed like a simple demonstration, it was created show how the outputs can be used. So now you know how to control the I/O pins set as outputs. Note that you can’t source more than 25 mA of current from each pin, so if switching higher current loads use a transistor and an external power supply and so on.
Now let’s turn the tables and work on using the I/O pins as digital inputs. The MCP23017 I/O pins default to input mode, so all we need to do is set the addressing method as such in void setup()
// setup addressing style
Wire.beginTransmission(0x20);
Wire.send(0x12);
Wire.send(0x20); // use table 1.4 addressing
Wire.endTransmission();
To Hex, or not to hex?.... [table A or table B][c or d]
An alternative conversion process
A shortcut to manually convert a binary number into its two's complement is to start at the least significant bit (LSB), and copy all the zeros (working from LSB toward the most significant bit) until the first 1 is reached; then copy that 1, and flip all the remaining bits. This shortcut allows a person to convert a number to its two's complement without first forming its ones' complement. For example: the two's complement of "0011 1100" is "1100 0100", where the underlined digits were unchanged by the copying operation (while the rest of the digits were flipped).
In computer circuitry, this method is no faster than the "complement and add one" method; both methods require working sequentially from right to left, propagating logic changes. The method of complementing and adding one can be sped up by a standard carry look-ahead adder circuit; the alternative method can be sped up by a similar logic transformation.
source: Two's complement - Wikipedia
defining the LED and Note bits like so:
if(midiNote == 64) ledBits |= 0x1;
if(midiNote == 65) ledBits |= 0x2;
if(midiNote == 66) ledBits |= 0x4;
if(midiNote == 67) ledBits |= 0x8;
if(midiNote == 68) ledBits |= 0x10;
the same goes for turning the LED off:-
if(midiNote == 64) ledBits &= ~0x1;
if(midiNote == 65) ledBits &= ~0x2;
if(midiNote == 66) ledBits &= ~0x4;
if(midiNote == 67) ledBits &= ~0x8;
if(midiNote == 68) ledBits &= ~0x10;