如何将代码从 Arduino 翻译成 Raspberry Pi?
How to translate code from Arduino to Raspberry Pi?
我有一个 Arduino Uno 程序,想将其翻译成代码 Raspberry Pi 2. 我正在构建一个机器人厨房餐具室,并编写了一个 LED 状态机以表示它。我打算控制的物理机主要有两个功能。
函数
(1) 电梯移动到以下三层之一:
- 0:重置/主页
- 1 : 搁置 1
- 2 : 搁置 2
(2) 电梯的货架移动in/out。
- 山
- 卸载
我目前正在使用 LED 来表示电机/传感器,以便对我的代码进行单元测试。我明白,为了让我的代码更健壮,我需要更好地处理时序,这是 Raspberry Pi 可以负担得起的事情。
这是我当前的代码:
// Sensors for shelves. True if shelf is loaded.
boolean s1 = false;
boolean s2 = false;
// Buttons to ask to shelves.
boolean input1 = false;
boolean input2 = false;
// Elevator level (0, 1, or 2)
int elevator = 0;
// Elevator Level LEDs (Red)
int elevatorReset = 13;
int elevatorOne = 12;
int elevatorTwo = 11;
// Shelve State LEDs (Green) (On if loaded, Off if hidden)
int ShelveOne = 10; // Top Shelve
int ShelveTwo = 9; // Bottom Shelve
// Buttons
int ButtonOne = 2; // Request Shelve One
int ButtonTwo = 3; // Request Shelve Two
int ButtonReset = 4; // Request Reset
// Debouncing
unsigned long lastTime1 = 0;
unsigned long lastTime2 = 0;
const long interval = 300;
void setup() {
pinMode(elevatorReset, OUTPUT); // declare LED as output
pinMode(elevatorOne, OUTPUT); // declare LED as output
pinMode(elevatorTwo, OUTPUT); // declare LED as output
pinMode(ShelveOne, OUTPUT); // declare LED as output
pinMode(ShelveTwo, OUTPUT); // declare LED as output
pinMode(ButtonOne, INPUT); // make button 1 an input
pinMode(ButtonTwo, INPUT); // make button 2 an input
pinMode(ButtonReset, INPUT); // make button 3 an input
}
void loop() {
unsigned long currentTime = millis();
level(0);
// Request Shelf 1
if (digitalRead(ButtonOne) == LOW)
{
pickup(1);
deliver(1);
}
// Request Shelf 2
if (digitalRead(ButtonTwo) == LOW)
{
pickup(2);
deliver(2);
}
// Request Reset
if (digitalRead(ButtonReset) == LOW)
{
reset();
}
}
void pickup(int num){
if (num == 1)
{
level(0);
delay(500);
level(1);
delay(500);
load(1);
}
else if (num == 2)
{
level(0);
delay(500);
level(1);
delay(500);
level(2);
delay(500);
load(2);
}
else if (num == 0)
{
}
}
void dropoff(int num){
if (num == 1)
{
level(1);
delay(500);
unload(1);
}
else if (num == 2)
{
level(1);
delay(500);
level(2);
delay(500);
unload(2);
}
}
void deliver(int num)
{
if (elevator == 1)
{
delay(1000);
level(0);
//blink();
}
if (elevator == 2)
{
delay(1000);
level(1);
delay(500);
level(0);
//blink();
}
}
void level(int num)
{
if (num == 0)
{
digitalWrite(elevatorReset, HIGH);
digitalWrite(elevatorOne, LOW);
digitalWrite(elevatorTwo, LOW);
elevator = 0;
}
else if (num == 1)
{
digitalWrite(elevatorReset, LOW);
digitalWrite(elevatorOne, HIGH);
digitalWrite(elevatorTwo, LOW);
elevator = 1;
}
else if (num == 2)
{
digitalWrite(elevatorReset, LOW);
digitalWrite(elevatorOne, LOW);
digitalWrite(elevatorTwo, HIGH);
elevator = 2;
}
}
void load(int num){
if (num == 1)
{
digitalWrite(ShelveOne, HIGH);
digitalWrite(ShelveTwo, LOW);
s1 = true;
}
else if (num == 2)
{
digitalWrite(ShelveOne, LOW);
digitalWrite(ShelveTwo, HIGH);
s2 = true;
}
}
void unload(int num){
if (num == 1)
{
digitalWrite(ShelveOne, LOW);
s1 = false;
}
else if (num == 2)
{
digitalWrite(ShelveTwo, LOW);
s2 = false;
}
}
void reset()
{
if (s1 == true)
{
delay(500);
dropoff(1);
delay(500);
level(0);
}
else if (s2 == true)
{
delay(500);
dropoff(2);
delay(500);
level(1);
delay(500);
level(0);
}
}
void blink ()
{
delay(1000);
while( !(digitalRead(ButtonOne) == LOW || digitalRead(ButtonTwo) == LOW || digitalRead(ButtonReset) == LOW) )
{
digitalWrite(elevatorReset, HIGH); // wait for a second
delay(200);
digitalWrite(elevatorReset, LOW); // wait for a second
delay(200);
}
}
澄清一下,您仍然可以使用 C++ 为 Win10 IoT 开发应用程序。
我用 C# 为你构建了一个类似的:
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Runtime.InteropServices.WindowsRuntime;
using System.Threading.Tasks;
using Windows.Devices.Gpio;
using Windows.Foundation;
using Windows.Foundation.Collections;
using Windows.UI.Xaml;
using Windows.UI.Xaml.Controls;
using Windows.UI.Xaml.Controls.Primitives;
using Windows.UI.Xaml.Data;
using Windows.UI.Xaml.Input;
using Windows.UI.Xaml.Media;
using Windows.UI.Xaml.Navigation;
// The Blank Page item template is documented at http://go.microsoft.com/fwlink/?LinkId=402352&clcid=0x409
namespace App6
{
/// <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 static GpioPin GpioPin1;
private static GpioPin GpioPin2;
private static GpioPin GpioPin3;
private static GpioPin GpioPin4;
private static GpioPin GpioPin5;
private static GpioPin GpioPin6;
private static GpioPin GpioPin7;
private static GpioPin GpioPin8;
// Sensors for shelves. True if shelf is loaded.
bool s1 = false;
bool s2 = false;
// Buttons to ask to shelves.
bool input1 = false;
bool input2 = false;
// Elevator level (0, 1, or 2)
int elevator = 0;
// Elevator Level LEDs (Red)
int elevatorReset = 13;
int elevatorOne = 12;
int elevatorTwo = 11;
// Shelve State LEDs (Green) (On if loaded, Off if hidden)
int ShelveOne = 10; // Top Shelve
int ShelveTwo = 9; // Bottom Shelve
// Buttons
int ButtonOne = 2; // Request Shelve One
int ButtonTwo = 3; // Request Shelve Two
int ButtonReset = 4; // Request Reset
// Debouncing
long lastTime1 = 0;
long lastTime2 = 0;
const long interval = 300;
private DispatcherTimer timer;
public MainPage()
{
this.InitializeComponent();
timer = new DispatcherTimer();
timer.Interval = TimeSpan.FromMilliseconds(500);
timer.Tick += Timer_Tick;
InitGPIO();
}
private void InitGPIO()
{
var gpio = GpioController.GetDefault();
// Show an error if there is no GPIO controller
if (gpio == null)
{
GpioPin1 = null;
GpioPin2 = null;
GpioPin3 = null;
GpioPin4 = null;
GpioPin5 = null;
GpioPin6 = null;
GpioPin7 = null;
GpioPin8 = null;
return;
}
//pinMode(elevatorReset, OUTPUT); // declare LED as output
//pinMode(elevatorOne, OUTPUT); // declare LED as output
//pinMode(elevatorTwo, OUTPUT); // declare LED as output
//pinMode(ShelveOne, OUTPUT); // declare LED as output
//pinMode(ShelveTwo, OUTPUT); // declare LED as output
//pinMode(ButtonOne, INPUT); // make button 1 an input
//pinMode(ButtonTwo, INPUT); // make button 2 an input
//pinMode(ButtonReset, INPUT); // make button 3 an input
GpioPin1 = gpio.OpenPin(elevatorReset);
GpioPin2 = gpio.OpenPin(elevatorOne);
GpioPin3 = gpio.OpenPin(elevatorTwo);
GpioPin4 = gpio.OpenPin(ShelveOne);
GpioPin5 = gpio.OpenPin(ShelveTwo);
GpioPin6 = gpio.OpenPin(ButtonOne);
GpioPin7 = gpio.OpenPin(ButtonTwo);
GpioPin8 = gpio.OpenPin(ButtonReset);
GpioPin1.Write(GpioPinValue.Low);
GpioPin2.Write(GpioPinValue.Low);
GpioPin3.Write(GpioPinValue.Low);
GpioPin4.Write(GpioPinValue.Low);
GpioPin5.Write(GpioPinValue.Low);
GpioPin1.SetDriveMode(GpioPinDriveMode.Output);
GpioPin2.SetDriveMode(GpioPinDriveMode.Output);
GpioPin3.SetDriveMode(GpioPinDriveMode.Output);
GpioPin4.SetDriveMode(GpioPinDriveMode.Output);
GpioPin5.SetDriveMode(GpioPinDriveMode.Output);
// Check if input pull-up resistors are supported
if (GpioPin6.IsDriveModeSupported(GpioPinDriveMode.InputPullUp))
GpioPin6.SetDriveMode(GpioPinDriveMode.InputPullUp);
else
GpioPin6.SetDriveMode(GpioPinDriveMode.Input);
if (GpioPin7.IsDriveModeSupported(GpioPinDriveMode.InputPullUp))
GpioPin7.SetDriveMode(GpioPinDriveMode.InputPullUp);
else
GpioPin7.SetDriveMode(GpioPinDriveMode.Input);
if (GpioPin8.IsDriveModeSupported(GpioPinDriveMode.InputPullUp))
GpioPin8.SetDriveMode(GpioPinDriveMode.InputPullUp);
else
GpioPin8.SetDriveMode(GpioPinDriveMode.Input);
}
private void Timer_Tick(object sender, object e)
{
//unsigned long currentTime = millis();
level(0);
// Request Shelf 1
if (GpioPin6.Read() == GpioPinValue.Low)
{
pickup(1);
deliver(1);
}
// Request Shelf 2
if (GpioPin7.Read() == GpioPinValue.Low)
{
pickup(2);
deliver(2);
}
// Request Reset
if (GpioPin8.Read() == GpioPinValue.Low)
{
reset();
}
}
async void pickup(int num)
{
if (num == 1)
{
level(0);
await Task.Delay(500);
level(1);
await Task.Delay(500);
load(1);
}
else if (num == 2)
{
level(0);
await Task.Delay(500);
level(1);
await Task.Delay(500);
level(2);
await Task.Delay(500);
load(2);
}
else if (num == 0)
{
}
}
async void dropoff(int num)
{
if (num == 1)
{
level(1);
await Task.Delay(500);
unload(1);
}
else if (num == 2)
{
level(1);
await Task.Delay(500);
level(2);
await Task.Delay(500);
unload(2);
}
}
async void deliver(int num)
{
if (elevator == 1)
{
await Task.Delay(1000);
level(0);
//blink();
}
if (elevator == 2)
{
await Task.Delay(1000);
level(1);
await Task.Delay(500);
level(0);
//blink();
}
}
void level(int num)
{
if (num == 0)
{
GpioPin1.Write(GpioPinValue.High);
GpioPin2.Write(GpioPinValue.Low);
GpioPin3.Write(GpioPinValue.Low);
elevator = 0;
}
else if (num == 1)
{
GpioPin1.Write(GpioPinValue.Low);
GpioPin2.Write(GpioPinValue.High);
GpioPin3.Write(GpioPinValue.Low);
elevator = 1;
}
else if (num == 2)
{
GpioPin1.Write(GpioPinValue.Low);
GpioPin2.Write(GpioPinValue.Low);
GpioPin3.Write(GpioPinValue.High);
elevator = 2;
}
}
void load(int num)
{
if (num == 1)
{
GpioPin4.Write(GpioPinValue.High);
GpioPin5.Write(GpioPinValue.Low);
s1 = true;
}
else if (num == 2)
{
GpioPin4.Write(GpioPinValue.Low);
GpioPin5.Write(GpioPinValue.High);
s2 = true;
}
}
void unload(int num)
{
if (num == 1)
{
GpioPin4.Write(GpioPinValue.Low);
s1 = false;
}
else if (num == 2)
{
GpioPin5.Write(GpioPinValue.Low);
s2 = false;
}
}
async void reset()
{
if (s1 == true)
{
await Task.Delay(500);
dropoff(1);
await Task.Delay(500);
level(0);
}
else if (s2 == true)
{
await Task.Delay(500);
dropoff(2);
await Task.Delay(500);
level(1);
await Task.Delay(500);
level(0);
}
}
async void blink()
{
await Task.Delay(1000);
while (!(GpioPin6.Read() == GpioPinValue.Low || GpioPin7.Read() == GpioPinValue.Low || GpioPin8.Read() == GpioPinValue.Low))
{
GpioPin1.Write(GpioPinValue.High); // wait for a second
await Task.Delay(200);
GpioPin1.Write(GpioPinValue.Low); // wait for a second
await Task.Delay(200);
}
}
}
}
这里有几项需要实现
- 物联网应用程序有后台应用程序的概念。请参阅此处的文档:http://ms-iot.github.io/content/en-US/win10/BackgroundApplications.htm
注意:它说的是后台应用程序,这可能会造成混淆,因为它不像典型 UWP 中的后台应用程序那样 运行。 IoT 的引导加载程序消除了通常强加给 UWP 后台应用程序的性能和 cpu 优先级瓶颈,因此 运行s 就像前台应用程序一样,只是它是无头的,并且是一个更容易的无头起点。它也更类似于您的 Arduino 代码。
- 你应该使用枚举来管理你的状态,这样它是集中的并且更容易处理。
- 在 windows10 IoT 中,您可以为事件发生时设置事件处理程序并处理它们,而不必循环和观察。这将有助于将事件排队然后进行处理。然而,在某些情况下它可能不会那么快,但在这种情况下应该没问题。如果你需要循环,你可能想分拆一个循环和监视的任务
- 最后,在基于事件的多线程系统中,您需要通过锁定一个对象来保护来自不同线程的同时处理状态更改。
我已经根据您的代码库提供了解决上述所有问题的示例代码。请注意,它尚未完成,但应该作为一个很好的起点。
首先,您需要创建后台应用程序并添加对 IoT 扩展的引用。
代码如下:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Net.Http;
using Windows.ApplicationModel.Background;
using Windows.Devices.Gpio;
using System.Threading.Tasks;
// The Background Application template is documented at http://go.microsoft.com/fwlink/?LinkID=533884&clcid=0x409
// Sensors for shelves. True if shelf is loaded.
namespace BackgroundApplication1
{
public sealed class StartupTask : IBackgroundTask
{
public enum MachineState
{
unknown,
initial,
elevatorLevelOne,
elevatorLevelTwo,
transitionOnetoTwo,
transitionTwotoOne,
transitionOnetoReset,
transitionTwotoReset
}
private MachineState currentState;
private object lObj;
// Elevator Level LEDs (Red)
private const int elevatorResetPin = 13;
private const int elevatorOnePin = 12;
private const int elevatorTwoPin = 11;
//Gpio for each
GpioPin elevOneLed;
GpioPin resetLed;
GpioPin elevTwoLed;
// Shelve State LEDs (Green) (On if loaded, Off if hidden)
private const int ShelveOnePin = 10; // Top Shelve
private const int ShelveTwoPin = 9; // Bottom Shelve
GpioPin shelfOneLed;
GpioPin shelfTwoLed;
// Buttons
private const int ButtonOne = 2; // Request Shelve One
private const int ButtonTwo = 3; // Request Shelve Two
private const int ButtonReset = 4; // Request Reset
// Debouncing
long lastTime1 = 0;
long lastTime2 = 0;
const long interval = 300;
public void Run(IBackgroundTaskInstance taskInstance)
{
this.Initialize();
Task.Run(() =>
{
while (true)
{
//thats right...do nothing.
}
});
}
public void Initialize()
{
GpioController gCon = GpioController.GetDefault();
//Elevator LEDs
elevOneLed = gCon.OpenPin(elevatorResetPin);
resetLed = gCon.OpenPin(elevatorOnePin);
elevTwoLed = gCon.OpenPin(elevatorTwoPin);
elevOneLed.SetDriveMode(GpioPinDriveMode.Output);
elevTwoLed.SetDriveMode(GpioPinDriveMode.Output);
resetLed.SetDriveMode(GpioPinDriveMode.Output);
//Shelf LEDs
shelfOneLed = gCon.OpenPin(ShelveOnePin);
shelfTwoLed = gCon.OpenPin(ShelveTwoPin);
shelfOneLed.SetDriveMode(GpioPinDriveMode.Output);
shelfTwoLed.SetDriveMode(GpioPinDriveMode.Output);
//Buttons
GpioPin buttonOne = gCon.OpenPin(ButtonOne);
GpioPin buttonTwo = gCon.OpenPin(ButtonTwo);
GpioPin buttonReset = gCon.OpenPin(ButtonReset);
buttonOne.SetDriveMode(GpioPinDriveMode.Input);
buttonTwo.SetDriveMode(GpioPinDriveMode.Input);
buttonReset.SetDriveMode(GpioPinDriveMode.Input);
buttonOne.ValueChanged += ButtonOne_ValueChanged;
buttonTwo.ValueChanged += ButtonTwo_ValueChanged;
buttonReset.ValueChanged += ButtonReset_ValueChanged;
this.GetShelfOne();
}
private void GetShelfOne()
{
switch(this.currentState)
{
case MachineState.unknown: this.Reset();
break;
case MachineState.elevatorLevelOne:
break;
case MachineState.elevatorLevelTwo: this.TransitionToShelfTwoFromOne();
break;
case MachineState.transitionOnetoReset: //handle the rest of your stuff similiarly...
break;
}
}
private void TransitionToShelfTwoFromOne()
{
this.shelfOneLed.Write(GpioPinValue.Low);
this.shelfTwoLed.Write(GpioPinValue.High);
this.currentState = MachineState.elevatorLevelTwo;
}
private void Reset()
{
throw new NotImplementedException();
}
private void ButtonReset_ValueChanged(GpioPin sender, GpioPinValueChangedEventArgs args)
{
throw new NotImplementedException();
}
private void ButtonTwo_ValueChanged(GpioPin sender, GpioPinValueChangedEventArgs args)
{
throw new NotImplementedException();
}
private void ButtonOne_ValueChanged(GpioPin sender, GpioPinValueChangedEventArgs args)
{
//rising edge means you pushed the button
if(args.Edge == GpioPinEdge.RisingEdge)
{
lock(lObj)
{
this.GetShelfOne();
}
}
//falling edge means you released the button.
//you could start a timer to see how long you held the button.
}
}
}
有两种方法:
- 方式 1 - 您可以直接在您的 Windows IoT 上使用 Arduino 代码,稍作改动。
- 方式 2 - 通过将 Arduino 代码转换为等效的 C# UWP。
方式 1:直接在您的 Windows IoT
上使用 Arduino 代码
- 为 Windows IoT (refer this link)
设置 Arduino 布线
- 将您的 Arduino 代码(上面写的)移植到您的 Windows IoT 上,引脚图为 Raspberry Pi 2。
Important Note: There are some rules to port Arduino written code to Windows IoT which is described at ms-iot website. The Arduino code you have provided can directly be ported on to Raspberry Pi 2 (make sure to change Arduino pin numbers to RPi2 pinmap).
方式 2:将 Arduino 代码转换为 C# UWP
将 Arduino 代码转换为 C# UWP 并不复杂。您只需将 Arduino 函数转换为等效的 C# UWP Windows IoT 函数:
我有一个 Arduino Uno 程序,想将其翻译成代码 Raspberry Pi 2. 我正在构建一个机器人厨房餐具室,并编写了一个 LED 状态机以表示它。我打算控制的物理机主要有两个功能。
函数
(1) 电梯移动到以下三层之一: - 0:重置/主页 - 1 : 搁置 1 - 2 : 搁置 2
(2) 电梯的货架移动in/out。 - 山 - 卸载
我目前正在使用 LED 来表示电机/传感器,以便对我的代码进行单元测试。我明白,为了让我的代码更健壮,我需要更好地处理时序,这是 Raspberry Pi 可以负担得起的事情。
这是我当前的代码:
// Sensors for shelves. True if shelf is loaded.
boolean s1 = false;
boolean s2 = false;
// Buttons to ask to shelves.
boolean input1 = false;
boolean input2 = false;
// Elevator level (0, 1, or 2)
int elevator = 0;
// Elevator Level LEDs (Red)
int elevatorReset = 13;
int elevatorOne = 12;
int elevatorTwo = 11;
// Shelve State LEDs (Green) (On if loaded, Off if hidden)
int ShelveOne = 10; // Top Shelve
int ShelveTwo = 9; // Bottom Shelve
// Buttons
int ButtonOne = 2; // Request Shelve One
int ButtonTwo = 3; // Request Shelve Two
int ButtonReset = 4; // Request Reset
// Debouncing
unsigned long lastTime1 = 0;
unsigned long lastTime2 = 0;
const long interval = 300;
void setup() {
pinMode(elevatorReset, OUTPUT); // declare LED as output
pinMode(elevatorOne, OUTPUT); // declare LED as output
pinMode(elevatorTwo, OUTPUT); // declare LED as output
pinMode(ShelveOne, OUTPUT); // declare LED as output
pinMode(ShelveTwo, OUTPUT); // declare LED as output
pinMode(ButtonOne, INPUT); // make button 1 an input
pinMode(ButtonTwo, INPUT); // make button 2 an input
pinMode(ButtonReset, INPUT); // make button 3 an input
}
void loop() {
unsigned long currentTime = millis();
level(0);
// Request Shelf 1
if (digitalRead(ButtonOne) == LOW)
{
pickup(1);
deliver(1);
}
// Request Shelf 2
if (digitalRead(ButtonTwo) == LOW)
{
pickup(2);
deliver(2);
}
// Request Reset
if (digitalRead(ButtonReset) == LOW)
{
reset();
}
}
void pickup(int num){
if (num == 1)
{
level(0);
delay(500);
level(1);
delay(500);
load(1);
}
else if (num == 2)
{
level(0);
delay(500);
level(1);
delay(500);
level(2);
delay(500);
load(2);
}
else if (num == 0)
{
}
}
void dropoff(int num){
if (num == 1)
{
level(1);
delay(500);
unload(1);
}
else if (num == 2)
{
level(1);
delay(500);
level(2);
delay(500);
unload(2);
}
}
void deliver(int num)
{
if (elevator == 1)
{
delay(1000);
level(0);
//blink();
}
if (elevator == 2)
{
delay(1000);
level(1);
delay(500);
level(0);
//blink();
}
}
void level(int num)
{
if (num == 0)
{
digitalWrite(elevatorReset, HIGH);
digitalWrite(elevatorOne, LOW);
digitalWrite(elevatorTwo, LOW);
elevator = 0;
}
else if (num == 1)
{
digitalWrite(elevatorReset, LOW);
digitalWrite(elevatorOne, HIGH);
digitalWrite(elevatorTwo, LOW);
elevator = 1;
}
else if (num == 2)
{
digitalWrite(elevatorReset, LOW);
digitalWrite(elevatorOne, LOW);
digitalWrite(elevatorTwo, HIGH);
elevator = 2;
}
}
void load(int num){
if (num == 1)
{
digitalWrite(ShelveOne, HIGH);
digitalWrite(ShelveTwo, LOW);
s1 = true;
}
else if (num == 2)
{
digitalWrite(ShelveOne, LOW);
digitalWrite(ShelveTwo, HIGH);
s2 = true;
}
}
void unload(int num){
if (num == 1)
{
digitalWrite(ShelveOne, LOW);
s1 = false;
}
else if (num == 2)
{
digitalWrite(ShelveTwo, LOW);
s2 = false;
}
}
void reset()
{
if (s1 == true)
{
delay(500);
dropoff(1);
delay(500);
level(0);
}
else if (s2 == true)
{
delay(500);
dropoff(2);
delay(500);
level(1);
delay(500);
level(0);
}
}
void blink ()
{
delay(1000);
while( !(digitalRead(ButtonOne) == LOW || digitalRead(ButtonTwo) == LOW || digitalRead(ButtonReset) == LOW) )
{
digitalWrite(elevatorReset, HIGH); // wait for a second
delay(200);
digitalWrite(elevatorReset, LOW); // wait for a second
delay(200);
}
}
澄清一下,您仍然可以使用 C++ 为 Win10 IoT 开发应用程序。
我用 C# 为你构建了一个类似的:
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Runtime.InteropServices.WindowsRuntime;
using System.Threading.Tasks;
using Windows.Devices.Gpio;
using Windows.Foundation;
using Windows.Foundation.Collections;
using Windows.UI.Xaml;
using Windows.UI.Xaml.Controls;
using Windows.UI.Xaml.Controls.Primitives;
using Windows.UI.Xaml.Data;
using Windows.UI.Xaml.Input;
using Windows.UI.Xaml.Media;
using Windows.UI.Xaml.Navigation;
// The Blank Page item template is documented at http://go.microsoft.com/fwlink/?LinkId=402352&clcid=0x409
namespace App6
{
/// <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 static GpioPin GpioPin1;
private static GpioPin GpioPin2;
private static GpioPin GpioPin3;
private static GpioPin GpioPin4;
private static GpioPin GpioPin5;
private static GpioPin GpioPin6;
private static GpioPin GpioPin7;
private static GpioPin GpioPin8;
// Sensors for shelves. True if shelf is loaded.
bool s1 = false;
bool s2 = false;
// Buttons to ask to shelves.
bool input1 = false;
bool input2 = false;
// Elevator level (0, 1, or 2)
int elevator = 0;
// Elevator Level LEDs (Red)
int elevatorReset = 13;
int elevatorOne = 12;
int elevatorTwo = 11;
// Shelve State LEDs (Green) (On if loaded, Off if hidden)
int ShelveOne = 10; // Top Shelve
int ShelveTwo = 9; // Bottom Shelve
// Buttons
int ButtonOne = 2; // Request Shelve One
int ButtonTwo = 3; // Request Shelve Two
int ButtonReset = 4; // Request Reset
// Debouncing
long lastTime1 = 0;
long lastTime2 = 0;
const long interval = 300;
private DispatcherTimer timer;
public MainPage()
{
this.InitializeComponent();
timer = new DispatcherTimer();
timer.Interval = TimeSpan.FromMilliseconds(500);
timer.Tick += Timer_Tick;
InitGPIO();
}
private void InitGPIO()
{
var gpio = GpioController.GetDefault();
// Show an error if there is no GPIO controller
if (gpio == null)
{
GpioPin1 = null;
GpioPin2 = null;
GpioPin3 = null;
GpioPin4 = null;
GpioPin5 = null;
GpioPin6 = null;
GpioPin7 = null;
GpioPin8 = null;
return;
}
//pinMode(elevatorReset, OUTPUT); // declare LED as output
//pinMode(elevatorOne, OUTPUT); // declare LED as output
//pinMode(elevatorTwo, OUTPUT); // declare LED as output
//pinMode(ShelveOne, OUTPUT); // declare LED as output
//pinMode(ShelveTwo, OUTPUT); // declare LED as output
//pinMode(ButtonOne, INPUT); // make button 1 an input
//pinMode(ButtonTwo, INPUT); // make button 2 an input
//pinMode(ButtonReset, INPUT); // make button 3 an input
GpioPin1 = gpio.OpenPin(elevatorReset);
GpioPin2 = gpio.OpenPin(elevatorOne);
GpioPin3 = gpio.OpenPin(elevatorTwo);
GpioPin4 = gpio.OpenPin(ShelveOne);
GpioPin5 = gpio.OpenPin(ShelveTwo);
GpioPin6 = gpio.OpenPin(ButtonOne);
GpioPin7 = gpio.OpenPin(ButtonTwo);
GpioPin8 = gpio.OpenPin(ButtonReset);
GpioPin1.Write(GpioPinValue.Low);
GpioPin2.Write(GpioPinValue.Low);
GpioPin3.Write(GpioPinValue.Low);
GpioPin4.Write(GpioPinValue.Low);
GpioPin5.Write(GpioPinValue.Low);
GpioPin1.SetDriveMode(GpioPinDriveMode.Output);
GpioPin2.SetDriveMode(GpioPinDriveMode.Output);
GpioPin3.SetDriveMode(GpioPinDriveMode.Output);
GpioPin4.SetDriveMode(GpioPinDriveMode.Output);
GpioPin5.SetDriveMode(GpioPinDriveMode.Output);
// Check if input pull-up resistors are supported
if (GpioPin6.IsDriveModeSupported(GpioPinDriveMode.InputPullUp))
GpioPin6.SetDriveMode(GpioPinDriveMode.InputPullUp);
else
GpioPin6.SetDriveMode(GpioPinDriveMode.Input);
if (GpioPin7.IsDriveModeSupported(GpioPinDriveMode.InputPullUp))
GpioPin7.SetDriveMode(GpioPinDriveMode.InputPullUp);
else
GpioPin7.SetDriveMode(GpioPinDriveMode.Input);
if (GpioPin8.IsDriveModeSupported(GpioPinDriveMode.InputPullUp))
GpioPin8.SetDriveMode(GpioPinDriveMode.InputPullUp);
else
GpioPin8.SetDriveMode(GpioPinDriveMode.Input);
}
private void Timer_Tick(object sender, object e)
{
//unsigned long currentTime = millis();
level(0);
// Request Shelf 1
if (GpioPin6.Read() == GpioPinValue.Low)
{
pickup(1);
deliver(1);
}
// Request Shelf 2
if (GpioPin7.Read() == GpioPinValue.Low)
{
pickup(2);
deliver(2);
}
// Request Reset
if (GpioPin8.Read() == GpioPinValue.Low)
{
reset();
}
}
async void pickup(int num)
{
if (num == 1)
{
level(0);
await Task.Delay(500);
level(1);
await Task.Delay(500);
load(1);
}
else if (num == 2)
{
level(0);
await Task.Delay(500);
level(1);
await Task.Delay(500);
level(2);
await Task.Delay(500);
load(2);
}
else if (num == 0)
{
}
}
async void dropoff(int num)
{
if (num == 1)
{
level(1);
await Task.Delay(500);
unload(1);
}
else if (num == 2)
{
level(1);
await Task.Delay(500);
level(2);
await Task.Delay(500);
unload(2);
}
}
async void deliver(int num)
{
if (elevator == 1)
{
await Task.Delay(1000);
level(0);
//blink();
}
if (elevator == 2)
{
await Task.Delay(1000);
level(1);
await Task.Delay(500);
level(0);
//blink();
}
}
void level(int num)
{
if (num == 0)
{
GpioPin1.Write(GpioPinValue.High);
GpioPin2.Write(GpioPinValue.Low);
GpioPin3.Write(GpioPinValue.Low);
elevator = 0;
}
else if (num == 1)
{
GpioPin1.Write(GpioPinValue.Low);
GpioPin2.Write(GpioPinValue.High);
GpioPin3.Write(GpioPinValue.Low);
elevator = 1;
}
else if (num == 2)
{
GpioPin1.Write(GpioPinValue.Low);
GpioPin2.Write(GpioPinValue.Low);
GpioPin3.Write(GpioPinValue.High);
elevator = 2;
}
}
void load(int num)
{
if (num == 1)
{
GpioPin4.Write(GpioPinValue.High);
GpioPin5.Write(GpioPinValue.Low);
s1 = true;
}
else if (num == 2)
{
GpioPin4.Write(GpioPinValue.Low);
GpioPin5.Write(GpioPinValue.High);
s2 = true;
}
}
void unload(int num)
{
if (num == 1)
{
GpioPin4.Write(GpioPinValue.Low);
s1 = false;
}
else if (num == 2)
{
GpioPin5.Write(GpioPinValue.Low);
s2 = false;
}
}
async void reset()
{
if (s1 == true)
{
await Task.Delay(500);
dropoff(1);
await Task.Delay(500);
level(0);
}
else if (s2 == true)
{
await Task.Delay(500);
dropoff(2);
await Task.Delay(500);
level(1);
await Task.Delay(500);
level(0);
}
}
async void blink()
{
await Task.Delay(1000);
while (!(GpioPin6.Read() == GpioPinValue.Low || GpioPin7.Read() == GpioPinValue.Low || GpioPin8.Read() == GpioPinValue.Low))
{
GpioPin1.Write(GpioPinValue.High); // wait for a second
await Task.Delay(200);
GpioPin1.Write(GpioPinValue.Low); // wait for a second
await Task.Delay(200);
}
}
}
}
这里有几项需要实现
- 物联网应用程序有后台应用程序的概念。请参阅此处的文档:http://ms-iot.github.io/content/en-US/win10/BackgroundApplications.htm 注意:它说的是后台应用程序,这可能会造成混淆,因为它不像典型 UWP 中的后台应用程序那样 运行。 IoT 的引导加载程序消除了通常强加给 UWP 后台应用程序的性能和 cpu 优先级瓶颈,因此 运行s 就像前台应用程序一样,只是它是无头的,并且是一个更容易的无头起点。它也更类似于您的 Arduino 代码。
- 你应该使用枚举来管理你的状态,这样它是集中的并且更容易处理。
- 在 windows10 IoT 中,您可以为事件发生时设置事件处理程序并处理它们,而不必循环和观察。这将有助于将事件排队然后进行处理。然而,在某些情况下它可能不会那么快,但在这种情况下应该没问题。如果你需要循环,你可能想分拆一个循环和监视的任务
- 最后,在基于事件的多线程系统中,您需要通过锁定一个对象来保护来自不同线程的同时处理状态更改。
我已经根据您的代码库提供了解决上述所有问题的示例代码。请注意,它尚未完成,但应该作为一个很好的起点。
首先,您需要创建后台应用程序并添加对 IoT 扩展的引用。
代码如下:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Net.Http;
using Windows.ApplicationModel.Background;
using Windows.Devices.Gpio;
using System.Threading.Tasks;
// The Background Application template is documented at http://go.microsoft.com/fwlink/?LinkID=533884&clcid=0x409
// Sensors for shelves. True if shelf is loaded.
namespace BackgroundApplication1
{
public sealed class StartupTask : IBackgroundTask
{
public enum MachineState
{
unknown,
initial,
elevatorLevelOne,
elevatorLevelTwo,
transitionOnetoTwo,
transitionTwotoOne,
transitionOnetoReset,
transitionTwotoReset
}
private MachineState currentState;
private object lObj;
// Elevator Level LEDs (Red)
private const int elevatorResetPin = 13;
private const int elevatorOnePin = 12;
private const int elevatorTwoPin = 11;
//Gpio for each
GpioPin elevOneLed;
GpioPin resetLed;
GpioPin elevTwoLed;
// Shelve State LEDs (Green) (On if loaded, Off if hidden)
private const int ShelveOnePin = 10; // Top Shelve
private const int ShelveTwoPin = 9; // Bottom Shelve
GpioPin shelfOneLed;
GpioPin shelfTwoLed;
// Buttons
private const int ButtonOne = 2; // Request Shelve One
private const int ButtonTwo = 3; // Request Shelve Two
private const int ButtonReset = 4; // Request Reset
// Debouncing
long lastTime1 = 0;
long lastTime2 = 0;
const long interval = 300;
public void Run(IBackgroundTaskInstance taskInstance)
{
this.Initialize();
Task.Run(() =>
{
while (true)
{
//thats right...do nothing.
}
});
}
public void Initialize()
{
GpioController gCon = GpioController.GetDefault();
//Elevator LEDs
elevOneLed = gCon.OpenPin(elevatorResetPin);
resetLed = gCon.OpenPin(elevatorOnePin);
elevTwoLed = gCon.OpenPin(elevatorTwoPin);
elevOneLed.SetDriveMode(GpioPinDriveMode.Output);
elevTwoLed.SetDriveMode(GpioPinDriveMode.Output);
resetLed.SetDriveMode(GpioPinDriveMode.Output);
//Shelf LEDs
shelfOneLed = gCon.OpenPin(ShelveOnePin);
shelfTwoLed = gCon.OpenPin(ShelveTwoPin);
shelfOneLed.SetDriveMode(GpioPinDriveMode.Output);
shelfTwoLed.SetDriveMode(GpioPinDriveMode.Output);
//Buttons
GpioPin buttonOne = gCon.OpenPin(ButtonOne);
GpioPin buttonTwo = gCon.OpenPin(ButtonTwo);
GpioPin buttonReset = gCon.OpenPin(ButtonReset);
buttonOne.SetDriveMode(GpioPinDriveMode.Input);
buttonTwo.SetDriveMode(GpioPinDriveMode.Input);
buttonReset.SetDriveMode(GpioPinDriveMode.Input);
buttonOne.ValueChanged += ButtonOne_ValueChanged;
buttonTwo.ValueChanged += ButtonTwo_ValueChanged;
buttonReset.ValueChanged += ButtonReset_ValueChanged;
this.GetShelfOne();
}
private void GetShelfOne()
{
switch(this.currentState)
{
case MachineState.unknown: this.Reset();
break;
case MachineState.elevatorLevelOne:
break;
case MachineState.elevatorLevelTwo: this.TransitionToShelfTwoFromOne();
break;
case MachineState.transitionOnetoReset: //handle the rest of your stuff similiarly...
break;
}
}
private void TransitionToShelfTwoFromOne()
{
this.shelfOneLed.Write(GpioPinValue.Low);
this.shelfTwoLed.Write(GpioPinValue.High);
this.currentState = MachineState.elevatorLevelTwo;
}
private void Reset()
{
throw new NotImplementedException();
}
private void ButtonReset_ValueChanged(GpioPin sender, GpioPinValueChangedEventArgs args)
{
throw new NotImplementedException();
}
private void ButtonTwo_ValueChanged(GpioPin sender, GpioPinValueChangedEventArgs args)
{
throw new NotImplementedException();
}
private void ButtonOne_ValueChanged(GpioPin sender, GpioPinValueChangedEventArgs args)
{
//rising edge means you pushed the button
if(args.Edge == GpioPinEdge.RisingEdge)
{
lock(lObj)
{
this.GetShelfOne();
}
}
//falling edge means you released the button.
//you could start a timer to see how long you held the button.
}
}
}
有两种方法:
- 方式 1 - 您可以直接在您的 Windows IoT 上使用 Arduino 代码,稍作改动。
- 方式 2 - 通过将 Arduino 代码转换为等效的 C# UWP。
方式 1:直接在您的 Windows IoT
上使用 Arduino 代码- 为 Windows IoT (refer this link) 设置 Arduino 布线
- 将您的 Arduino 代码(上面写的)移植到您的 Windows IoT 上,引脚图为 Raspberry Pi 2。
Important Note: There are some rules to port Arduino written code to Windows IoT which is described at ms-iot website. The Arduino code you have provided can directly be ported on to Raspberry Pi 2 (make sure to change Arduino pin numbers to RPi2 pinmap).
方式 2:将 Arduino 代码转换为 C# UWP
将 Arduino 代码转换为 C# UWP 并不复杂。您只需将 Arduino 函数转换为等效的 C# UWP Windows IoT 函数: