I have been trying to setup a I2C communication using Wire.h library between an Arduino Uno (Slave) and Raspberry Pi (Master), running Windows IoT, in order to read the values of two push buttons connected to the Arduino.
The issue is that on the Pi I receive wrong values. In the Arduino's serial monitor values of buttonStatePin2
and buttonStatePin4
can be constantly 0
but on a timer tick the pi, see code of MainPage, will receive wrong values, meaning that it will receive 1
even though I never physically press the push button.
The behavior doesn't seem to have any pattern. Sometimes the Pi won't receive 1
as value, sometimes it continuously does, usually from pin 4
/ button4
which seems strange.
I used Arduino IDE 1.06 as suggested here to upload the sketch but no success. Instead of Timer
I have used DispatcherTimer resulting in the same behavior. I was suspecting also that the delay inbetween the void loop()
on the Arduino and the timer have to be somehow "synced", so I try and error added higher/lower delay or timerTick interval on either side but issue remained the same.
This is the Arduino sketch.
#include <Wire.h>
#define SLAVE_ADDRESS 0x40
const int pinButton2 = 2;
const int pinButton4 = 4;
byte Response[2];
byte receivedByte;
void setup() {
pinMode(pinButton2, INPUT);
pinMode(pinButton4, INPUT);
Serial.begin(9600);
Wire.begin(SLAVE_ADDRESS);
Wire.onRequest(sendData);
Wire.onReceive(receiveData);
}
void loop() {
int buttonStatePin2 = digitalRead(pinButton2);
int buttonStatePin4 = digitalRead(pinButton4);
Serial.println("Button 2: ");
Serial.println(buttonStatePin2);
Serial.println("Button 4: ");
Serial.println(buttonStatePin4);
if (buttonStatePin2 == HIGH) {
Response[0] = (byte)1;
}
if (buttonStatePin4 == HIGH)
{
Response[1] = (byte)1;
}
// delay(500);
Wire.onRequest(sendData);
}
void sendData()
{
Wire.write(Response, 2);
}
void receiveData(int huh)
{
receivedByte = Wire.read();
Serial.println(receivedByte);
if (receivedByte == 1)
{
sendData();
}
}
On the Raspberry Pi the I2cHelper handles connection/reading etc.
class I2cHelper
{
private static string AQS;
private static DeviceInformationCollection DIS;
private I2cDevice i2cDev;
private int button2 = 0, button4 = 0;
const byte SLAVE_ADDRESS = 0x40;
//button event handlers
public event EventHandler Button2Pressed;
public event EventHandler Button4Pressed;
public int Button2
{
get { return button2; }
set
{
this.button2 = value;
OnButton2Pressed(value);
}
}
public int Button4
{
get { return button4; }
set
{
this.button4 = value;
OnButton4Pressed(value);
}
}
public I2cHelper()
{
}
private void OnButton2Pressed(int value)
{
if (value == 1)
{
Button2Pressed.Invoke(this, new EventArgs());
}
}
private void OnButton4Pressed(int value)
{
if (value == 1)
{
Button4Pressed.Invoke(this, new EventArgs());
}
}
public async void Setup()
{
var Settings = new I2cConnectionSettings(SLAVE_ADDRESS);
Settings.BusSpeed = I2cBusSpeed.StandardMode;
if (AQS == null || DIS == null)
{
AQS = I2cDevice.GetDeviceSelector("I2C1");
DIS = await DeviceInformation.FindAllAsync(AQS);
}
i2cDev = await I2cDevice.FromIdAsync(DIS[0].Id, Settings);
}
public async Task<byte[]> AsyncGetResponse()
{
byte[] response = new byte[2];
i2cDev.Read(response);
return response;
}
}
In the MainPage I am using the helper class as follows:
Library.I2cHelper i2cDev;
Library.Connection connection;
private DispatcherTimer timer;
//private Timer periodicTimer;
private int tickCount;
public MainPage()
{
timer = new DispatcherTimer();
timer.Tick += Timer_Tick;
timer.Interval = new TimeSpan(0, 0, 0, 0, 100);
connection = new Library.Connection();
connection.ReceivedDataHandler += Connection_ReceivedDataHandler;
Task t = Task.Run(() =>
{
i2cDev = new Library.I2cHelper();
i2cDev.Setup();
i2cDev.Button2Pressed += I2cDev_Button2Pressed;
i2cDev.Button4Pressed += I2cDev_Button4Pressed;
});
t.Wait();
//periodicTimer = new Timer(this.timerCallback, null, 0, 100);
timer.Start();
this.InitializeComponent();
}
private void timerCallback(object state)
{
readButtons();
}
private async void I2cDev_Button4Pressed(object sender, EventArgs e)
{
listBoxClients.Items.Add("Button 4: " + i2cDev.Button4.ToString());
i2cDev.Button4 = 0;
}
private async void I2cDev_Button2Pressed(object sender, EventArgs e)
{
listBoxClients.Items.Add("Button 2: " + i2cDev.Button2.ToString());
i2cDev.Button2 = 0;
}
private void Timer_Tick(object sender, object e)
{
readButtons();
}
private void readButtons()
{
try
{
var response = i2cDev.AsyncGetResponse().Result;
i2cDev.Button2 = response[0];
i2cDev.Button4 = response[1];
}
catch (NullReferenceException exc)
{
Debug.WriteLine("Read failed with error: " + exc.Message);
}
catch (AggregateException exc)
{
Debug.WriteLine("Read failed with error: " + exc.Message);
}
}