I am trying to run a treadmill using the serial port, I was able to do it using matlab however I am having a few probelms when I ported the same code to C#. I am sure that the port is open there is probably something wrong with the message format. Would be great if someone can tell me what mistake I am making.The matlab code (which works) and the C# code (which doesn't work) are given below.
MATLAB CODE :
ctr = char(12); %control character
rel = char(169); %release
set_speed = char(163);
set_dir = char (184);
%initializing the ports
R = serial('COM4');
set(R, 'BaudRate', 4800, 'Parity', 'none', 'DataBits', 8, 'StopBits', 1, 'Terminator', 'CR');
set(R, 'InputBufferSize', 128, 'OutputBufferSize', 128);
fopen(R);
if R.status == 'open'
fprintf(R, [rel ctr]);
disp('port for R belt open and released');
else
disp('error with R port-- COM3');
end;
%initial direction to FORWARD
fprintf(R, [set_dir '0' char(12)]);
%set speed to
fprintf(R, [set_speed '0005' ctr]);
My C# version of the matlab code above
char ctr = (char)12;
char rel = (char)169; //release
char set_speed = (char)163;
char set_dir = (char)184;
void Start () {
try{
SerialPort R = new SerialPort();
R.BaudRate = 4800;
R.Parity = Parity.None;
R.DataBits = 8;
R.StopBits = StopBits.One;
R.ReadBufferSize = 128;
R.WriteBufferSize = 128;
R.Open();
if(R.IsOpen){
//Release
R.Write(rel+""+ctr);
print ("Serial port is open");
}
else print ("Serial port is close");
R.Write(set_dir+""+"0"+""+ctr);
R.Write(set_speed+""+"0005"+""+ctr);
}
catch(UnityException e){
print ("Exception");
print (e);
}
}
I'm not really familiar with C#, but I'll try to guess that you should also send terminator character in your C# code.
Check the fprintf (serial) documentation in MatLab:
fprintf(obj,'cmd') writes the string cmd to the device connected to the serial port object, obj. The default format is %s\n. The write operation is synchronous and blocks the command-line until execution completes.
fprintf(obj,'format','cmd') writes the string using the format specified by format.
In your calls you are using 1st syntax so your call
fprintf(R, [rel ctr]);
is actually
fprintf(R, '%s\n', [rel ctr]);
Usually, serial devices read input data until the terminator character is found. This means that transmission of the command string or data is completed and the device now can execute the command. This is much like hitting ENTER in MatLab command window: command is executed only after you do this.
Which terminator character to use should be specified in your device programming manual.
Seems that CR is OK since your MatLab code works.
In your MatLAb code you set the terminator to be CR character (ASCII code 13). I do not see this in your C# code so your device waits for CR which is not sent so there should be no reaction from your device.
I do not think that C# will send the terminator character for you, you should take care of it by yourself.
My guess is that
R.Write(rel+""+ctr + "\r");
should solve the problem (thanks dodald for reminding me that I missed the proper conclusion).
See also Terminator property of SERIAL object and Rules for Writing the Terminator.
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();
The problem is, that I can trigger scanner using Serial Port software "Hercules" sending command <SYN>T<CR><LF>, in datasheet is said to use command [SYN]T[CR] to trigger scanner, but I cant trigger it (both commands) using my serial port comunication bellow.
I get input when use scanner manually but can't trigger it... What is a problem?
(The port is virtual)
private static SerialPort port;
private static bool _continue = false;
public static void Main(string[] args)
{
port = new SerialPort();
port.PortName = "COM8";
port.BaudRate = 115200;
port.Parity = Parity.None;
port.DataBits = 8;
port.StopBits = StopBits.One;
port.Handshake = Handshake.None;
port.RtsEnable = true;
port.DtrEnable = true;
port.ReadTimeout = 500;
port.WriteTimeout = 500;
port.Open();
_continue = true;
Thread thr = new Thread(SerialPortProgram);
thr.Start();
}
private static void SerialPortProgram()
{
Console.WriteLine("Writing to port: <SYN>T<CR><LF>");
string command = "<SYN>T<CR><LF>";
port.WriteLine(command);
while (_continue)
{
try
{
string input = port.ReadLine();
Console.WriteLine("Input is - " + input);
}
catch (TimeoutException) { }
}
}
Python barcode scanner serial trigger is an article that I answered similar Python question.
The contents are shown below.
This happens because you coded the abstract expression written in the document as raw output data.
The document represents 3 bytes of data transmission.
'SYN' and 'CR' are the following hexadecimal numbers.
'SYN' = \x16
'CR' = \x0d or escape sequence \r
'T' is an ordinary ASCII character.
Whitespace and < > [ ] { } are used to delimit the data in the document, not the data to send.
And, even you need to command prefix it.
Also use Write instead of WriteLine as written by #Turbofant.
You should write like this. Please try it.
string command = "\x16M\x0d\x16T\x0d";
port.Write(command);
I guess the problem is, that you are sending the wrong command string.
The <Syn>, <CR> and <LF> stands for the special, non printable ascii characters synchronous idle, Carriage return and line feed.
You need to encode them correctly in the string
Try sending:
string command = "\x16t\r\n";
port.Write(command);
\x16is <Syn> (Because Syn is ascii character 0x16, or 22 in decimal )
\r is <CR>
\n is <LN>
And use port.Write instead of port.WriteLine, because WriteLine automatically adds the \r\n at the end of the string.
I'm trying to print on Olivetti PR 4 SL. In of out .NET application ("Print Test Page", Word, ...) it works. But in my .NET application, it doesn't.
This is my simplified code:
using (var serialPort = new SerialPort())
{
serialPort.PortName = "COM1"; // Where the printer is installed.
serialPort.Open();
serialPort.Write("Hello world!");
}
The error message is:
The given port name does not start with COM/com or does not resolve to
a valid serial port. Parameter name: portName
Would anyone help me to solve this problem?
You need to finalize the character stream which are sent to the printer by NEW_LINE (ASCII code is 10).
You can use the following line of code in order to print;
serialPort.Write(new byte[] { 10 });
I have a program that reads serial data from an arduino through a com port.
It works successfully when i program it to print the serial data onto a console, and it does so.
For example, the arduino says outputs "21", and the console writes "21".
But if I make an if statement saying If(data == "21"){/*dosomething*/}
it doesnt work even if the data is printed as "21".
Here are the parts of my code related to this issue.
Arduino
if(digitalRead(i) == HIGH && stat[i-2] == false){
Serial.print(i); Serial.println(1);
stat[i-2] = true;
}
The arduino code is kind of difficult to understand without the rest of the code, but all it does is scans all the ports to see if one of them is high. If it is, it prints the port number and a 1 next to it. For example if port 2 is high, it outputs "21". The same happens when port 2 is low, it outputs "20".
C# (an event handler)
private static void DataReceivedHandler(object sender, SerialDataReceivedEventArgs e)
{
SerialPort serialPort1 = sender as SerialPort;
string dataString = (serialPort1).ReadLine();
screen.clearline();
Console.Write(dataString);
if (dataString == "connectAlready")
{
connect.con();
}
if (dataString == "20")
{
Console.WriteLine("pdown");
}
if (dataString == "21")
{
Console.WriteLine("pup");
}
}
This is the event handler called when data is received.
It prints data to the screen such as "21","20", but it does not perform the functions in the If statements.
Any help would be appreciated, thank you very much.
My guess is that the strings you are comparing aren't completely equal. Arduino's documentation for its println() function states that the serial print ends in a carriage return character ('\r'), followed by the newline character ('\n'). The SerialPort.ReadLine() function reads and returns the string "up to the NewLine value in the input buffer" (found here), so the '\r' character is probably still in dataString.
If this is your problem, you can solve it by removing the last character with something like:
dataString = dataString.TrimEnd('\r');
I'm trying to convert TCL code, used to communicate with a serial port to a "robot", to C#. But for some reason my commands are not getting responses.
This is the serial com init in TCL:
proc openUart {} {
set robot::fd_ [open COM${robot::port_num}: w+]
fconfigure $robot::fd_ -mode 9600,e,7,1
fconfigure $robot::fd_ -blocking 0
fconfigure $robot::fd_ -buffering none
fileevent $robot::fd_ readable ""
}
A "command" is sent like this:
proc SendCmd {command} {
set commandlen [string length $command]
for {set i 0} {$i < $commandlen} {incr i} {
set letter [string index $command $i]
after 10
puts -nonewline $robot::fd_ $letter
}
after [expr 2 * 10]
puts -nonewline $robot::fd_ "\n"
flush $robot::fd_
}
This is how I translated this to C#. Opening the port:
private void Initialize(string com)
{
_comPort = new SerialPort(com,9600,Parity.Even,7,StopBits.One)
{
Encoding = Encoding.ASCII,
NewLine = "\n"
};
_comPort.Open();
}
And sending a command:
private string SendCommand(Commands cmd)
{
string commandToWrite = Command(cmd);
for (int i = 0; i < CommandLen; i++)
{
Thread.Sleep(10);
_comPort.Write(commandToWrite.ToCharArray(), i, 1);
}
Thread.Sleep(10 * 2);
_comPort.Write("\n");
_comPort.BaseStream.Flush();
}
I connected my PC to the robot with a serial to USB cable and ran both TCL and C# programs -
The TCL script turns on a LED on the robot.
My C# code doesn't turn the LED on, meaning the robot did not recognize the command.
I'm using the same com port, so I believe the problem is one of these:
I did not initialize the com port correctly in C#. How do you set the blocking and buffering?
Could there be an encoding issue in C#? isn't ASCII the default encoding in TCL?
Could there be a timing difference in how I'm sending the command letter-by-letter between the two languages?
Issue resolved!
I finally looped back the cable into my PC using another serial cable and 2 blue wires, crossing the RX\TX (thanks don_q for the idea!).
Using a simple serial monitor, "UART Terminal", I sniffed the commands, and to my surprise the TCL script was adding a '\r' before the '\n'!
So in fact the robot was expecting this command format -
:010508010000F1\r\n
I changed the NewLine property in C# to be "\r\n", and now I finish a command by using -
_comPort.WriteLine("");
And now everything works.