Go Down

Topic: Multi I/O Library (16 Inputs and Outputs) (Read 5 times) previous topic - next topic

robtillaart

#15
Dec 28, 2010, 01:09 pm Last Edit: Dec 28, 2010, 01:23 pm by robtillaart Reason: 1
Quote
I still want to know how I could improve the constructor and tick so the pin numbers doesn't need to be called twice and wouldn't use extra RAM.

Same for the other lib of course...



Then you need three local vars to hold the pinnumbers set by the constructor. It will use the same amount of memory I think but the calls to tick won't need parameters, so it becomes easier to use the library as the pins don't need to be supplied and the programmer doesn't need to remember the order of the pins. Note these three bytes should be declared in the .h file as private.
Code: [Select]

#include "WConstants.h"
#include "C595.h"

byte _latchPin;
byte _clockPin;
byte _dataPin;

C595::C595(byte latchPin, byte clockPin, byte dataPin)
{
       _latchPin = latchPin;
       _clockPin = clockPin;
       _dataPin = dataPin;

     pinMode(_latchPin, OUTPUT);
     pinMode(_clockPin, OUTPUT);
     pinMode(_dataPin, OUTPUT);

     reset();
}

void C595::tick()
{
     digitalWrite(_latchPin, LOW);
     for (int i=(BUS_WIDTH-1); i>=0; i--)
     {
       digitalWrite(_clockPin, LOW);
       if (bitRead(output, i)) digitalWrite(_dataPin, HIGH); else digitalWrite(_dataPin, LOW);
       digitalWrite(_clockPin, HIGH);
     }
     digitalWrite(_clockPin, LOW);
     digitalWrite(_latchPin, HIGH);
}


Q: what kind of license do you think of? I noticed the (c) in the header...
Rob Tillaart

Nederlandse sectie - http://arduino.cc/forum/index.php/board,77.0.html -
(Please do not PM for private consultancy)

robtillaart

#16
Dec 28, 2010, 01:43 pm Last Edit: Dec 28, 2010, 01:44 pm by robtillaart Reason: 1
William, what do you think of a slightly different Tick()..

Code: [Select]
unsigned int C165::Tick()
{
     byte tempInputs;
     
       [glow]prevvalues = values; // remember the previous values;[/glow]

     digitalWrite(loadPin, LOW);
     digitalWrite(loadPin, HIGH);
     for(int i=(BUS_WIDTH-1); i >= 0; i--)
     {
           tempInputs = digitalRead(dataPin);
           if (tempInputs == LOW && bitRead(prevhigh,i) > 0) bitSet(values,i);
           bitWrite(prevhigh,i,tempInputs);

           digitalWrite(clockPin, HIGH);
           digitalWrite(clockPin, LOW);
     }

[glow]    // return all changed bits at once
   // no bits changed == 0; otherwise > 0
   return values ^ prevvalues;       // X-or[/glow]
}
Rob Tillaart

Nederlandse sectie - http://arduino.cc/forum/index.php/board,77.0.html -
(Please do not PM for private consultancy)

WilliamK Govinda

Oh, good idea, that's pretty cool.  8-)

Also, I did some tests and using 3 small byte variables to hold the pin settings uses less memory than calling both constructor and tick with the pin values. And should also be faster, as a call with nothing to be parsed is faster, at least in real PC processors, so it should be the same for the Atmega too. (or not?)

Wk

WilliamK Govinda

I took the examples from the LCD library. ;-) Its using only 3 byte extra and works better.  8-)

I will post the files again in a few minutes.

Wk

robtillaart

#19
Dec 28, 2010, 01:53 pm Last Edit: Dec 28, 2010, 01:55 pm by robtillaart Reason: 1
Quote
using 3 small byte variables to hold the pin settings uses less memory

OK,

Quote
should also be faster

Yep it is faster but only in the order of ~1 micro as it only has to fetch 3 bytes from memory and push them on the stack. So I think most apps won't notice the speed diff.

Quote
Its using only 3 byte extra and works better

classic memory for speed trade-off
Rob Tillaart

Nederlandse sectie - http://arduino.cc/forum/index.php/board,77.0.html -
(Please do not PM for private consultancy)

robtillaart

#20
Dec 28, 2010, 01:59 pm Last Edit: Dec 28, 2010, 02:00 pm by robtillaart Reason: 1
Hi William, before pasting new code :

Think you should add the number of chips in the constructor so one doesn't has to change the library if one uses only one chip in project A and two chips in project B.
Rob Tillaart

Nederlandse sectie - http://arduino.cc/forum/index.php/board,77.0.html -
(Please do not PM for private consultancy)

WilliamK Govinda

Got it, but again, I only left as a #define as if the user only needs one chip, he could save 1 byte, as it would only use 8 bits instead of 16 bits. But again, what would be better?

WilliamK Govinda

Here we go!

Download at http://arduino.wusik.com

C165.h
Code: [Select]
     /*

     Created by WilliamK @ Wusik Dot Com (c) 2010
     http://arduino.wusik.com

     8 to 16 Inputs with only 3 pins on the Arduino using the following chip: 74HC165N
     http://www.sparkfun.com/products/9519

     Typical Usage:

           Setup:

                 C165 inputs = C165(25,27,26,2);

                 // C165(      Connects to Parallel load pin the 165,
                 //                  Connects to the Q7 (data) pin the 165,
                 //                  Connects to the Clock pin the 165,
                 //                  Number of C165 Chips - 1 or 2);

           Loop:

                 unsigned int tempinputs = inputs.tick();
                 if (tempinputs) // Returns > 0 if something changed //
                 {
                       // Check each bit now //
                       if (bitRead(tempinputs,1)) Serial.println("1 Changed !");
                       if (bitRead(tempinputs,7)) Serial.println("7 Changed !");

                       // Call Reset so it restarts //
                       inputs.reset();
                 }

*/

#ifndef C165_h
#define C165_h

#include <inttypes.h>
#include "HardwareSerial.h"

class C165
{
public:
   C165(uint8_t _loadPin, uint8_t _dataPin, uint8_t _clockPin, uint8_t _chips);
     unsigned int tick(void);
     void reset(void);

private:
     uint8_t loadPin;
     uint8_t dataPin;
     uint8_t clockPin;
     uint8_t chips;

     unsigned int values;
     unsigned int prevvalues;
     unsigned int prevhigh;
};

#endif


C165.cpp
Code: [Select]
/*

     Created by WilliamK @ Wusik Dot Com (c) 2010
     http://arduino.wusik.com

     Check the C165.h file for instructions

*/

#include "WConstants.h"
#include "C165.h"

// ------------------------------------------------------------------------------------------- //
C165::C165(uint8_t _loadPin, uint8_t _dataPin, uint8_t _clockPin, uint8_t _chips)
{
     loadPin = _loadPin;
     dataPin = _dataPin;
     clockPin = _clockPin;
     chips = _chips;

     pinMode(loadPin, OUTPUT);
     pinMode(clockPin, OUTPUT);
     pinMode(dataPin, INPUT);
     digitalWrite(clockPin, LOW);
     digitalWrite(loadPin, HIGH);

     reset();            
}

// ------------------------------------------------------------------------------------------- //
unsigned int C165::tick()
{
     uint8_t tempInputs;
     prevvalues = values;

     digitalWrite(loadPin, LOW);
     digitalWrite(loadPin, HIGH);
     for(int i=((chips*8)-1); i >= 0; i--)
     {
           tempInputs = digitalRead(dataPin);
           if (tempInputs == LOW && bitRead(prevhigh,i) > 0) bitSet(values,i);
           bitWrite(prevhigh,i,tempInputs);

           digitalWrite(clockPin, HIGH);
           digitalWrite(clockPin, LOW);
     }

     return values ^ prevvalues;      // X-or
}

// ------------------------------------------------------------------------------------------- //
void C165::reset()
{
     values = prevvalues = prevhigh = 0;
}

WilliamK Govinda

And here's the C595 code.

http://arduino.wusik.com

C595.h
Code: [Select]
/*

     Created by WilliamK @ Wusik Dot Com (c) 2010
     http://arduino.wusik.com

     8 to 16 Outputs with only 3 pins on the Arduino using the following chip: 74HC595
     http://www.sparkfun.com/products/733

     Typical Usage:

           Variables:

                 C595 outputs = C595(22,24,23,2);
                 unsigned int outvalue = 0;

                 // C595(Latch Pin, Clock Pin, Data Pin, Number of Chips - 1 or 2) //

           Loop:

                 outvalue = 61680; // 1111000011110000
                 outputs.tick(outvalue);

                 // Or you can also use bitRead/bitWrite //

                 bitWrite(outvalue,0,1);
                 bitWrite(outvalue,1,1);
                 bitWrite(outvalue,2,0);
                 bitWrite(outvalue,3,1);
                 // ... //
                 bitWrite(outvalue,15,1);

*/

#ifndef C595_h
#define C595_h

#include <inttypes.h>
#include "HardwareSerial.h"

// ======================================================================================= //
class C595
{
public:
     C595(uint8_t _latchPin, uint8_t _clockPin, uint8_t _dataPin, uint8_t _chips);
     void tick(unsigned int output);

private:
     uint8_t latchPin;
     uint8_t clockPin;
     uint8_t dataPin;
     uint8_t chips;
};

#endif


C595.cpp
Code: [Select]
/*

     Created by WilliamK @ Wusik Dot Com (c) 2010
     http://arduino.wusik.com

     Check the C595.h file for instructions

*/

#include "WConstants.h"
#include "C595.h"

// ------------------------------------------------------------------------------------------- //
C595::C595(uint8_t _latchPin, uint8_t _clockPin, uint8_t _dataPin, uint8_t _chips)
{
     latchPin = _latchPin;
     clockPin = _clockPin;
     dataPin = _dataPin;
     chips = _chips;

     pinMode(latchPin, OUTPUT);
     pinMode(clockPin, OUTPUT);
     pinMode(dataPin, OUTPUT);
}

// ------------------------------------------------------------------------------------------- //
void C595::tick(unsigned int output)
{
     digitalWrite(latchPin, LOW);
     for (int i=((chips*8)-1); i>=0; i--)  
     {
       digitalWrite(clockPin, LOW);
       if (bitRead(output,i)) digitalWrite(dataPin, HIGH); else digitalWrite(dataPin, LOW);
       digitalWrite(clockPin, HIGH);
     }
     digitalWrite(clockPin, LOW);
     digitalWrite(latchPin, HIGH);
}


C595_Example.pde
Code: [Select]
/*

     Created by WilliamK @ Wusik Dot Com (c) 2010
     http://arduino.wusik.com

*/

#include <C595.h>

unsigned int outvalue = 0;
C595 outputs = C595(22,24,23,2);

void setup()
{
 //
}

void loop()
{
 outvalue = 61680; // 1111000011110000
 outputs.tick(outvalue);
 delay(1000);
 outvalue = 44230; // 1010110011000110;
 outputs.tick(outvalue);
 delay(1000);  
}

WilliamK Govinda

And here's an example of both used together. ;-)

Code: [Select]
/*

   Created by WilliamK @ Wusik Dot Com (c) 2010
   http://arduino.wusik.com

*/

#include <C165.h>
#include <C595.h>

C165 WButtons = C165(25,27,26,2);
C595 WLEDs = C595(22,24,23,2);

unsigned int WLEDsTemp = 0;
unsigned int WButtonsTemp = 0;

void setup()
{
 //
}

void loop()
{
 WButtonsTemp = WButtons.tick();
 if (WButtonsTemp)
 {
   WLEDsTemp ^= WButtonsTemp;
   WLEDs.tick(WLEDsTemp);  
   WButtons.reset();
 }
}

robtillaart

#25
Dec 28, 2010, 08:11 pm Last Edit: Dec 28, 2010, 08:11 pm by robtillaart Reason: 1
@William, think it looks quite good, still 3 minor points.

1) What is the function of prevhigh, it is only written to but never used, or am I missing something?  -- bitWrite(prevhigh,i,tempInputs);  ??

2) I don't like (opinion) that outValue is a parameter of tick(). Think making it a public member is better. For me the outvalue belongs to the object. And as a public member it still can be set all @ once.
Code: [Select]
outputs.outvalue = 61680; // 1111000011110000
outputs.tick();


3) The param  _chips could have a default value of 1? makes it possible to call it with only the 3 pin params.

Code: [Select]
C595(uint8_t _latchPin, uint8_t _clockPin, uint8_t _dataPin, uint8_t _chips = 1);


Rob Tillaart

Nederlandse sectie - http://arduino.cc/forum/index.php/board,77.0.html -
(Please do not PM for private consultancy)

WilliamK Govinda

Humm, the Tick option still makes more sense to me like that, but I could be wrong. ;-) ;-)

prevhigh is used, to check when the value changes from low to high, like a button for instance. (or the other way around) In any event, if the user don't want that, just remove that.

Wk

robtillaart

#27
Dec 28, 2010, 08:50 pm Last Edit: Dec 28, 2010, 09:10 pm by robtillaart Reason: 1
Quote
the Tick option still makes more sense to me like that

OK,

Quote
prevhigh is used, to check when the value changes from low to high

But prevhigh is a private member of the lib so the user of the lib cannot see it unless he "dives" into the library code (and normally users should not need to dive into it)
Rob Tillaart

Nederlandse sectie - http://arduino.cc/forum/index.php/board,77.0.html -
(Please do not PM for private consultancy)

WilliamK Govinda

YES! It is possible. I just ported my MIDI Drum-Machine code so it uses less I/Os, making it compatible with the UNO board. ;-)

Here's the code, which reads and outputs to 16 buttons and LEDs using only 5 pins! (shares the same clock pin)

C165_595.h
Code: [Select]
/*

     Created by WilliamK @ Wusik Dot Com (c) 2010
     http://arduino.wusik.com

*/

#ifndef C165_595_h
#define C165_595_h

#include <inttypes.h>
#include "HardwareSerial.h"

class C165_595
{
public:
   C165_595(uint8_t _loadPin, uint8_t _latchPin, uint8_t _dataPinInput, uint8_t _dataPinOutput, uint8_t _clockPin);
     unsigned int tick(unsigned int output);
     void reset(void);

private:
     uint8_t loadPin;
     uint8_t latchPin;
     uint8_t dataPinInput;
     uint8_t dataPinOutput;
     uint8_t clockPin;

     unsigned int values;
     unsigned int prevvalues;
     unsigned int prevhigh;
};

#endif


C165_595.cpp
Code: [Select]
/*

     Created by WilliamK @ Wusik Dot Com (c) 2010
     http://arduino.wusik.com

     Check the C165_595.h file for instructions

*/

#include "WConstants.h"
#include "C165_595.h"

// ------------------------------------------------------------------------------------------- //
C165_595::C165_595(uint8_t _loadPin, uint8_t _latchPin, uint8_t _dataPinInput, uint8_t _dataPinOutput, uint8_t _clockPin)
{
     loadPin = _loadPin;
     latchPin = _latchPin;
     dataPinInput = _dataPinInput;
     dataPinOutput = _dataPinOutput;
     clockPin = _clockPin;

     pinMode(loadPin, OUTPUT);
     pinMode(latchPin, OUTPUT);
     pinMode(clockPin, OUTPUT);
     pinMode(_dataPinInput, INPUT);
     pinMode(_dataPinOutput, OUTPUT);
     digitalWrite(clockPin, LOW);
     digitalWrite(latchPin, LOW);
     digitalWrite(loadPin, HIGH);

     reset();            
}

// ------------------------------------------------------------------------------------------- //
unsigned int C165_595::tick(unsigned int output)
{
     uint8_t tempInputs;
     prevvalues = values;

     digitalWrite(latchPin, LOW);
     digitalWrite(loadPin, LOW);
     digitalWrite(loadPin, HIGH);

     for(int i=15; i >= 0; i--)
     {
           digitalWrite(clockPin, LOW);

           tempInputs = digitalRead(dataPinInput);
           if (tempInputs == LOW && bitRead(prevhigh,i) > 0) bitSet(values,i);
           bitWrite(prevhigh,i,tempInputs);

           if (bitRead(output,i)) digitalWrite(dataPinOutput, HIGH); else digitalWrite(dataPinOutput, LOW);

           digitalWrite(clockPin, HIGH);
     }

     digitalWrite(clockPin, LOW);
     digitalWrite(latchPin, HIGH);

     return values ^ prevvalues;      // X-or
}

// ------------------------------------------------------------------------------------------- //
void C165_595::reset()
{
     values = prevvalues = prevhigh = 0;
}

robtillaart

Good to hear that it works. Still think that if you use separate classes you can merge more pins, but will have separate ticks(). The only pin not shared is a "chip select" like of line.

Furthermore how to use -  prevhigh -  from a sketch is still not clear to me as it is private and in the libcode it is not used, only set.
Rob Tillaart

Nederlandse sectie - http://arduino.cc/forum/index.php/board,77.0.html -
(Please do not PM for private consultancy)

Go Up