New York City, NY
Offline
Jr. Member
Karma: 0
Posts: 86
Arduino Rocks! Think befor you code | Thinking supercollider/clojure
|
 |
« on: May 06, 2012, 09:44:55 am » |
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: #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. 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_disjunctionMy 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/Bitwisecurious 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
|
|
|
|
|
Austin, TX
Offline
Faraday Member
Karma: 41
Posts: 5166
CMiYC
|
 |
« Reply #1 on: May 06, 2012, 02:35:41 pm » |
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/HomePageComparison and Boolean Operators are shown as well.
|
|
|
|
|
Logged
|
|
|
|
|
Sydney
Offline
God Member
Karma: 14
Posts: 717
Big things come in large packages
|
 |
« Reply #2 on: May 06, 2012, 02:54:52 pm » |
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
|
|
|
|
|
New York City, NY
Offline
Jr. Member
Karma: 0
Posts: 86
Arduino Rocks! Think befor you code | Thinking supercollider/clojure
|
 |
« Reply #3 on: May 06, 2012, 05:19:24 pm » |
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
|
|
|
|
|
Sydney
Offline
God Member
Karma: 14
Posts: 717
Big things come in large packages
|
 |
« Reply #4 on: May 06, 2012, 05:38:35 pm » |
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
|
|
|
|
|
Sydney
Offline
God Member
Karma: 14
Posts: 717
Big things come in large packages
|
 |
« Reply #5 on: May 06, 2012, 06:09:01 pm » |
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
|
|
|
|
|
Sydney
Offline
God Member
Karma: 14
Posts: 717
Big things come in large packages
|
 |
« Reply #6 on: May 06, 2012, 07:32:56 pm » |
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
|
|
|
|
|
New York City, NY
Offline
Jr. Member
Karma: 0
Posts: 86
Arduino Rocks! Think befor you code | Thinking supercollider/clojure
|
 |
« Reply #7 on: May 07, 2012, 07:34:20 pm » |
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: #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 // 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 // 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 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
|
|
|
|
|
Sydney
Offline
God Member
Karma: 14
Posts: 717
Big things come in large packages
|
 |
« Reply #8 on: May 07, 2012, 11:58:48 pm » |
That's a bit vague. What specifically is the problem?
|
|
|
|
|
Logged
|
|
|
|
|
Sydney
Offline
God Member
Karma: 14
Posts: 717
Big things come in large packages
|
 |
« Reply #9 on: May 08, 2012, 12:12:04 am » |
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
|
|
|
|
|
Sydney
Offline
God Member
Karma: 14
Posts: 717
Big things come in large packages
|
 |
« Reply #10 on: May 08, 2012, 12:24:45 am » |
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
|
|
|
|
|
|
|
Sydney
Offline
God Member
Karma: 14
Posts: 717
Big things come in large packages
|
 |
« Reply #12 on: May 08, 2012, 02:53:14 am » |
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. #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
|
|
|
|
|
Sydney
Offline
God Member
Karma: 14
Posts: 717
Big things come in large packages
|
 |
« Reply #13 on: May 08, 2012, 03:29:41 am » |
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
|
|
|
|
|
Sydney
Offline
God Member
Karma: 14
Posts: 717
Big things come in large packages
|
 |
« Reply #14 on: May 08, 2012, 03:50:22 am » |
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
|
|
|
|
|
|