first StackOverflow question so hopefully its a decent one.
I'm in the process of making a sensor network using RPi's and Arduino boards. I have done this in the past using Raspbian but now have to do it using Windows IOT.
The Arduino Uno boards are connected to the Raspberry Pi using I2C communication. The problem is that my C# code produces a "Slave address is not recognized" error.
The RPi is configured as a master and the Arduino as a slave. There is no logic voltage converter, but it should work fine in this configuration as per:
https://create.arduino.cc/projecthub/phantom_override/arduino-i2c-ommunication-with-raspi-2-wiot-63d599?ref=user&ref_id=11763&offset=0
Will use a bidirectional voltage converter when I can get my hands on one.
I have tried the following:
1.) I2C connection between Windows IOT and Arduino Nano using C#
2.) Checking the connections between the RPi and the Arduino (SDA to SDA and SCL to SCL
3.) Adding 3.3V pullup resistors
4) Raspberry pi 2 and BMP280 : Slave address was not acknowledged
5.) Changing the slave address of the Arduino
6.) Swapping the both the Arduino and RPi out in case the pins were blown
7.) Digitally writing the Arduino pins low in case they were interfering with the i2c commmunication
Here is the corresponding Arduino Code:
//**********************Libraries**********************
#include <Wire.h>
//*********************Definitions*********************
#define SERIAL Serial
#define SLAVE_ADDRESS 0x40
//********************Global Variables*******************
float humidity, temperature, temp, motion;
byte ReceivedData[4];
byte Response[4];
bool DataReceived;
//Analoge Pin setup
int clockFrequency = 100000;
//***********************************Setup******************************
void setup(){
//digitalWrite(SCL, 0);
//digitalWrite(SDA, 0);
//i2c communication setup
Wire.begin(SLAVE_ADDRESS);
Wire.onReceive(receiveData);
Wire.onRequest(sendData);
//Wire.setClock(clockFrequency);
//Baud rate
Serial.begin(9600);
dht.begin();
}
//*********************************Loop*********************************
void loop()
{
getSensors();
delay(100);
}
void getSensors()
{
//sensors data retrieved
Response[0]=(byte)humidity;
Response[1]=(byte)temperature;
Response[2]=(byte)proximity;
Response[3]=(byte)motion;
}
void sendData()
{
Wire.beginTransmission(SLAVE_ADDRESS);
//Loop to iterate i2c transmissions
for (int i = 0; i <= 3; i++) {
Wire.write((uint8_t *)Response[i], sizeof(Response));
}
Wire.endTransmission();
}
And here is the corresponding C# methods for the RPi
private async Task InitI2C()
{
var settings = new I2cConnectionSettings(0x40); // Arduino address
settings.BusSpeed = I2cBusSpeed.StandardMode;
string aqs = I2cDevice.GetDeviceSelector("I2C1");
var dis = await DeviceInformation.FindAllAsync(aqs);
_device = await I2cDevice.FromIdAsync(dis[0].Id, settings);
}
private async Task GetArduino()
{
try
{
byte[] ReadBuf = new byte[32];
_device.Read(ReadBuf);
//convert buffer into floats here
}
Any help would be greatly appreciated as WIOT resources are quite scarce compared to other IOT OS's.
#MichaelXu-MSFT and #jdweng Thank you for your help. I worked out the problem. The Arduino code had unnecessary wire.beginTransmission and wire.endTransmission statements, which seem to be for sending data from master to slave on i2c, whereas I had a configuration of the master device requesting data from the slave. Just using the wire.write(data, length) length function in the sendData() ISR did the trick. I highly recommend http://www.gammon.com.au/i2c, as he has excellent i2c resources on his site.
The correction is as follows:
void sendData()
{
//Wire.beginTransmission(SLAVE_ADDRESS); remove this statement
Wire.write(Response, sizeof(Response));
//Wire.endTransmission(); remove this statement as well
}
Related
I am trying to send the bytes (b'\x03\r') to a device on COM5. The result will be the micropython board on the other end crashing. The python code results in the board freezing (As intended). The C# code results in no changes on the device's end, and the serial port not working until it is replugged. How can I get the C# code to do the same thing that the python code does?
This python code works:
import serial # this is installed with 'pip install pyserial'
ser = serial.Serial(
port='COM5',
baudrate=115200,
)
ser.write(b'\x03\r')
I tried to make this C# code to do the same thing but it does not work
using System.IO.Ports;
public static class tester {
public static void main(/* String[] args */) {
SerialPort sport = new SerialPort("COM5", 115200);
sport.Open();
sport.Write(new byte[]{0x03, 0xD}, 0, 2);
sport.Close();
}
}
Thanks for trying to help me :)
The solution as #kunif and #Hans Passant said was that I needed to set certain parameters as their defaults are not the same on different implementations of serial port libraries. To use a serial device that works fine with the default settings of PySerial use the following code. You will likely have to change the baud rate based on your specific device.
SerialPort sport = new SerialPort("COM5", 115200);
// I love StackOverflow
sport.Handshake = Handshake.None;
sport.DtrEnable = true;
sport.RtsEnable = true;
sport.StopBits = StopBits.One;
sport.DataBits = 8;
sport.Parity = Parity.None;
sport.Open();
We are implementing temperature reading using PT100 (3 wires) and Raspberry 4 with .NET 6.
We are able to read the temperature using as reference this article.
SpiConnectionSettings settings = new(0, 0)
{
ClockFrequency = Max31865.SpiClockFrequency,
Mode = Max31865.SpiMode1,
DataFlow = Max31865.SpiDataFlow
};
using (SpiDevice device = SpiDevice.Create(settings))
{
using (Max31865 sensor = new(device, PlatinumResistanceThermometerType.Pt100, ResistanceTemperatureDetectorWires.ThreeWire, ElectricResistance.FromOhms(430)))
{
while (true)
{
Console.WriteLine(sensor.Faults.ToString());
Thread.Sleep(1000);
}
}
}
Actually to work the script need the CS pin of Max31865 connected to pin 12 of raspberry GPIO. We would like to connect more than one Max31865 in order to record some temperatures from different Pt100.
How we can specify the right/specific GPIO port in the C# script for every Max31865 CS output pin? Actually seems there are no properties to change that pin but this feature will permit us to read more than one sensor.
The easiest thing is to do the CS handling manually, as automatic CS handling with multiple devices on the same bus is not fully implemented for the Raspberry Pi.
var controller = new GpioController();
controller.OpenPin(CsPinOfSensor1);
controller.OpenPin(CsPinOfSensor2);
controller.Write(CsPinOfSensor1, PinValue.Low); // CS is low-active!
controller.Write(CsPinOfSensor2, PinValue.High);
using Max31865 sensor1 = new(device, PlatinumResistanceThermometerType.Pt100, ResistanceTemperatureDetectorWires.ThreeWire, ElectricResistance.FromOhms(430));
controller.Write(CsPinOfSensor1, PinValue.High); // CS is low-active!
controller.Write(CsPinOfSensor2, PinValue.Low);
using Max31865 sensor2 = new(device, PlatinumResistanceThermometerType.Pt100, ResistanceTemperatureDetectorWires.ThreeWire, ElectricResistance.FromOhms(430));
{
while (true)
{
controller.Write(CsPinOfSensor1, PinValue.Low); // CS is low-active!
controller.Write(CsPinOfSensor2, PinValue.High);
Console.WriteLine(sensor1.Temperature.ToString());
controller.Write(CsPinOfSensor1, PinValue.High);
controller.Write(CsPinOfSensor2, PinValue.Low);
Console.WriteLine(sensor2.Temperature.ToString());
Thread.Sleep(1000);
}
}
There are multiple pins reserved as CS pins for each SPI bus, but I honestly do not even know how they would need to be selected at the OS level.
Alternatively, you can of course also connect the second sensor to a second SPI bus. The Raspberry Pi4 has a total of 6 SPI channels.
I'm using inTheHand library (32feet.NET).
I have a device with bluetooth enabled and I want to connect with the device to my computer and than send data from the device to computer. I then want to catch that information with my program and process it.
The device will send me 3 variables (all 3 float).
How do I catch that information with bluetooth? I never worked with bluetooth on a computer before.
I tried like this post said:
Pair bluetooth devices to a computer with 32feet .NET Bluetooth library
But don't know what I'm doing, so I can't make it work.
I'm using Visual Studio 2017 and Windows 10. I heard there are problems for Windows 10 and authenticating bluetooth devices.
Thanks for all the help!
UPDATE:
static string domaciaddress = "MY_ADDRESS";
static string tujadress = "DEVICE_ADDRESS";
//reciever
private static BluetoothEndPoint EP = new BluetoothEndPoint(BluetoothAddress.Parse(domaciaddress), BluetoothService.BluetoothBase);
private static BluetoothClient BC = new BluetoothClient(EP);
//sender
private static BluetoothDeviceInfo BTDevice = new BluetoothDeviceInfo(BluetoothAddress.Parse(tujadress));
private static NetworkStream stream = null;
static void neke231(string[] args)
{
string paircode = "paircode";
if (BluetoothSecurity.PairRequest(BTDevice.DeviceAddress, paircode))
{
Console.WriteLine("PairRequest: OK");
if (BTDevice.Authenticated)
{
Console.WriteLine("Authenticated: OK");
BC.SetPin(paircode);
BC.BeginConnect(BTDevice.DeviceAddress, BluetoothService.SerialPort, new AsyncCallback(Connect), BTDevice);
}
else
{
Console.WriteLine("Authenticated: No");
}
}
else
{
Console.WriteLine("PairRequest: No");
}
Console.ReadLine();
}
I now connect to my bluetooth like this. But I still don't know how to get those 3 floats that my device sends, and save it here in float, so I can later in program use them.
EDIT:
This code in fact doesn't work exactly... I don't know why, but it won't connect to android phone. When I run program instead of getting what I write into console, I get only BluetoothGetDeviceInfo returned: 0x80070057
I have made Arduino UNO as a slave and Raspberry Pi 2 as a master. The code running on Arduino UNO is as follows :
#include "DHT.h"
#include<Wire.h>
#define DHTPIN 4 // what digital pin we're connected to
#define DHTTYPE DHT11 // DHT 11
#define SLAVE_ADDRESS 0x29
DHT dht(DHTPIN, DHTTYPE);
int t;
void setup() {
Serial.begin(9600); //setting baud rate for communication
Wire.begin(SLAVE_ADDRESS); //assigning slave with i2c at defined slave address
Wire.onRequest(sendData); //Event for sending the data through i2c
dht.begin();
}
void loop() {
float h = dht.readHumidity();
// Read temperature as Celsius (the default)
t = dht.readTemperature();
// Check if any reads failed and exit early (to try again).
if (isnan(h) || isnan(t) || isnan(f)) {
Serial.println("Failed to read from DHT sensor!");
return;
}
Serial.print("Humidity: ");
Serial.print(h);
Serial.print(" %\t");
Serial.print("Temperature: ");
Serial.print(t);
Serial.print(" *C ");
Serial.print("\n");
Wire.onRequest(sendData); // asked to send the data
delay(1000);
}
void sendData(){
Wire.write(t);
Serial.print("in send data:"+t);
}
The Raspberry Pi 2 code is written in c#. It is as follows :
using System;
using Windows.UI.Xaml.Controls;
using Windows.Devices.Enumeration;
using Windows.Devices.I2c;
using System.Diagnostics;
using System.Threading;
namespace App2
{
public sealed partial class MainPage : Page
{
private I2cDevice Device;
private Timer periodicTimer;
public MainPage()
{
this.InitializeComponent();
initcomunica();
}
private async void initcomunica()
{
var settings = new I2cConnectionSettings(0x29); // Arduino address
Debug.WriteLine(settings);
settings.BusSpeed = I2cBusSpeed.StandardMode;
Debug.WriteLine(settings.BusSpeed);
string aqs = I2cDevice.GetDeviceSelector("I2C1");
Debug.WriteLine(aqs);
var dis = await DeviceInformation.FindAllAsync(aqs);
Debug.WriteLine(dis);
Debug.WriteLine(dis[0].Id);
Device = await I2cDevice.FromIdAsync(dis[0].Id,settings );
periodicTimer = new Timer(this.TimerCallback, null, 0, 1000); // Create a timmer
}
private void TimerCallback(object state)
{
byte[] RegAddrBuf = new byte[] { 0x08 };
byte[] ReadBuf = new byte[5];
try
{
Device.Read(ReadBuf); // read the data
Debug.WriteLine(ReadBuf);
}
catch (Exception f)
{
Debug.WriteLine("error in reading from buffer"+f.Message);
}
// Converte Byte to CharArray
char[] cArray = System.Text.Encoding.UTF8.GetString(ReadBuf, 0,5).ToCharArray();
String c = new String(cArray);
Debug.WriteLine(c);
}
}
}
Connections done between Raspberry Pi 2 and Arduino UNO :
Analog pin of Arduino UNO (A4-SDA) connected to pin 5(SCL) of Raspberry Pi 2
Analog pin of Arduino UNO (A5-SCL) connected to pin 3(SDA) of Raspberry Pi 2
Used a voltage divider circuit with resistances 1K ohm and 2k ohm to give 3.3V to Pi instead of 5V.
DHT11 sensor connections with Arduino UNO.
Problem : I have deployed Universal windows app from Visual Studio on Pi code written in c# but I am getting an Exception in the code. The exception and error is as follows :
Exception thrown:
'System.Runtime.InteropServices.COMException' in mscorlib.ni.dll
WinRT information: Failed to apply connection settings to the device.
Additional information: A device attached to the system is not functioning.
Requirement : I have searched on Internet everything regarding this exception but didn't found any solution and Raspberry Pi 2 is unable to communicate with Arduino UNO.Don't know whether it is problem from Arduino side or Raspberry Pi side.
Please help me solve this problem.
It seems Your lines are wrong.
Usually SCL pin connects to SCL and SDA connects to SDA. It's not reversed like on UART.
I'm attempting to write a C# library which looks at all available USB serial ports on a Raspberry Pi so that I can enumerate, identify and communicate with a set of Arduinos connected to the Pi via a USB hub.
I am able to make this work on my windows machine (several Arduinos connected to my desktop computer) and have even been able to make it work on my Pi however, I am struggling to understand how to generalize the fix.
If I attempt to run the program by itself on the Pi, I am able to open the serial port and send data however, I cannot receive anything from the Arduinos: I get timeout exceptions. I understand that Mono's implementation of SerialPort is limited and I must use SerialPort.ReadByte() instead of Readline() and the data received events (my solution is based on code from HowToSystemIOPorts). My Serial port enumeration is using a method outlined in another stack exchange response here.
My timeout is currently set to 4 seconds, which is several orders of magnitude longer than I expect to receive the message.
After a lot of googling, I came across mention of using minicom to initialize the serial port here, which to my surprise allowed me to receive data from the Arduino. The biggest drawback is that I need to initialize the port using minicom and leave the process opening each time I boot the Pi. I also can't seem to figure out how to make this work with multiple Arduinos.
Here is what I have tried so far:
Updated the Pi firmware and software to their latest versions
Attempted to use both an Arduino MEGA 2560 R3 and Arduino UNO
Changed the owner of the tty* ports (ttyACM0 and ttyUSB0 in this case) to both my user and group
Successfully configured the port via minicom, left the process running and start the program and read/wrote data. A manual process which only seems to work for one Arduino at a time
Successfully run the program in Windows without fault
Verified the Arduinos are recognized by the Pi running "dmesg | grep tty"
Here is what I hope to solve:
Automatic setup/initialization of the Arduino serial ports. Whether through a shell script run before the main program or within Mono code so that the code below can run as intended.
Here is my connection code:
public bool StartArduinoComms()
{
string[] ports = GetPortNames();
foreach (string port in ports)
{
mLogger.LogMessage(ProsthesisCore.Utility.Logger.LoggerChannels.Arduino, string.Format("Found serial port {0}", port));
}
bool foundCorrectArduino = false;
var idPacket = new ArduinoMessageBase();
idPacket.ID = ArduinoMessageValues.kIdentifyValue;
string jsonOutput = Newtonsoft.Json.JsonConvert.SerializeObject(idPacket);
foreach (string port in ports)
{
SerialPort serialPort = new SerialPort(port, kArduinoCommsBaudRate);
serialPort.Parity = Parity.None;
serialPort.DataBits = 8;
serialPort.StopBits = StopBits.One;
//Only check unopened ports
if (!serialPort.IsOpen)
{
serialPort.Open();
//Disable telemtry just incase
var toggle = new { ID = ArduinoMessageValues.kTelemetryEnableValue, EN = false };
string disableTelem = Newtonsoft.Json.JsonConvert.SerializeObject(toggle);
serialPort.Write(disableTelem);
//Discard any built up data
serialPort.DiscardInBuffer();
serialPort.Write(jsonOutput);
serialPort.ReadTimeout = kIDTimeoutMilliseconds;
string response = string.Empty;
for (int i = 0; i < kNumRetries; ++i)
{
try
{
//This is guaranteed to timeout if not configured through minicom
response = ReadLine(serialPort);
break;
}
//Catch case where the serial port is unavailable. MOve to next port
catch (TimeoutException)
{
continue;
}
}
if (!string.IsNullOrEmpty(response))
{
//Perform response validation
}
else
{
//Got no response
}
if (!foundCorrectArduino)
{
serialPort.Close();
}
}
}
return foundCorrectArduino;
}
/// <summary>
/// From https://stackoverflow.com/questions/434494/serial-port-rs232-in-mono-for-multiple-platforms
/// </summary>
/// <returns></returns>
private static string[] GetPortNames()
{
int p = (int)Environment.OSVersion.Platform;
List<string> serial_ports = new List<string>();
// Are we on Unix?
if (p == 4 || p == 128 || p == 6)
{
string[] ttys = System.IO.Directory.GetFiles("/dev/", "tty*");
foreach (string dev in ttys)
{
//Arduino MEGAs show up as ttyACM due to their different USB<->RS232 chips
if (dev.StartsWith("/dev/ttyS") || dev.StartsWith("/dev/ttyUSB") || dev.StartsWith("/dev/ttyACM"))
{
serial_ports.Add(dev);
}
}
}
else
{
serial_ports.AddRange(SerialPort.GetPortNames());
}
return serial_ports.ToArray();
}
Have a look at stty command. It will let you set/read teminal settings
http://linux.about.com/od/lna_guide/a/gdelna38t01.htm will give a rundown on it's use.
It would be easier to call out to than minicom, and the settings stay on the device.
I have done something like the same as you before.
I had to read and write data through USB Serial adapter, and didnt use minicom.
It may not be god code but i found that inorder to read the data I could create a new thread and have that check for data, my code include a lot of stuff but basicly i did this:
System.Threading.Thread newThread;
newThread = new System.Threading.Thread(this.check_get_data);
and the check_get_data method
public void check_get_data ()
{
byte tmpByte = 0;
while (m_objSerialPort.BytesToRead != 0) {
tmpByte = (byte)m_objSerialPort.ReadByte ();
DoSomethingWithByte(tmpByte);
Thread.Sleep(20);
}
}
this is currently running with two usbserials. dont know if it helps but hope you find your solution