C# HMI comm with micro

Status
Not open for further replies.

boroko

Active member
Hi all,
Trying to build an interface with some buttons to communicate with a micro. No joy. Win10, VS17, Arduino 1.8.5. Eventually going to be run on a Win7 tablet. I can successfully sent commands in the Serial Monitor, but C# will not open the comm port (COM5 in this case) and do the same. If I leave the Serial monitor open in Arduino, the C# complains, so I know it is trying, but I can't see why it isn't completing the link.

The scheme is one connected to the tablet talking to 20 or so coming in and out of range using RFM69's. All the functions work if I'm using "command line" in the Serial monitor, but I'm trying to automate it and make it a bit more operator proof.

I realize this is not specifically a Teensy question, but I wonder if anyone has run into a similar issue.

Sure would be nice to build a front end to manage these.

Code:
public partial class Form1 : Form    {
        SerialPort port;        public Form1()
        {
            InitializeComponent();            
           this.FormClosed += new FormClosedEventHandler(Form1_FormClosed);           
           if (port == null)
            {
                //Change the portname according to your computer
                port = new SerialPort("COM5", 9600);
                port.Open();
            }
        }void Form1_FormClosed(object sender, FormClosedEventArgs e)        {
            if (port != null && port.IsOpen)
            {
                port.Close();
            }
        }private void button1_Click(object sender, EventArgs e)        {
            
                PortWrite("1");
            
        }        
        private void button2_Click(object sender, EventArgs e)
        {
           
                PortWrite("0");
            
        }private void PortWrite(string message)        {
            if (port != null && port.IsOpen)
            {
                port.Write(message);
            }
        }
    }

Thanks
bo
 
Would be nice for you to post your arduino sketch so we could see where the actual problem is located, the above code wouldn't really help us see the problem.
 
Sorry, the Arduino code works, and is very basic so I can test, so I didn't think to post it.
Code:
const int LedPin = 13;
int ledState = 0;


void setup() {
  pinMode(LedPin, OUTPUT);
  Serial.begin(9600);

}

void loop() {
  char receiveVal;
  if (Serial.available() > 0)
  {
    receiveVal = Serial.read();
    if (receiveVal == '1')
      ledState = 1;

    else
      ledState = 0;
  }
  digitalWrite(LedPin, ledState);
  delay(50);

}
bo
 
did you try putting a slight delay in startup?

Code:
void setup() {
  pinMode(LedPin, OUTPUT);
  Serial.begin(9600);
  delay(1000);

}

I say this because just the serial monitor will work doesnt mean an external app would without the slight delay
 
Last edited:
No success. Tried giving it delay(2000) and still nothing. Also tried RealTerm and it worked sending an ASCII 1 and 0. Still a serial terminal, but an independent one to see if there was a difference.

bo
 
Not sure what the expected versus observed behavior is? There is a line end character from SerMon after the sent char. With SerMon the code above would see '1' and enable LED for one 50 ms delay in that case, then go off when the next char was not '1'.

Perhaps code explicit '1' and '0' for on and off and not have the default any other char turn the LED off. To see the line end and other chars as received - do an else { Serial.print( receiveVal ); Serial.print( (int) receiveVal ); } to see the other chars being passed.
 
defragster, thanks for replying.

I think I understand you to say that an EOL or CR being sent could be tripping it up as a "non 1". I'm not seeing that using SerMon or RealTerm, they both persistently change the LED. Changed it anyway to just to remove that ambiguity.
Code:
if (Serial.available() >0)
{
receiveVal = Serial.read();
if (receiveVal =='1');
ledState = 1;
if (receiveVal =='0');
ledState = 0;
}
digitalWrite(LedPin, ledState);
delay(50);
}

What seems to be missing is for the C# code to connect to the serial port (through USB on COM5) and send similar commands.

I'm trying to take a crash course in C# to see if there are any requirements that I'm unaware of in using the System.IO.Ports class to just act like a SerMon port.
I have long wanted to make a front end to control micros, but since the demise of VB6, I have struggled and gave up each time. Somehow, I need to get this skill set. It's like the giant missing piece. Of course, every example in the world is internal or network oriented. Seems like no one wants to control something physical. What fun is that?
bo
 
Have you tried setting the start and stop bits and parity?

Below is some of my code I once wrote:

Code:
m_SerialPort = new SerialPort(strSerialPort, BAUD_RATE, Parity.Even, 8, StopBits.One);
 
bigpilot: From my understanding, the comm port defaults to that, but Ill look and make sure.

defragster: I will look at that link and hopefully learn something.

I have managed to find a VB10 program that acts as a terminal program and does turn on and off my LED. I'm going to dissect it and see what I can learn. Just to be clear, I'm not really concerned on which framework I have to work in, I'm inexperienced in anything recent anyway, I just want to be able to create some buttons on a PC that drive my arduino board and give me some basic response.

breaks over, back on your heads...

bo
 
If any has familiarity with this process, I would appreciate you taking a quick look. I'm trying the simplest form of this and not understanding what I'm missing. The example of this is on https://www.hackster.io/haoming-weng/c-arduino-gui-to-control-the-led-0877f8.
The Arduino code is:
Code:
const int LedPin = 13; // the built in led
int ledState = 0;

void setup()
{ 
  pinMode(LedPin, OUTPUT);
  
  Serial.begin(9600);  
}
void loop()
{ 
    char receiveVal;   
   
    if(Serial.available() > 0)
    {        
        receiveVal = Serial.read();
        
       if(receiveVal == '1')    
          ledState = 1;   
       else
          ledState = 0;     
    }   
      
    digitalWrite(LedPin, ledState); 
      
    delay(50);    
}

The Visual Studio code is using C# and follows:
Code:
using System;
using System.IO.Ports;
using System.Windows.Forms;

namespace HacksterArdComm
{
   
public partial class Form1 : Form
    {
        SerialPort port; public Form1()
        {
            InitializeComponent(); this.FormClosed += new FormClosedEventHandler(Form1_FormClosed); if (port == null)
            {
                //Change the portname according to your computer
                port = new SerialPort("COM5", 9600);
                port.Open();
            }
        }
        void Form1_FormClosed(object sender, FormClosedEventArgs e)
        {
            if (port != null && port.IsOpen)
            {
                port.Close();
            }
        }
        private void button1_Click(object sender, EventArgs e)
        {
            PortWrite("1");
        }
        private void button2_Click(object sender, EventArgs e)
        {
            PortWrite("0");
        }
        private void PortWrite(string message)
        {
            if (port != null && port.IsOpen)
            {
                port.Write(message);
            }
        }
    }
}

The Arduino code works through a terminal program, but will not connect with the C# code. If I can understand how this is functioning, I can build from there.

I have to be missing something fundamental, and I have not tracked it down.

Sorry to keep dwelling here, but I have to find a way to communicate with them and, so far each example seems to hit a wall and this is the simplest that I have found. One issue is that almost every C# tutorial does not deal with sending something out the serial port. I'm thinking that there is something fundamental about C# or .net that I don't understand.

Thanks
bo
 
When I was connecting OTG to my phone the terminal program I found to work had a setting for asserting DTR (IIRC …. it's been some time and others didn't have that and failed to work) - perhaps that is needed in the C# code in some fashion
 
I'll look into DTR.
Is there any way to snoop the serial port and see whats going on there? Really don't feel like learning Wireshark or Lorris Toolbox (or something similar), and I'm not even sure if they could do what I need.
This is turning into a strange roadblock for me. I didn't suspect that I'd have so much of a challenge in this part.

Thanks for the ideas, back to monkey poking...
bo
 
I guess I'm a little puzzled.... do DTR and RTS apply when you're doing serial over a USB port? I can see hardware serial, but I never thought they were used when making a serial-over-usb connection.

I'm knee deep in another portion of the system and haven't looked at it yet.
 
Actually, reading from and writing to the com port is quite simple in c#. Here a working minimal example

Teensy Firmware:
Code:
#include "Arduino.h"  

uint8_t count = 0;

void setup()
{
    Serial.begin(0);
}

void loop()
{
    Serial.print(count++);
    delay(100);                
}

And here the minimal c# code to read and display the received bytes (console application):
Code:
using System;
using System.IO.Ports;

namespace SerialTest
{
    class Program
    {
        static void Main(string[] args)
        {
            Console.WriteLine("Serial Test");

            var port = new SerialPort("COM3", 9600);
            port.Open();

            while (!Console.KeyAvailable)
            {
                while (port.BytesToRead > 0)
                {
                    Console.WriteLine(port.ReadByte());
                }
            }
        }
    }
}

Of course you need to adapt the COM Port to the one you are using. You can choose any baud rate you want, transfer will always happen with the full USB bandwidth. In a real program you would safeguard the code for not available ports of course.

I recommend to start with something simple like that and switch to a GUI later.
 
OK, thank you, finally some sign of progress.

I do get the console to start scrolling the numbers 48 through 57 and they aren't always sequential, so I'm a bit confused about that. I would have suspected that they would start near 0 and just continue to increment until you stopped or it went out of range. Maybe you can explain that artifact to me.
Bottom line is that it looks like its opening the port and actually communicating. Bravo, I will build on that.

bo
 
Sorry for the confusion, didn't test the code careful enough. The Teensy code from above converts the byte value of "count" to a cstring before it sends it out. But the c# code reads it as bytes. The numbers 48 through 57 which you saw are just the ascii values of those numbers.

=> Please change Serial.print() to Serial.write() to write binary values instead of strings to the port.
Code:
#include "Arduino.h"  

uint8_t count = 0;

void setup()
{
    Serial.begin(0);
}

void loop()
{
    Serial.write(count++);
    delay(100);
}
 
I know nothing of these Microsoft APIs, but I can at least answer this question.

I guess I'm a little puzzled.... do DTR and RTS apply when you're doing serial over a USB port? I can see hardware serial, but I never thought they were used when making a serial-over-usb connection.

DTR and RTS are virtual settings by USB serial protocol (which is technically called Communication Device Class, Abstract Control Model). They aren't actually used by USB, but they are communicated to the device side as info you can read. So is the baud rate.

The idea is you could program Teensy (or any other hardware) to use CDC ACM protocol to act as a USB-serial converter. While CDC ACM always runs at the full USB speed, whatever baud rate you set on the PC side is communicated as a virtual setting to Teensy. If you're implementing an actual USB-serial converter, Teensy can read whatever baud rate the PC wants and configure the actual hardware serial side to the PC's intended speed. Teensyduino comes with an example that does exactly this. You can open in from Arduino with File > Examples > Teensy > USB_Serial > USBtoSerial. If you look at that example code, you'll see it reads the baud rate setting the PC wants to uses it to configure the actual serial port setting. The USB communication never uses the baud rate, but you can so the final result to the PC user is as if a real serial port is connected to the PC.

DTR and RTS are similar, not actually used by CDC ACM, but communicated as virtual signals. Teensyduino provides functions you can use read the state of these, in case you want to find out what the PC is sending. If you wanted to make Teensy respond to the DTR signal, you certainly could. In fact, there's a small check of sample code in the documentation. Or if you want to use a pin to send the DTR signal to a real serial devices, you can. But rarely is this done. Most applications just ignore DTR & RTS, the same as most real serial devices. However, if you really wanted to make something respond like an 1980s-era serial interfaced modem where it shuts off when the PC lowers DTR, you can do so.

USB has built-in flow control. It's always present and can not be turned off, because it's fundamental to how USB works. RTS/CTS flow control is not needed on USB side, because superior flow control is already built into the USB protocol.

For your application, where you're communicating with code running on the Teensy, you can just ignore these virtual serial settings. They're never actually used by the USB communication. They exist only so you write code in the Teensy side which sees the settings the PC used, which is typically only needed when making a USB-serial converter where you need the hardware serial port on Teensy to have the settings the PC intended.
 
Thanks Paul,
That was my general understanding, although you detailed it much better than I could have. For a while I chased down the CDC ACM path and didn't find my answer. At least I can start picking apart why the example luni gave works, and none of the other examples I found did even though they claimed to. I undoubtedly need to study C# and Visual Studio more and hope to get where I need to be.

bo
 
Status
Not open for further replies.
Back
Top