The Netduino forums have been replaced by new forums at community.wildernesslabs.co.
This site has been preserved for archival purposes only
and the ability to make new accounts or posts has been turned off.
As seen on the SparkFun and Mayhew Labs websites. (schematic) The board comes fully assembled with quality components. Very well built. I'm happy to announce that it is 100% Netduino compatible with no flaws, although there is a bit of confusion about what this board is and is not.
3 TI 74HC4067 Analog/Digital Muxer chips allow you to work with analog or digital signals from 2-6V. (but it just passes them through to your Netduino, so more than 5V isn't safe)
48 GPIO pins for the cost of 7 (D2-5, A0-2)
All pins are individually addressable (although not all at the same time, and without a "latch")
Very convenient 5v and Ground pins adjacent to every header.
In a compact, stackable shield.
First the code to drive the 74HC4067. The code below should also compatible with any other 74HC4067 usage. (like the SparkFun breakout)
public class Ic74HC4067 {
private readonly OutputPort _s0 = null;
private readonly OutputPort _s1 = null;
private readonly OutputPort _s2 = null;
private readonly OutputPort _s3 = null;
private readonly Port _commonRead = null;
private readonly OutputPort _commonWrite = null;
private readonly AnalogInput _analogRead = null;
private readonly OutputPort _enable = null;
/// <summary>
/// A list of all General Purpose Input/Output pins
/// </summary>
public enum Pins : byte {
/// <summary>1st GPO pin</summary>
GPIO_PIN_00,
/// <summary>2nd GPO pin</summary>
GPIO_PIN_01,
/// <summary>3rd GPO pin</summary>
GPIO_PIN_02,
/// <summary>4th GPO pin</summary>
GPIO_PIN_03,
/// <summary>5th GPO pin</summary>
GPIO_PIN_04,
/// <summary>6th GPO pin</summary>
GPIO_PIN_05,
/// <summary>7th GPO pin</summary>
GPIO_PIN_06,
/// <summary>8th GPO pin</summary>
GPIO_PIN_07,
/// <summary>9th GPO pin</summary>
GPIO_PIN_08,
/// <summary>10th GPO pin</summary>
GPIO_PIN_09,
/// <summary>11th GPO pin</summary>
GPIO_PIN_10,
/// <summary>12th GPO pin</summary>
GPIO_PIN_11,
/// <summary>13th GPO pin</summary>
GPIO_PIN_12,
/// <summary>14th GPO pin</summary>
GPIO_PIN_13,
/// <summary>15th GPO pin</summary>
GPIO_PIN_14,
/// <summary>16th GPO pin</summary>
GPIO_PIN_15,
/// <summary>Common I/O disabled</summary>
GPIO_PIN_OFF = 0x10
}
public Ic74HC4067(Cpu.Pin s0, Cpu.Pin s1, Cpu.Pin s2, Cpu.Pin s3, Cpu.Pin common, Cpu.Pin enable, bool analog) :
this(new OutputPort(s0, false), new OutputPort(s1, false), new OutputPort(s2, false), new OutputPort(s3, false)) {
if (enable != Cpu.Pin.GPIO_NONE)
_enable = new OutputPort(enable, true);
if (common != Cpu.Pin.GPIO_NONE) {
if (analog)
_analogRead = new AnalogInput(common);
else {
_commonWrite = new OutputPort(common, false);
_commonRead = _commonWrite;
}
}
}
public Ic74HC4067(OutputPort s0, OutputPort s1, OutputPort s2, OutputPort s3) : this(s0, s1, s2, s3, null, null) { }
public Ic74HC4067(OutputPort s0, OutputPort s1, OutputPort s2, OutputPort s3, Port common) : this(s0, s1, s2, s3, common, null) { }
public Ic74HC4067(OutputPort s0, OutputPort s1, OutputPort s2, OutputPort s3, Port common, OutputPort enable) {
if (s0 == null) throw new ArgumentNullException("s0", "s0 is required");
if (s1 == null) throw new ArgumentNullException("s1", "s1 is required");
if (s2 == null) throw new ArgumentNullException("s2", "s2 is required");
if (s3 == null) throw new ArgumentNullException("s3", "s3 is required");
_s0 = s0;
_s1 = s1;
_s2 = s2;
_s3 = s3;
_commonRead = common;
if(common != null)
_commonWrite = common as OutputPort;
_enable = enable;
}
public Ic74HC4067(OutputPort s0, OutputPort s1, OutputPort s2, OutputPort s3, AnalogInput common){
_s0 = s0;
_s1 = s1;
_s2 = s2;
_s3 = s3;
_analogRead = common;
}
/// <summary>
/// Sets the currently operating GPIO pin.
/// </summary>
public Pins CurrentPin {
get {
if (_enable != null && _enable.Read())
return Pins.GPIO_PIN_OFF;
byte ret = 0;
if (_s3.Read())
ret |= 0x08;
if (_s2.Read())
ret |= 0x04;
if (_s1.Read())
ret |= 0x02;
if (_s0.Read())
ret |= 0x01;
return (Pins)ret;
}
set {
if (value == Pins.GPIO_PIN_OFF)
Enabled = false;
_s3.Write(((byte)value & 0x08) == 0x08);
_s2.Write(((byte)value & 0x04) == 0x04);
_s1.Write(((byte)value & 0x02) == 0x02);
_s0.Write(((byte)value & 0x01) == 0x01);
}
}
/// <summary>
/// When true, disables all GPIO output pins. (true=low, false=high)
/// </summary>
public bool Enabled {
get {
if (_enable == null) throw new InvalidOperationException("Enable pin is not specified.");
return !_enable.Read(); }
set {
if (_enable == null) throw new InvalidOperationException("Enable pin is not specified.");
_enable.Write(!value);
}
}
public bool ReadBit() {
if (_commonRead == null) throw new InvalidOperationException("CommonIO pin is not specified or not in digital mode.");
return _commonRead.Read();
}
public void WriteBit(bool value) {
if (_commonWrite == null) throw new InvalidOperationException("CommonIO pin is not specified or is not writeable.");
_commonWrite.Write(value);
}
public int ReadValue() {
if (_analogRead == null) throw new InvalidOperationException("CommonIO pin is not specified or not in analog mode.");
return _analogRead.Read();
}
public override string ToString() {
if (_commonWrite != null)
return "Ic74HC4067 out=" + (_commonWrite.Read() ? "1" : "0");
if (_commonRead != null)
return "Ic74HC4067 dIn=" + (_commonRead.Read() ? "1" : "0");
if (_analogRead != null)
return "Ic74HC4067 aIn=" + _analogRead.Read();
return base.ToString();
}
}
And now the MuxShield driver class:
public class MuxShield {
public readonly Ic74HC4067[] muxes = new Ic74HC4067[3];
public readonly OutputPort S0 = new OutputPort(Pins.GPIO_PIN_D2, false);
public readonly OutputPort S1 = new OutputPort(Pins.GPIO_PIN_D3, false);
public readonly OutputPort S2 = new OutputPort(Pins.GPIO_PIN_D4, false);
public readonly OutputPort S3 = new OutputPort(Pins.GPIO_PIN_D5, false);
public readonly OutputPort D13LED = new OutputPort(Pins.GPIO_PIN_D13, false);
const Cpu.Pin GPIO_MUX0 = Pins.GPIO_PIN_A0;
const Cpu.Pin GPIO_MUX1 = Pins.GPIO_PIN_A1;
const Cpu.Pin GPIO_MUX2 = Pins.GPIO_PIN_A2;
public enum MuxMode{
AnalogInput,
DigitalInput,
DigitalOutput
}
public MuxShield(MuxMode mode0, MuxMode mode1, MuxMode mode2) {
muxes[0] = CreateMux(mode0, GPIO_MUX0);
muxes[1] = CreateMux(mode1, GPIO_MUX1);
muxes[2] = CreateMux(mode2, GPIO_MUX2);
}
protected Ic74HC4067 CreateMux(MuxMode mode, Cpu.Pin iopin) {
switch (mode) {
case MuxMode.AnalogInput:
return new Ic74HC4067(S0, S1, S2, S3, new AnalogInput(iopin));
case MuxMode.DigitalInput:
return new Ic74HC4067(S0, S1, S2, S3, new InputPort(iopin, false, Port.ResistorMode.PullDown));
case MuxMode.DigitalOutput:
return new Ic74HC4067(S0, S1, S2, S3, new OutputPort(iopin, false));
default:
throw new InvalidOperationException();
}
}
/// <summary>
/// Sets the currently operating pins
/// </summary>
public Ic74HC4067.Pins CurrentPin {
get {
//On the MuxShield, all Ic74HC4067 chips share the same s0-s3 pins, so setting one of them is good enough.
return MUX0.CurrentPin; }
set { MUX0.CurrentPin = value; }
}
public Ic74HC4067 this[int index]{
get{
return muxes[index];
}
}
public Ic74HC4067 MUX0 { get{return this[0];} }
public Ic74HC4067 MUX1 { get{return this[1];} }
public Ic74HC4067 MUX2 { get{return this[2];} }
public override string ToString() {
string ret = "MuxShield ";
ret += (S3.Read() ? "1" : "0");
ret += (S2.Read() ? "1" : "0");
ret += (S1.Read() ? "1" : "0");
ret += (S0.Read() ? "1" : "0");
ret += " ";
ret += MUX0.ToString();
ret += " ";
ret += MUX1.ToString();
ret += " ";
ret += MUX2.ToString();
return ret;
}
}
And the sample program to make it blink a handful of LEDs in sequence:
public static void Main() {
MuxShield shield = new MuxShield(MuxShield.MuxMode.DigitalOutput, MuxShield.MuxMode.DigitalOutput, MuxShield.MuxMode.DigitalOutput);
//Set the pins high so that as we move through the pins, LEDs will light up
shield.MUX0.WriteBit(true);
shield.MUX1.WriteBit(true);
shield.MUX2.WriteBit(true);
while (true) {
for (byte x = 0; x <= 15; x+=2) {
//itterate over the pins
shield.CurrentPin = (Ic74HC4067.Pins)x;
//blink the onboard led
shield.D13LED.Write(!shield.D13LED.Read());
Debug.Print(shield.ToString());
Thread.Sleep(100);
}
}
}
I don't have an NP2 but those errors suggest Pins.GPIO_PIN_Ax are not const but variables on the NP2 which seems a little odd.
Anyway, try removing the leading "const" in each of the three lines.
The board should not get _hot_ so check your wiring and make sure you're not using more current than the board(s) can handle.
How did it go, does it work after removing the "const" statement?
can you send me an example to use the digital input?
I'm obviously not Eric, but early in this post he gave an example with three multiplexed digital outputs:
public static void Main() { MuxShield shield = new MuxShield(MuxShield.MuxMode.DigitalOutput, MuxShield.MuxMode.DigitalOutput, MuxShield.MuxMode.DigitalOutput); //Set the pins high so that as we move through the pins, LEDs will light up shield.MUX0.WriteBit(true); shield.MUX1.WriteBit(true); shield.MUX2.WriteBit(true); while (true) { for (byte x = 0; x <= 15; x+=2) { //itterate over the pins shield.CurrentPin = (Ic74HC4067.Pins)x; //blink the onboard led shield.D13LED.Write(!shield.D13LED.Read()); Debug.Print(shield.ToString()); Thread.Sleep(100); } }}
If you need digital input(s), simply modify the three parameters in the call to the constructor according to your needs. You would then use the readBit method to read the pin after having set CurrentPin according to which of the multiplexed inputs you wish to read.
For example, this should give you one multiplexed input and two outputs.
// digital in, out, outMuxShield shield = new MuxShield(MuxShield.MuxMode.DigitalInput, MuxShield.MuxMode.DigitalOutput, MuxShield.MuxMode.DigitalOutput);
do this istruction shield[color=rgb(102,102,0);].[/color]MUX0[color=rgb(102,102,0);].[/color][color=rgb(102,0,102);]WriteBit[/color][color=rgb(102,102,0);]([/color][color=rgb(0,0,136);]true[/color][color=rgb(102,102,0);]) put high all pins of the mux0?[/color]
another question:
I use:
[color=rgb(0,0,136);]public[/color][color=rgb(0,0,136);]static[/color][color=rgb(0,0,136);]void[/color][color=rgb(102,0,102);]Main[/color][color=rgb(102,102,0);]()[/color] [color=rgb(102,102,0);]{[/color] [color=rgb(102,0,102);]MuxShield[/color] shield [color=rgb(102,102,0);]=[/color][color=rgb(0,0,136);]new[/color][color=rgb(102,0,102);]MuxShield[/color][color=rgb(102,102,0);]([/color][color=rgb(102,0,102);]MuxShield[/color][color=rgb(102,102,0);].[/color][color=rgb(102,0,102);]MuxMode[/color][color=rgb(102,102,0);].[/color][color=rgb(102,102,0);]DigitalInput,[/color]MuxShield.MuxMode.DigitalOutput,MuxShield.MuxMode.DigitalOutput); while (true) {
for (byte x = 0; x <= 7; x+=1) {
shield.CurrentPin = (Ic74HC4067.Pins)x;
Debug.Print(shield.MUX0.ReadBit().ToString());
Thread.Sleep(1000);
}
}
[color=rgb(102,102,0);]}[/color]
but receive this error:
An unhandled exception of type 'System.ArgumentException' occurred in Microsoft.SPOT.Hardware.dll. Break Or Continue.
and a green arrow in this istruction of MuxShield.cs
--> 43 return new Ic74HC4067(S0, S1, S2, S3, new InputPort(iopin, false, Port.ResistorMode.PullDown));
No, it should only output a logic high on the currently selected pin but if you cycle through all pins writing a high level to one pin after another, they will all be high eventually since outputs are latched. The latch makes the output "remember" its level after you have selected another pin.
You can think of a multiplexer like one of those rotating platforms that they used to have in front of train garages in the old days. Pins s0...s3 form a 4 bit number 0...15 that is used to select which of the 16 tracks to use: http://www.yeeeeee.c...eneralele-1.jpg
I'll have a closer look later but the error could be pull-down mode is not supported on the input pin. Certain combinations are not allowed but I can never remember which. I'll get back shortly.
Hmm...after removing the "const" statements, I basically get 3 errors when trying to compile as an NP2 project.
These two errors:
[font="'courier new', courier, monospace;"]Error 1 The best overloaded method match for 'Microsoft.SPOT.Hardware.AnalogInput.AnalogInput(Microsoft.SPOT.Hardware.Cpu.AnalogChannel)'[/font]
[font="'courier new', courier, monospace;"]Error 2 Argument 1: cannot convert from 'Microsoft.SPOT.Hardware.Cpu.Pin' to 'Microsoft.SPOT.Hardware.Cpu.AnalogChannel'[/font]
...refers to this code
public Ic74HC4067(Cpu.Pin s0, Cpu.Pin s1, Cpu.Pin s2, Cpu.Pin s3, Cpu.Pin common, Cpu.Pin enable, bool analog) : this(new OutputPort(s0, false), new OutputPort(s1, false), new OutputPort(s2, false), new OutputPort(s3, false)){ if (enable != Cpu.Pin.GPIO_NONE) _enable = new OutputPort(enable, true); if (common != Cpu.Pin.GPIO_NONE) { if (analog) _analogRead = new AnalogInput(common); else { _commonWrite = new OutputPort(common, false); _commonRead = _commonWrite; } }}
While this one:
[font="'courier new', courier, monospace;"]Error 3 Cannot implicitly convert type 'double' to 'int'. An explicit conversion exists (are you missing a cast?)[/font]
...refers to this code:
public int ReadValue(){ if (_analogRead == null) throw new InvalidOperationException("CommonIO pin is not specified or not in analog mode."); return _analogRead.Read();}
I'll see if I got one of those multiplexers in my junk box, if so I'll try the driver with an NP I got in there too.
Eric said for the shield to be "100% Netduino compatible with no flaws" but unfortunately, this does not seem to go for the driver class unless only tested for something else than a regular N or NP.