In this lab you will create a simple Thing using the Universal Windows Platform on a Windows 10 IoT device.
The Raspberry Pi 3 connects to the physical world through the GPIO pins. GPIO stands for General Purpose Input/Output and refers to the two rows of pins on the Raspberry Pi 3. The GPIO pins are a physical interface between the Raspberry Pi 3 and the physical world. Through your app you can designate pins to either receive input or send output. The inputs can be from switches, sensors or other devices. The outputs can be LEDs, servos, motors or countless other devices. Twenty-six of the 40 pins are GPIO pins; the others are power, ground, or reserved pins.
Wire the Raspberry Pi 3 to the solderless breadboard as described below.
- GPIO 12 is connected to the positive (longer) lead on the LED. In the app you will build in this workshop, you will control whether or not GPIO pin 12 sends voltage over the circuit.
- The negative (shorter) lead on the LED is connected to a resistor to reduce the amount of current pulled through the circuit.
- The other end of the resistor is connected to one of the ground GPIO pins, completing the circuit.
The LED will light up when current is passed through the circuit by the app you will build. Because that app isn't created yet, the LED doesn't do anything right now.
A Universal Windows app is a Windows experience that is built upon the Universal Windows Platform (UWP), which was first introduced in Windows 8 as the Windows Runtime. The UWP enables you to write an app that targets a device family, such as IoT devices. In fact, the Universal app that you write may be able to run on multiple devices families, depending on the device characteristics that it takes advantage of. In this lab you will create a Universal app targeting IoT devices running Windows 10. In theory this could be nearly any device, such as a phone, a tablet or a Raspberry Pi 3. The Universal app you will write, however, will access the General Purpose Input/Output (GPIO) of the device, so the app won't be compatible with devices that don't have a GPIO.
- Launch Visual Studio and start a new Blank App (Universal Windows) (found in the C# -> Windows -> Universal node).
- Name the application HelloWindowsIoT.
The Windows IoT Extenstions for the UWP are not included in a new Blank Application by default. The IoT extensions enable namespaces, such as Windows.Devices.Gpio
to be referenced and uses in the application. You must add a reference to the Windows IoT Extensions for the UWP.
- Click on the Project menu and select Add Reference.
- In the Reference Manager dialog, expand the Universal Windows node and select Extensions.
- In the list of extensions,check the box next to Windows IoT Extensions for the UWP and click OK. (Make sure to select the same version number as the OS running on the Raspberry Pi 3.) It is easy to accidently select the Windows Mobile Extensions for the UWP, (which is just below the IoT extensions) so take extra care to make sure you have added the correct reference.
This application has a UI that duplicates what is happening with the hardware. (It has a blinking virtual LED on-screen.)
- Open the MainPage.xaml file (This is the layout definition for the initial page that loads when the app is run.)
- Replace the
<Grid>...</Grid>
code with the following:
<Grid Background="{ThemeResource ApplicationPageBackgroundThemeBrush}">
<StackPanel HorizontalAlignment="Center" VerticalAlignment="Center">
<Ellipse x:Name="LedGraphic" Fill="LightGray" Stroke="White" Width="100" Height="100" Margin="10"/>
<TextBlock x:Name="DelayText" Text="500ms" Margin="10" TextAlignment="Center" FontSize="26"/>
<TextBlock x:Name="GpioStatus" Text="Waiting to initialize GPIO..." Margin="10,50,10,10" TextAlignment="Center" FontSize="26"/>
</StackPanel>
</Grid>
Throughout this lab you will use a feature in Visual Studio called light bulbs. Light bulbs are a new productivity feature in Visual Studio 2015. They are icons that appear in the Visual Studio editor and that you can click to perform quick actions including refactoring fixing errors. Light bulbs bring error-fixing and refactoring assistance into a single focal point, often right on the line where you are typing. As you write the code in this lab you will add calls to methods that don't yet exist. The editor will indicate this to you by putting a red squiggle underline beneath the method call. When you hover over the offending code a light bulb will appear and you can expand it to see options for generating the missing method.
- Open the MainPage.xaml.cs file. This is the code behind the layout for the MainPage.xaml.
- Add the following to the using statements to the end of the list of similar using statements at the top of the file.
// Enable asynchronous tasks
using System.Threading.Tasks;
// Enable access to the GPIO bus on the Raspberry Pi 3
using Windows.Devices.Gpio;
There are a number of constants and variables that you will be using throughout this application. Define these in the MainPage
class definition.
- Locate the
public sealed partial class MainPage : Page
class definition. This defines a class called MainPage and inherits all of the capabilities of the Page class). - Add the following constant and variable definitions:
public sealed partial class MainPage : Page
{
// Define the physical pin connected to the LED.
private const int LED_PIN = 12;
// Define a variable to represent the pin as an object.
private GpioPin pin;
// Define a variable to hold the value of the pin (HIGH or LOW).
private GpioPinValue pinValue;
// Define a time used to control the frequency of events.
private DispatcherTimer timer;
// Define a color brushes for the on screen representation of the LED.
private SolidColorBrush redBrush = new SolidColorBrush(Windows.UI.Colors.Red);
private SolidColorBrush grayBrush = new SolidColorBrush(Windows.UI.Colors.LightGray);
public MainPage()
{
this.InitializeComponent();
// TODO: Create an instance of a Timer that will raise an event every 500ms
}
}
The LED connected to GPIO pin 12 will turn on and off at an interval defined by the timer
object. The TODO
comment is the placeholder for configuring the timer
. Following the call to InitializeComponent
, configure the timer
to raise an event every 500ms. (Soon you will create an event handler that will do the real work.)
- Locate the
// TODO: Create an instance of a Timer that will raise an event every 500ms
comment in thepublic MainPage()
constructor. - Replace the comment with the following code.
// Create an instance of a Timer that will raise an event every 500ms
timer = new DispatcherTimer();
timer.Interval = TimeSpan.FromMilliseconds(500);
timer.Tick += Timer_Tick;
// TODO: Initialize the GPIO bus
The Timer_Tick
reference should have a red squiggle under it. This indicates that that event handler doesn't exist yet.
The timer
will raise an event at the interval it was configured with, which is 500ms in this case. When the Timer.Tick event is fired the application will query the current state of the LED and if it is set to Low (off) then it will be changed to High (on) and the virtual LED on the screen will be filled with the color red. If the state is High then it will be switched to Low and the virtual LED will be filled with the color light gray. You will use pin.Write(pinValue)
to execute the change on the GPIO bus.
You can create an event handler that will fire every time the Timer.Tick event is raised. You can do this using the Visual Studio light bulb refactoring tool.
- Hover the mouse over the Timer\Tick reference until a light bulb appears.
- Click the down arrow and select Generate method 'MainPage.Timer_Tick'.
- Add the following code for the Timer_Tick event handler.
private void Timer_Tick(object sender, object e)
{
// This Timer event will be raised on each timer interval (defined above)
if (pinValue == GpioPinValue.Low)
{
// If the current state of the pin is LOW (off), then set it to HIGH (on)
// and update the on screen UI to represent the LED in the on state
pinValue = GpioPinValue.High;
LedGraphic.Fill = redBrush;
}
else
{
// If the current state of the pin is HIGH (on), then set it to LOW (off)
// and update the on screen UI to represent the LED in the off state
pinValue = GpioPinValue.Low;
LedGraphic.Fill = grayBrush;
}
// Write the state to to pin
pin.Write(pinValue);
}
Of course, pin
is null - you haven't done anything more than simply define it thus far. (You defined it in the class-level variables as private GpioPin pin;
.) You need to initialize the GPIO controller to get access to the pin
.
The GPIO controller is the object that provides access to the GPIO bus. It exposes the GPIO pins that you are connecting physical things to.
- Replace the
// TODO: Initialize the GPIO bus
comment in thepublic MainPage()
constructor with the following:
// Initialize the GPIO bus
InitGpioAsync();
- Just like you did with the Timer_Tick code earlier, use the refactoring light bulb tool to generate the
InitGpioAsync()
method. In the InitGpioAsync() method you will get the instance of the default GPIO controller. If the GPIO controller instance is null then the device the app is running on doesn't support GPIO, and you will display a message on the screen indicating this, and that will be the end of the app functionality. If there is a GPIO controller instance, then you will use it to open the GPIO pin that you have connected to the LED and prepare it for use. Add a null check on the pin instance. If it is not null, go ahead and start the timer. The timer will begin invoking the Timer_Tick event every 500ms.
The GpioController.GetDefaultAsync() asynchronous method was added to the Windows IoT Extensions for the UWP in the 10.0.10586 version. If you are running Windows 10 (version 10.0.10240) or earlier, the GpioController.GetDefaultAsync() method will not work.
Add the following code for the InitGpioAsync()
method.
private async Task InitGpioAsync()
{
// Get the default GPIO controller
var gpio = await GpioController.GetDefaultAsync();
// If the default GPIO controller is not present, then the device
// running this app isn't capable of GPIO operations.
if (gpio == null)
{
pin = null;
GpioStatus.Text = "There is no GPIO controller on this device.";
return;
}
// Open the GPIO channel
pin = gpio.OpenPin(LED_PIN);
// As long as the pin object is not null, proceed
if (pin != null)
{
// Define the pin as an output pin
pin.SetDriveMode(GpioPinDriveMode.Output);
// Define the initial status as LOW (off)
pinValue = GpioPinValue.Low;
// Write the tate to the pin
pin.Write(pinValue);
// Update the on screen text to indicate that the GPIO is ready
GpioStatus.Text = "GPIO pin is initialized correctly.";
// Start the timer.
timer.Start();
}
}
Note that we added the async
modifier to the method signature and changed the return type from void
to Task
.
The application is ready to be deployed and run on the Raspberry Pi 3. You must set the target in Visual Studio to ARM and point the debugger at a Remote Machine (your Raspberry Pi 3).
- Select ARM from the Solution Platforms list in the toolbar.
- Select REMOTE MACHINE from the Device dropdown list in the toolbar.
You will be prompted with the Remote Connections dialog.
- Select your device from the list of Auto Detected devices. (Note: The Raspberry Pi 3 you are working with is named ptiotXX where the XX is replaced with the number on your Raspberry Pi 3.) If your device is not listed, type your device's name into the Manual Configuration textbox.
- Set the Authentication Mode to Universal (Unencrypted Protocol).
- If Visual Studio asks for a remote debugging PIN, head to the Web Portal (http://) and in the homepage you can set the PIN.
- Click Select.
NOTE: You can verify or modify these values by navigating to the project properties (select Properties in the Solution Explorer) and choosing the Debug tab on the left.
- Press F5 to run the application and you should see it deploy on the Raspberry Pi 3. You will see the red LED blink in unison with the red circle on the screen. If the red LED is not blinking, but the display on the screen is, recheck your wiring.
Congratulations! You have built a Universal Windows Platform application that controlled one of the GPIO pins and deployed the app to a Raspberry Pi 3. The core concepts you've learned are:
- Building a Universal Windows Platform application that can run on any Windows 10 device.
- Testing for the existence of the GPIO controller to inform the application of what capabilities are accessible.
- Controlling the state of a device via the GPIO pins.
In the next lab you will set up a Microsoft Azure IoT Hub that will act as the cloud backend for your IoT devices.
Back to Lab 1 - Windows IoT
Back to IoT Labs homepage