Pages: [1] 2 3 ... 6   Go Down
Author Topic: Addressing 23017/4051 using I2C Serial Interface & PROGMEM  (Read 10500 times)
0 Members and 1 Guest are viewing this topic.
New York City, NY
Offline Offline
Full Member
***
Karma: 0
Posts: 101
Arduino Rocks!
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Hello, I'm trying to understand how to use an I2c port expander to drive 16 LEDs. An Example of what I'm trying to do is coded like this:
Code:
#include <Wire.h>
lastLedVal = 0;
// Setup I2C devices
Wire.begin(); // start the I2C interface
// Initilise registers
gpio_write(ledAddress, ddrTrigger, I2CregisterConfig); // Make into outputs
gpio_write(ledAddress, 0, I2CregisterInput); // turn them all off
doSensorScan(); // get initial states

// the value of threshold determins the on / off point
void lookForChange(){
int ledVal = 0;
int ledMask = 1;
for(int i=0; i<16; i++){
if(currentState[i] < threshold) ledVal |= ledMask; // add a 1 in the position of sensors under threshold
ledMask = ledMask << 1;
}
if(lastLedVal != ledVal) { // something has changed
ledMask = 1;
for(int i=0; i<16; i++){
if((ledMask & ledVal) != (ledMask & lastLedVal)){
if((ledMask & ledVal) == 0) {
// note off
controlSend(0x80, control[i], 0x00); // turn off control message
//noTone(8);
 
}
else{
// note on
controlSend(0x90, control[i], currentState[i]>>3); // turn on control message
//tone(8, notes[i], 20);

}
}
ledMask = ledMask << 1;
}
// Update the trigger LEDs
gpio_writeByteInverse(ledAddress, ledVal, I2CregisterInput);
}
lastLedVal = ledVal; // record current state of LEDs and MIDI notes / messages

}
From my research I've learned that it's called  exclusive disjunction.
Quote
Logical disjunction [i.e.] exclusive disjunction
The logical operation exclusive disjunction, also called exclusive or (symbolized by the prefix operator J, or by the infix operators XOR, EOR, EXOR, ⊻ or ⊕,  /ˌɛks ˈɔr/ or /ˈzɔr/), is a type of logical disjunction on two operands that results in a value of true if exactly one of the operands has a value of true.[1] A simple way to state this is "one or the other but not both."
Put differently, exclusive disjunction is a logical operation on two logical values, typically the values of two propositions, that produces a value of true only in cases where the truth value of the operands differ.
http://en.wikipedia.org/wiki/Exclusive_disjunction

My question is: are the code snippet and the quote above the same?
A related post http://arduino.cc/forum/index.php/topic,103925.msg784024.html#msg784024 deals with wiring and the required libraries, this post is concerned with the coding of the chip.
http://www.arduino.cc/en/Reference/Bitwise
curious thing is that I don't see  the caret symbol ^ in the code I see symbols like: &, =!, <<, ==0 etc. I have the arduino ref docs so I recognize shift left, shit right, is not and so on, But I'm little unclear on what the code is doing. Can someone help me understand what the code is doing.

Thanks much.
« Last Edit: May 20, 2012, 09:26:05 am by Pitchoilcan » Logged

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

Austin, TX
Offline Offline
Faraday Member
**
Karma: 71
Posts: 6146
Baldengineer
View Profile
WWW
 Bigger Bigger  Smaller Smaller  Reset Reset

That article is missing a few (read: all?) of the actual bitwise operators.

If you look at the "Bitwise Operators" section of the Reference Page, you'll see all of them.
http://arduino.cc/it/Reference/HomePage

Comparison and Boolean Operators are shown as well.

Logged

Capacitor Expert By Day, Enginerd by night.  ||  Personal Blog: www.baldengineer.com  || Electronics Tutorials for Beginners:  www.addohms.com

Sydney, Australia
Offline Offline
Edison Member
*
Karma: 33
Posts: 1273
Big things come in large packages
View Profile
WWW
 Bigger Bigger  Smaller Smaller  Reset Reset

IMHO opinion you should think about what you want to do and build it up from there, as this code is doing something very specific.

Here's what the code in lookForChange is doing:

for(int i=0; i<16; i++){
if(currentState < threshold) ledVal |= ledMask; // add a 1 in the position of sensors under threshold
ledMask = ledMask << 1;
}

This builds up an integer sized (16 bits) mask of devices with a 1 in the position where the device's current state is less than the threshold. The loop counter is just used to step through the 16 bits and move the ledMask bit through all 16 positions by the right shift (ie, it start in 0001 then 0010 then 0100, etc). You end up with a pattern of 16 bits defining the devices that meet the condition in ledVal because ledMask is ORed into the original 0 value of ledVal (0 OR 1 is 1, 0 OR 0 is 0).

The next loop uses a similar technique to check the bits. By using AND instead of OR, you can extract the value that was packed into the 16 bits (eg, 0110 AND 0001 is 0000 - we are looking at the value of the rightmost bit - and 0110 AND 0010 is 0010 - this is not zero and so means that the second bit was turned on. The code

if((ledMask & ledVal) != (ledMask & lastLedVal)){

uses this technique to check which bit changes since the last time, as ledMask is used to skip through the bits. Note in this case we don't care what the value is, just that it is not the same as last time.

I think the rest of the code is straightforward. Not sure if this answers your question, but I am confident it explains the code...
« Last Edit: May 06, 2012, 05:46:58 pm by marco_c » Logged

Arduino libraries http://arduinocode.codeplex.com
Parola hardware & library http://parola.codeplex.com

New York City, NY
Offline Offline
Full Member
***
Karma: 0
Posts: 101
Arduino Rocks!
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Thanks marco_c, what I want to do is something very specific and that is: turn on 1 of 16 LEDs depending on which of 16 sensors and pressed. So when the program starts ALL LEDS are off i.e. writtten LOW, when one of the sensors are turned on (by Touch) a corresponding LED is written HIGH, when the senors are OFF the corresponding LEDs are off. So there are only two values. 0 or 1. One is LED on and the other is LED off. So IYHO this snippet is sufficient to accomplish is objective?
« Last Edit: May 06, 2012, 07:30:13 pm by Pitchoilcan » Logged

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

Sydney, Australia
Offline Offline
Edison Member
*
Karma: 33
Posts: 1273
Big things come in large packages
View Profile
WWW
 Bigger Bigger  Smaller Smaller  Reset Reset

It can be modified to do what you want but it is also probably more complex than it needs to be.

If the LED is on while the input is on, then you really don't need a lot of logic. Remember that the loop function is running all the time (ie, when it is finished it starts again), so you really only need to check that your input and write the same value to the output.

So build up the 16 bits as for the ledMask and then write those same 16 bits to the output. Would that work?

Otherwise the code will do what you need with the right mods.

« Last Edit: May 06, 2012, 05:49:26 pm by marco_c » Logged

Arduino libraries http://arduinocode.codeplex.com
Parola hardware & library http://parola.codeplex.com

Sydney, Australia
Offline Offline
Edison Member
*
Karma: 33
Posts: 1273
Big things come in large packages
View Profile
WWW
 Bigger Bigger  Smaller Smaller  Reset Reset

I forgot that you had I2C in the way so it is not a straight copy/paste between digital pins, but the concept remains (As you responded as I was changing the post).

With all embedded/microcontrol applications, the circuitry needs to be developed with the software(or vice versa) because they are interdependent. If your hardware is EXACTLY the same as the example, then you can also make the code exactly the same.

If you are changing the hardware, then you need to understand what the changes are and modify the code to suit. In this case, you need to understand the characterictics of the original device and those of the device you are using instead and go from there.
« Last Edit: May 06, 2012, 06:11:32 pm by marco_c » Logged

Arduino libraries http://arduinocode.codeplex.com
Parola hardware & library http://parola.codeplex.com

Sydney, Australia
Offline Offline
Edison Member
*
Karma: 33
Posts: 1273
Big things come in large packages
View Profile
WWW
 Bigger Bigger  Smaller Smaller  Reset Reset

OK then, based on what you have said and done, then you should be able to contruct a 16 bit integer with appropriate bits turned on and send it out to turn on the LEDs. I don't think there is a need to check if the status changed from last time, so eliminating all the code that does that will simplify your routine somewhat.

Good luck with your project!
Logged

Arduino libraries http://arduinocode.codeplex.com
Parola hardware & library http://parola.codeplex.com

New York City, NY
Offline Offline
Full Member
***
Karma: 0
Posts: 101
Arduino Rocks!
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Thanks again, for letting me bend your ear.
from my notes thus far we have Comparison Operators and Bitwise Operators in the code snippet
The pre-setup:
Code:
#include <Wire.h>
// Defines
#define I2CregisterInput 0
#define I2CregisterOutput 2
#define I2CregisterPolarity 4
#define I2CregisterConfig 6
#define I2CregisterInterrupt 8
#define I2CregisterExpander 10
// I2C device addresses
#define ledAddress   (0x20 | 0x0)     // address of trigger LED indicators output
// Control Switch device bit masks
#define ddrTrigger 0x00000     // data direction register for trigger indictor LEDs
// Variable definations
int currentstate[16]; // current state of sensors
int laststate[16];    // the last state of the sensors
int threshold = 0x90;  // sets the threshold value in deciding if a sensor is pressd.
int w;
The setup
Code:
// Start of code
void setup() {
   w = 0;
// Setup I2C devices
   Wire.begin();                      // start the I2C interface
// Initilise registers
   gpio_write(ledAddress, ddrTrigger, I2CregisterConfig);   // Make into outputs
   gpio_write(ledAddress, 0, I2CregisterInput);            // turn them all off
The algorithm
Code:
// the value of threshold determins the on / off point

  int x = 0;
  int y = 1;
  for(int i=0; i<16; i++){
    if(currentstate[i] < threshold) x |= y;   // add a 1 in the position of sensors under threshold
     y = y << 1;
   }
   if(w != x) {   // something has changed
   y = 1;

     for(int i=0; i<16; i++){
       if((y & x) != (y & w)){
         if((y & x) == 0) {
           // midi note off          
         }
         else{
           // midi note on
         }
       }
       y = y << 1;
     }
     // Update the trigger LEDs
       gpio_writeByteInverse(ledAddress, x, I2CregisterInput);
   }
   w = x;        // record current state of LEDs
}
upon review I find it more appropriate to call THIS the OUTPUT section
Code:
void gpio_write(int address, int data, int reg) {
  //  Send output register address
  Wire.beginTransmission(address);
  Wire.send(reg);
  //  Connect to device and send two bytes
  Wire.send(0xff & data);  //  low byte
  Wire.send(data >> 8);    //  high byte
  Wire.endTransmission();
}

void gpio_writeByteInverse(int address, int data, int reg) {
  //  Send output register address
  Wire.beginTransmission(address);
  Wire.send(reg);
  //  Connect to device and send two bytes
    Wire.send(data >> 8);    //  high byte
    Wire.send(0xff & data);  //  low byte
  Wire.endTransmission();
}

int gpio_read(int address) {
  int data = 0;
 //  Send input register address
  Wire.beginTransmission(address);
  Wire.send(I2CregisterInput);
  Wire.endTransmission();
  //  Connect to device and request two bytes
 // Wire.beginTransmission(address);
  Wire.requestFrom(address, 2);
 if (!Wire.available()) { } // do nothing until data arrives
    data = Wire.receive();

 if (!Wire.available()) { } // do nothing until data arrives
    data |= Wire.receive() << 8;
  Wire.endTransmission();
  return data;
}
« Last Edit: May 20, 2012, 09:24:55 am by Pitchoilcan » Logged

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

Sydney, Australia
Offline Offline
Edison Member
*
Karma: 33
Posts: 1273
Big things come in large packages
View Profile
WWW
 Bigger Bigger  Smaller Smaller  Reset Reset

That's a bit vague. What specifically is the problem?
Logged

Arduino libraries http://arduinocode.codeplex.com
Parola hardware & library http://parola.codeplex.com

Sydney, Australia
Offline Offline
Edison Member
*
Karma: 33
Posts: 1273
Big things come in large packages
View Profile
WWW
 Bigger Bigger  Smaller Smaller  Reset Reset

All of those compiler errors will come with a line number at the start that tells you the exact line the error happens, so you should look on that line. Don't worry too much about the number of errors, as the first few often cascade a flurry as the compiler gets confused about where it is. Just focus on the first one and work your way down the list.

Also, make sure that the example code is compatible with the version 1.0 IDE as there were some changes at that time that cause all sorts of errors.
« Last Edit: May 08, 2012, 12:18:42 am by marco_c » Logged

Arduino libraries http://arduinocode.codeplex.com
Parola hardware & library http://parola.codeplex.com

Sydney, Australia
Offline Offline
Edison Member
*
Karma: 33
Posts: 1273
Big things come in large packages
View Profile
WWW
 Bigger Bigger  Smaller Smaller  Reset Reset

This bit of the code seems not to have a closing brace in the code online:

 //This for loop is used to scroll through and store the 16 inputs on the FIRST multiplexer
  for (int i=0; i<16; i++)
  {
    //The following 4 commands set the correct logic for the control pins to select the desired input
    //See the Arduino Bitwise AND Reference: http://www.arduino.cc/en/Reference/BitwiseAnd
    //See the Aruino Bitshift Reference: http://www.arduino.cc/en/Reference/Bitshift
    digitalWrite(CONTROL0, (i&15)>>3);
    digitalWrite(CONTROL1, (i&7)>>2); 
    digitalWrite(CONTROL2, (i&3)>>1); 
    digitalWrite(CONTROL3, (i&1));     
   

That would cause a lot of errors as the nesting of braces is all out of sequence after that.
Logged

Arduino libraries http://arduinocode.codeplex.com
Parola hardware & library http://parola.codeplex.com

New York City, NY
Offline Offline
Full Member
***
Karma: 0
Posts: 101
Arduino Rocks!
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

In your humble opinion do you think I'm merging these two sketches correctly? http://mayhewlabs.com/code/Mux_Shield_AnalogIn_Example.pde is the setup that comes with the mux shield. This is my attempt to merge the code snippet we are discussing into the mux shield setup.
Quote
121:8: x was not declared in this scope
At global scope:
125:3: 'Serial' does not have a type
126:17: 'i' does not have a type
putting a closing bracket didn't fix it. I fear I've made larger faux pas.

the vanilla mux code is herehttp://mayhewlabs.com/code/Mux_Shield_AnalogIn_Example.pde
and the mpc23017/mcp23016 LED snippets are taken from here http://www.thebox.myzen.co.uk/Hardware/MIDI_Footsteps_files/Footsteps%20Software.zip
http://www.thebox.myzen.co.uk/Hardware/MIDI_Footsteps.html
what am I doing wrong?
« Last Edit: May 20, 2012, 09:23:38 am by Pitchoilcan » Logged

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

Sydney, Australia
Offline Offline
Edison Member
*
Karma: 33
Posts: 1273
Big things come in large packages
View Profile
WWW
 Bigger Bigger  Smaller Smaller  Reset Reset

I have cobbled together your code from the sections above and created a sketch, but I am in no way sure that you have put all the code up as there were gaps and stuff looked like it was missing. Anyway, the code below compiles ok (no errors). No idea if it runs ok, as I don't have your hardware.

You had some syntax errors and then the main problem was your example used an obsolete version of the TwoWire library with calls that needed to be substituted.

Here's a couple of tips:
 - Format the code properly. Often you will see what is wrong (especially missing brackets and such) just from the formatting.
 - Call your variables descriptive names (no need for an essay though!) and it will help you be able to 'read' what the code is doing (eg, instead or x or y call them mask and value).
 - When you post code, leave it all together (ie, don't split it up). Invariably you will miss bits and they are harder for others to download.

Code:
#include <Wire.h>

// Defines
#define I2CregisterInput ((uint8_t)0)
#define I2CregisterOutput ((uint8_t)2)
#define I2CregisterPolarity ((uint8_t)4)
#define I2CregisterConfig ((uint8_t)6)
#define I2CregisterInterrupt ((uint8_t)8)
#define I2CregisterExpander ((uint8_t)10)

// I2C device addresses
#define ledAddress   (0x20 | 0x0)     // address of trigger LED indicators output

// Control Switch device bit masks
#define ddrTrigger 0x00000     // data direction register for trigger indictor LEDs

// Variable definations
int currentstate[16]; // current state of sensors
int laststate[16];    // the last state of the sensors
int threshold = 0x90;  // sets the threshold value in deciding if a sensor is pressd.
int w;

// Start of code
void setup()
{
   w = 0;
// Setup I2C devices
   Wire.begin();                      // start the I2C interface
// Initilise registers
   gpio_write(ledAddress, ddrTrigger, I2CregisterConfig);   // Make into outputs
   gpio_write(ledAddress, 0, I2CregisterInput);            // turn them all off
}

void loop()
{
// the value of threshold determines the on / off point

  int x = 0;
  int y = 1;
 
  for (int i=0; i<16; i++)
  {
    if(currentstate[i] < threshold) x |= y;   // add a 1 in the position of sensors under threshold
     y = y << 1;
  }
  if(w != x)
  {   // something has changed
    y = 1;
 
    for(int i=0; i<16; i++)
    {
      if((y & x) != (y & w))
      {
        if((y & x) == 0)
        {
           // midi note off         
        }
        else
        {
          // midi note on
        }
      }
         y = y << 1;
    }
    // Update the trigger LEDs
    gpio_writeByteInverse(ledAddress, x, I2CregisterInput);
  }

   w = x;        // record current state of LEDs
}

void gpio_write(int address, int data, int reg)
{
  //  Send output register address
  Wire.beginTransmission(address);
  Wire.write(reg);
  //  Connect to device and send two bytes
  Wire.write(0xff & data);  //  low byte
  Wire.write(data >> 8);    //  high byte
  Wire.endTransmission();
}

void gpio_writeByteInverse(int address, int data, int reg)
{
  //  Send output register address
  Wire.beginTransmission(address);
  Wire.write(reg);
  //  Connect to device and send two bytes
  Wire.write(data >> 8);    //  high byte
  Wire.write(0xff & data);  //  low byte
  Wire.endTransmission();
}

int gpio_read(int address)
{
  int data = 0;
 
  //  Send input register address
  Wire.beginTransmission(address);
  Wire.write(I2CregisterInput);
  Wire.endTransmission();
  //  Connect to device and request two bytes
  // Wire.beginTransmission(address);
  Wire.requestFrom(address, 2);
  if (!Wire.available()) { } // do nothing until data arrives
    data = Wire.read();

  if (!Wire.available()) { } // do nothing until data arrives
    data |= Wire.read() << 8;
  Wire.endTransmission();
  return data;
}

« Last Edit: May 08, 2012, 02:55:06 am by marco_c » Logged

Arduino libraries http://arduinocode.codeplex.com
Parola hardware & library http://parola.codeplex.com

Sydney, Australia
Offline Offline
Edison Member
*
Karma: 33
Posts: 1273
Big things come in large packages
View Profile
WWW
 Bigger Bigger  Smaller Smaller  Reset Reset

What version of the Arduino IDE are you using?

write() substitutes for send()
read() substitutes for receive()

if you change them back you should be ok.
Logged

Arduino libraries http://arduinocode.codeplex.com
Parola hardware & library http://parola.codeplex.com

Sydney, Australia
Offline Offline
Edison Member
*
Karma: 33
Posts: 1273
Big things come in large packages
View Profile
WWW
 Bigger Bigger  Smaller Smaller  Reset Reset

If you are using Windows the latest version is 1.0 and you really should get it (free) from the Arduino website.

The version number for the Windows version can be found in the Help menu, About. The popup contains the version number.

Not sure about other operating systems.

Once you get it to compile, make changes a few at a time and compile so that you know what caused the errors (the last few things you added). This is the best way to build up experience in debugging compiler errors.
« Last Edit: May 08, 2012, 03:55:06 am by marco_c » Logged

Arduino libraries http://arduinocode.codeplex.com
Parola hardware & library http://parola.codeplex.com

Pages: [1] 2 3 ... 6   Go Up
Jump to: