Write data using I2C windows iot and Arduino - c#

So I have a Arduino and Raspberry pi 3 with windows IoT connected as show in the image below:
[][1
I want to read from, and write to, the Arduino slave using the RPI as master with I2C. I have the following code so far:
C# Master:
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];
byte[] request = new byte[] { 0x40, 0x40 };
try
{
arduio.Read(response); // this funtion will request data from Arduino and read it
arduio.Write(request); // this function will send data to Arduino
}
catch (Exception p)
{
//Windows.UI.Popups.MessageDialog msg = new Windows.UI.Popups.MessageDialog(p.Message);
Debug.WriteLine(p.Message);
//await msg.ShowAsync(); // this will show error message(if Any)
}
text.Text = response[0].ToString();
}
Slave Arduino:
include <Wire.h>
#define SLAVE_ADDRESS 0x40
byte response[1]; // this data is sent to PI
void setup() {
Wire.begin(SLAVE_ADDRESS); // join i2c bus with address slaveAddress
Wire.onReceive(I2CReceived);
Wire.onRequest(I2CRequest);
}
void loop() {
delay(100);
}
// function that executes whenever data is requested by master
// this function is registered as an event, see setup()
void I2CRequest() {
response[0] = (byte)17;
Wire.write(response, 2); // return data to PI
}
// function that executes whenever data is received from master
// this function is registered as an event, see setup()
void I2CReceived(int howMany) {
Serial.println("test");
while (1 < Wire.available()) { // loop through all but the last
char c = Wire.read(); // receive byte as a character
Serial.print(c); // print the character
}
int x = Wire.read(); // receive byte as an integer
Serial.println(x); // print the integer
}
I can successfully read data from the Arduino and print them to the textblock on windows IoT. But I also want to write text to the Arduino. I tried something but it isn't working. Can someone please explain how to write data.
I really need some help and I'm no professional programmer so please keep it as simple as possible. If something is wrong with my current code please comment so I can try to improve my code.

I think the issue is due to the missing of Serial.begin,in fact the data sent from master to slaver has been received,just not printed.Please try again with the following code on slaver.
#include <Wire.h>
#define SLAVE_ADDRESS 0x40
byte response[1]; // this data is sent to PI
static int index = 0;
void setup() {
Serial.begin(9600);
Wire.begin(SLAVE_ADDRESS); // join i2c bus with address slaveAddress
Wire.onReceive(I2CReceived);
Wire.onRequest(I2CRequest);
}
void loop() {
delay(100);
}
// function that executes whenever data is requested by master
// this function is registered as an event, see setup()
void I2CRequest() {
Serial.println("I2C-Request");
response[0] = (byte) index ++ ;
Wire.write(response, 2); // return data to PI
}
// function that executes whenever data is received from master
// this function is registered as an event, see setup()
void I2CReceived(int howMany) {
Serial.println("I2C-Received");
while (1 < Wire.available()) { // loop through all but the last
char c = Wire.read(); // receive byte as a character
Serial.print(c); // print the character
}
int x = Wire.read(); // receive byte as an integer
Serial.println(x); // print the integer
}
I tested with my Arduino UNO,it works.The received data could be shown in serial monitor.

Related

How to send numbers from C# to Arduino Uno with a usb port?

I want to send integer numbers (between 101 and 1616)from the c# program to the arduino Uno using a usb port.
I know how to use registers of the arduino Uno and wanted to know if there is a interrupt when reviving data over this USB port.
At the moment I am using this but it isn't working.
if(Serial.available()!=0)
{
input= (unsigned char)Serial.read();
}
And on the C# program I am using this code:
byte[] b = BitConverter.GetBytes(MyIntx);
SerialPort.Write(b, 0, 4);
How can i send bigger numbers between the c# program and the arduino uno?
And is there a special interrupt for receiving these type of numbers?
What you need to do is send byte by byte. There are complex solutions and there are easy ones
Complex: from https://www.baldengineer.com/arduino-multi-digit-integers.html
void setup() {
Serial.begin(9600);
}
unsigned int integerValue=0; // Max value is 65535
char incomingByte;
void loop() {
if (Serial.available() > 0) { // something came across serial
integerValue = 0; // throw away previous integerValue
while(1) { // force into a loop until 'n' is received
incomingByte = Serial.read();
if (incomingByte == '\n') break; // exit the while(1), we're done receiving
if (incomingByte == -1) continue; // if no characters are in the buffer read() returns -1
integerValue *= 10; // shift left 1 decimal place
// convert ASCII to integer, add, and shift left 1 decimal place
integerValue = ((incomingByte - 48) + integerValue);
}
Serial.println(integerValue); // Do something with the value
}
}
My Version:
Convert Int to Char, Send byte by byte and In Arduino Convert it back to Int.
int x=150;
string x_char = x.ToString();
for(int i=0;i<x_char.length();i++)
{
//Send Each Character to Arduino "c_char[i]".
}
//Send a new line or any special character to mark the break. For Instance "\n";
IN Arduino:
String a;
void setup() {
Serial.begin(9600); // opens serial port, sets data rate to 9600 bps
}
void loop() {
while(Serial.available()) {
a= Serial.readStringUntil('\n'); //Read until new line
x = Serial.parseInt(); //This is your Integer value
}
}
Connect();
if (serialPort1.IsOpen)
{
int MyInt = ToInt32(lblMixerCase.Text);
byte[] b = GetBytes(MyInt);
serialPort1.Write(b, 0, 1);
int MyInt2 = ToInt32(txtRPM.Text);
if (MyInt2<=255)
{
byte[] z = GetBytes(MyInt2);
serialPort1.Write(z, 0, 1); //For first 1 byte numbers
}
else if (MyInt2<=510)
{
byte[] r = GetBytes(MyInt2);
serialPort1.Write(r, 0, 2); for 2 byte numbers
}
else if (MyInt2<=765)
{
byte[] a = GetBytes(MyInt2);
serialPort1.Write(a, 0, 3); //for 3 byte numbers
}
else if (MyInt2<=1020)
{
byte[] q = GetBytes(MyInt2);
serialPort1.Write(q, 0, 4); //for 4 byte numbers
}

SerialPort in c# , Data Receive Incomplete Message

I'm working on Serialport. I'm facing a new problem that once I receive data my data are incomplete. How can I check if my data are complete then process them, and if not, don't process them?
Here are my data receive and my send function:
private void Send(byte[] cmd)
{
bResponse = new byte[0];
Write(cmd);
}
void comPort_DataReceived(object sender, SerialDataReceivedEventArgs e)
{
int iCount = comPort.BytesToRead;
byte[] bBuffer = new byte[iCount];
comPort.Read(bBuffer, 0, iCount)
if (bBuffer.Length == 1 && bBuffer[0] == ACK)
Write(new byte[] { ENQ });
else if (bBuffer.Length == 1 && bBuffer[0] == NAK)
{
Debug.WriteLine("Incomplete Message detected!");
}
else
{
bResponse = bResponse.Concat(bBuffer).ToArray();
rResponse = Decode(bResponse);
Write(new byte[] { ACK });
}
}
I know my data are received in a few packages and I need to wait until the response is complete, but I don't know based on the code above. How should I check whether the data are complete to determine whether to wait? (P.S: The size of the received response varies.)
There is no built-in concept of completeness or packet size.
You'll have to append to a buffer until you see some recognizable end-of-packet pattern that you (or someone else) defined as part of the protocol specification. - And then probably time out after a while if you haven't seen what you are looking for.
Example of old project, notice the firstindex, lastindex, you put in a character to know the length, the start/end character is predefined and can be any character you choose, just be sure not to take any common characters
This is for tcp/ip, but same principle can be used for serialport
public void ReceiveMessage(IAsyncResult ar)
{
int bytesRead;
try
{
lock (client1.GetStream())
{
bytesRead = client1.GetStream().EndRead(ar);
}
string messageReceived = System.Text.Encoding.ASCII.GetString(data, 0, bytesRead);
received = messageReceived;
int firstindex = received.IndexOf((char)2);
int lastindex = received.IndexOf((char)3);
if (firstindex > 0 && lastindex > 0)
{
string first = received.Substring(firstindex, 1);
string last = received.Substring(lastindex, 1);
}
lock (client1.GetStream())
{
client1.GetStream().BeginRead(data, 0, System.Convert.ToInt32(client1.ReceiveBufferSize), ReceiveMessage, null);
}
}
catch (Exception ex)
{
MessageBox.Show(ex.ToString());
}
}
I have some code for you.
First, you implement the DataReceived Event (as you have done already). This event is only called when there is data to process. While I would not call it interrupt-based (as in "realtime capable") is is definitely not polling. Which is good.
Second: When the event is called you may have only one byte, but there may be more bytes. To capture each packet you need to implement an custom buffer.
Third: After you append one byte to your buffer, you check whether the buffer contains a valid packet. If so, process it. If not: Append another one. If no bytes are left, wait for the event to be called again.
In code it looks like this:
const BUFFERLENGTH = 17; // Bytes
byte[] buffer = new byte[BUFFERLENGTH];
private void COM_Port_DataReceived(object sender, SerialDataReceivedEventArgs e)
{
var port = (SerialPort)sender;
while (port.BytesToRead > 0)
{
var data = (byte)port.ReadByte();
Read(data);
}
}
private void Read(byte value)
{
// Append Byte to buffer
System.Buffer.BlockCopy(buffer, 1, buffer, 0, BUFFERLENGTH- 1);
buffer[BUFFERLENGTH - 1] = value;
// Check for valid Packet
if (IsValidPacket(buffer))
{
// Yeah! Gotcha :-)
// Now copy your Packet from the Buffer to your struct/whatever
}
}
private bool IsValidPacket(byte[] buffer)
{
// Todo: Check whether buffer contains a valid Packet.
// Some think like:
// return buffer != null && buffer[0] == 0xF4 && buffer[2] == buffer.length
throw new NotImplementedException();
}
Note that I did not "append the byte to the buffer". I discarded the first byte, shifted every byte by one position and inserted the new byte at the end. If a valid Packet was found I could just copy it in one block into a struct. So the buffer size is always constant and exactly as long as one packet.
This may not be the fastest code out there (because it's reading each byte separately) but it works well for me :-)
Oh, and remember to use Begininvoke() if you want to display that stuff in your GUI.

Serial port data receive handling

I have a form in which I am able to receive data and show it in a richtextbox, but what I need is to read the data that is coming continuously from serial port and decode accordingly.
For ex: I am receiving data in bytes in the format as 36 0 0 0 1 0 0...., 36 is used to indicate start of frame n rest are the data through which an event will be fired.
My code:
private void serialPort1_DataReceived(object sender, System.IO.Ports.SerialDataReceivedEventArgs e)
{
// get number off bytes in buffer
Bytenumber = serialPort1.BytesToRead;
// read one byte from buffer
ByteToRead = serialPort1.ReadByte();
this.Invoke(new EventHandler(DoUpdate));
}
Above code is used to receive data and fire an event. The code for the event is as follows:
int w=0;
public void DoUpdate(object sender, System.EventArgs e)
{
byte[] t = new byte[Bytenumber];
for(int g=0; g<Bytenumber;g++)
{
t[g] = Convert.ToByte(ByteToRead);
}
w++;
// richTextBox1.Text += ByteToRead;
if (ByteToRead == 36)
{
for (int r = 0; r <= 73; r++)
{
if (ByteToRead == 0x01)
{
timer1.Start();
w++;
}
}
}
}
In the data received event handler I am looking for 36 (i.e., start of frame) once I get that I am looking for 1s from the buffer. The problem is when I get 36 (i.e., start of frame) the same data is retained in the if loop and tries to compare with 1 which will not be true # any case. All I need is to read the next bytes of data coming from the buffer once I get 36.
I can spot a few problems. A little code-review:
Bytenumber = serialPort1.BytesToRead;
ByteNumber is the Bytes-to-Read at this moment. It is not thread-safe to keep this in a member field.
ByteToRead = serialPort1.ReadByte();
This only reads 1 Byte. And then, on another thread:
byte[] t = new byte[Bytenumber]; // ByteNumber may have changed already
for(int g=0; g<Bytenumber;g++)
{
t[g] = Convert.ToByte(ByteToRead); // store the _same_ byte in all elements
}
What you should do (not complete code):
private void serialPort1_DataReceived(object sender, System.IO.Ports.SerialDataReceivedEventArgs e)
{
// get number off bytes in buffer
int n = serialPort1.BytesToRead;
byte[] buffer = new byte[n];
// read one byte from buffer
int bytesToProcess = serialPort1.Read(buffer, 0, n);
this.Invoke(UpdateMethod, buffer, bytesToProcess);
}
But do search the internet for working code. I just made this up.

How to send and recieve over rs-485 serial port?

I want to communicate between my PC and some controller boards.
The expectation is that the PC will send an identifier of the board on RS-485 and then it should receive the answer from the board.
When I try to receive the response, I receive the wrong data.
Here is my code:
public void set()
{
SerialPort sp = new SerialPort("COM1");
sp.Open();
if (sp.IsOpen)
{
byte[] id = new byte[]{0,0,0,0,0,0,0,0,0,0};
byte[] rec = new byte[540];
while (!end)
{
sp.Write(id,0,id.Length);
sp.Read(rec,0,rec.Length);
//do some with rec
//WORKING
//do soem with rec
}
}
sp.Close();
}
It works if I am using RS-232, but not when I am using RS-485.
UPDATE :
It is RS-485 2 wire.(http://en.wikipedia.org/wiki/RS-485)
I found the problem.
sp.Read(rec,0,rec.Length);
Read is a non-blocking method so it reads the buffer but does not wait for all of the bytes. So you need to use the return value of this function which returns an integer with a number of bytes that it could read.
I am using this:
int read = 0;
int shouldRead = readData1.Length;
int len;
while (read < shouldRead )
{
len = serialport.Read(buffer, 0, readData1.Length);
if (len == 0)
continue;
Array.Copy(buffer, 0, readData1, read, len);
read += len;
Thread.Sleep(20);
}

Sockets in C++ and C# under Windows not working properly

I'm using UDP sockets to communicate a C++ application with a C# application.
In the C# -> C++ direction everything seems to be working fine, but the other way around is the one that's driving me nuts.
Communication does work, but messages are getting way late (like 2 secs delay) in the C# app, even though they're being sent every frame (it's a 3D app), and the receiving code is executing every 10 ms.
I need real time so this is a very painful problem. Do you think this might be related to packet losses? Then why don't they get lost in the other direction?
EDIT:
C# app code for syncing data:
public void RecibeDatos()
{
if (MessageReceived && U != null && S != null)
{
MessageReceived = false;
//Console.WriteLine("listening for messages");
U.BeginReceive(ReceiveCallback, S);
}
}
public void ReceiveCallback(IAsyncResult ar)
{
UdpClient u = ((UdpState)(ar.AsyncState)).U;
IPEndPoint e = ((UdpState)(ar.AsyncState)).E;
receivedBytes = u.EndReceive(ar, ref e);
//int currentProtocol = (int) numero;
//ResetSignal = reset > 0;
//Console.WriteLine("Received: " + currentProtocol);
MessageReceived = true;
}
C++ Code for sending data:
float indiceFloat[1];
indiceFloat[0] = indice_protocolo_actual;
sender->setBuffer((void *)indiceFloat, sizeof(indiceFloat));
sender->sync();
sync method on J_Enviar (sender) class:
void J_Enviar::sync( void )
{
if(!_initialized) init();
if( _buffer == 0L )
{
fprintf( stderr, "Broadcaster::sync() - No buffer\n" );
return;
}
#if defined (WIN32) && !defined(__CYGWIN__)
unsigned int size = sizeof( SOCKADDR_IN );
sendto( _so, (const char *)_buffer, _buffer_size, 0, (struct sockaddr *)&saddr, size );
int err = WSAGetLastError ();
if (err!=0)
fprintf( stderr, "Broadcaster::sync() - error %d\n",err );
#else
unsigned int size = sizeof( struct sockaddr_in );
sendto( _so, (const void *)_buffer, _buffer_size, 0, (struct sockaddr *)&saddr, size );
#endif
}
Providing full SocketManager code for Receiving C# end:
using System;
using System.Net;
using System.Net.Sockets;
namespace WpfApplication1
{
public class SocketManager
{
private static SocketManager _instance = null;
static readonly object Padlock = new object();
private IPEndPoint E;
private UdpClient U;
private UdpState S;
private byte[] receivedBytes;
public static bool MessageReceived = true;
private SocketManager()
{
}
public byte[] ReceivedBytes
{
get { return receivedBytes; }
}
public static SocketManager Instance
{
get
{
lock(Padlock)
{
return _instance ?? (_instance = new SocketManager());
}
}
}
public void CreateReceivingSocket(IPAddress a, int puerto)
{
if(E==null || (E.Address != a && E.Port != puerto))
{
E = new IPEndPoint(a, puerto);
U = new UdpClient(puerto);
S = new UdpState { E = E, U = U };
}
}
public void ReceiveCallback(IAsyncResult ar)
{
UdpClient u = ((UdpState)(ar.AsyncState)).U;
IPEndPoint e = ((UdpState)(ar.AsyncState)).E;
receivedBytes = u.EndReceive(ar, ref e);
//int currentProtocol = (int) numero;
//ResetSignal = reset > 0;
//Console.WriteLine("Received: " + currentProtocol);
MessageReceived = true;
}
public void RecibeDatos()
{
if (MessageReceived && U != null && S != null)
{
MessageReceived = false;
//Console.WriteLine("listening for messages");
U.BeginReceive(ReceiveCallback, S);
}
}
public void CloseConnection()
{
if (E != null)
{
E.Port = 5502;
E = null;
}
if (U != null)
U.Close();
}
}
public class UdpState
{
public IPEndPoint E;
public UdpClient U;
}
}
And this is my dispatchertimerclick which makes the program receive each 10 ms:
_dispatcherTimer.Tick += DispatcherTimerTick;
_dispatcherTimer.Interval = new TimeSpan(0, 0, 0, 0, 1);
_dispatcherTimer.Start();
private void DispatcherTimerTick(object sender, EventArgs e)
{
_exp1Class.sendData();
_sm.RecibeDatos();
byte[] recibidos = _sm.ReceivedBytes;
if (recibidos != null)
{
float numero = BitConverter.ToSingle(recibidos, 0);
_exp1Class.CurrentProtocol = (int) numero;
}
}
I don't see when you kick off your first BeginReceive. (Ah, it is done from your first timer tick I think?) It should be initaited as soon as you are ready to receive data. Secondly, your ReceiveCallback should take the received data and place it into a queue of some sort and immediately call BeginReceive again. Otherwise you are holding up thge arrival of the next data frame until the prior was consumed. Finally, watch for threading issues, as the Threading timer and the UDP callback each will run on seperate threads from your application main thread.
The only reason your code works at all is because you pre-initialized MessageReceived = true even before you receive any callbacks. When the first tick happens the call to RecibeDatos invokes BeginReceive because that bool was set to true.
Think of BeginReceive as saying "call me back when you have some data from the network". You don't need to poll the network using your timer. (You can choose to consume that data via your timer if your application requires that, but lets leave that aside for the moment).
Here are the rough steps:
First, upon start (or enable, run, etc) you should call BeginReceive. You will now receive a notification when data arrives.
Secondly, when the callback happens you complete that read of the data bytes using EndReceive. That data would typically be buffered or otherwise dispatched. You should then call BeginReceive again (within the callback) so that upon the next set of data being available you will again get notified. It becomes a kind of async loop.
The question is what to do with the data you are reading. You might consider placing the data into a queue, and then having your Timer pop these data frames off of the queue for processing. Be aware that the data can arrive multiple times between your Ticks.

Categories

Resources