Welcome to Hackster!
Hackster is a community dedicated to learning hardware, from beginner to pro. Join us, it's free!
Peter Oakes
Published

PiFace Digital 2 on a Rasberry PI 2 and Windows 10 IoT

A library and example UI for using the PiFace Digital 2 under Windows 10 IoT. you can find more examples here: youtube.com/c/thebreadboardca

IntermediateFull instructions provided10,420
PiFace Digital 2 on a Rasberry PI 2 and Windows 10 IoT

Things used in this project

Hardware components

Raspberry Pi 2 Model B
Raspberry Pi 2 Model B
×1
Piface digital 2
×1

Software apps and online services

Visual Studio Community Edition
Windows 10 IoT Core
Microsoft Windows 10 IoT Core

Story

Read more

Schematics

PIFaceDigitalII.JPG

Code

MCP23S17.cs

C#
Library for the MCP23S17 chip
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;
    }

}
}

Mainpage.xaml

C#
XAML Main Page layout
<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>

MainPage.xaml.cs

C#
Code behind for the MainPage.xaml
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#
A helper class linrary for PiFace Digital 2 pins and other variables to make it easy to use
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)
    }
}

Credits

Peter Oakes
6 projects • 37 followers
Electronics Engineer, Programmer, and love to make Videos on Electronics Engineering related stuff and post on my YouTube Channel "thebreadboardca"
Contact

Comments

Please log in or sign up to comment.