如何在 UWP 项目中通过 Raspberry Pi 物联网通过 I2C 连接到 Arduino 打开和关闭 LED?

How to turn on and off LEDs by Raspberry Pi IoT connected to Arduino with I2C on an UWP project?

我有一个 Arduino Uno 和一个带有 Windows IoT Core 的 Raspberry Pi 3。我尝试使用 this method 将一些信息传递给我的 Arduino,比如告诉它启动一个 pin 或获取并解析一个字符串。此方法非常适合从 Arduino 获取信息(如传感器参数)。

我能够向 Arduino 发送一个字节,并根据发送的字节在我的 Arduino 代码中执行操作(如获取数字 2 时的 init 引脚 7)。但它只能工作一次。我必须重置 Arduino,以便它再次接受来自 Raspberry Pi 的字节(我可以打开从我的 Raspberry Pi 连接到 Arduino 的 LED,但无法关闭它。反之亦然。

我的目标是在 Raspberry Pi 中创建一个网站来控制事物。但首先我使用的是 UWP。我正在尝试将数据从 Raspberry Pi 3 上的 IoT Core 运行 传递到 Arduino Uno(不是相反)或通过 I2C 连接管理和控制 Arduino Uno 引脚。

我的MainPage.xaml:

using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Runtime.InteropServices.WindowsRuntime;
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;
using Windows.Devices.I2c;
using System.Threading.Tasks;
// The Blank Page item template is documented at http://go.microsoft.com/fwlink/?LinkId=402352&clcid=0x409

namespace I2CComm {
    /// <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 I2cDevice arduio; // Used to Connect to Arduino
        private DispatcherTimer timer = new DispatcherTimer();
        public MainPage() {
            this.InitializeComponent();
            Initialiasecom();
        }
        public async void Initialiasecom() {
            var settings = new I2cConnectionSettings(0x40);
            // Slave Address of Arduino Uno
            settings.BusSpeed = I2cBusSpeed.FastMode;
            // this bus has 400Khz speed
            string aqs =  I2cDevice.GetDeviceSelector("I2C1");
            // This will return Advanced Query String which is used to select i2c device
            var dis = await Windows.Devices.Enumeration.DeviceInformation.FindAllAsync(aqs);
            arduio = await I2cDevice.FromIdAsync(dis[0].Id, settings);
            timer.Tick += Timer_Tick;
            // We will create an event handler
            timer.Interval = new TimeSpan(0,0,0,0,500);
            // Timer_Tick is executed every 500 milli second
            timer.Start();
        }

        private async void Timer_Tick(object sender, object e) {
            byte[] response = new byte[2];
            try {
                arduio.Read(response);
                // this function will read data from Arduino
            }
            catch (Exception p) {
                Windows.UI.Popups.MessageDialog msg = new Windows.UI.Popups.MessageDialog(p.Message);
                await msg.ShowAsync();
                // this will show error message(if any)
            }
        }

        private void TurnOn_Click(object sender, RoutedEventArgs e) {
            try {
                byte[] sendpos;
                sendpos = BitConverter.GetBytes(2);
                arduio.Write(sendpos);
            }
            catch (Exception p) {
                Windows.UI.Popups.MessageDialog msg = new Windows.UI.Popups.MessageDialog(p.Message);
            }
        }

        private void TurnOff_Click(object sender, RoutedEventArgs e) {
            try {
                byte[] sendpos;
                sendpos = BitConverter.GetBytes(1);
                arduio.Write(sendpos);
            }
            catch (Exception p) {
                Windows.UI.Popups.MessageDialog msg = new Windows.UI.Popups.MessageDialog(p.Message);
            }
        }
    }
}

我的 Arduino 代码是:

#include <Wire.h>
// Library that contains functions to have I2C Communication
#define SLAVE_ADDRESS 0x40
// Define the I2C address to Communicate to Uno

byte response[2]; // this data is sent to PI
volatile short LDR_value; // Global Declaration
const int LDR_pin=A0; //pin to which LDR is connected A0 is analog A0 pin
const int ledPin = 7;

void setup() {
  Serial.begin(9600);
  pinMode(ledPin, OUTPUT);
  Wire.begin(SLAVE_ADDRESS);
  // this will begin I2C Connection with 0x40 address
  Wire.onRequest(sendData);
  // sendData is a function called when Pi requests data
  Wire.onReceive(I2CReceived);
  pinMode(LDR_pin,INPUT);
  digitalWrite(ledPin, HIGH);
}

void loop() {
  delay(500);
}

void I2CReceived(int NumberOfBytes) {
  /* WinIoT have sent data byte; read it */
  byte ReceivedData = Wire.read();
  Serial.println(ReceivedData);
  if (ReceivedData == 2) {
    digitalWrite(ledPin, HIGH);
    return;
  } else if (ReceivedData == 1) {
    digitalWrite(ledPin, LOW);
    return;
  }
}

void sendData() {
  LDR_value=analogRead(LDR_pin);
  // Arduino returns 10-bit data but we need to convert it to 8 bits
  LDR_value=map(LDR_value,0,1023,0,255);
  response[0]=(byte)LDR_value;
  Wire.write(response,2); // return data to PI
}

Raspberry Pi 发送 4 个字节(2 是 Int)而不是 1 个字节。您需要接收 Arduino 中的所有字节。你可以这样做:

void I2CReceived(int NumberOfBytes) {
  /* WinIoT have sent data byte; read it */
  byte ReceivedData = Wire.read();
  Serial.println(ReceivedData);

  while (0 < Wire.available()) {
    byte UselessData = Wire.read();
    Serial.println(UselessData);
  }

  if (ReceivedData == 2) {
    digitalWrite(ledPin, HIGH);
    return;
  } else if (ReceivedData == 1) {
    digitalWrite(ledPin, LOW);
    return;
  }  
}