I'd like to know if there is a way to get the Baud Rate when it's connected on the RS232 port
BEFORE you initialize the SerialPort class and set it's values. Let me try to explain the reason for that...
Today, I'm working with two different RFID Reader devices, each one works on a different BaudRate, so if I set a wrong baudrate when I create the SerialPort class, it will read the card id all wrong, instead get the real card's id, it will get something like ????|W2???.
Also, there's a possibilite that the device have a USB port.
That's why I'd like to know the device's baud rate before I instantiate the SerialPort class.
I tried for my serial usb devices. Keep changing the baud rate and check. ComboBox contains series of possible baudrates.
public void initConfig(SerialPort serialPort)
{
// you can assign these values in a combo box
string[] ports= "{COM1", "COM2", "COM3", "COM4", "COM5", "COM6", "COM7", "COM8"};
//you can assign these values in a combo box in a string format
int[] baudRate = { 4800, 9600, 19200, 38400, 57600, 115200, 230400 };
serialPort.PortName = ports[0]; //else get from combobox : portCombobox.SelectedItem
serialPort.BaudRate = baudRate[0];
//serialPort.BaudRate = Int32.Parse(speedComboBox.SelectedItem.ToString());
//you can have controls to store and change these values if required
serialPort.Handshake = System.IO.Ports.Handshake.None;
serialPort.Parity = System.IO.Ports.Parity.None;
serialPort.DataBits = 8;
serialPort.StopBits = System.IO.Ports.StopBits.One;
serialPort.ReadTimeout = 200;
serialPort.WriteTimeout = 50;
}
change the strings into respective types and call open.
finally:
public void callingMethod() //or your connect event attached control
{
SerialPort serialPort = new SerialPort();
initConfig(serialPort);
try
{
serialPort.Open();
}
catch
{
MessageBox.Show("Error: Unable to Open the serial interface !");
return;
}
}
Depending upon the details of what you connect to etc. You can loop through a list of baud rates, attempt to connect and then perform an echo test. If you connect at the wrong rate, your echo will be returned as garbage instead of the string you sent. This methodology is working for me.
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();
I am new to C# and programming in general.
I am trying to communicate with a ohmmeter which is conneted via usb to my computer.
I am able to configurate the device and even recieve data.
But i can not acces this data. I can just print it on to the console.
(Was inspired by the code on the microsoft site)
Here is the constructer of my "communication"-class where i configurate the port:
public SCPI_Commands()
{
_SerialPort.PortName = SetPortName(_SerialPort.PortName);
_SerialPort.BaudRate = 115200;
_SerialPort.Parity = Parity.None;
_SerialPort.DataBits = 8;
_SerialPort.StopBits = StopBits.One;
_SerialPort.Handshake = Handshake.None;
_SerialPort.ReadTimeout = 500;
_SerialPort.WriteTimeout = 500;
_SerialPort.Open();
_SerialPort.DataReceived += _serialPort_DataReceived;
}
Here is my function which sends a query to the device (The constant Measurment_Value represents a scpi command which is understood by my ohmmeter) :
public void get_measurement()
{
_SerialPort.WriteLine(Measurment_Value);
}
And here is the private function which checks if the device is sending data and printing it on the console (not sure how this function works) :
private void _serialPort_DataReceived(object sender, SerialDataReceivedEventArgs e)
{
Console.WriteLine(_SerialPort.ReadLine());
}
Unfortunately i am not able to return the data as a string. My goal is to do some calculations with the received data.
Does someone has any ideas ?
Greetings from Germany.
Luke
You can read from buffer to temp byte array and then get it as string, see the below example. Put this in _serialPort_DataReceived
// this the read buffer
byte[] buff = new byte[9600];
int readByteCount = _serialPort.BaseStream.Read(buff, 0, _serialPort.BytesToRead);
// you can specify other encodings, or use default
string response = System.Text.Encoding.UTF8.GetString(buff);
Side Note
If you want to keep your sanity while working with SerialPort, always send and receive as byte array. Then, get the equivalent string using Encoding.
I create small test app to test connection between app and some device which measure temperature. When I write some command to device it's ok, but when device return me response, a string, for that I use ReadExisting() method. But app reads just first character of the string. If I send command again, it's same situation. I try to test connection with program called Terminal.exe, it's happens the same. But when I change BaudRate at some value and return BaudRate on 9600 ( it's ok rate ), then it's worked fine. Also I try to change BaudRate in my app, but it give me the same, just first character of string. Also I have an app written in LabView which works fine.
Also I tested my app with another PC with Terminal.exe , and it's worked fine.
private void SetUpPort()
{
port = new SerialPort();
port.PortName = port_name;
port.BaudRate = 9600;
port.Parity = Parity.None;
port.DataBits = 8;
port.StopBits = StopBits.One;
port.Handshake = Handshake.None;
port.ReadTimeout = 1000;
p.DataReceived += new SerialDataReceivedEventHandler(PortDataReceived);
}
private void PortDataReceived(object sender, SerialDataReceivedEventArgs e)
{
recived_data += port.ReadExisting();
}
I would be very thankful for any help.
That is not how to use the SerialPort component. You need to attach the DataReceived event handler, which is called every time data comes in on the serial port. An example is found on the page I linked.
You need to append data until you know you're done! You can't just call ReadExisting and assume you get all the information. Do something like this:
private string inBuffer = String.Empty;
private static void DataReceivedHandler(object sender, SerialDataReceivedEventArgs e)
{
SerialPort sp = (SerialPort)sender;
string indata = sp.ReadExisting();
inBuffer += indata;
if (<inBuffer fulfills some criteria that tells you it's a complete message>)
{
ProcessInBuffer(inBuffer);
inBuffer = String.Empty;
}
}
It is your task to determine the criteria to fulfill. This may be that the received data as a certain length (if the records are fixed length), or maybe they end with newline characters or something else.
you will use datareceived event to store all the data in a array or string and after you can use every data of that string indata += sp.ReadExisting();
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
When opening a serial port, the device I am trying to access may not have a baudrate of 9600 set so I will have to go thru each baudrate until the device opens correctly.
What error, ArgumentOutOfRangeException or an IOException or some other, should I look for after performing the Port.Open ? Or do I perform this check using the PortOpen statement ?
Sorry to have to ask all of these simple questions, but I am unsure how else to get the information ?
Is there any way that I can tell how to use the PortOpen procedures correctly, including the error handling too, so that I dont have to keep asking everyone ?
Thanks, George.
IOException
InvalidOperationException
is what You should receive in case of errors.
Here You have great example in C#:
http://msdn.microsoft.com/en-us/library/system.io.ports.serialport.open.aspx
You could find all exceptions explanation down there.
For more general advice, have a look at the System.IO.Ports namespace which has a more complete example. Personally I'd adapt what they have there to set your general port settings and then try a few different baud rates in debug mode (some bad, one known good). You'll very quickly see what a bad configuration gives vs a good one. I'm assuming you have access to test the device here?
It's worth noting that you won't see any problems with the call to open the port (just opening it will only test that you've set some parameters which the port supports). You'll start to see issues when you try and read/write to the device and it's there that you'll want to do the error checking for a valid baud rate.
[EDIT] Try something along these lines (NOTE: I've not tested this with any hardware but it at least compiles):
using System;
using System.Collections.Generic;
using System.Collections;
using System.Linq;
using System.Text;
using System.Threading;
using System.IO.Ports;
namespace SerialPortExperiments
{
class Program
{
public static void Main()
{
// Create a new SerialPort object with default settings.
SerialPort _serialPort = new SerialPort();
// Set some generic settings
SetBasicSettings(ref _serialPort);
// Try and find something valid
int baudRate = FindValidBaud(ref _serialPort);
if (baudRate > 0)
{
Console.WriteLine(String.Format("Found baudrate: {0}", baudRate));
}
else
{
Console.WriteLine("ERROR: Failed to identify baudrate");
}
}
public static void SetBasicSettings(ref SerialPort port)
{
port.PortName = "COM1";
port.Parity = Parity.None;
port.DataBits = 8;
port.StopBits = 0;
port.Handshake = Handshake.None;
port.ReadTimeout = 500;
port.WriteTimeout = 500;
}
public static int FindValidBaud(ref SerialPort port)
{
bool buadrateIdentified = false;
// Pick some baudrates to try
List<int> baudrates = new List<int>();
baudrates.Add(9600);
baudrates.Add(19200);
// Try and open the port at each baud rate in turn, trying one write/read to verify success
for (int i = 0; i < baudrates.Count; i++)
{
// Pick a baud rate
port.BaudRate = baudrates[i];
// Try opening a connection and exchanging some data
port.Open();
buadrateIdentified = AttemptValidExchange(ref port);
port.Close();
if (buadrateIdentified)
{
return port.BaudRate;
}
}
return -1;
}
public static bool AttemptValidExchange(ref SerialPort port)
{
try
{
// Send a test command
port.Write("SOME_TEST_COMMAND");
// Check to see what the device responded with
const int expectedReturnLength = 1024;
byte[] buffer = new byte[expectedReturnLength];
port.Read(buffer, 0, expectedReturnLength);
if (buffer.ToString().Equals("EXPECTED_RETURN_VALUE"))
{
return true;
}
}
catch (TimeoutException) // NOTE: You'll probably need to catch other exceptions like parity errors here
{
}
return false;
}
}
}