未验证 提交 e059421c 编写于 作者: R Rich Lander 提交者: GitHub

Merge pull request #1 from dotnet/samples

Add initial samples
......@@ -8,6 +8,7 @@
*.user
*.userosscache
*.sln.docstates
.vscode/
# User-specific files (MonoDevelop/Xamarin Studio)
*.userprefs
......
# Using .NET Core for IoT Scenarios
.NET Core can be used to build applications for [IoT](https://en.wikipedia.org/wiki/Internet_of_things) devices and scenarios. IoT applications typically interact with sensors, displays and input devices that require the use of [GPIO pins](https://en.wikipedia.org/wiki/General-purpose_input/output), serial ports or similar hardware. The [Raspberry Pi](https://www.raspberrypi.org/) is commonly used for IoT applications.
## Samples
The following samples demonstrate various scenarios:
* [Blinking LED](led-blink/README.md)
* [More blinking lights](led-more-blinking-lights/README.md)
* [Trimpot (potentiometer)](trimpot/README.md)
## Libraries
These samples use the [System.Devices.Gpio](https://dotnet.myget.org/feed/dotnet-corefxlab/package/nuget/System.Devices.Gpio) library. It will be supported on Linux and Windows IoT Core. At present, the library works on Linux. The library is currently in early preview, based on [source in dotnet/corefxlab](https://github.com/dotnet/corefxlab/tree/master/src/System.Devices.Gpio).
There are many libraries that are important beyond GPIO, I2C and related fundamental protocols. We are working on a plan where the .NET Team and the community can work together to build up a shared repository of implementations.
## Breadboard layouts
The samples expect the device pins to be connected in particular way to function, typically on a breadboard. Each example includes a [Fritzing](http://fritzing.org/home/) diagram of the required breadboard layout, such as the following one (taken from the [More blinking lights](led-more-blinking-lights/README.md) sample).
![Rasperry Pi Breadboard diagram](led-more-blinking-lights/rpi-more-blinking-lights_bb.png)
## Requirements
You need to use at least [.NET Core 2.1](https://www.microsoft.com/net/download/archives). [.NET Core 3.0](https://github.com/dotnet/announcements/issues/82) is required for ARM64 devices.
Many of these samples use the [Raspberry Pi](https://www.raspberrypi.org/), however, .NET Core can be used for other devices. A [Raspberry Pi Starter Pack](https://www.adafruit.com/product/3058) contains enough electronics to get started on many projects.
.NET Core is supported on Raspberry Pi 2 and 3. Raspberry Pi 3 B+ is recommended, based on the faster CPU. .NET Core is not supported on Raspberry Pi Zero or any of the Raspberry Pi model A devices. .NET Core does is not supported on ARMv6 chips, only ARMv7 and ARMv8. It is not supported on Arduino.
## Resources
* [How to Use a Breadboard](https://www.youtube.com/watch?v=6WReFkfrUIk)
* [Collin's Lab: Breadboards & Perfboards](https://www.youtube.com/watch?v=w0c3t0fJhXU)
using System;
using System.Devices.Gpio;
using System.Threading;
namespace led_blink
{
class Program
{
static void Main(string[] args)
{
var pin = 17;
var lightTime = 1000;
var dimTime = 200;
Console.WriteLine($"Let's blink an LED!");
GpioController controller = new GpioController(PinNumberingScheme.Gpio);
GpioPin ledPin = controller.OpenPin(pin, PinMode.Output);
Console.WriteLine($"GPIO pin enabled for use: {pin}");
Console.CancelKeyPress += (object sender, ConsoleCancelEventArgs eventArgs) =>
{
controller.ClosePin(pin);
};
while (true)
{
Console.WriteLine($"Light for {lightTime}ms");
ledPin.Write(PinValue.High);
Thread.Sleep(lightTime);
Console.WriteLine($"Dim for {dimTime}ms");
ledPin.Write(PinValue.Low);
Thread.Sleep(dimTime);
}
}
}
}
# Blink an LED with .NET Core on a Raspberry Pi
This [sample](Program.cs) demonstrates blinking an LED at a given interval. It repeatedly toggles a GPIO pin on and off, which powers the LED. This sample also demonstrates the most basic usage of the [.NET Core GPIO library](https://dotnet.myget.org/feed/dotnet-corefxlab/package/nuget/System.Devices.Gpio).
### Code
The following code provides write access to a GPIO pin (GPIO 17 in this case):
```csharp
GpioController controller = new GpioController(PinNumberingScheme.Gpio);
GpioPin ledPin = controller.OpenPin(17, PinMode.Output);
```
Given a `GpioPin`, the following code blinks the LED on a schedule for an indefinite duration (forever):
```csharp
while (true)
{
Console.WriteLine($"Light for {lightTime}ms");
ledPin.Write(PinValue.High);
Thread.Sleep(lightTime);
Console.WriteLine($"Dim for {dimTime}ms");
ledPin.Write(PinValue.Low);
Thread.Sleep(dimTime);
}
```
### Breadboard layout
The following [fritzing diagram](rpi-led.fzz) demonstrates how you should wire your device in order to run the [program](Program.cs). It uses the GND and GPIO 17 pins on the Raspberry Pi.
![Rasperry Pi Breadboard diagram](rpi-led_bb.png)
## Hardware elements
The following elements are used in this sample:
* [Diffused LEDs](https://www.adafruit.com/product/297)
## Resources
* [Using .NET Core for IoT Scenarios](../README.md)
* [All about LEDs](https://learn.adafruit.com/all-about-leds)
\ No newline at end of file
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFramework>netcoreapp2.1</TargetFramework>
<RootNamespace>led_blink</RootNamespace>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="System.Devices.Gpio" Version="0.1.0-preview2-180912-2" />
</ItemGroup>
</Project>
<?xml version="1.0" encoding="utf-8"?>
<configuration>
<packageSources>
<clear />
<add key="corefxlab" value="https://dotnet.myget.org/F/dotnet-corefxlab/api/v3/index.json" />
<add key="NuGet.org" value="https://api.nuget.org/v3/index.json" />
</packageSources>
</configuration>
\ No newline at end of file
using System;
using System.Devices.Gpio;
using System.Devices.Spi;
public class Mcp3008
{
private SpiDevice _spiDevice;
private GpioPin _CLK;
private GpioPin _MISO;
private GpioPin _MOSI;
private GpioPin _CS;
public Mcp3008(SpiDevice spiDevice)
{
_spiDevice = spiDevice;
}
public Mcp3008(GpioController controller, int CLK, int MISO, int MOSI, int CS)
{
_CLK = controller.OpenPin(CLK, PinMode.Output);
_MISO = controller.OpenPin(MISO, PinMode.Input);
_MOSI = controller.OpenPin(MOSI, PinMode.Output);
_CS = controller.OpenPin(CS, PinMode.Output);
}
public int Read(int adc_channel)
{
if (adc_channel < 0 && adc_channel > 7)
{
throw new ArgumentException("ADC channel must be within 0-7 range.");
}
if (_spiDevice != null)
{
return ReadSpi(adc_channel);
}
else
{
return ReadGpio(adc_channel);
}
}
private int ReadGpio(int adc_channel)
{
//port of https://gist.github.com/ladyada/3151375
while (true)
{
var commandout = 0;
var trim_pot = 0;
_CS.Write(PinValue.High);
_CLK.Write(PinValue.Low);
_CS.Write(PinValue.Low);
commandout |= 0x18;
commandout <<= 3;
for (var i = 0; i < 5; i++)
{
if ((commandout & 0x80) > 0)
{
_MOSI.Write(PinValue.High);
}
else
{
_MOSI.Write(PinValue.Low);
}
commandout <<= 1;
_CLK.Write(PinValue.High);
_CLK.Write(PinValue.Low);
}
for (var i = 0; i < 12; i++)
{
_CLK.Write(PinValue.High);
_CLK.Write(PinValue.Low);
trim_pot <<= 1;
if (_MISO.Read() == PinValue.High)
{
trim_pot |= 0x1;
}
}
_CS.Write(PinValue.High);
trim_pot >>= 1;
//var pot_adjust = Math.Abs(trim_pot - last_read);
return trim_pot;
}
}
private int ReadSpi(int adc_channel)
{
// ported code from:
// https://github.com/adafruit/Adafruit_Python_MCP3008/blob/master/Adafruit_MCP3008/MCP3008.py
int command = 0b11 << 6; //Start bit, single channel read
command |= (adc_channel & 0x07) << 3; // Channel number (in 3 bits)
var input = new Byte[] { (Byte)command, 0, 0 };
var output = new Byte[3];
_spiDevice.TransferFullDuplex(input, output);
var result = (output[0] & 0x01) << 9;
result |= (output[1] & 0xFF) << 1;
result |= (output[2] & 0x80) >> 7;
result = result & 0x3FF;
return result;
}
}
\ No newline at end of file
using System;
using System.Devices.Gpio;
using System.Threading;
namespace led_more_blinking_lights
{
class Program
{
static void Main(string[] args)
{
Console.WriteLine("Hello World!");
// pins
var pinOne = 17;
var pinTwo = 16;
var pinThree = 20;
var pinFour = 21;
// volume support
var initialSleep = 100;
var sleep = initialSleep;
Volume volume = null;
// this line should only be enabled if a trimpot is connected
volume = Volume.EnableVolume();
Console.WriteLine($"Let's blink some LEDs!");
GpioController controller = new GpioController(PinNumberingScheme.Gpio);
GpioPin ledOne = controller.OpenPin(pinOne, PinMode.Output);
GpioPin ledTwo = controller.OpenPin(pinTwo, PinMode.Output);
GpioPin ledThree = controller.OpenPin(pinThree, PinMode.Output);
GpioPin buttonOne = controller.OpenPin(pinFour, PinMode.Input);
Console.CancelKeyPress += (object sender, ConsoleCancelEventArgs eventArgs) =>
{
controller.ClosePin(pinOne);
controller.ClosePin(pinTwo);
controller.ClosePin(pinThree);
controller.ClosePin(pinFour);
Console.WriteLine("Pin cleanup complete!");
};
var timer1 = new TimeEnvelope(1000);
var timer2 = new TimeEnvelope(1000);
var timer3 = new TimeEnvelope(4000);
var timers = new TimeEnvelope[] {timer1, timer2, timer3};
while (true)
{
// behavior for ledOne
if (timer1.Time == 0)
{
Console.WriteLine($"Light LED one for 800ms");
ledOne.Write(PinValue.High);
}
else if (timer1.IsLastMultiple(200))
{
Console.WriteLine($"Dim LED one for 200ms");
ledOne.Write(PinValue.Low);
}
// behavior for ledTwo
if (timer2.IsMultiple(200))
{
Console.WriteLine($"Light LED two for 100ms");
ledTwo.Write(PinValue.High);
}
else if (timer2.IsMultiple(100))
{
Console.WriteLine($"Dim LED two for 100ms");
ledTwo.Write(PinValue.Low);
}
// behavior for ledThree
if (timer3.Time == 0)
{
Console.WriteLine("Light LED two for 2000 ms");
ledThree.Write(PinValue.High);
}
else if (timer3.IsFirstMultiple(2000))
{
Console.WriteLine("Dim LED two for 2000 ms");
ledThree.Write(PinValue.Low);
}
// behavior for buttonOne
if (volume != null)
{
var update = true;
var value = 0;
while (update)
{
(update,value) = volume.GetSleepforVolume(initialSleep);
if (update)
{
sleep = value;
Thread.Sleep(250);
}
}
}
while (buttonOne.Read() == PinValue.High)
{
Console.WriteLine("Button one pin value high!");
ledOne.Write(PinValue.High);
ledTwo.Write(PinValue.High);
ledThree.Write(PinValue.High);
Thread.Sleep(250);
}
Console.WriteLine($"Sleep: {sleep}");
Thread.Sleep(sleep); // starts at 100ms
TimeEnvelope.AddTime(timers,100); // always stays at 100
}
}
}
}
# More blinking lights, with hardware controls
This [sample](Program.cs) demonstrates blinking multiple LED on different schedules and controlling the LEDs from hardware controls. The sample builds on the [Blink an LED](../led-blink/README.md) and [Trimpot](../trimpot/README.md) samples.
## Code
This sample demonstrates how to use five different elements together, three LEDs, a potentiometer and a button. There is no one specific code element to call out here. Each element is controlled in a different way. You will find that different algorithms were needed to control LED timing than in the [Blink an LED](../led-blink/README.md) example. In particular, this sample implements the following:
* Different lighting schedules for different LEDs using the [TimeEnvelope](TimeEnvelope.cs) type.
* Integrating a factor in the lighting schedule based on the value returned from the potentiometer, implemented in the [Volume ](Volume.cs) type.
## Breadboard layout
The following [fritzing diagram](rpi-more-blinking-lights.fzz) demonstrates how you should wire your device in order to run the [program](Program.cs). It uses several pins on the Raspberry Pi.
![Rasperry Pi Breadboard diagram](rpi-more-blinking-lights_bb.png)
## Hardware elements
The following elements are used in this sample:
* [Diffused LEDs](https://www.adafruit.com/product/297)
* [Potentiometer](https://www.adafruit.com/product/356)
* [MCP3008](https://www.adafruit.com/product/856)
* [Button](https://www.adafruit.com/product/367)
## Resources
* [Using .NET Core for IoT Scenarios](../README.md)
* [All about LEDs](https://learn.adafruit.com/all-about-leds)
\ No newline at end of file
using System;
using System.Collections.Generic;
public class TimeEnvelope
{
private int _count;
private int _time = 0;
private bool _throwOnOverflow;
public static void AddTime(IEnumerable<TimeEnvelope> envelopes, int value)
{
foreach(var envelope in envelopes)
{
envelope.AddTime(value);
}
}
public TimeEnvelope(int count, bool throwOnOverthrow = true)
{
_count = count;
_throwOnOverflow = throwOnOverthrow;
}
public int Count
{
get
{
return _count;
}
}
public int Time
{
get
{
return _time;
}
}
public int AddTime(int value)
{
_time += value;
if (_time == _count)
{
_time = 0;
}
else if (_throwOnOverflow && _time > _count)
{
throw new Exception ("TimeEnvelope count overflowed!");
}
return _time;
}
public bool IsFirstMultiple(int value)
{
if (_time == value)
{
return true;
}
return false;
}
public bool IsLastMultiple(int value)
{
if (_time - value == 0)
{
return true;
}
return false;
}
public bool IsMultiple(int value)
{
if (_time % value == 0)
{
return true;
}
return false;
}
}
\ No newline at end of file
using System;
using System.Devices.Spi;
public class Volume
{
public static Volume EnableVolume()
{
var connection = new SpiConnectionSettings(0,0);
connection.ClockFrequency = 1000000;
connection.Mode = SpiMode.Mode0;
var spi = new UnixSpiDevice(connection);
var mcp3008 = new Mcp3008(spi);
var volume = new Volume(mcp3008);
volume.Init();
return volume;
}
private Mcp3008 _mcp3008;
private int _lastValue = 0;
public Volume(Mcp3008 mcp3008)
{
_mcp3008 = mcp3008;
}
public int GetVolumeValue()
{
double value = _mcp3008.Read(0);
value = value / 10.24;
value = Math.Round(value);
return (int)value;
}
private void Init()
{
_lastValue = GetVolumeValue();
}
public (bool update, int value) GetSleepforVolume(int sleep)
{
var value = GetVolumeValue();
if (value > _lastValue - 2 && value < _lastValue +2)
{
return (false,0);
}
_lastValue = value;
Console.WriteLine($"Volume: {value}");
var tenth = value / 10;
if (tenth == 5)
{
return (true, sleep);
}
var factor = 5 - tenth;
factor = factor * 2;
factor = Math.Abs(factor);
var newValue = 0;
if (tenth < 5)
{
newValue = sleep * factor;
}
else
{
newValue = sleep / factor;
}
if (newValue >=10 && newValue <=1000)
{
return (true,newValue);
}
return (true, sleep);
}
}
\ No newline at end of file
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFramework>netcoreapp2.1</TargetFramework>
<RootNamespace>led_more_blinking_lights</RootNamespace>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="System.Devices.Gpio" Version="0.1.0-preview2-180912-2" />
</ItemGroup>
</Project>
<?xml version="1.0" encoding="utf-8"?>
<configuration>
<packageSources>
<clear />
<add key="corefxlab" value="https://dotnet.myget.org/F/dotnet-corefxlab/api/v3/index.json" />
<add key="NuGet.org" value="https://api.nuget.org/v3/index.json" />
</packageSources>
</configuration>
using System;
using System.Devices.Gpio;
using System.Devices.Spi;
public class Mcp3008
{
private SpiDevice _spiDevice;
private GpioPin _CLK;
private GpioPin _MISO;
private GpioPin _MOSI;
private GpioPin _CS;
public Mcp3008(SpiDevice spiDevice)
{
_spiDevice = spiDevice;
}
public Mcp3008(GpioController controller, int CLK, int MISO, int MOSI, int CS)
{
_CLK = controller.OpenPin(CLK, PinMode.Output);
_MISO = controller.OpenPin(MISO, PinMode.Input);
_MOSI = controller.OpenPin(MOSI, PinMode.Output);
_CS = controller.OpenPin(CS, PinMode.Output);
}
public int Read(int adc_channel)
{
if (adc_channel < 0 && adc_channel > 7)
{
throw new ArgumentException("ADC channel must be within 0-7 range.");
}
if (_spiDevice != null)
{
return ReadSpi(adc_channel);
}
else
{
return ReadGpio(adc_channel);
}
}
private int ReadGpio(int adc_channel)
{
//port of https://gist.github.com/ladyada/3151375
while (true)
{
var commandout = 0;
var trim_pot = 0;
_CS.Write(PinValue.High);
_CLK.Write(PinValue.Low);
_CS.Write(PinValue.Low);
commandout |= 0x18;
commandout <<= 3;
for (var i = 0; i < 5; i++)
{
if ((commandout & 0x80) > 0)
{
_MOSI.Write(PinValue.High);
}
else
{
_MOSI.Write(PinValue.Low);
}
commandout <<= 1;
_CLK.Write(PinValue.High);
_CLK.Write(PinValue.Low);
}
for (var i = 0; i < 12; i++)
{
_CLK.Write(PinValue.High);
_CLK.Write(PinValue.Low);
trim_pot <<= 1;
if (_MISO.Read() == PinValue.High)
{
trim_pot |= 0x1;
}
}
_CS.Write(PinValue.High);
trim_pot >>= 1;
//var pot_adjust = Math.Abs(trim_pot - last_read);
return trim_pot;
}
}
private int ReadSpi(int adc_channel)
{
// ported code from:
// https://github.com/adafruit/Adafruit_Python_MCP3008/blob/master/Adafruit_MCP3008/MCP3008.py
int command = 0b11 << 6; //Start bit, single channel read
command |= (adc_channel & 0x07) << 3; // Channel number (in 3 bits)
var input = new Byte[] { (Byte)command, 0, 0 };
var output = new Byte[3];
_spiDevice.TransferFullDuplex(input, output);
var result = (output[0] & 0x01) << 9;
result |= (output[1] & 0xFF) << 1;
result |= (output[2] & 0x80) >> 7;
result = result & 0x3FF;
return result;
}
}
\ No newline at end of file
using System;
using System.Devices.Gpio;
using System.Devices.Spi;
using System.Threading;
namespace trimpot
{
class Program
{
static void Main(string[] args)
{
Console.WriteLine("Hello Trimpot!");
// This sample implements two different ways of accessing the MCP3008.
// The SPI option is enabled in the sample by default, but you can switch
// to the GPIO bit-banging option by switching which one is commented out.
// The sample uses local functions to make it easier to switch between
// the two implementations
// SPI implementation
Mcp3008 GetMCP3008WithSPI()
{
var connection = new SpiConnectionSettings(0,0);
connection.ClockFrequency = 1000000;
connection.Mode = SpiMode.Mode0;
var spi = new UnixSpiDevice(connection);
var mcp3008 = new Mcp3008(spi);
return mcp3008;
}
// the GPIO (via bit banging) implementation
Mcp3008 GetMCP3008WithGPIO()
{
GpioController controller = new GpioController(PinNumberingScheme.Gpio);
var mcp3008 = new Mcp3008(controller, 18, 23, 24, 25);
return mcp3008;
}
// Using SPI implementation
var mcp = GetMCP3008WithSPI();
// Using GPIO implementation
// var mcp = GetMCP3008WithGPIO();
while (true)
{
double value = mcp.Read(0);
value = value / 10.24;
value = Math.Round(value);
Console.WriteLine(value);
Thread.Sleep(500);
}
}
}
}
# Reading Analog Input from a Potentiometer
You can use .NET Core to read analog values from a [potentiometer](https://en.wikipedia.org/wiki/Trimmer_(electronics)), like a [volume control](https://www.adafruit.com/product/356).
The Rasperry Pi cannot read analog values directly so relies on an analog to digital converter, like the [MCP3008 ADC](https://www.adafruit.com/product/856). The MCP3008 supports the SPI interface. The 10-bit chip can be accessed as an SPI device or manually via raw GPIO pins. Both options are demonstrated.
## Accessing the MCP3008 via SPI
The Raspberry Pi has support for SPI. You need to [enable the SPI interface on the Raspberry Pi](https://www.raspberrypi-spy.co.uk/2014/08/enabling-the-spi-interface-on-the-raspberry-pi/) since it is not enabled by default.
You can use the following code to [access the MCP3008 via SPI](Program.cs#L17-L22):
```csharp
var connection = new SpiConnectionSettings(0,0);
connection.ClockFrequency = 1000000;
connection.Mode = SpiMode.Mode0;
var spi = new UnixSpiDevice(connection);
var mcp = new Mcp3008(spi);
```
The following pin layout can be used (also shown in a [fritzing diagram](rpi-trimpot-spi.fzz)):
* MCP3008 VDD to RPi 3.3V
* MCP3008 VREF to RPi 3.3V
* MCP3008 AGND to RPi GND
* MCP3008 DGND to RPi GND
* MCP3008 CLK to RPi SCLK
* MCP3008 DOUT to RPi MISO
* MCP3008 DIN to RPi MOSI
* MCP3008 CS/SHDN to RPi CE0
![Raspberry Pi Breadboard diagram](rpi-trimpot_spi.png)
## Accessing the MCP3008 via GPIO
You can also access the MCP3008 via GPIO pins, implementing SPI manually. This method is referred to as [bit-banging](https://en.wikipedia.org/wiki/Serial_Peripheral_Interface#Example_of_bit-banging_the_master_protocol).
You can use the following code to [access the MCP3008 via GPIO](Program.cs#L29-L30):
```csharp
GpioController controller = new GpioController(PinNumberingScheme.Gpio);
var mcp = new Mcp3008(controller, 18, 23, 24, 25);
```
The following pin layout can be used (also shown in a [fritzing diagram](rpi-trimpot-gpio.fzz)):
* MCP3008 VDD to RPi 3.3V
* MCP3008 VREF to RPi 3.3V
* MCP3008 AGND to RPi GND
* MCP3008 DGND to RPi GND
* MCP3008 CLK to RPi pin 18
* MCP3008 DOUT to RPi pin 23
* MCP3008 DIN to RPi pin 24
* MCP3008 CS/SHDN to RPi pin 25
![Raspberry Pi Breadboard diagram](rpi-trimpot_gpio.png)
## Processing the data
Independent of the way in which you access the MCP3008 chip, the code to process its results is the same, which follows.
```csharp
while (true)
{
double value = mcp.Read(0);
value = value / 10.24;
value = Math.Round(value);
Console.WriteLine(value);
Thread.Sleep(500);
}
```
The chip is 10-bit, which means that it will generate values from 0-1023 (recall that 2^10 is 1024). We can transform the value to a more familiar 0-100 scale by dividing the 10-bit value by 10.24.
## Hardware elements
The following elements are used in this sample:
* [Potentiometer](https://www.adafruit.com/product/356)
* [MCP3008](https://www.adafruit.com/product/856)
## References
The sample is based on following resources:
* [Analog Inputs for Raspberry Pi Using the MCP3008](https://learn.adafruit.com/reading-a-analog-in-and-controlling-audio-volume-with-the-raspberry-pi)
* [Raspberry Pi Analog to Digital Converters](https://learn.adafruit.com/raspberry-pi-analog-to-digital-converters).
* [Raspbery Pi Analog Input with MCP3008](https://gist.github.com/ladyada/3151375)
* [MCP3008.py](https://github.com/adafruit/Adafruit_Python_MCP3008/blob/master/Adafruit_MCP3008/MCP3008.py)
Major thanks to [Adafruit](https://adafruit.com) for providing python implementations, which were ported to C# for this sample.
See [Using .NET Core for IoT Scenarios](../README.md) for more samples.
<?xml version="1.0" encoding="utf-8"?>
<configuration>
<packageSources>
<clear />
<add key="corefxlab" value="https://dotnet.myget.org/F/dotnet-corefxlab/api/v3/index.json" />
<add key="NuGet.org" value="https://api.nuget.org/v3/index.json" />
</packageSources>
</configuration>
\ No newline at end of file
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFramework>netcoreapp2.1</TargetFramework>
<RootNamespace>led_pwm</RootNamespace>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="System.Devices.Gpio" Version="0.1.0-preview2-180912-2" />
</ItemGroup>
</Project>
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册