XYZ_XYZ 发表于 2024-1-28 14:36:19

用C语言写一个串口收发的上位机

用C语言写一个串口收发的上位机。执行文件是.exe文件@FishC

FishC 发表于 2024-1-28 14:37:31

首先,你需要选择一个可用的串口库来完成串口收发功能。在C语言中,常用的串口库有Windows API、libserialport等。在这里,我使用Windows API来演示。

下面是一个简单的例子,展示如何通过串口与设备进行收发数据。

#include <stdio.h>
#include <windows.h>

int main()
{
    HANDLE hSerial;
    DCB dcbSerialParams = { 0 };
    COMMTIMEOUTS timeouts = { 0 };
    char port[] = "\\\\.\\COM1"; // 根据实际的串口号修改

    // 打开串口
    hSerial = CreateFile(port, GENERIC_READ | GENERIC_WRITE, 0, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
    if (hSerial == INVALID_HANDLE_VALUE) {
      printf("无法打开串口\n");
      return 1;
    }

    // 配置串口参数
    dcbSerialParams.DCBlength = sizeof(dcbSerialParams);
    if (!GetCommState(hSerial, &dcbSerialParams)) {
      printf("无法获取串口参数\n");
      CloseHandle(hSerial);
      return 1;
    }
    dcbSerialParams.BaudRate = CBR_9600; // 波特率设置为9600bps
    dcbSerialParams.ByteSize = 8; // 数据位设置为8位
    dcbSerialParams.StopBits = ONESTOPBIT; // 停止位设置为1位停止位
    dcbSerialParams.Parity = NOPARITY; // 校验位设置为无校验
    if (!SetCommState(hSerial, &dcbSerialParams)){
      printf("无法设置串口参数\n");
      CloseHandle(hSerial);
      return 1;
    }

    // 设置串口读写超时时间
    timeouts.ReadIntervalTimeout = 50;
    timeouts.ReadTotalTimeoutConstant = 50;
    timeouts.ReadTotalTimeoutMultiplier = 10;
    timeouts.WriteTotalTimeoutConstant = 50;
    timeouts.WriteTotalTimeoutMultiplier = 10;
    if (!SetCommTimeouts(hSerial, &timeouts)) {
      printf("无法设置串口超时时间\n");
      CloseHandle(hSerial);
      return 1;
    }

    // 向串口发送数据
    char sendData[] = "Hello, Serial!";
    DWORD bytesWritten = 0;
    if (!WriteFile(hSerial, sendData, sizeof(sendData), &bytesWritten, NULL)) {
      printf("无法向串口发送数据\n");
      CloseHandle(hSerial);
      return 1;
    }
    printf("已发送数据:%s\n", sendData);

    // 从串口接收数据
    char recvData = { 0 };
    DWORD bytesRead = 0;
    if (!ReadFile(hSerial, recvData, sizeof(recvData), &bytesRead, NULL)) {
      printf("无法从串口接收数据\n");
      CloseHandle(hSerial);
      return 1;
    }
    printf("已接收数据:%s\n", recvData);

    // 关闭串口
    CloseHandle(hSerial);

    return 0;
}

请注意,上述代码使用了Windows API中的串口相关函数。在运行之前,你需要根据实际的串口号修改`port[]`的值,并确保你的计算机上具有相应的串口设备。

这只是一个简单的示例,用于演示如何使用C语言进行串口收发的上位机控制。你可以根据自己的需求进行进一步的开发和扩展。希望对你有所帮助!

以上回复来自 FishC AI 小助理,如未能正确解答您的问题,请继续追问。

XYZ_XYZ 发表于 2024-1-28 14:46:00

FishC 发表于 2024-1-28 14:37
首先,你需要选择一个可用的串口库来完成串口收发功能。在C语言中,常用的串口库有Windows API、libserialp ...

请先设计出一个上位机窗口

FishC 发表于 2024-1-28 14:47:18

XYZ_XYZ 发表于 2024-01-28 14:46
请先设计出一个上位机窗口

好的!首先,我们需要选择一个图形用户界面(GUI)库来创建上位机窗口。在C语言中,常用的GUI库有GTK、Qt等。在这里,我使用Qt来演示。下面是一个简单的例子,展示如何使用Qt创建一个上位机窗口。#include <QApplication>#include <QWidget>#include <QVBoxLayout>#include <QLabel>#include <QPushButton>#include <QSerialPort>#include <QSerialPortInfo>class UpperComputer : public QWidget{    Q_OBJECTpublic:    explicit UpperComputer(QWidget *parent = nullptr) : QWidget(parent){      // 创建串口选择标签和下拉框      QLabel* labelSerialPort = new QLabel("选择串口:", this);      comboSerialPort = new QComboBox(this);      // 获取可用的串口列表      QList<QSerialPortInfo> serialPortList = QSerialPortInfo::availablePorts();      for(const auto& portInfo : serialPortList){            comboSerialPort->addItem(portInfo.portName());      }      // 创建发送按钮      QPushButton* sendButton = new QPushButton("发送", this);      connect(sendButton, &QPushButton::clicked, this, &UpperComputer::sendDataToSerialPort);      // 创建布局      QVBoxLayout* layout = new QVBoxLayout;      layout->addWidget(labelSerialPort);      layout->addWidget(comboSerialPort);      layout->addWidget(sendButton);      setLayout(layout);    }private slots:    void sendDataToSerialPort(){      // 获取选择的串口号      QString portName = comboSerialPort->currentText();      // 打开串口      QSerialPort serialPort(portName);      if(!serialPort.open(QIODevice::ReadWrite)){            qDebug() << "无法打开串口";            return;      }      // 向串口发送数据      QByteArray data = "Hello, Serial!";      serialPort.write(data);      qDebug() << "已发送数据:" << data;      // 关闭串口      serialPort.close();    }private:    QComboBox* comboSerialPort;};int main(int argc, char *argv[]){    QApplication app(argc, argv);    UpperComputer upperComputer;    upperComputer.show();    return app.exec();}#include "main.moc"首先,你需要安装Qt并配置好环境。然后使用Qt Creator创建一个新的Qt Widgets项目,将上述代码复制到项目中,并编译运行。这段代码创建了一个简单的上位机窗口,其中包含一个标签用于选择串口,一个下拉框显示可用的串口列表,以及一个发送按钮。当点击发送按钮时,会向选择的串口发送数据(在代码中是"Hello, Serial!")。请注意,你可能需要根据你的环境进行必要的配置和修改。希望对你有帮助!

以上回复来自 FishC AI 小助理,如未能正确解答您的问题,请继续追问。

XYZ_XYZ 发表于 2024-3-4 21:35:27

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.IO.Ports;
using System.Windows.Forms;

namespace 串口数据显示
{
    public partial class Form1 : Form
    {
      private SerialPort serialPort = null;// 初始化为null,以便我们可以检查它是否已被实例化


      public Form1()
      {
            InitializeComponent();
            this.comboBox1.DropDown += new System.EventHandler(this.comboBox1_DropDown);
            this.button1.Click += new System.EventHandler(this.button1_Click);
            this.button2.Click += new System.EventHandler(this.button2_Click);
      }

      private void comboBox1_DropDown(object sender, EventArgs e)
      {
            string[] ports = SerialPort.GetPortNames();
            comboBox1.Items.Clear();
            foreach (string port in ports)
            {
                comboBox1.Items.Add(port);
            }

            if (comboBox1.Items.Count > 0)
            {
                comboBox1.SelectedIndex = 0;
            }
      }

      private void button1_Click(object sender, EventArgs e)
      {
            try
            {
                if (serialPort == null)
                {
                  serialPort = new SerialPort(); // 创建SerialPort对象实例
                }

                if (!serialPort.IsOpen && comboBox1.SelectedItem != null)
                {
                  serialPort.PortName = comboBox1.SelectedItem.ToString();
                  serialPort.BaudRate = 9600;
                  serialPort.Parity = Parity.None;
                  serialPort.StopBits = StopBits.One;
                  serialPort.DataBits = 8;
                  serialPort.Handshake = Handshake.None;

                  serialPort.Open(); // 现在打开串口
                  MessageBox.Show("串口已打开");
                }
                else
                {
                  MessageBox.Show("请选择一个串口或串口已经打开");
                }
            }
            catch (Exception ex)
            {
                MessageBox.Show("打开串口时出错: " + ex.Message);
                if (serialPort != null)
                {
                  serialPort.Close(); // 尝试关闭串口,以便下次可以尝试重新打开
                }
            }
      }

      private void button2_Click(object sender, EventArgs e)
      {
            if (serialPort != null && serialPort.IsOpen)
            {
                serialPort.Close();
                serialPort.Dispose();
                MessageBox.Show("串口已关闭");
            }
      }
      private void MainForm_FormClosing(object sender, FormClosingEventArgs e)
      {
            if (serialPort != null && serialPort.IsOpen)
            {
                serialPort.Close();
                serialPort.Dispose();
            }
      }
    }
}
这是我的C#代码,请简单的介绍一下@FishC

FishC 发表于 2024-3-4 21:35:49

XYZ_XYZ 发表于 2024-03-04 21:35
using System;
using System.Collections.Generic;
...

这是一个简单的串口数据显示程序。让我来解释一下代码的功能。

首先,在命名空间“串口数据显示”中,我们定义了一个名为"Form1"的窗体类。这个类继承自Windows Forms的Form类,表示一个应用程序窗体。

在Form1类中,我们声明了一个私有变量"serialPort",用来表示串口对象。并将其初始化为null,以便我们可以检查它是否已经实例化。

接下来,在Form1类的构造函数中,我们完成了一些初始化工作。我们为comboBox1控件的DropDown事件和button1、button2按钮的Click事件注册了事件处理程序。

在comboBox1的DropDown事件处理程序中,我们通过SerialPort.GetPortNames()方法获取当前计算机上所有可用的串口号,并将它们添加到comboBox1控件中进行选择。

在button1的Click事件处理程序中,当用户点击了“打开串口”按钮时,我们首先判断serialPort对象是否为空,并创建一个新的SerialPort对象实例。然后,我们根据用户选择的串口号和一些默认设置(波特率、校验位、停止位、数据位、握手方式),对serialPort对象进行配置。最后,我们通过调用Open方法打开串口,并显示一个提示对话框告知用户串口已打开。

button2的Click事件处理程序中,当用户点击了“关闭串口”按钮时,我们判断serialPort对象是否为空且串口是否处于打开状态,然后调用Close方法关闭串口,并通过调用Dispose方法释放资源,最后显示一个提示对话框告知用户串口已关闭。

最后,在Form1类中,我们还定义了一个MainForm_FormClosing事件处理程序,当窗体即将关闭时,如果串口已打开,则先关闭串口并释放资源。

这就是这个程序的主要功能。当用户在comboBox1中选择了一个串口号并点击“打开串口”按钮后,就可以打开串口并开始接收来自串口的数据。当用户点击“关闭串口”按钮时,程序会关闭串口并停止接收数据。

希望这段解释对你有帮助!如果还有其他问题,请随时提问。

以上回复来自 FishC AI 小助理,如未能正确解答您的问题,请继续追问。

XYZ_XYZ 发表于 2024-3-4 21:42:06

FishC 发表于 2024-3-4 21:35
这是一个简单的串口数据显示程序。让我来解释一下代码的功能。

首先,在命名空间“串口数据显示”中 ...

我想将两个按键合并成一个按键,应该怎么写代码。功能是点击button1,串口打开,button1 的 text 显示打开;再点击button1,串口关闭,button1 的 text 显示关闭。

FishC 发表于 2024-3-4 21:42:36

XYZ_XYZ 发表于 2024-03-04 21:42
我想将两个按键合并成一个按键,应该怎么写代码。功能 ...

要将两个按钮合并成一个按钮,并根据串口的状态来切换按钮的文本,你可以使用一个标志变量来表示串口的状态。当串口关闭时,将标志变量设置为false;当串口打开时,将标志变量设置为true。然后,在按钮的Click事件处理程序中,根据标志变量的值来执行相应的操作并更新按钮的文本。以下是一个示例代码:bool isSerialPortOpen = false; // 标志变量,表示串口是否已打开private void button1_Click(object sender, EventArgs e){    if (isSerialPortOpen){      // 如果串口已打开,则关闭串口      if (serialPort != null && serialPort.IsOpen){            serialPort.Close();            serialPort.Dispose();      }      isSerialPortOpen = false;      button1.Text = "打开";    }    else{      // 如果串口未打开,则打开串口      try{            if (serialPort == null){                serialPort = new SerialPort();            }            if (!serialPort.IsOpen && comboBox1.SelectedItem != null){                serialPort.PortName = comboBox1.SelectedItem.ToString();                serialPort.BaudRate = 9600;                serialPort.Parity = Parity.None;                serialPort.StopBits = StopBits.One;                serialPort.DataBits = 8;                serialPort.Handshake = Handshake.None;                serialPort.Open();                MessageBox.Show("串口已打开");                isSerialPortOpen = true;                button1.Text = "关闭";            }            else{                MessageBox.Show("请选择一个串口或串口已经打开");            }      }      catch (Exception ex){            MessageBox.Show("打开串口时出错: " + ex.Message);            if (serialPort != null){                serialPort.Close();                serialPort.Dispose();            }      }    }}在这个示例代码中,我添加了一个名为"isSerialPortOpen"的标志变量,并将其初始化为false。在按钮的Click事件处理程序中,如果isSerialPortOpen为true,则表示串口已打开,那么执行关闭串口的操作,并将isSerialPortOpen设置为false,同时将按钮的文本设置为"打开";如果isSerialPortOpen为false,则表示串口未打开,那么执行打开串口的操作,并将isSerialPortOpen设置为true,同时将按钮的文本设置为"关闭"。希望这个示例代码能满足你的需求!如果还有其他问题,请随时提问。

以上回复来自 FishC AI 小助理,如未能正确解答您的问题,请继续追问。

XYZ_XYZ 发表于 2024-3-4 21:47:59

FishC 发表于 2024-3-4 21:42
要将两个按钮合并成一个按钮,并根据串口的状态来切换按钮的文本,你可以使用一个标志变量来表示串口的 ...

请重新整理一下代码格式

FishC 发表于 2024-3-4 21:48:20

XYZ_XYZ 发表于 2024-03-04 21:47
请重新整理一下代码格式

当然!以下是重新整理过的代码,以提高可读性:
bool isSerialPortOpen = false; // 标志变量,表示串口是否已打开

private void button1_Click(object sender, EventArgs e)
{
    if (isSerialPortOpen)
    {
      // 如果串口已打开,则关闭串口
      if (serialPort != null && serialPort.IsOpen)
      {
            serialPort.Close();
            serialPort.Dispose();
      }
      
      isSerialPortOpen = false;
      button1.Text = "打开";
    }
    else
    {
      // 如果串口未打开,则打开串口
      try
      {
            if (serialPort == null)
            {
                serialPort = new SerialPort();
            }
            
            if (!serialPort.IsOpen && comboBox1.SelectedItem != null)
            {
                serialPort.PortName = comboBox1.SelectedItem.ToString();
                serialPort.BaudRate = 9600;
                serialPort.Parity = Parity.None;
                serialPort.StopBits = StopBits.One;
                serialPort.DataBits = 8;
                serialPort.Handshake = Handshake.None;
                serialPort.Open();
               
                MessageBox.Show("串口已打开");
                isSerialPortOpen = true;
                button1.Text = "关闭";
            }
            else
            {
                MessageBox.Show("请选择一个串口或串口已经打开");
            }
      }
      catch (Exception ex)
      {
            MessageBox.Show("打开串口时出错: " + ex.Message);
            
            if (serialPort != null)
            {
                serialPort.Close();
                serialPort.Dispose();
            }
      }
    }
}
这段代码包含了一个名为"isSerialPortOpen"的标志变量,用于表示串口的状态。在按钮的Click事件处理程序中,根据isSerialPortOpen的值来执行相应的操作,并更新按钮的文本。希望这样更易于阅读和理解!如果还有其他问题,请随时提问。

以上回复来自 FishC AI 小助理,如未能正确解答您的问题,请继续追问。

XYZ_XYZ 发表于 2024-3-4 21:58:19

FishC 发表于 2024-3-4 21:48
当然!以下是重新整理过的代码,以提高可读性:

这段代码包含了一个名为"isSerialPortOpen"的标志变 ...

我想个button1加一个功能,当串口打开时,按键显示绿色。

FishC 发表于 2024-3-4 21:58:36

XYZ_XYZ 发表于 2024-03-04 21:58
我想个button1加一个功能,当串口打开时,按键显示绿 ...

好的!你可以使用以下代码在串口打开时将按钮的背景颜色设置为绿色:private void button1_Click(object sender, EventArgs e){    if (isSerialPortOpen)    {      // 如果串口已打开,则关闭串口      if (serialPort != null && serialPort.IsOpen)      {            serialPort.Close();            serialPort.Dispose();      }                isSerialPortOpen = false;      button1.Text = "打开";      button1.BackColor = DefaultBackColor; // 恢复默认背景颜色    }    else    {      // 如果串口未打开,则打开串口      try      {            if (serialPort == null)            {                serialPort = new SerialPort();            }                        if (!serialPort.IsOpen && comboBox1.SelectedItem != null)            {                serialPort.PortName = comboBox1.SelectedItem.ToString();                serialPort.BaudRate = 9600;                serialPort.Parity = Parity.None;                serialPort.StopBits = StopBits.One;                serialPort.DataBits = 8;                serialPort.Handshake = Handshake.None;                serialPort.Open();                              MessageBox.Show("串口已打开");                isSerialPortOpen = true;                button1.Text = "关闭";                button1.BackColor = Color.Green; // 设置背景颜色为绿色            }            else            {                MessageBox.Show("请选择一个串口或串口已经打开");            }      }      catch (Exception ex)      {            MessageBox.Show("打开串口时出错: " + ex.Message);                        if (serialPort != null)            {                serialPort.Close();                serialPort.Dispose();            }      }    }}在这段代码中,我在按钮的Click事件处理程序中添加了`button1.BackColor = Color.Green;`这一行代码。当串口打开时,按钮的背景颜色将被设置为绿色。希望这个功能满足了你的需求!

以上回复来自 FishC AI 小助理,如未能正确解答您的问题,请继续追问。

XYZ_XYZ 发表于 2024-3-4 21:59:15

FishC 发表于 2024-3-4 21:58
好的!你可以使用以下代码在串口打开时将按钮的背景颜色设置为绿色:private void button1_Click(objec ...

请整理代码格式

FishC 发表于 2024-3-4 21:59:27

XYZ_XYZ 发表于 2024-03-04 21:59
请整理代码格式

当然!以下是经过整理的代码,以更好地展示可读性:void button1_Click(object sender, EventArgs e)
{
    if (isSerialPortOpen)
    {
      // 如果串口已打开,则关闭串口
      if (serialPort != null && serialPort.IsOpen)
      {
            serialPort.Close();
            serialPort.Dispose();
      }
      
      isSerialPortOpen = false;
      button1.Text = "打开";
      button1.BackColor = DefaultBackColor; // 恢复默认背景颜色
    }
    else
    {
      // 如果串口未打开,则打开串口
      try
      {
            if (serialPort == null)
            {
                serialPort = new SerialPort();
            }
            
            if (!serialPort.IsOpen && comboBox1.SelectedItem != null)
            {
                serialPort.PortName = comboBox1.SelectedItem.ToString();
                serialPort.BaudRate = 9600;
                serialPort.Parity = Parity.None;
                serialPort.StopBits = StopBits.One;
                serialPort.DataBits = 8;
                serialPort.Handshake = Handshake.None;
               
                serialPort.Open();
                MessageBox.Show("串口已打开");
               
                isSerialPortOpen = true;
                button1.Text = "关闭";
                button1.BackColor = Color.Green; // 设置背景颜色为绿色
            }
            else
            {
                MessageBox.Show("请选择一个串口或串口已经打开");
            }
      }
      catch (Exception ex)
      {
            MessageBox.Show("打开串口时出错: " + ex.Message);
            
            if (serialPort != null)
            {
                serialPort.Close();
                serialPort.Dispose();
            }
      }
    }
}
通过以上整理,代码更加清晰易读。希望对你有所帮助!

以上回复来自 FishC AI 小助理,如未能正确解答您的问题,请继续追问。

XYZ_XYZ 发表于 2024-3-4 22:12:41

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.IO.Ports;
using System.Windows.Forms;

namespace 串口数据显示
{
    public partial class Form1 : Form
    {
      private SerialPort serialPort = null;// 初始化为null,以便我们可以检查它是否已被实例化


      public Form1()
      {
            InitializeComponent();
            this.comboBox1.DropDown += new System.EventHandler(this.comboBox1_DropDown);
            this.button1.Click += new System.EventHandler(this.button1_Click);
      }

      private void comboBox1_DropDown(object sender, EventArgs e)
      {
            string[] ports = SerialPort.GetPortNames();
            comboBox1.Items.Clear();
            foreach (string port in ports)
            {
                comboBox1.Items.Add(port);
            }

            if (comboBox1.Items.Count > 0)
            {
                comboBox1.SelectedIndex = 0;
            }
      }

      bool isSerialPortOpen = false; // 标志变量,表示串口是否已打开

      void button1_Click(object sender, EventArgs e)
      {
            if (isSerialPortOpen)
            {
                // 如果串口已打开,则关闭串口
                if (serialPort != null && serialPort.IsOpen)
                {
                  serialPort.Close();
                  serialPort.Dispose();
                }

                isSerialPortOpen = false;
                button1.Text = "打开";
            }
            else
            {
                // 如果串口未打开,则打开串口
                try
                {
                  if (serialPort == null)
                  {
                        serialPort = new SerialPort();
                  }

                  if (!serialPort.IsOpen && comboBox1.SelectedItem != null)
                  {
                        serialPort.PortName = comboBox1.SelectedItem.ToString();
                        serialPort.BaudRate = 115200;
                        serialPort.Parity = Parity.None;
                        serialPort.StopBits = StopBits.One;
                        serialPort.DataBits = 8;
                        serialPort.Handshake = Handshake.None;

                        serialPort.Open();
                        //MessageBox.Show("串口已打开");

                        isSerialPortOpen = true;
                        button1.Text = "关闭";
                  }
                  else
                  {
                        MessageBox.Show("请选择一个串口或串口已经打开");
                  }
                }
                catch (Exception ex)
                {
                  MessageBox.Show("打开串口时出错: " + ex.Message);

                  if (serialPort != null)
                  {
                        serialPort.Close();
                        serialPort.Dispose();
                  }
                }
            }
      }

      private void Form1_FormClosing(object sender, FormClosingEventArgs e)
      {
            if (serialPort != null && serialPort.IsOpen)
            {
                serialPort.Close();
                serialPort.Dispose();
            }
      }
    }
}
我想要在我的代码基础上添加一个按键button2,并按下button2,实现串口发送0x99的功能。请完善代码,并规范代码格式。

FishC 发表于 2024-3-4 22:13:12

XYZ_XYZ 发表于 2024-03-04 22:12
using System;
using System.Collections.Generic;
...

好的!以下是在你的代码基础上添加了button2按键,并实现了串口发送0x99功能的完整代码,并进行了格式规范化: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.IO.Ports;using System.Windows.Forms;namespace 串口数据显示{    public partial class Form1 : Form    {      private SerialPort serialPort = null;      private bool isSerialPortOpen = false;      public Form1()      {            InitializeComponent();            this.comboBox1.DropDown += new System.EventHandler(this.comboBox1_DropDown);            this.button1.Click += new System.EventHandler(this.button1_Click);            this.button2.Click += new System.EventHandler(this.button2_Click);            this.FormClosing += new System.Windows.Forms.FormClosingEventHandler(this.Form1_FormClosing);      }      private void comboBox1_DropDown(object sender, EventArgs e)      {            string[] ports = SerialPort.GetPortNames();            comboBox1.Items.Clear();            foreach (string port in ports)            {                comboBox1.Items.Add(port);            }            if (comboBox1.Items.Count > 0)            {                comboBox1.SelectedIndex = 0;            }      }      private void button1_Click(object sender, EventArgs e)      {            if (isSerialPortOpen)            {                // 如果串口已打开,则关闭串口                if (serialPort != null && serialPort.IsOpen)                {                  serialPort.Close();                  serialPort.Dispose();                }                isSerialPortOpen = false;                button1.Text = "打开";            }            else            {                // 如果串口未打开,则打开串口                try                {                  if (serialPort == null)                  {                        serialPort = new SerialPort();                  }                  if (!serialPort.IsOpen && comboBox1.SelectedItem != null)                  {                        serialPort.PortName = comboBox1.SelectedItem.ToString();                        serialPort.BaudRate = 115200;                        serialPort.Parity = Parity.None;                        serialPort.StopBits = StopBits.One;                        serialPort.DataBits = 8;                        serialPort.Handshake = Handshake.None;                        serialPort.Open();                        isSerialPortOpen = true;                        button1.Text = "关闭";                  }                  else                  {                        MessageBox.Show("请选择一个串口或串口已经打开");                  }                }                catch (Exception ex)                {                  MessageBox.Show("打开串口时出错: " + ex.Message);                  if (serialPort != null)                  {                        serialPort.Close();                        serialPort.Dispose();                  }                }            }      }      private void button2_Click(object sender, EventArgs e)      {            if (isSerialPortOpen)            {                try                {                  // 发送0x99给串口                  byte[] sendData = { 0x99 };                  serialPort.Write(sendData, 0, sendData.Length);                }                catch (Exception ex)                {                  MessageBox.Show("发送数据时出错: " + ex.Message);                }            }            else            {                MessageBox.Show("请先打开串口");            }      }      private void Form1_FormClosing(object sender, FormClosingEventArgs e)      {            if (serialPort != null && serialPort.IsOpen)            {                serialPort.Close();                serialPort.Dispose();            }      }    }}希望这段代码满足了你的需求!如果还有其他问题,请随时提问。

以上回复来自 FishC AI 小助理,如未能正确解答您的问题,请继续追问。

XYZ_XYZ 发表于 2024-3-4 22:14:39

FishC 发表于 2024-3-4 22:13
好的!以下是在你的代码基础上添加了button2按键,并实现了串口发送0x99功能的完整代码,并进行了格式 ...

请规范代码格式

FishC 发表于 2024-3-4 22:15:05

XYZ_XYZ 发表于 2024-03-04 22:14
请规范代码格式

以下是格式规范化后的代码: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.IO.Ports;
using System.Windows.Forms;

namespace 串口数据显示
{
    public partial class Form1 : Form
    {
      private SerialPort serialPort = null;
      private bool isSerialPortOpen = false;

      public Form1()
      {
            InitializeComponent();

            this.comboBox1.DropDown += new System.EventHandler(this.comboBox1_DropDown);
            this.button1.Click += new System.EventHandler(this.button1_Click);
            this.button2.Click += new System.EventHandler(this.button2_Click);
            this.FormClosing += new System.Windows.Forms.FormClosingEventHandler(this.Form1_FormClosing);
      }

      private void comboBox1_DropDown(object sender, EventArgs e)
      {
            string[] ports = SerialPort.GetPortNames();
            comboBox1.Items.Clear();
            foreach (string port in ports)
            {
                comboBox1.Items.Add(port);
            }
            if (comboBox1.Items.Count > 0)
            {
                comboBox1.SelectedIndex = 0;
            }
      }

      private void button1_Click(object sender, EventArgs e)
      {
            if (isSerialPortOpen)
            {
                // 如果串口已打开,则关闭串口
                if (serialPort != null && serialPort.IsOpen)
                {
                  serialPort.Close();
                  serialPort.Dispose();
                }

                isSerialPortOpen = false;
                button1.Text = "打开";
            }
            else
            {
                // 如果串口未打开,则打开串口
                try
                {
                  if (serialPort == null)
                  {
                        serialPort = new SerialPort();
                  }

                  if (!serialPort.IsOpen && comboBox1.SelectedItem != null)
                  {
                        serialPort.PortName = comboBox1.SelectedItem.ToString();
                        serialPort.BaudRate = 115200;
                        serialPort.Parity = Parity.None;
                        serialPort.StopBits = StopBits.One;
                        serialPort.DataBits = 8;
                        serialPort.Handshake = Handshake.None;
                        serialPort.Open();

                        isSerialPortOpen = true;
                        button1.Text = "关闭";
                  }
                  else
                  {
                        MessageBox.Show("请选择一个串口或串口已经打开");
                  }
                }
                catch (Exception ex)
                {
                  MessageBox.Show("打开串口时出错: " + ex.Message);

                  if (serialPort != null)
                  {
                        serialPort.Close();
                        serialPort.Dispose();
                  }
                }
            }
      }

      private void button2_Click(object sender, EventArgs e)
      {
            if (isSerialPortOpen)
            {
                try
                {
                  // 发送0x99给串口
                  byte[] sendData = { 0x99 };
                  serialPort.Write(sendData, 0, sendData.Length);
                }
                catch (Exception ex)
                {
                  MessageBox.Show("发送数据时出错: " + ex.Message);
                }
            }
            else
            {
                MessageBox.Show("请先打开串口");
            }
      }

      private void Form1_FormClosing(object sender, FormClosingEventArgs e)
      {
            if (serialPort != null && serialPort.IsOpen)
            {
                serialPort.Close();
                serialPort.Dispose();
            }
      }
    }
}希望这次的格式满足了你的要求!如果还有其他问题,请随时提问。

以上回复来自 FishC AI 小助理,如未能正确解答您的问题,请继续追问。

XYZ_XYZ 发表于 2024-3-4 22:21:46

FishC 发表于 2024-3-4 22:15
以下是格式规范化后的代码:using System;
using System.Collections.Generic;
using System.Compone ...

请在加上串口接收的功能

FishC 发表于 2024-3-4 22:23:20

XYZ_XYZ 发表于 2024-03-04 22:21
请在加上串口接收的功能

以下是加上串口接收功能的代码示例:

#include <stdio.h>
#include <Windows.h>

#define MAX_BUF_SIZE 255

int main() {
    HANDLE hSerial;
    DCB dcbSerialParams = { 0 };
    COMMTIMEOUTS timeouts = { 0 };
    char port[] = "\\\\.\\COM1"; // 根据实际的串口号修改

    // 打开串口
    hSerial = CreateFile(port, GENERIC_READ | GENERIC_WRITE, 0, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
    if (hSerial == INVALID_HANDLE_VALUE) {
      printf("无法打开串口\n");
      return 1;
    }

    // 配置串口参数
    dcbSerialParams.DCBlength = sizeof(dcbSerialParams);
    if (!GetCommState(hSerial, &dcbSerialParams)) {
      printf("无法获取串口参数\n");
      CloseHandle(hSerial);
      return 1;
    }
    dcbSerialParams.BaudRate = CBR_9600; // 波特率设置为9600bps
    dcbSerialParams.ByteSize = 8; // 数据位设置为8位
    dcbSerialParams.StopBits = ONESTOPBIT; // 停止位设置为1位停止位
    dcbSerialParams.Parity = NOPARITY; // 校验位设置为无校验
    if (!SetCommState(hSerial, &dcbSerialParams)){
      printf("无法设置串口参数\n");
      CloseHandle(hSerial);
      return 1;
    }

    // 设置串口读写超时时间
    timeouts.ReadIntervalTimeout = 50;
    timeouts.ReadTotalTimeoutConstant = 50;
    timeouts.ReadTotalTimeoutMultiplier = 10;
    timeouts.WriteTotalTimeoutConstant = 50;
    timeouts.WriteTotalTimeoutMultiplier = 10;
    if (!SetCommTimeouts(hSerial, &timeouts)) {
      printf("无法设置串口超时时间\n");
      CloseHandle(hSerial);
      return 1;
    }

    // 向串口发送数据
    char sendData[] = "Hello, Serial!";
    DWORD bytesWritten = 0;
    if (!WriteFile(hSerial, sendData, sizeof(sendData), &bytesWritten, NULL)) {
      printf("无法向串口发送数据\n");
      CloseHandle(hSerial);
      return 1;
    }
    printf("已发送数据:%s\n", sendData);

    // 从串口接收数据
    char recvData = { 0 };
    DWORD bytesRead = 0;
    if (!ReadFile(hSerial, recvData, MAX_BUF_SIZE, &bytesRead, NULL)) {
      printf("无法从串口接收数据\n");
      CloseHandle(hSerial);
      return 1;
    }
    recvData = '\0'; // 添加字符串结束符
    printf("已接收数据:%s\n", recvData);

    // 关闭串口
    CloseHandle(hSerial);
    return 0;
}

这个示例代码演示了如何通过C语言进行串口发送和接收数据的操作。你可以根据实际情况对代码进行修改和扩展。

希望对你有所帮助!如有其他问题,请随时提问。

以上回复来自 FishC AI 小助理,如未能正确解答您的问题,请继续追问。
页: [1] 2
查看完整版本: 用C语言写一个串口收发的上位机