Hardware components | ||||||
| × | 1 | ||||
| × | 1 | ||||
Software apps and online services | ||||||
| ||||||
|
OK, so continueing my the series on PI 2 with windows 10 for IoT, I decided to create a demo app for the PiFace Digital 2, there where no libraries for the primary chip on the board. The MCP23S17 SPI to 16 pin expander so I wrote my own, then put a cool UI ontop of it so I can play with the board under Windows 10. The UI was based in spirit on the original emulator from http://www.piface.org.uk/products/piface_digital/. I copied no code and simply replicated the functionality but with my own design UI
Element14 where kind enough to send me the gear so forgive my showcasing their name, they deserve it.
You can use it by simply clicking on the relays (The graphics update to show the state of the contacts, the LED 0 through 7 or the 4 switches, they all work and actually drive the outputs (The switches simulate the button being pressed, im not that good !!) but if you short the input to ground it is happily recognized and reflected in the state of one of the green indicators. Pushing hte real switches also works.Both the Inputs and the Putputs are monitored every 200mS and the virtual LEDS (Red and Green) are updated based on the bit pattern found
The inputs have a weak 100K pullup on them to V+ so all you need is a switch to ground and they will work, the outputs are either open collector or one of the two relays.
It should also be noted that even though the default for the PiFace is that the green pins are inputs, there is nothing stopping he coder setting some as an output and extending the range of features. My library supports this, the UI does not yet. I may add this in a future version
So this is a very short post as there is not a huge amount to say,, as its all int he software and the UI. you can download my Visual Studio project from here, you should be able to simply load it into Visual Studio Community edition and upload to your PI2 after seting its remote parameters of course
The MCP23S17 Class library is here for those not wanting to wait for a download, there is a method to get most things done with it and you can use as you wish
The PDF for the chip on the PIFace can be found here and it is one consistently used by the PiFace series to drive their boardshttp://ww1.microchip.com/downloads/en/DeviceDoc/21952b.pdf
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Windows.Devices.Spi;
using Windows.Devices.Enumeration;
namespace SPI_GPIO
{
public class MCP23S17
{
private const byte IODIRA = 0x00 ; // I/O Direction Register
private const byte IODIRB = 0x01; // 1 = Input (default), 0 = Output
private const byte IPOLA = 0x02 ; // MCP23x17 Input Polarity Register
private const byte IPOLB = 0x03 ; // 0 = Normal (default)(low reads as 0), 1 = Inverted (low reads as 1)
private const byte GPINTENA = 0x04 ; // MCP23x17 Interrupt on Change Pin Assignements
private const byte GPINTENB = 0x05 ; // 0 = No Interrupt on Change (default), 1 = Interrupt on Change
private const byte DEFVALA = 0x06 ; // MCP23x17 Default Compare Register for Interrupt on Change
private const byte DEFVALB = 0x07 ; // Opposite of what is here will trigger an interrupt (default = 0)
private const byte INTCONA = 0x08 ; // MCP23x17 Interrupt on Change Control Register
private const byte INTCONB = 0x09 ; // 1 = pin is compared to DEFVAL, 0 = pin is compared to previous state (default)
private const byte IOCONA = 0x0A ; // MCP23x17 Configuration Register
private const byte IOCONB = 0x0B ; // Also Configuration Register
private const byte GPPUA = 0x0C ; // MCP23x17 Weak Pull-Up Resistor Register
private const byte GPPUB = 0x0D ; // INPUT ONLY: 0 = No Internal 100k Pull-Up (default) 1 = Internal 100k Pull-Up
private const byte INTFA = 0x0E ; // MCP23x17 Interrupt Flag Register
private const byte INTFB = 0x0F ; // READ ONLY: 1 = This Pin Triggered the Interrupt
private const byte INTCAPA = 0x10 ; // MCP23x17 Interrupt Captured Value for Port Register
private const byte INTCAPB = 0x11 ; // READ ONLY: State of the Pin at the Time the Interrupt Occurred
private const byte GPIOA = 0x12; // MCP23x17 GPIO Port Register
private const byte GPIOB = 0x13; // Value on the Port - Writing Sets Bits in the Output Latch
private const byte OLATA = 0x14; // MCP23x17 Output Latch Register
private const byte OLATB = 0x15; // 1 = Latch High, 0 = Latch Low (default) Reading Returns Latch State, Not Port Value!
public const byte On = 1;
public const byte Off= 0;
public const byte Output= 0;
public const byte Input = 1;
private const byte Address = 0x00; // offset address if hardware addressing is on and is 0 - 7 (A0 - A2)
private const byte BaseAddW = 0x40; // MCP23S17 Write base address
private const byte BaseAddR = 0x41; // MCP23S17 Read Base Address
private const byte HAEN = 0x08; // IOCON register for MCP23S17, x08 enables hardware address so sent address must match hardware pins A0-A2
private static UInt16 PinMode = 0XFFFF; // default Pinmode for the MXP23S17 set to inputs
private static UInt16 PullUpMode = 0XFFFF; // default pullups for the MXP23S17 set to weak pullup
private static UInt16 InversionMode = 0X0000; // default invert to normal
private static UInt16 PinState = 0X0000; // default pinstate to all 0's
/*RaspBerry Pi2 Parameters*/
private const string SPI_CONTROLLER_NAME = "SPI0"; /* For Raspberry Pi 2, use SPI0 */
private const Int32 SPI_CHIP_SELECT_LINE = 0; /* Line 0 maps to physical pin number 24 on the Rpi2, line 1 to pin 26 */
private static byte[] readBuffer3 = new byte[3]; /*this is defined to hold the output data*/
private static byte[] readBuffer4 = new byte[4]; /*this is defined to hold the output data*/
private static byte[] writeBuffer3 = new byte[3];//register, then 16 bit value
private static byte[] writeBuffer4 = new byte[4];//register, then 16 bit value
private static SpiDevice SpiGPIO;
public static async Task InitSPI()
{
try
{
var settings = new SpiConnectionSettings(SPI_CHIP_SELECT_LINE);
settings.ClockFrequency = 1000000;// 10000000;
settings.Mode = SpiMode.Mode0; //Mode0,1,2,3; MCP23S17 needs mode 0
string spiAqs = SpiDevice.GetDeviceSelector(SPI_CONTROLLER_NAME);
var deviceInfo = await DeviceInformation.FindAllAsync(spiAqs);
SpiGPIO = await SpiDevice.FromIdAsync(deviceInfo[0].Id, settings);
}
/* If initialization fails, display the exception and stop running */
catch (Exception ex)
{
//statusText.Text = "\nSPI Initialization Failed";
}
}
public static void InitMCP23S17()
{
WriteRegister8(IOCONA, HAEN); // enable the hardware address incase there is more than one chip
WriteRegister16(IODIRA, PinMode); // Set the default or current pin mode
}
public static void WriteRegister8(byte register, byte value)
{
// Direct port manipulation speeds taking Slave Select LOW before SPI action
writeBuffer3[0] = (BaseAddW | (Address << 1));
writeBuffer3[1] = register;
writeBuffer3[2] = value;
try
{
SpiGPIO.Write(writeBuffer3);
}
/* If initialization fails, display the exception and stop running */
catch (Exception ex)
{
//statusText.Text = "\nFailed to Wrie to DAC";
}// Send the byte
}
public static void WriteRegister16(byte register, UInt16 value)
{
writeBuffer4[0] = (BaseAddW | (Address << 1));
writeBuffer4[1] = register;
writeBuffer4[2] = (byte)(value >> 8);
writeBuffer4[3] = (byte)(value & 0XFF);
try
{
SpiGPIO.Write(writeBuffer4);
}
/* If initialization fails, display the exception and stop running */
catch (Exception ex)
{
//statusText.Text = "\nFailed to Wrie to DAC";
}
}
// Set the pin mode a pin at a time or all 16 in one go
// any value other then Input is taken as output
public static void setPinMode(byte pin, byte mode)
{
if (pin > 15) return; // only a 16bit port so do a bounds check, it cant be less than zero as this is a byte value
if (mode == Input)
{
PinMode |= (UInt16)(1 << (pin)); // update the pinMode register with new direction
}
else
{
PinMode &= (UInt16)(~(1 << (pin))); // update the pinMode register with new direction
}
WriteRegister16(IODIRA, PinMode); // Call the generic word writer with start register and the mode cache
}
public static void setPinMode(UInt16 mode)
{
WriteRegister16(IODIRA, mode);
PinMode = mode;
}
// Set the pullup a pin at a time or all 16 in one go
// any value other than On is taken as off
public static void pullupMode(byte pin, byte mode)
{
if (pin > 15) return;
if (mode == On)
{
PullUpMode |= (UInt16)(1 << (pin));
}
else
{
PullUpMode &= (UInt16)(~(1 << (pin)));
}
WriteRegister16(GPPUA, PullUpMode);
}
public static void pullupMode(UInt16 mode)
{
WriteRegister16(GPPUA, mode);
PullUpMode = mode;
}
// Set the inversion a pin at a time or all 16 in one go
public static void InvertMode(byte pin, byte mode)
{
if (pin > 15) return;
if (mode == On)
{
InversionMode |= (UInt16)(1 << (pin - 1));
}
else
{
InversionMode &= (UInt16)(~(1 << (pin - 1)));
}
WriteRegister16(IPOLA, InversionMode);
}
public static void InvertMode(UInt16 mode)
{
WriteRegister16(IPOLA, mode);
InversionMode = mode;
}
// WRITE FUNCTIONS - BY WORD AND BY PIN
public static void WritePin(byte pin, byte value)
{
if (pin > 15) return;
if (value > 1) return;
if (value == 1)
{
PinState |= (UInt16)(1 << pin);
}
else
{
PinState &= (UInt16)(~(1 << pin));
}
WriteRegister16(GPIOA, PinState);
}
public static void WriteWord(UInt16 value)
{
WriteRegister16(GPIOA, value);
PinState = value;
}
// READ FUNCTIONS - BY WORD, BYTE ANWrite Register8 or WriteRegister16D BY PIN
public static UInt16 ReadRegister16()
{
writeBuffer4[0] = (BaseAddR | (Address << 1));
writeBuffer4[1] = GPIOA;
writeBuffer4[2] = 0;
writeBuffer4[3] = 0;
SpiGPIO.TransferFullDuplex(writeBuffer4, readBuffer4);
return convertToInt(readBuffer4); // Return the constructed word, the format is 0x(register value)
}
public static byte ReadRegister8(byte register)
{ // This function will read a single register, and return it
writeBuffer3[0] = (BaseAddR | (Address << 1)); // Send the MCP23S17 opcode, chip address, and read bit
writeBuffer3[1] = register;
SpiGPIO.TransferFullDuplex(writeBuffer3, readBuffer3);
return readBuffer4[2]; // convertToInt(readBuffer); // Return the constructed word, the format is 0x(register value)
}
public static UInt16 ReadPin(byte pin)
{
if (pin > 15) return 0x00; // If the pin value is not valid (1-16) return, do nothing and return
UInt16 value = ReadRegister16(); // Initialize a variable to hold the read values to be returned
UInt16 pinmask = (UInt16)(1 << pin); // Initialize a variable to hold the read values to be returned
return ((value & pinmask) > 0) ? On : Off; // Call the word reading function, extract HIGH/LOW information from the requested pin
}
private static UInt16 convertToInt(byte[] data)
{
// byte[0] = command, byte[1] register, byte[2] = data high, byte[3] = data low
UInt16 result = (UInt16)(data[2] & 0xFF);
result <<= 8;
result += data[3];
return result;
}
}
}
<Page
x:Class="PIFace_Digital_II.MainPage"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="using:PIFace_Digital_II"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
mc:Ignorable="d" Width="1680" Height="1050" >
<Grid Background="White" BorderBrush="#FF0093B9" BorderThickness="10" CornerRadius="50" >
<Border BorderBrush="Black" BorderThickness="2" HorizontalAlignment="Left" Height="98" Margin="945,40,0,0" VerticalAlignment="Top" Width="507" CornerRadius="5"/>
<TextBlock x:Name="textBlock_Copy11" HorizontalAlignment="Left" Margin="945,40,0,0" TextWrapping="Wrap" Text="Outputs - Open Collector" VerticalAlignment="Top" FontSize="32" FontWeight="Bold" Width="507" TextAlignment="Center" Foreground="#FF0093B9"/>
<Border BorderBrush="Black" BorderThickness="2" HorizontalAlignment="Left" Height="98" Margin="446,40,0,0" VerticalAlignment="Top" Width="494" CornerRadius="5"/>
<Border BorderBrush="Black" BorderThickness="2" HorizontalAlignment="Left" Height="145" Margin="1460,723,0,0" VerticalAlignment="Top" Width="121" CornerRadius="5"/>
<Border BorderBrush="Black" BorderThickness="2" HorizontalAlignment="Left" Height="145" Margin="1461,558,0,0" VerticalAlignment="Top" Width="121" CornerRadius="5"/>
<Image x:Name="image" HorizontalAlignment="Left" Height="904" Margin="384,138,0,0" VerticalAlignment="Top" Width="1079" Source="Assets/PIFaceDigitalII.JPG"/>
<ToggleButton x:Name="RelayA" HorizontalAlignment="Left" Margin="1025,462,0,0" VerticalAlignment="Top" Checked="RelayA_Checked" Unchecked="RelayA_Unchecked" Width="275" Height="160" ToolTipService.ToolTip="Click with the mouse to toggle Relay R1 on and off wih Output 1">
<Image x:Name="RelayAImage" Source="Assets/Relay_OFF.jpg" />
</ToggleButton>
<ToggleButton x:Name="RelayB" HorizontalAlignment="Left" Margin="1036,715,0,0" VerticalAlignment="Top" Height="180" Width="275" Checked="RelayB_Checked" Unchecked="RelayB_Unchecked" BorderThickness="0" ToolTipService.ToolTip="Click with the mouse to toggle Relay R0 on and off wih Output 0">
<Image x:Name="RelayBImage" Source="Assets/Relay_OFF.jpg" Margin="0" />
</ToggleButton>
<Button x:Name="Switch3" Content="Switch3" HorizontalAlignment="Left" Height="93" Margin="461,271,0,0" VerticalAlignment="Top" Width="90" ToolTipService.ToolTip="Click the button with the mouse to simulate S3 being pressed, You can also press the real one"/>
<Button x:Name="Switch2" Content="Switch2" HorizontalAlignment="Left" Height="93" Margin="577,267,0,0" VerticalAlignment="Top" Width="93" ToolTipService.ToolTip="Click the button with the mouse to simulate S2 being pressed, You can also press the real one"/>
<Button x:Name="Switch1" Content="Switch1" HorizontalAlignment="Left" Height="93" Margin="694,271,0,0" VerticalAlignment="Top" Width="93" ToolTipService.ToolTip="Click the button with the mouse to simulate S1 being pressed, You can also press the real one"/>
<Button x:Name="Switch0" Content="Switch0" HorizontalAlignment="Left" Height="93" Margin="812,271,0,0" VerticalAlignment="Top" Width="93" ToolTipService.ToolTip="Click the button with the mouse to simulate S0 being pressed, You can also press the real one"/>
<ToggleButton x:Name="LED7" Content="7" HorizontalAlignment="Left" Height="73" Margin="958,250,0,0" VerticalAlignment="Top" Width="30" Checked="LED7_Checked" Unchecked="LED7_Unchecked" FontSize="32" FontWeight="Bold" BorderThickness="0" FontFamily="Arial Black" Foreground="Black" Background="#33FFD100" ToolTipService.ToolTip="Click with the mouse to toggle on and off output 7"/>
<ToggleButton x:Name="LED6" Content="6" HorizontalAlignment="Left" Height="73" Margin="1012,250,0,0" VerticalAlignment="Top" Width="31" Checked="LED6_Checked" Unchecked="LED6_Unchecked" FontSize="32" FontWeight="Bold" BorderThickness="0" FontFamily="Arial Black" Foreground="Black" Background="#33FFD100" ToolTipService.ToolTip="Click with the mouse to toggle on and off output 6"/>
<ToggleButton x:Name="LED5" Content="5" HorizontalAlignment="Left" Height="73" Margin="1065,250,0,0" VerticalAlignment="Top" Width="32" Checked="LED5_Checked" Unchecked="LED5_Unchecked" FontSize="32" FontWeight="Bold" BorderThickness="0" FontFamily="Arial Black" Foreground="Black" Background="#33FFD100" ToolTipService.ToolTip="Click with the mouse to toggle on and off output 5"/>
<ToggleButton x:Name="LED4" Content="4" HorizontalAlignment="Left" Height="73" Margin="1121,250,0,0" VerticalAlignment="Top" Width="31" Checked="LED4_Checked" Unchecked="LED4_Unchecked" FontSize="32" FontWeight="Bold" BorderThickness="0" FontFamily="Arial Black" Foreground="Black" Background="#33FFD100" ToolTipService.ToolTip="Click with the mouse to toggle on and off output 4"/>
<ToggleButton x:Name="LED3" Content="3" HorizontalAlignment="Left" Height="73" Margin="1179,250,0,0" VerticalAlignment="Top" Width="31" Checked="LED3_Checked" Unchecked="LED3_Unchecked" FontSize="32" FontWeight="Bold" BorderThickness="0" FontFamily="Arial Black" Foreground="Black" Background="#33FFD100" ToolTipService.ToolTip="Click with the mouse to toggle on and off output 3"/>
<ToggleButton x:Name="LED2" Content="2" HorizontalAlignment="Left" Height="73" Margin="1234,250,0,0" VerticalAlignment="Top" Width="31" Checked="LED2_Checked" Unchecked="LED2_Unchecked" FontSize="32" FontWeight="Bold" BorderThickness="0" FontFamily="Arial Black" Foreground="Black" Background="#33FFD100" ToolTipService.ToolTip="Click with the mouse to toggle on and off output 2"/>
<ToggleButton x:Name="LED1" Content="1" HorizontalAlignment="Left" Height="73" Margin="1290,250,0,0" VerticalAlignment="Top" Width="30" Checked="LED1_Checked" Unchecked="LED1_Unchecked" FontSize="32" FontWeight="Bold" BorderThickness="0" FontFamily="Arial Black" Foreground="Black" Background="#33FFD100" ToolTipService.ToolTip="Click with the mouse to toggle on and off output 1 and Relay R1"/>
<ToggleButton x:Name="LED0" Content="0" HorizontalAlignment="Left" Height="73" Margin="1343,250,0,0" VerticalAlignment="Top" Width="30" Checked="LED0_Checked" Unchecked="LED0_Unchecked" FontSize="32" FontWeight="Bold" BorderThickness="0" FontFamily="Arial Black" Foreground="Black" Background="#33FFD100" ToolTipService.ToolTip="Click with the mouse to toggle on and off output 0 and Relay R2"/>
<Image x:Name="image0" HorizontalAlignment="Left" Height="50" Margin="890,88,0,0" VerticalAlignment="Top" Width="50" Source="Assets/green-led-off-md.png" />
<Image x:Name="image1" HorizontalAlignment="Left" Height="50" Margin="831,88,0,0" VerticalAlignment="Top" Width="50" Source="Assets/green-led-off-md.png"/>
<Image x:Name="image2" HorizontalAlignment="Left" Height="50" Margin="776,88,0,0" VerticalAlignment="Top" Width="50" Source="Assets/green-led-off-md.png" />
<Image x:Name="image3" HorizontalAlignment="Left" Height="50" Margin="721,88,0,0" VerticalAlignment="Top" Width="50" Source="Assets/green-led-off-md.png" />
<Image x:Name="image4" HorizontalAlignment="Left" Height="50" Margin="666,88,0,0" VerticalAlignment="Top" Width="50" Source="Assets/green-led-off-md.png"/>
<Image x:Name="image5" HorizontalAlignment="Left" Height="50" Margin="611,88,0,0" VerticalAlignment="Top" Width="50" Source="Assets/green-led-off-md.png"/>
<Image x:Name="image6" HorizontalAlignment="Left" Height="50" Margin="556,88,0,0" VerticalAlignment="Top" Width="50" Source="Assets/green-led-off-md.png"/>
<Image x:Name="image7" HorizontalAlignment="Left" Height="50" Margin="501,88,0,0" VerticalAlignment="Top" Width="50" Source="Assets/green-led-off-md.png"/>
<Image x:Name="imageOn" Grid.Column="1" HorizontalAlignment="Left" Height="51" Margin="409,74,0,0" VerticalAlignment="Top" Width="61" Source="Assets/green-led-on-md.png" Visibility="Collapsed"/>
<Image x:Name="imageOff" Grid.Column="1" HorizontalAlignment="Left" Height="50" Margin="475,74,0,0" VerticalAlignment="Top" Width="55" Source="Assets/green-led-off-md.png" Visibility="Collapsed"/>
<Image x:Name="RelayOn" Grid.Column="1" HorizontalAlignment="Left" Height="51" Margin="409,74,0,0" VerticalAlignment="Top" Width="61" Source="Assets/Relay_ON.jpg" Visibility="Collapsed"/>
<Image x:Name="RelayOff" Grid.Column="1" HorizontalAlignment="Left" Height="50" Margin="475,74,0,0" VerticalAlignment="Top" Width="55" Source="Assets/Relay_OFF.jpg" Visibility="Collapsed"/>
<Image x:Name="image8" HorizontalAlignment="Left" Height="224.5" Margin="-312,449.5,0,0" VerticalAlignment="Top" Width="869.5" Source="Assets/Element14 Logo.png" RenderTransformOrigin="0.5,0.5" UseLayoutRounding="False" d:LayoutRounding="Auto">
<Image.RenderTransform>
<CompositeTransform Rotation="-90"/>
</Image.RenderTransform>
</Image>
<TextBlock x:Name="textBlock" HorizontalAlignment="Left" Margin="1468,819,0,0" TextWrapping="Wrap" Text="NO" VerticalAlignment="Top" FontSize="32" FontWeight="Bold" Foreground="#FF0192B8"/>
<TextBlock x:Name="textBlock_Copy" HorizontalAlignment="Left" Margin="1468,771,0,0" TextWrapping="Wrap" Text="C - R0" VerticalAlignment="Top" FontSize="32" FontWeight="Bold" Foreground="#FF0192B8"/>
<TextBlock x:Name="textBlock_Copy1" HorizontalAlignment="Left" Margin="1468,723,0,0" TextWrapping="Wrap" Text="NC" VerticalAlignment="Top" FontSize="32" FontWeight="Bold" Foreground="#FF0192B8"/>
<TextBlock x:Name="textBlock_Copy2" HorizontalAlignment="Left" Margin="1463,660,0,0" TextWrapping="Wrap" Text="NO" VerticalAlignment="Top" FontSize="32" FontWeight="Bold" Foreground="#FF0192B8"/>
<TextBlock x:Name="textBlock_Copy3" HorizontalAlignment="Left" Margin="1468,606,0,0" TextWrapping="Wrap" Text="C - R1" VerticalAlignment="Top" FontSize="32" FontWeight="Bold" Foreground="#FF0192B8"/>
<TextBlock x:Name="textBlock_Copy4" HorizontalAlignment="Left" Margin="1468,558,0,0" TextWrapping="Wrap" Text="NC" VerticalAlignment="Top" FontSize="32" FontWeight="Bold" Foreground="#FF0192B8"/>
<Border BorderBrush="Black" BorderThickness="2" HorizontalAlignment="Left" Height="145" Margin="1461,396,0,0" VerticalAlignment="Top" Width="92" CornerRadius="5"/>
<TextBlock x:Name="textBlock_Copy5" HorizontalAlignment="Left" Margin="1463,498,0,0" TextWrapping="Wrap" Text="GND" VerticalAlignment="Top" FontSize="32" FontWeight="Bold" Foreground="#FF0192B8"/>
<TextBlock x:Name="textBlock_Copy6" HorizontalAlignment="Left" Margin="1468,444,0,0" TextWrapping="Wrap" Text="GND" VerticalAlignment="Top" FontSize="32" FontWeight="Bold" Foreground="#FF0192B8"/>
<TextBlock x:Name="textBlock_Copy7" HorizontalAlignment="Left" Margin="1468,396,0,0" TextWrapping="Wrap" Text="5V" VerticalAlignment="Top" FontSize="32" FontWeight="Bold" Foreground="#FF0192B8"/>
<TextBlock x:Name="textBlock_Copy8" HorizontalAlignment="Left" Margin="1054,831,0,0" TextWrapping="Wrap" Text="R0" VerticalAlignment="Top" FontSize="32" FontWeight="Bold"/>
<TextBlock x:Name="textBlock_Copy9" HorizontalAlignment="Left" Margin="1054,565,0,0" TextWrapping="Wrap" Text="R1" VerticalAlignment="Top" FontSize="32" FontWeight="Bold"/>
<TextBlock x:Name="textBlock_Copy10" HorizontalAlignment="Left" Margin="446,40,0,0" TextWrapping="Wrap" VerticalAlignment="Top" FontSize="32" FontWeight="Bold" Width="494" TextAlignment="Center" Foreground="#FF0093B9">
<Run Text="Inputs"/>
<Run Text=" - Weak pullup"/>
</TextBlock>
<Button x:Name="btnExit" Content="Quit PiFaceDigital II" HorizontalAlignment="Left" Margin="55,33,0,0" VerticalAlignment="Top" Click="btnExit_Click" Height="108" Width="279" Foreground="White" FontSize="26.667" FontWeight="Bold" BorderBrush="#FF0093B9" ToolTipService.ToolTip="Click to exit the application, Come back soon!">
<Button.Background>
<LinearGradientBrush EndPoint="0.5,1" StartPoint="0.5,0">
<GradientStop Color="#FF0093B9" Offset="0"/>
<GradientStop Color="#FFF57E22" Offset="1"/>
</LinearGradientBrush>
</Button.Background>
</Button>
<TextBlock x:Name="textBlock_Copy12" HorizontalAlignment="Left" Margin="432,72,0,0" TextWrapping="Wrap" Text="GND" VerticalAlignment="Top" FontSize="32" FontWeight="Bold" RenderTransformOrigin="0.5,0.5" UseLayoutRounding="False" d:LayoutRounding="Auto" Foreground="#FF0192B8">
<TextBlock.RenderTransform>
<CompositeTransform Rotation="-90"/>
</TextBlock.RenderTransform>
</TextBlock>
<TextBlock x:Name="textBlock_Copy13" HorizontalAlignment="Left" Margin="1403,84.5,0,0" TextWrapping="Wrap" Text="5V" VerticalAlignment="Top" FontSize="32" FontWeight="Bold" RenderTransformOrigin="0.5,0.5" UseLayoutRounding="False" d:LayoutRounding="Auto" Foreground="#FF0093B9">
<TextBlock.RenderTransform>
<CompositeTransform Rotation="-90"/>
</TextBlock.RenderTransform>
</TextBlock>
<Image x:Name="image0_Out" HorizontalAlignment="Left" Height="50" Margin="1340,88,0,0" VerticalAlignment="Top" Width="50" Source="Assets/red-led-off-md.png" />
<Image x:Name="image1_Out" HorizontalAlignment="Left" Height="50" Margin="1281,88,0,0" VerticalAlignment="Top" Width="50" Source="Assets/red-led-off-md.png"/>
<Image x:Name="image2_Out" HorizontalAlignment="Left" Height="50" Margin="1226,88,0,0" VerticalAlignment="Top" Width="50" Source="Assets/red-led-off-md.png" />
<Image x:Name="image3_Out" HorizontalAlignment="Left" Height="50" Margin="1171,88,0,0" VerticalAlignment="Top" Width="50" Source="Assets/red-led-off-md.png" />
<Image x:Name="image4_Out" HorizontalAlignment="Left" Height="50" Margin="1116,88,0,0" VerticalAlignment="Top" Width="50" Source="Assets/red-led-off-md.png"/>
<Image x:Name="image5_Out" HorizontalAlignment="Left" Height="50" Margin="1061,88,0,0" VerticalAlignment="Top" Width="50" Source="Assets/red-led-off-md.png"/>
<Image x:Name="image6_Out" HorizontalAlignment="Left" Height="50" Margin="1006,88,0,0" VerticalAlignment="Top" Width="50" Source="Assets/red-led-off-md.png"/>
<Image x:Name="image7_Out" HorizontalAlignment="Left" Height="50" Margin="951,88,0,0" VerticalAlignment="Top" Width="50" Source="Assets/red-led-off-md.png"/>
<Image x:Name="imageROn" HorizontalAlignment="Left" Height="50" Margin="1495,148,0,0" VerticalAlignment="Top" Width="50" Source="Assets/red-led-on-md.png" Visibility="Collapsed"/>
<Image x:Name="imageROff" HorizontalAlignment="Left" Height="50" Margin="1495,213,0,0" VerticalAlignment="Top" Width="50" Source="Assets/red-led-off-md.png" Visibility="Collapsed"/>
<TextBlock x:Name="textBlock1" HorizontalAlignment="Left" Margin="-119.25,530.75,0,0" TextWrapping="Wrap" VerticalAlignment="Top" Width="755" Height="94.5" RenderTransformOrigin="0.5,0.5" UseLayoutRounding="False" d:LayoutRounding="Auto" FontSize="40" FontWeight="Bold" FontFamily="Arial Black" Text="Brought to you by theBreadboard.ca Youtube.com/user/thebreadboardca" Foreground="#FFFACAA1" TextAlignment="Center">
<TextBlock.RenderTransform>
<CompositeTransform Rotation="-90"/>
</TextBlock.RenderTransform>
</TextBlock>
<TextBlock x:Name="textBlock2" HorizontalAlignment="Left" Margin="1471,50,0,0" TextWrapping="Wrap" VerticalAlignment="Top" Width="180" FontSize="18.667" FontWeight="Bold" Foreground="#FF0092B9" TextAlignment="Center" Height="333">
<Run Text="Indicators are updated 5 times per second"/>
<LineBreak/>
<Run/>
<LineBreak/>
<Run Text="If yo"/>
<Run Text="u"/>
<Run Text=" ground an input the LED will light"/>
<LineBreak/>
<Run/>
<LineBreak/>
<Run Text="C"/>
<Run Text="lick an Output LED"/>
<Run Text=" to toggle its state"/>
<LineBreak/>
<Run/>
<LineBreak/>
<Run Text="LED0 and 1 also drive the Relays"/>
<LineBreak/>
<Run/>
</TextBlock>
</Grid>
</Page>
using System;
using Windows.UI.Xaml;
using Windows.UI.Xaml.Media;
using Windows.UI.Xaml.Controls;
using SPI_GPIO;
using Windows.UI.Xaml.Input;
// The Blank Page item template is documented at http://go.microsoft.com/fwlink/?LinkId=402352&clcid=0x409
namespace PIFace_Digital_II
{
/// <summary>
/// An empty page that can be used on its own or navigated to within a Frame.
/// </summary>
public sealed partial class MainPage : Page
{
private DispatcherTimer timer; // create a timer
private const byte Off = MCP23S17.Off;
private const byte On = MCP23S17.On;
public MainPage()
{
this.InitializeComponent();
/* Register for the unloaded event so we can clean up upon exit */
Unloaded += MainPage_Unloaded;
/* Initialize GPIO, SPI, and the display */
InitAll();
}
private void MainPage_Unloaded(object sender, object args)
{
/* Cleanup */
}
private void initTimer()
{
// read timer
timer = new DispatcherTimer();
timer.Interval = TimeSpan.FromMilliseconds(200); //sample every 200mS
timer.Tick += Timer_Tick;
timer.Start();
}
// read GPIO and display it
private void Timer_Tick(object sender, object e)
{
LightLEDs(MCP23S17.ReadRegister16()); // do something with the values
}
/* Initialize GPIO, SPI, and the display */
private async void InitAll()
{
try
{
await MCP23S17.InitSPI();
MCP23S17.InitMCP23S17();
MCP23S17.setPinMode(0x00FF); // 0x0000 = all outputs, 0xffff=all inputs, 0x00FF is PIFace Default
MCP23S17.pullupMode(0x00FF); // 0x0000 = no pullups, 0xffff=all pullups, 0x00FF is PIFace Default
MCP23S17.WriteWord(0x0000); // 0x0000 = no pullups, 0xffff=all pullups, 0x00FF is PIFace Default
Switch0.AddHandler(PointerPressedEvent, new PointerEventHandler(Switch0_PointerPressed), true);
Switch0.AddHandler(PointerReleasedEvent, new PointerEventHandler(Switch0_PointerReleased), true);
Switch1.AddHandler(PointerPressedEvent, new PointerEventHandler(Switch1_PointerPressed), true);
Switch1.AddHandler(PointerReleasedEvent, new PointerEventHandler(Switch1_PointerReleased), true);
Switch2.AddHandler(PointerPressedEvent, new PointerEventHandler(Switch2_PointerPressed), true);
Switch2.AddHandler(PointerReleasedEvent, new PointerEventHandler(Switch2_PointerReleased), true);
Switch3.AddHandler(PointerPressedEvent, new PointerEventHandler(Switch3_PointerPressed), true);
Switch3.AddHandler(PointerReleasedEvent, new PointerEventHandler(Switch3_PointerReleased), true);
initTimer();
}
catch (Exception ex)
{
//Text_Status.Text = "Exception: " + ex.Message;
//if (ex.InnerException != null)
//{
// Text_Status.Text += "\nInner Exception: " + ex.InnerException.Message;
//}
//return;
}
}
private void LightLEDs(UInt16 Inputs)
{
image0.Source = ((Inputs & 1 << PFDII.IN0) != 0 && !Switch0.IsPressed) ? imageOn.Source : imageOff.Source;
image1.Source = ((Inputs & 1 << PFDII.IN1) != 0 && !Switch1.IsPressed) ? imageOn.Source : imageOff.Source;
image2.Source = ((Inputs & 1 << PFDII.IN2) != 0 && !Switch2.IsPressed) ? imageOn.Source : imageOff.Source;
image3.Source = ((Inputs & 1 << PFDII.IN3) != 0 && !Switch3.IsPressed) ? imageOn.Source : imageOff.Source;
image4.Source = ((Inputs & 1 << PFDII.IN4) != 0) ? imageOn.Source : imageOff.Source;
image5.Source = ((Inputs & 1 << PFDII.IN5) != 0) ? imageOn.Source : imageOff.Source;
image6.Source = ((Inputs & 1 << PFDII.IN6) != 0) ? imageOn.Source : imageOff.Source;
image7.Source = ((Inputs & 1 << PFDII.IN7) != 0) ? imageOn.Source : imageOff.Source;
image0_Out.Source = ((Inputs & 1 << PFDII.LED0) != 0) ? imageROn.Source : imageROff.Source;
image1_Out.Source = ((Inputs & 1 << PFDII.LED1) != 0) ? imageROn.Source : imageROff.Source;
image2_Out.Source = ((Inputs & 1 << PFDII.LED2) != 0) ? imageROn.Source : imageROff.Source;
image3_Out.Source = ((Inputs & 1 << PFDII.LED3) != 0) ? imageROn.Source : imageROff.Source;
image4_Out.Source = ((Inputs & 1 << PFDII.LED4) != 0) ? imageROn.Source : imageROff.Source;
image5_Out.Source = ((Inputs & 1 << PFDII.LED5) != 0) ? imageROn.Source : imageROff.Source;
image6_Out.Source = ((Inputs & 1 << PFDII.LED6) != 0) ? imageROn.Source : imageROff.Source;
image7_Out.Source = ((Inputs & 1 << PFDII.LED7) != 0) ? imageROn.Source : imageROff.Source;
}
//Note RelayA = R1, RelayB = R0
private void RelayA_Checked(object sender, RoutedEventArgs e)
{
MCP23S17.WritePin(PFDII.RelayA , On);
RelayAImage.Source = RelayOn.Source;
LED1.IsChecked = true; ;
}
private void RelayB_Checked(object sender, RoutedEventArgs e)
{
MCP23S17.WritePin(PFDII.RelayB, On);
RelayBImage.Source = RelayOn.Source;
LED0.IsChecked = true; ;
}
private void RelayA_Unchecked(object sender, RoutedEventArgs e)
{
MCP23S17.WritePin(PFDII.RelayA, Off);
RelayAImage.Source = RelayOff.Source;
LED1.IsChecked = false; ;
}
private void RelayB_Unchecked(object sender, RoutedEventArgs e)
{
MCP23S17.WritePin(PFDII.RelayB, Off);
RelayBImage.Source = RelayOff.Source;
LED0.IsChecked = false; ;
}
private void LED0_Checked(object sender, RoutedEventArgs e)
{
MCP23S17.WritePin(PFDII.LED0, On);
RelayB.IsChecked = true; // LED0 and RelayA are the same output pin
}
private void LED1_Checked(object sender, RoutedEventArgs e)
{
MCP23S17.WritePin(PFDII.LED1, On);
RelayA.IsChecked = true; // LED1 and RelayB are the same output pin
}
private void LED2_Checked(object sender, RoutedEventArgs e)
{
MCP23S17.WritePin(PFDII.LED2, On);
}
private void LED3_Checked(object sender, RoutedEventArgs e)
{
MCP23S17.WritePin(PFDII.LED3, On);
}
private void LED4_Checked(object sender, RoutedEventArgs e)
{
MCP23S17.WritePin(PFDII.LED4, On);
}
private void LED5_Checked(object sender, RoutedEventArgs e)
{
MCP23S17.WritePin(PFDII.LED5, On);
}
private void LED6_Checked(object sender, RoutedEventArgs e)
{
MCP23S17.WritePin(PFDII.LED6, On);
}
private void LED7_Checked(object sender, RoutedEventArgs e)
{
MCP23S17.WritePin(PFDII.LED7, On);
}
private void LED0_Unchecked(object sender, RoutedEventArgs e)
{
MCP23S17.WritePin(PFDII.LED0, Off);
RelayB.IsChecked = false; // LED0 and RelayA are the same output pin
}
private void LED1_Unchecked(object sender, RoutedEventArgs e)
{
MCP23S17.WritePin(PFDII.LED1, Off);
RelayA.IsChecked = false; // LED1 and RelayB are the same output pin
}
private void LED2_Unchecked(object sender, RoutedEventArgs e)
{
MCP23S17.WritePin(PFDII.LED2, Off);
}
private void LED3_Unchecked(object sender, RoutedEventArgs e)
{
MCP23S17.WritePin(PFDII.LED3, Off);
}
private void LED4_Unchecked(object sender, RoutedEventArgs e)
{
MCP23S17.WritePin(PFDII.LED4, Off);
}
private void LED5_Unchecked(object sender, RoutedEventArgs e)
{
MCP23S17.WritePin(PFDII.LED5, Off);
}
private void LED6_Unchecked(object sender, RoutedEventArgs e)
{
MCP23S17.WritePin(PFDII.LED6, Off);
}
private void LED7_Unchecked(object sender, RoutedEventArgs e)
{
MCP23S17.WritePin(PFDII.LED7, Off);
}
private void Switch0_PointerPressed(object sender, Windows.UI.Xaml.Input.PointerRoutedEventArgs e)
{
Switch0.BorderBrush = new SolidColorBrush(Windows.UI.Colors.Red);
}
private void Switch0_PointerReleased(object sender, Windows.UI.Xaml.Input.PointerRoutedEventArgs e)
{
Switch0.BorderBrush = new SolidColorBrush(Windows.UI.Colors.Black);
}
private void Switch1_PointerPressed(object sender, Windows.UI.Xaml.Input.PointerRoutedEventArgs e)
{
Switch1.BorderBrush = new SolidColorBrush(Windows.UI.Colors.Red);
}
private void Switch1_PointerReleased(object sender, Windows.UI.Xaml.Input.PointerRoutedEventArgs e)
{
Switch1.BorderBrush = new SolidColorBrush(Windows.UI.Colors.Black);
}
private void Switch2_PointerPressed(object sender, Windows.UI.Xaml.Input.PointerRoutedEventArgs e)
{
Switch2.BorderBrush = new SolidColorBrush(Windows.UI.Colors.Red);
}
private void Switch2_PointerReleased(object sender, Windows.UI.Xaml.Input.PointerRoutedEventArgs e)
{
Switch2.BorderBrush = new SolidColorBrush(Windows.UI.Colors.Black);
}
private void Switch3_PointerPressed(object sender, Windows.UI.Xaml.Input.PointerRoutedEventArgs e)
{
Switch3.BorderBrush = new SolidColorBrush(Windows.UI.Colors.Red);
}
private void Switch3_PointerReleased(object sender, Windows.UI.Xaml.Input.PointerRoutedEventArgs e)
{
Switch3.BorderBrush = new SolidColorBrush(Windows.UI.Colors.Black);
}
private void btnExit_Click(object sender, RoutedEventArgs e)
{
App.Current.Exit(); // exit the app
}
} // End of Class
} // End of NS
PiFaceDigital2.cs
C#using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace SPI_GPIO
{
public class PFDII
{
public const byte LED0 = 0x08; // I/O Direction Register
public const byte LED1 = 0x09; // 1 = Input (default), 0 = Output
public const byte LED2 = 0x0A; // MCP23x17 Input Polarity Register
public const byte LED3 = 0x0B; // 0 = Normal (default)(low reads as 0), 1 = Inverted (low reads as 1)
public const byte LED4 = 0x0C; // MCP23x17 Interrupt on Change Pin Assignements
public const byte LED5 = 0x0D; // 1 = Input (default), 0 = Output
public const byte LED6 = 0x0E; // MCP23x17 Input Polarity Register
public const byte LED7 = 0x0F; // 0 = Normal (default)(low reads as 0), 1 = Inverted (low reads as 1)
public const byte IN0 = 0x00; // I/O Direction Register
public const byte IN1 = 0x01; // 1 = Input (default), 0 = Output
public const byte IN2 = 0x02; // MCP23x17 Input Polarity Register
public const byte IN3 = 0x03; // 0 = Normal (default)(low reads as 0), 1 = Inverted (low reads as 1)
public const byte IN4 = 0x04; // MCP23x17 Interrupt on Change Pin Assignements
public const byte IN5 = 0x05; // 1 = Input (default), 0 = Output
public const byte IN6 = 0x06; // MCP23x17 Input Polarity Register
public const byte IN7 = 0x07; // 0 = Normal (default)(low reads as 0), 1 = Inverted (low reads as 1)
public const byte Sw0 = IN0; // I/O Direction Register
public const byte Sw1 = IN1; // 1 = Input (default), 0 = Output
public const byte Sw2 = IN2; // MCP23x17 Input Polarity Register
public const byte Sw3 = IN3; // 0 = Normal (default)(low reads as 0), 1 = Inverted (low reads as 1)
public const byte RelayA = LED1; // MCP23x17 Input Polarity Register
public const byte RelayB = LED0; // 0 = Normal (default)(low reads as 0), 1 = Inverted (low reads as 1)
}
}
Comments