【问题标题】:Using Windows Form as a serial communicator to Arduino Uno使用 Windows 窗体作为 Arduino Uno 的串行通信器
【发布时间】:2018-09-04 21:47:31
【问题描述】:

我是 Arduino 和串行通信的新手,我有一段时间没有编码了,但我正在尝试做我认为应该相当简单的事情,并且遇到了很多麻烦。我想做的是在 Windows 窗体上创建一个简单的 GUI 并控制一个 Arduino。每次新会话时,我似乎都会遇到不同的问题。

我一直在尝试做的是创建一个简单的 GUI,可以打开和关闭 LED,然后使用 NumericUpDown 来切换它的闪烁。以前,我可以让 numericUpDown 切换值,但没有任何反应,现在如果我尝试切换,它会告诉我端口已关闭。我一直在尝试不同的端口通信方法。由于表单说我的端口已关闭,因此我无法测试我所写的内容是否有效。请忽略注释代码,因为我还在尝试不同的东西。

当我尝试调用 blink 函数时,与我将它保持在循环中相比,它在 if 语句中没有正确闪烁。我不确定如何以及在何处将值从 Winform 发送到 Arduino。

Winform 与使用串行监视器命令有很大不同吗?

EDIT1:我离开了我的计算机,现在当我运行 Windows 窗体时,它没有显示任何错误,但程序已退出,代码为 0 (0x0)。我有计时器,还没有真正搞砸它,但它没有早点告诉我这个错误,并且运行表单很好。

我的 Arduino 代码:

// Define Function Prototypes that use User Types below here or use a .h file

    int dorun;
    int Blinks;

    void setup() {
// initialize digital pin LED_BUILTIN as an output.
pinMode(LED_BUILTIN, OUTPUT);
Serial.begin(9600);
getBlinks();
    }

    // the loop function runs over and over again forever
    void loop()
    {


if (Serial.available() > 0)
    /*
{
    byte Blinktimes = Serial.readBytes[];

}
*/
{
    String serialInput = Serial.readString();
    //Toggle LED
    if (serialInput == "On")    
        {
            digitalWrite(LED_BUILTIN, !digitalRead(LED_BUILTIN)); //I have this just to see that the LED is staying on and off, and will need to change things.
             for (int x = 1; x = Blinks; x++)
                {
                        blink();
                }
        }
    else
        {
            digitalWrite(LED_BUILTIN, LOW);   // turn the LED on (LOW is the voltage level)

        }
    Serial.flush();                         //Clear Serial
}
/*
digitalWrite(LED_BUILTIN, HIGH);
if ((Serial.available()))
{
    int dorun = Serial.read();
    if (dorun = 1)
    {
        blink();
    }
    else
    {
        digitalWrite(LED_BUILTIN, LOW);
    }
}
*/



/*turnon();
if (dorun == 1)
{
    blink();
}
else
{
    digitalWrite(LED_BUILTIN, LOW);
}
*/

    }
    void getBlinks()
    {
        byte message[3];
        if (Serial.available())        
        {
            Serial.readBytes(message, 3);
            Blinks = message[3];
        }
    }

    void blink()
    {
        digitalWrite(LED_BUILTIN, HIGH);   // turn the LED on (HIGH is the 
        voltage level)
        delay(250);                       // wait for a second
        digitalWrite(LED_BUILTIN, LOW);  //!digitalRead(LED_BUILTIN);    // turn the LED off by making the voltage LOW
        delay(1000);
    }

    void turnon()
    {
        if (Serial.available()> 0)
        {
            String run = Serial.readString();
            if (run == "Run")
            {
                dorun == 1;
            }
            if (run == "Off")
            {
                dorun == 0;
            }
        }
    }                

我的 Windows 窗体代码

using System;
    using System.Collections.Generic;
    using System.ComponentModel;
    using System.Data;
    using System.Drawing;
    using System.Linq;
    using System.Text;
    using System.Threading.Tasks;
    using System.Windows.Forms;
    using System.IO.Ports;


    namespace WindowsFormsApp9
    {

        public partial class Form1 : Form
        {
            SerialPort serial;          // create serial port
                                        /*
    * public class Port
    {
    public string Name { get; set; }
    public int Value { get; set; }
    public Port(string n, int i)
    {
        Name = n;
        Value = i;
    }
    }
                                    */
            SerialPort port;
            string[] availablePorts = SerialPort.GetPortNames();
            public Form1()
            {
                InitializeComponent();
            }
        private void button1_Click(object sender, EventArgs e)
            {
        port = new SerialPort("COM3", 9600, Parity.None, 8, StopBits.One);
        port.Open();
        port.Write("On");
        port.Close();

    }
private void button2_Click(object sender, EventArgs e)
    {
        port = new SerialPort("COM3", 9600, Parity.None, 8, StopBits.One);
        port.Open();
        port.Write("Off");
        port.Close();

    }
private void numericUpDown1_ValueChanged(object sender, EventArgs e)
    {
        UpdateBlink();
    }
void UpdateBlink()
    {
        port = new SerialPort("COM3", 9600, Parity.None, 8, StopBits.One);
        port.Open();
        const byte messageType = 2;
        byte Blinkcount = (byte)numericUpDown1.Value;
        byte[] serialBlink = { messageType, Blinkcount };
        serialPort1.Write(serialBlink, 0, serialBlink.Length);
        port.Close();

    }





    private void timer1_Tick(object sender, EventArgs e)
    {

    }

    private void Form1_Load(object sender, EventArgs e)
    {

    }

    private void serialPort1_DataReceived(object sender, System.IO.Ports.SerialDataReceivedEventArgs e)
    {

    }

我一直在查看这些链接:

点击here我如何切换LED

点击here如何返回int,因为NumericUpDown返回小数 点击[这里] (https://www.instructables.com/id/Arduino-Visual-Studio-Serial-Communication/) Arduino Visual Studio 串口通讯定时器的东西 点击[这里] (https://www.instructables.com/id/Communication-From-a-WinForms-to-a-TinyDuino/) Winforms to TinyDuino的说明,他们应该使用与Arduino类似的命令吧?


所以我决定做一个小修。我没有尝试处理发送多种不同类型的输入(String 和 int),而是决定将所有内容更改为字节数组,然后一次性发送。

关于 1. 我真的只是想知道是否可以创建一个函数来返回一个值,而不仅仅是在 void 函数中构建代码。所以我尝试了它并且它起作用了,因此发生了变化。据我了解并看到您的受保护覆盖​​ bool ProcessCmdKey,基本上您想查看该键是否是箭头键。如果是返回真。所以我所做的基本上是如果它是选定的颜色之一,返回一个与颜色对应的值。

  1. 我只是希望您能帮助我了解串行和 COM 端口连接,或者如果您有更多解释的链接。早些时候,当我尝试发送一个字符串(开/关)然后发送一个数字(字节/整数)来设置闪烁次数时,我无法确定 COM 端口是否有点像单个通道。如果我从 Windows 窗体发送一个字符串,我可以在同一个通道中发送一个 int/byte 吗?现在一切都是一个关键字(字节),我可以创建一个字节数组并找出 Windows 窗体和 Arduino 之间的通信。我对底层的 Serial 方面有点困惑。当我看到你的代码时,我开始有一些不同的想法。

在你的代码中,如果我理解正确的话,似乎 MyVCOM 是如何来回通信的,就像 port.Write 一样。我相信它是单一的,因为它基本上就像旧的电话线,如果我正在通话,你打电话给我,你的电话被阻止,因为我的线路已经被使用。 因此,在您的 ConnReset 中,您要确保 COM 未打开,以便您可以设置通信。因此,如果它已经打开,您的 ConReset 将清除该行。我感到困惑的是其他部分。如果你的端口没有打开,打开COM+PortNumber,所以基本上打开通道可以通信,但是你声明的端口号是8,所以你不应该只使用:

MyVCOM.PortName = "COM8";

用户在哪里选择哪个 COM?所有的通信都是在 COM8 上完成的,不是吗?或者那部分是内置库的所有部分吗?我相信我现在需要做的就是将我的字节数组发送到我的 Arduino,然后在后端工作以获取 Windows 窗体正在发送的数据。

        public int Colorselection(string label3, int color)     //Toggle a pin 
    {
        if (label3 == "Red")
        {
            color = 6;
        }
        else if (label3 == "Green")
        {
            color = 5;
        }
        else if (label3 == "Blue")
        {
            color = 3;
        }
        return color;
    }
    private void comboBox1_SelectedIndexChanged(object sender, EventArgs e)
    {
        String label4 = LEDColor.SelectedItem.ToString();               //Generate A string of selected Color
        int xled = Colorselection(label4, color);                       //Toggle the string into an int
        LEDLabel.Text = xled.ToString();                                //Generate a string from the int
    }

    private void Run_Click(object sender, EventArgs e)                  //Generate byte to send instead of sending strings and int/byte
    {
        byte RGBLED = Convert.ToByte(color);
        byte BlinkNum = Convert.ToByte(number1.Value);
        byte BlinkDur = Convert.ToByte(number2.Value);
        byte[] array2 = new byte[] { RGBLED, BlinkNum, BlinkDur };
        port = new SerialPort("COM3", 9600, Parity.None, 8, StopBits.One);
        /*
        port.Open();
        port.Write(array2, 0, 2);
        port.Close();
        */
    }

【问题讨论】:

    标签: c# winforms arduino serial-communication


    【解决方案1】:

    您的 WinForms 应用程序假定您的 Arduino 已连接到 COM3。您是否知道实际情况是否如此,或者您刚刚复制并粘贴的示例代码? (检查 COM 端口下的 Windows 设备管理器以查看哪些端口可用,然后拔下/插入您的设备以查看它被映射到哪个端口)

    除此之外,您是否尝试过在目标上调试您的 Arduino 代码以查看实际接收到的内容(如果有的话)?

    从 MS 文档中,不清楚 SerialPort.Write 命令在同步方面是如何工作的,因此在发送命令后立即关闭端口可能不是一个好主意。不幸的是,由于我没有 Arduino,我无法测试您的代码。但我确实创建了一个 WinForms GUI 来完成几年前我发布到 github (https://github.com/mbhul/RoboCOM) 的基本相同任务(以及您可能不需要的更多任务)。让我知道这是否有帮助,否则请告诉我们更多关于您的开发环境的信息。

    【讨论】:

    • 是的,它是 COM3,我已经能够向 Arduino 发送字符串。我只是不知道如何将一个 int 从 Form 发送到 Arduino。我曾经编译过它并且没有任何反应,关于关闭它,这是我看到的一个视频正在做类似的事情。我担心的一件事是,如果使用 serialWrite 输出多个框,那么某些数据可能会被覆盖,因此我说有一次它编译并运行但什么也没发生?我会看你的代码,谢谢。是的,有些文档非常详细,但我不清楚。
    • 好的,您可以发送字符串“On”和“Off”(即您的 Arduino 可以接收这些值),但是您想发送 numericUpDown1.Value 的值吗?是这样吗?如果是这种情况,您的第一个问题就是这一行:“Blinks = message[3];”不确定 Arduino 运行时如何准确工作,但您正试图访问数组边界之外的元素(您将“消息”声明为大小为 3 的数组,但数组是零索引的,因此“消息 [3]”正在尝试获取未定义的第 4 个元素)。这可能就是您看到故障行为的原因...
    • 酷我会调查的。谢谢你的建议。那部分只是我看看一个人做了什么,看看这是否对我有用。感谢您将我链接到您使用的代码。我有一些问题希望你能帮助我理解。
    • 1.如果在 ProcessCmdKey 中按下箭头键,我可以创建一个 int 函数并让它返回 numericUpDown1.Value 类似于您返回 true 时所做的操作吗? 2.在Connreset中,能否详细说明关闭端口?您是否使用了多个控制器,这就是您需要更改 COM 的原因,还是您将不同的 COMS 用于其他目的?
    • 1.不知道你为什么要这样做。 ProcessCmdKey 是我专门重写的标准 WinForms 方法,因为我有一个案例,我将键盘用作输入控制器,并且不希望默认处理程序在这种情况下继续切换哪个控件具有焦点。您拥有的 numericUpDown1_ValueChanged 事件处理程序非常好。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-06-27
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-01-01
    • 1970-01-01
    相关资源
    最近更新 更多