Pages: [1] 2   Go Down
Author Topic: Multi I/O Library (16 Inputs and Outputs)  (Read 5331 times)
0 Members and 1 Guest are viewing this topic.
Brazil
Offline Offline
God Member
*****
Karma: 3
Posts: 616
Wusik Dot Com
View Profile
WWW
 Bigger Bigger  Smaller Smaller  Reset Reset

Dear All, I just created this free library that allows you to have 16 inputs and/or outputs with 3 I/O pins and a few extra cheap chips.

Here's the download URL:
http://www.wusik.com/download/arduino/Multi_IO.zip

And here's the code: (header, there's no cpp file)

Code:
/*
 
 www.Wusik.com - Created by WilliamK @ Wusik Dot Com (c) 2010
 
*/

#ifndef MULTIIO_h
#define MULTIIO_h

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

// 16 Inputs with only 3 pins on the Arduino using the following chip: 74HC165N //
// http://www.sparkfun.com/products/9519 //
#define BTploadPin 25      // Buttons Input C165N - Connects to Parallel load pin the 165
#define BTdataPin 27      // Buttons Input C165N - Connects to the Q7 pin the 165
#define BTclockPin 26      // Buttons Input C165N - Connects to the Clock pin the 165

// 16 Outputs with only 3 pins on the Arduino using the following chip: 74HC595 //
// http://www.sparkfun.com/products/733 //
#define LEDlatchPin 22      // LEDs Output C595N //
#define LEDclockPin 24      // LEDs Output C595N //
#define LEDdataPin 23      // LEDs Output C595N //

class Buttons
{
public:
    Buttons()
      {
            pinMode(BTploadPin, OUTPUT);
            pinMode(BTclockPin, OUTPUT);
            pinMode(BTdataPin, INPUT);
            digitalWrite(BTclockPin, LOW);
            digitalWrite(BTploadPin, HIGH);

            memset(Clicked,false,sizeof(Clicked));
            memset(prevHigh,false,sizeof(prevHigh));
      }

      bool Tick() // Returns True if something changed - check the Clicked[] variable and call Reset() after you do //
      {
            SomethingChanged = false;

            digitalWrite(BTploadPin, LOW);
            digitalWrite(BTploadPin, HIGH);
            for(int i = 0; i < 16; i++)
            {
                  tempButton = digitalRead(BTdataPin);
                  if (tempButton == LOW && prevHigh[15-i] == HIGH) { Clicked[15-i] = true; SomethingChanged = true; }
                  prevHigh[15-i] = tempButton;
                  digitalWrite(BTclockPin, HIGH);
                  digitalWrite(BTclockPin, LOW);
            }

            return SomethingChanged;
      }

      void Reset(void) { memset(Clicked,false,sizeof(Clicked)); }

      boolean Clicked[16];

private:
      boolean SomethingChanged;
      unsigned int tempButton;
      unsigned int prevHigh[16];
};

// ======================================================================================= //
class LEDs
{
public:
      LEDs()
      {
            pinMode(LEDlatchPin, OUTPUT);
            pinMode(LEDclockPin, OUTPUT);
            pinMode(LEDdataPin, OUTPUT);    

            Reset();
      }

      void Tick(void) // use the Value[] variable to turn outputs on and off //
      {
            digitalWrite(LEDlatchPin, LOW);
            digitalWrite(LEDdataPin, LOW);
            digitalWrite(LEDclockPin, LOW);
            for (int i=15; i>=0; i--)  
            {
              digitalWrite(LEDclockPin, LOW);
              if (Value[i]) digitalWrite(LEDdataPin, HIGH); else digitalWrite(LEDdataPin, LOW);
              digitalWrite(LEDclockPin, HIGH);
              digitalWrite(LEDdataPin, LOW);
            }
            digitalWrite(LEDclockPin, LOW);
            digitalWrite(LEDlatchPin, HIGH);
      }

      void Reset(void) { memset(Value,false,sizeof(Value)); }

      boolean Value[16];
};

#endif
Logged


Global Moderator
Netherlands
Offline Offline
Shannon Member
*****
Karma: 217
Posts: 13734
In theory there is no difference between theory and practice, however in practice there are many...
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Good to publish your code here, but some questions arise. It seems to me the lib is for the MEGA (based upon the defines) and unfortunately it has fixed pinnumbers. It would be great if I could define the three pins myself in a constructor.

Furthermore I think the names Buttons and Leds imply a purpose which doesn't need to be the case. iso a led I maybe want to connect relays or so. So a rename to something more generic would be appriciated.

I suggest to call the classes HC165N and HC595 and you could define the pinnumbers in the constructor, something like this:
(not tested)
Code:
class HC165N
{
public:
   HC165N(int load, int data, int clock)   // byte would be large enough
  {
    _load = load;  // copy to internal vars
    _data = data;
    _clock = clock;

    pinMode(_load, OUTPUT);
    pinMode(_clock, OUTPUT);
    pinMode(_data, INPUT);

    digitalWrite(_clock, LOW);
    digitalWrite(_load, HIGH);

    Reset();  // should also reset prevHigh array I think
    // memset(prevHigh, false, sizeof(prevHigh));
}

etc

If you can define the pins during initialization it becomes possible to have multiple HC165N objects and therfore even more pins!

Similar for the HC595.

But a very good start for a library and I hope you will take time to enhance it and maybe even write a playground article how the lib is used and how to connect the IC's etc.

Rob
Logged

Rob Tillaart

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

Brazil
Offline Offline
God Member
*****
Karma: 3
Posts: 616
Wusik Dot Com
View Profile
WWW
 Bigger Bigger  Smaller Smaller  Reset Reset

Thanks Rob, great feedback. Yes, I will make the changes and upload it again later next week.

How do I start a playground article?

I guess I could use Fritzing for the images?

Wk
Logged


Global Moderator
Netherlands
Offline Offline
Shannon Member
*****
Karma: 217
Posts: 13734
In theory there is no difference between theory and practice, however in practice there are many...
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Quote
How do I start a playground article?
You need to ask for a separate account - you cannot use the forum account - but you may use the same name and password

Quote
I guess I could use Fritzing for the images?
Yes sure

And when redoing the lin consider split current version in a .cpp and a .h file
« Last Edit: December 12, 2010, 01:13:54 pm by robtillaart » Logged

Rob Tillaart

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

Brazil
Offline Offline
God Member
*****
Karma: 3
Posts: 616
Wusik Dot Com
View Profile
WWW
 Bigger Bigger  Smaller Smaller  Reset Reset

Ah, yes, cpp and h file in the right way. I was too lazy yesterday.  :-[

Wk
Logged


Global Moderator
Netherlands
Offline Offline
Shannon Member
*****
Karma: 217
Posts: 13734
In theory there is no difference between theory and practice, however in practice there are many...
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset


Looks much better, well done!

I still don't understand why you are using BT (button?) and LED prefixes as they assume a usage that not allways is true. On the other hand as these are private I will never have to "see" them in my code.
Logged

Rob Tillaart

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

Brazil
Offline Offline
God Member
*****
Karma: 3
Posts: 616
Wusik Dot Com
View Profile
WWW
 Bigger Bigger  Smaller Smaller  Reset Reset

Ah, doh! indeed, sorry, I will fix that. ;-) (I was a bit tired yesterday when I did those...)

Wk
Logged


Brazil
Offline Offline
God Member
*****
Karma: 3
Posts: 616
Wusik Dot Com
View Profile
WWW
 Bigger Bigger  Smaller Smaller  Reset Reset

Another thing I changed is int to byte, as it uses less RAM and has the same effect.  8-)

int takes 2 bytes while byte takes 1 byte. (as the name suggests)

Wk
Logged


Brazil
Offline Offline
God Member
*****
Karma: 3
Posts: 616
Wusik Dot Com
View Profile
WWW
 Bigger Bigger  Smaller Smaller  Reset Reset

Could some Moderator remove the code from the first post or let me modify it? As I have a new code now that I think is nearly finished. ;-)

Wk
Logged


Brazil
Offline Offline
God Member
*****
Karma: 3
Posts: 616
Wusik Dot Com
View Profile
WWW
 Bigger Bigger  Smaller Smaller  Reset Reset

Here's the official page on our site:

http://www.wusik.com/ww/open-wusik/arduino/download-files

And here are the files.

C165.h
Code:
/*
 
      www.Wusik.com - Created by WilliamK @ Wusik Dot Com (c) 2010

      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);

                  C165(      Connects to Parallel load pin the 165,
                              Connects to the Q7 pin the 165,
                              Connects to the Clock pin the 165);      

            Loop:

                  if (Inputs.Tick()) // Returns True if something changed //
                  {
                        for (int xc=0; xc<16; xc++)
                        {
                              if (Inputs.isOn(xc))
                              {
                                    // Do Something //
                              }
                        }
                  }

*/

#ifndef C165_h
#define C165_h

#define NumberOfChips 2

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

class C165
{
public:
    C165(byte _loadPin, byte _dataPin, byte _clockPin);
      boolean Tick();
      void Reset(void);
      boolean isOn(byte Pos);

private:
      byte loadPin;
      byte dataPin;
      byte clockPin;

      boolean Changed;
      boolean On[NumberOfChips*8];
      byte tempInputs;
      byte prevHigh[NumberOfChips*8];
};

#endif

C165.cpp
Code:
/*
 
      www.Wusik.com - Created by WilliamK @ Wusik Dot Com (c) 2010
      Check the C165.h file for instructions
 
*/

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

// ------------------------------------------------------------------------------------------- //
C165::C165(byte _loadPin, byte _dataPin, byte _clockPin)
{
      Changed = false;

      loadPin = _loadPin;
      dataPin = _dataPin;
      clockPin = _clockPin;

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

      Reset();            
}

// ------------------------------------------------------------------------------------------- //
boolean C165::Tick()
{
      Changed = false;

      digitalWrite(loadPin, LOW);
      digitalWrite(loadPin, HIGH);
      for(int i = 0; i < (NumberOfChips*8); i++)
      {
            tempInputs = digitalRead(dataPin);
            if (tempInputs == LOW && prevHigh[((NumberOfChips*8)-1)-i] == HIGH) { On[((NumberOfChips*8)-1)-i] = true; Changed = true; }
            prevHigh[((NumberOfChips*8)-1)-i] = tempInputs;
            digitalWrite(clockPin, HIGH);
            digitalWrite(clockPin, LOW);
      }

      return Changed;
}

// ------------------------------------------------------------------------------------------- //
void C165::Reset()
{
      memset(On,false,sizeof(On));
      memset(prevHigh,false,sizeof(prevHigh));
}

// ------------------------------------------------------------------------------------------- //
boolean C165::isOn(byte Pos)
{
      if (On[Pos])
      {
            On[Pos] = false;
            return true;
      }

      return false;
}

C595.h
Code:
/*
 
      www.Wusik.com - Created by WilliamK @ Wusik Dot Com (c) 2010

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

      Typical Usage:

            Setup:

                  C595 Outputs = C595(22,24,23);

                  C595(Latch Pin, Clock Pin, Data Pin)

            Loop:

                  Outputs.setOutput(0, true);
                  Outputs.setOutput(1, true);
                  Outputs.setOutput(2, false);
                  ...
                  Outputs.setOutput(15, false);
                  
                  Outputs.Tick();

*/

#ifndef C595_h
#define C595_h

#define NumberOfChips 2

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

// ======================================================================================= //
class C595
{
public:
      C595(byte _latchPin, byte _clockPin, byte _dataPin);
      void Tick(void);
      void setOutput(byte Pos, boolean Value);
      void Reset(void);

private:
      byte latchPin;
      byte clockPin;
      byte dataPin;
      boolean Output[NumberOfChips*8];
};

#endif

C595.cpp
Code:
/*
 
      www.Wusik.com - Created by WilliamK @ Wusik Dot Com (c) 2010
      Check the C595.h file for instructions
 
*/

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

// ------------------------------------------------------------------------------------------- //
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);
      digitalWrite(dataPin, LOW);
      digitalWrite(clockPin, LOW);
      for (int i=15; i>=0; i--)  
      {
        digitalWrite(clockPin, LOW);
        if (Output[i]) digitalWrite(dataPin, HIGH); else digitalWrite(dataPin, LOW);
        digitalWrite(clockPin, HIGH);
        digitalWrite(dataPin, LOW);
      }
      digitalWrite(clockPin, LOW);
      digitalWrite(latchPin, HIGH);
}

// ------------------------------------------------------------------------------------------- //
void C595::Reset(void)
{
      memset(Output,false,sizeof(Output));
}

// ------------------------------------------------------------------------------------------- //
void C595::setOutput(byte Pos, boolean Value)
{
      Output[Pos] = Value;
}
Logged


Brazil
Offline Offline
God Member
*****
Karma: 3
Posts: 616
Wusik Dot Com
View Profile
WWW
 Bigger Bigger  Smaller Smaller  Reset Reset

I'm trying to improve the code so it uses less memory. Please, could you guys take a look at the following thread? Thanks.

http://www.arduino.cc/cgi-bin/yabb2/YaBB.pl?num=1293470091/0
Logged


Global Moderator
Netherlands
Offline Offline
Shannon Member
*****
Karma: 217
Posts: 13734
In theory there is no difference between theory and practice, however in practice there are many...
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

think these first two LOW's can be ommitted,
- clockpin low is also done in the begin of the for loop so not needed.
- datapin is only relevant when clockpin gets high, so no need to init it too

Code:
void C595::Tick()
{
      digitalWrite(latchPin, LOW);
[glow]      // digitalWrite(dataPin, LOW);
      // digitalWrite(clockPin, LOW);
[/glow]      for (int i=15; i>=0; i--)
      {
        digitalWrite(clockPin, LOW);
        if (Output[i]) digitalWrite(dataPin, HIGH); else digitalWrite(dataPin, LOW);
        digitalWrite(clockPin, HIGH);
        digitalWrite(dataPin, LOW);
      }
      digitalWrite(clockPin, LOW);
      digitalWrite(latchPin, HIGH);
}

Furthermore I notice that you hardcode 15 in the loop while that should be NumberOfChips * 8 -1 ???

Furthermore I would change the boolean array to an unsigned int and use bitset bitclear code

(code not tested but to get an impression)
Code:
#define NumberOfChips 2
boolean Output[NumberOfChips*8];
==>
unsigned int Output;

void reset()
{
  Output = 0;
}

void setOutput(byte Pos, boolean Value)
{
      Value ? Output | (1UL << Pos) : Output & ~(1UL << Pos);
}

// optional function
boolean getOutput(byte Pos)
{
  return Output & (1UL << Pos);
}
« Last Edit: December 28, 2010, 03:16:50 am by robtillaart » Logged

Rob Tillaart

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

Brazil
Offline Offline
God Member
*****
Karma: 3
Posts: 616
Wusik Dot Com
View Profile
WWW
 Bigger Bigger  Smaller Smaller  Reset Reset

Thanks, I was already taking a look at bitRead and the whole gang. ;-) But thanks again. I already updated my C165 code to use bitRead and now it uses much less memory than before. I will post updated code soon.

Wk
Logged


Brazil
Offline Offline
God Member
*****
Karma: 3
Posts: 616
Wusik Dot Com
View Profile
WWW
 Bigger Bigger  Smaller Smaller  Reset Reset

Why can't I edit my posts above?!?  :'( (I want to update the code)

Wk
Logged


Brazil
Offline Offline
God Member
*****
Karma: 3
Posts: 616
Wusik Dot Com
View Profile
WWW
 Bigger Bigger  Smaller Smaller  Reset Reset

I still wonder if I could drive all my C165 and C595 with the same clock port?

Wk
Logged


Pages: [1] 2   Go Up
Jump to: