Go Down

Topic: Addressing 23017/4051 using I2C Serial Interface & PROGMEM (Read 11871 times) previous topic - next topic

Grumpy_Mike

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.

Pitchoilcan

can the pitches and LED addresses be defined at the same time ?


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.
Code: [Select]
//find it easier to use a bunch of if statements:-
[code]
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:-
Code: [Select]

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.
[/code]
================================
http://twit.tv/floss61
Think different
Think UbuntuStudio
============================

Grumpy_Mike

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:-
1) Work out the number to use with a .digitalRead()
2) 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.

Pitchoilcan

#33
May 10, 2012, 07:27 pm Last Edit: May 11, 2012, 03:21 am by Pitchoilcan Reason: 1
pondering 48*2  'if' statements
TWO ways of turning the lights on, you only need to use one of them:-

2) 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:-
Code: [Select]

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:-
Code: [Select]

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.
================================
http://twit.tv/floss61
Think different
Think UbuntuStudio
============================

Grumpy_Mike

Quote
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.

Quote
pondering 48*2  'if' statements

Well that is just silly, you don't need 96 if statements to control just 16 LEDs do you?


Pitchoilcan

#35
May 10, 2012, 08:40 pm Last Edit: May 11, 2012, 06:12 am by Pitchoilcan Reason: 1
][font=Verdana]Alternative conversion process | Just a reminder[/font][/i]]
Quote

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.

[font=Verdana]source: http://en.wikipedia.org/wiki/Two%27s_complement[/font]
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! :smiley-yell:

guess I'm NOT '[font=Verdana][font=Verdana]doing the steps[/font][/font]'
Quote
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.
================================
http://twit.tv/floss61
Think different
Think UbuntuStudio
============================

Pitchoilcan

Quote

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)
[font=Verdana]00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F 10 11 12 13 14 15[/font]

table 5 (IOCON=1)
Address
(hex)[/b][/s]
[font=Verdana]00 01 02 03 04 05 06 07 08 09 0A 10 11 12 13 14 15 16 17 18 19 1A[/font][/b][/s][/u]

|     |    |    |     |    |    |    |     |    |    |    |     |    |    |     |    |     |    |    |    |  
__[font=Verdana][font=Verdana]C  C# D  D# E  F   F# G  G# A  A#  B  C[/font] [/font] OFF________________

    [font=Verdana]60 61 62 63 64 65 66 67 68 69 70 71 72[/font]   [font=Verdana]Note numbers[/font]
============================================================================
Table 1-5
 (iocon=1)    |     Table 1-6 (iocon=0)
           [font=Verdana]  A    |    B[/font]
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                      
=====================
[font=Verdana]Table #[/font]
[font=Verdana]a[/font]  00 01 02 03 04 05 06 07 08 09 0A   [font=Verdana]//bank A[/font]
b  10 11 12 13 14 15 16 17 18 19 1A   [font=Verdana]//bank B[/font]

[font=Verdana]a[/font] 00 02 04 06 08 0A 0C 0E 10 12 14    [font=Verdana]//bank A[/font]
[font=Verdana]b[/font] 01 03 05 07 09 0B 0D 0F 11 13 15   [font=Verdana]//bank B[/font]
[font=Verdana]Table #[/font]
Quote
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.


[font=Verdana]*[/font]CS.portMode(0, 0b0111111001111110); // 0 = output, 1 = input
[font=Verdana]*[/font]CS.portWrite(0, 0b1000000110000001); // 0 = LOW, 1 = HIGH

I also find this very helpful:
=====

Quote
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.


Quote
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.


[font=Verdana]Source: http://en.wikipedia.org/wiki/Arithmetic_shift[/font]

================================
http://twit.tv/floss61
Think different
Think UbuntuStudio
============================

marco_c

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).
Arduino libraries http://arduinocode.codeplex.com
Parola for Arduino http://parola.codeplex.com

Pitchoilcan

#38
May 11, 2012, 02:34 am Last Edit: May 20, 2012, 04:20 pm by Pitchoilcan Reason: 1
Not a bad tutorial- [using just the wire library]    [font=Verdana][ Two's complement ][/font][/b][/u] the [font=Verdana] 23017 data sheet[/font] again http://ww1.microchip.com/downloads/en/DeviceDoc/21952b.pdf
[font=Verdana][font=Verdana]tronixstuff 230x1 tutorial revisited:[/font][/font]
http://tronixstuff.wordpress.com/2011/08/26/tutorial-maximising-your-arduinos-io-ports/
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 - [font=Verdana]see tables 1.3[/font] and [font=Verdana]1.4[/font]  [font=Verdana] on page nine of the data sheet. In our examples we will use the addresses listed on[/font] [font=Verdana]table 1.4[/font]. So the first command to use in void setup() is:
Code: [Select]
 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:
Code: [Select]
 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. [font=Verdana]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[/font].
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:
Code: [Select]
 Wire.beginTransmission(0x20);
 Wire.send(0x12); // address bank A
 Wire.send(??);  // value to send
 Wire.endTransmission();

[font=Verdana]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).[/font][/b][/i]

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 [font=Verdana]bank B[/font] after [font=Verdana]bank A[/font]. [font=Verdana]For example, we want [font=Verdana]bank A[/font] to be 11001100 and [font=Verdana]bank B to be 10001000[/font] - so we send the following:[/font][/b]

 
Code: [Select]
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 [font=Verdana]bank B[/font], if so [font=Verdana]bank A[/font] 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
Code: [Select]

/*
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()
Code: [Select]
// setup addressing style
 Wire.beginTransmission(0x20);
 Wire.send(0x12);
 Wire.send(0x20); // use table 1.4 addressing
 Wire.endTransmission();
================================
http://twit.tv/floss61
Think different
Think UbuntuStudio
============================

Pitchoilcan

#39
May 11, 2012, 02:56 am Last Edit: May 12, 2012, 06:54 am by Pitchoilcan Reason: 1
To Hex, or not to hex?.... [table A or table B][c or d]
An alternative conversion process
Quote

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: http://en.wikipedia.org/wiki/Two%27s_complement
 defining the LED and Note bits like so:
Code: [Select]

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:-
Code: [Select]

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;

================================
http://twit.tv/floss61
Think different
Think UbuntuStudio
============================

marco_c

Pointers and integers are two different things which is why you are stopped form doing that. It has no meaning, like comparing the address of a house to the house itself.

What are you trying to do?
Arduino libraries http://arduinocode.codeplex.com
Parola for Arduino http://parola.codeplex.com

Pitchoilcan

#41
May 12, 2012, 08:10 am Last Edit: May 20, 2012, 04:19 pm by Pitchoilcan Reason: 1
//Table 1-2  (0)
if(PadNote == 60) ledBits |= 0x01;
if(PadNote == 61) ledBits |= 0x02;
if(PadNote == 62) ledBits |= 0x03;
if(PadNote == 63) ledBits |= 0x04;
if(PadNote == 64) ledBits |= 0x05;

              // the same goes for turning the LED off:-

if(PadNote == 60) ledBits &= ~0x01;
if(PadNote == 61) ledBits &= ~0x02;
if(PadNote == 62) ledBits &= ~0x03;
if(PadNote == 63) ledBits &= ~0x04;
if(PadNote == 64) ledBits &= ~0x05;
Quote
In mathematics and computer science, hexadecimal (also base 16, or hex) is a positional numeral system with a radix, or base, of 16. It uses sixteen distinct symbols, most often the symbols 0-9 to represent values zero to nine, and A,?B,?C,?D,?E,?F (or alternatively a-f) to represent values ten to fifteen. For example, the hexadecimal number 2AF3 is equal, in decimal, to (2?×?163) + (10?×?162) + (15?×?161) + (3?×?160), or 10,995.
Each hexadecimal digit represents four binary digits (bits), and the primary use of hexadecimal notation is a human-friendly representation of binary-coded values in computing and digital electronics. One hexadecimal digit represents a nibble, which is half of an octet (8 bits). For example, byte values can range from 0 to 255 (decimal), but may be more conveniently represented as two hexadecimal digits in the range 00 to FF. Hexadecimal is also commonly used to represent computer memory addresses.
OK back to my scrapbook
Quote
16 (hexadecimal)      0x7B    leading "0x"     characters 0-9, A-F, a-f valid  
================================
http://twit.tv/floss61
Think different
Think UbuntuStudio
============================

marco_c

#42
May 12, 2012, 08:39 am Last Edit: May 12, 2012, 09:30 am by marco_c Reason: 1
padNote is an array of characters (or bytes, probably)
Code: [Select]

unsigned char PadNote[48] = {35,36,37,38,39,40,41,42,


to access one of the values of padNote you need to reference it using an array index, shown as i in the code below

Code: [Select]

if (padNote[i] == 99) ledPin |=  0x1;


Just using padNote on it's own, in C++, tells the compiler you are using the address of the array. That is an advanced topic for you to learn later.
Arduino libraries http://arduinocode.codeplex.com
Parola for Arduino http://parola.codeplex.com

Pitchoilcan

void readSensors(int analogPin){
   //This for loop is used to scroll through and store the 16 inputs on the FIRST multiplexer
 for (int i=0; i<16; i++){
   digitalWrite(CONTROL0, (i&15)>>3);
   digitalWrite(CONTROL1, (i&7)>>2);  
   digitalWrite(CONTROL2, (i&3)>>1);  
   digitalWrite(CONTROL3, (i&1));    

   //Read and store the input value at a location in the array
   if(analogPin==0){
     mux0array = analogRead(analogPin);
   }
   else if(analogPin==1){
     mux1array = analogRead(analogPin);
   }
   else if(analogPin==2){
     mux2array = analogRead(analogPin);
   }
   //Table 1-2  (0)
if(PadNote == 60) ledBits |= 0x01;
if(PadNote == 61) ledBits |= 0x02;
if(PadNote == 62) ledBits |= 0x03;
if(PadNote == 63) ledBits |= 0x04;
if(PadNote == 64) ledBits |= 0x05;

if(PadNote == 65) ledBits |= 0x06;
if(PadNote == 66) ledBits |= 0x07;
if(PadNote == 67) ledBits |= 0x08;
if(PadNote == 68) ledBits |= 0x09;
if(PadNote == 69) ledBits |= 0x0A;

if(PadNote == 70) ledBits |= 0x0B;
if(PadNote == 71) ledBits |= 0x0C;
////if(PadNote == 72) ledBits |= 0x0D;
////if(PadNote == 73) ledBits |= 0x0E;
////if(PadNote == 74) ledBits |= 0x0F;

              // the same goes for turning the LED off:-

if(PadNote == 60) ledBits &= ~0x01;
if(PadNote == 61) ledBits &= ~0x02;
if(PadNote == 62) ledBits &= ~0x03;
if(PadNote == 63) ledBits &= ~0x04;
if(PadNote == 64) ledBits &= ~0x05;

if(PadNote == 65) ledBits &= ~0x06;
if(PadNote == 66) ledBits &= ~0x07;
if(PadNote == 67) ledBits &= ~0x08;
if(PadNote == 68) ledBits &= ~0x09;
if(PadNote == 69) ledBits &= ~0x0A;

if(PadNote == 70) ledBits &= ~0x0B;
if(PadNote == 71) ledBits &= ~0x0C;
////if(PadNote == 72) ledBits &= ~0x0D;
////if(PadNote == 73) ledBits &= ~0x0E;
////if(PadNote == 74) ledBits &= ~0x0F;
 }
}
================================
http://twit.tv/floss61
Think different
Think UbuntuStudio
============================

Pitchoilcan

#44
May 12, 2012, 10:07 am Last Edit: May 12, 2012, 10:38 pm by Pitchoilcan Reason: 1
added
Code: [Select]
#include <Centipede.h>
#include <Wire.h>

Centipede ledBits; // create  object

 ledBits.initialize(); // set all registers to default

 ledBits.portMode(0, 0b0000000000000000); // set all pins on chip 0 to output

Not I get
twelve of these :
Quote
no match for 'operator |=' in 'ledBits |=1'  

and
twelve of these :
Quote
no match for 'operator &=' in 'ledBits &= -0x0000000002'  

How do I resolve this ?
================================
http://twit.tv/floss61
Think different
Think UbuntuStudio
============================

Go Up