Qlql2464 2024-01-06 10:55 采纳率: 0%
浏览 15

c#wpf上位机串口通信led


    public partial class MainWindow : Window
    {
        //空车数组
        byte[] cCH_FreeTabB = {
0x0C,0x00,0x60,0x06,0x00,0x60,0x7F,0xF7,0xFF,0xE0,0x30,0xC0,0x19,0xC0,0xF0,0x30,
0x61,0xB0,0xE0,0x33,0xFE,0x3F,0xC0,0x30,0x06,0x00,0x30,0x06,0x07,0xFF,0x06,0x00,
0x30,0xFF,0xF0,0x30
};
        public SerialPort serialPort = new SerialPort();
        // 成员变量,用于判断是否收到应答
        private volatile bool isAckReceived = false;
        public MainWindow()
        {
            Encoding.RegisterProvider(CodePagesEncodingProvider.Instance);
            InitializeComponent();
            InitializeSerial();
            //添加数据接收事件
            serialPort.DataReceived += new SerialDataReceivedEventHandler(SerialPortDataReceived);

        }
        //初始化串口
        private void InitializeSerial()
        {
            //实例化SerialPort对象
            serialPort = new SerialPort();
            //设置串口参数都设置默认值
            serialPort.BaudRate = 9600;//波特率
            serialPort.Parity = Parity.None;//校验位
            serialPort.DataBits = 8;//数据位
            serialPort.StopBits = StopBits.One;//停止位
            string[] prots = SerialPort.GetPortNames();//获取当前机器的串口
            cb_Prots.ItemsSource = prots;//下拉框获取串口数据
            if (!serialPort.IsOpen)
            {
                cb_Prots.SelectedIndex = 0;//取默认第一个串口值
            }
        }
        //打开串口
        private void bt_SerialSwitch_Click(object sender, RoutedEventArgs e)
        {
            try
            {
                // 根据串口的当前打开状态来决定是打开还是关闭串口
                if (!serialPort.IsOpen)
                {
                    // 从ComboBox中获取选中的串口名称
                    string selectedPort = cb_Prots.SelectedItem as string;
                    if (string.IsNullOrEmpty(selectedPort))
                    {
                        MessageBox.Show("请先选择一个串口", "错误", MessageBoxButton.OK, MessageBoxImage.Error);
                        return;
                    }
                    serialPort.PortName = selectedPort;
                    serialPort.Open();//打开串口
                    MessageBox.Show("已打开");
                    bt_SerialSwitch.Content = "关闭串口";
                    tb_switchStatus.Text = "串口为打开状态";
                    e_status.Fill = new System.Windows.Media.SolidColorBrush(System.Windows.Media.Colors.Green);
                }
                else
                {
                    serialPort.Close();//关闭串口
                    MessageBox.Show("已关闭");
                    bt_SerialSwitch.Content = "打开串口";
                    tb_switchStatus.Text = "串口为关闭状态";
                    e_status.Fill = new System.Windows.Media.SolidColorBrush(System.Windows.Media.Colors.Red);
                }
            }
            catch (Exception ex)
            {
                MessageBox.Show(ex.Message, "异常", MessageBoxButton.OK, MessageBoxImage.Error);
            }
        }
        // 发送数据包,并等待应答
        private void SendDataPacketWithRetry(byte[] packet)
        {
            if (serialPort.IsOpen)
            {
                int retries = 0;
                const int maxRetries = 3;
                const int retryInterval = 1000; // 1秒重试间隔
                const int responseTimeout = 5000; // 5秒应答超时

                //创建计时器,用于应答超时
                System.Timers.Timer responseTimer = new System.Timers.Timer(responseTimeout);
                responseTimer.Elapsed += (sender, e) => isAckReceived = true; // 超时则视为断线,停止等待应答
                responseTimer.AutoReset = false;//触发定时器

                while (!isAckReceived && retries < maxRetries)
                {
                    try
                    {
                        //收发的数据包
                        serialPort.Write(packet, 0, packet.Length);
                        //开始答应
                        responseTimer.Start();
                        //等待或者知道收到数据
                        System.Threading.Thread.Sleep(retryInterval);
                        if (isAckReceived)
                        {
                            responseTimer.Stop();
                            break;//收到答应退出循环
                        }
                        retries++;
                    }
                    catch (Exception ex)
                    {
                        MessageBox.Show("发送失败: " + ex.Message);
                        return; // 发生异常,退出方法
                    }
                }

                if (!isAckReceived)
                {
                    MessageBox.Show("连接失败或丢失。"); // 重试三次后还未收到应答,通知用户
                }
                responseTimer.Dispose(); // 清理计时器资源
            }
            else
            {
                MessageBox.Show("串口未打开!");
            }
        }

        private void ResponseTimer_Elapsed(object? sender, System.Timers.ElapsedEventArgs e)
        {
            throw new NotImplementedException();
        }

        //串口数据接收事件
        private void SerialPortDataReceived(object sender, SerialDataReceivedEventArgs e)
        {
            //定义缓冲区
            byte[] buffer = new byte[serialPort.BytesToRead];
            //读取数据到缓冲区
            int byteRead = serialPort.Read(buffer, 0, buffer.Length);
            // 在UI线程上执行,因为我们可能需要更新UI
            Dispatcher.Invoke(() =>
            {
                serialPort.Write("");
                //收到数据答应
                if (IsAcknowledge(buffer))
                {
                    isAckReceived = true;
                }
                else
                {

                }
            });
        }
        //检查是否答应
        private bool IsAcknowledge(byte[] data)
        {
            // 具体的ACK字节可能会根据你的通信协议而不同。
            // 这里我们以ASCII字符的ACK(值为0x06)作为示例。
            const byte AckByte = 0x06;

            // 检查数据数组是否只包含一个字节,且该字节是ACK字节。
            return data.Length == 1 && data[0] == AckByte;
        }

        //构建数据包,报文头-长度-命令字-校验-报文尾
        private byte[] BuildDataPacket(byte commandByte, byte[] content)
        {
            List<byte> packet = new List<byte>();
            //报文头
            byte[] Header = new byte[] { 0x40, 0x40, 0x63 };
            packet.AddRange(Header);

            // 计算长度字段,长度为命令字到校验之前的字节数
            ushort length = (ushort)(1 + content.Length); // 命令字1个字节 + 内容的长度
            byte[] Length = BitConverter.GetBytes(length);

            // 如果系统为大端序,需要调整为小端序
            if (!BitConverter.IsLittleEndian)
            {
                Array.Reverse(Length);
            }

            // 添加长度字段到报文
            packet.AddRange(Length);

            // 命令字
            packet.Add(commandByte);

            // 内容
            packet.AddRange(content);

            // 校验,计算从长度到内容的所有字节进行异或(XOR)计算得出
            byte checksum = CalculateChecksum(packet.ToArray().Skip(3).ToArray()); // Skip Header
            packet.Add(checksum);

            // 报文尾
            byte[] Footer = new byte[] { 0x0D, 0x0A };
            packet.AddRange(Footer);

            return packet.ToArray();

        }
        // 校验方法
        private byte CalculateChecksum(byte[] data)
        {
            byte checksum = 0;
            foreach (byte b in data)
            {
                checksum ^= b;
            }
            return checksum;
        }
        //发送命令的方法
        private void SendCommand(byte[] dataPacket)
        {
            if (serialPort.IsOpen)
            {
                serialPort.Write(dataPacket, 0, dataPacket.Length);
                MessageBox.Show("命令已发送");
            }
            else
            {
                MessageBox.Show("串口未打开!", "错误", MessageBoxButton.OK, MessageBoxImage.Error);
            }
        }

wpf串口通信控制led点阵屏空车牌。各位抽出空闲时间看看我的代码有无问题,怎么通过空车按钮byte数组发送数据到led屏上显示出来卡住了。刚接触上位机。指点指点!

  • 写回答

1条回答 默认 最新

  • CSDN-Ada助手 CSDN-AI 官方账号 2024-01-06 12:04
    关注

    【以下回答由 GPT 生成】

    首先,我们需要调整"MainWindow"类中的一些实现。下面是根据你提供的要求进行优化的代码片段:

    public partial class MainWindow : Window
    {
        //空车数组
        byte[] cCH_FreeTabB = { 0x0C, 0x00, 0x60, 0x06, 0x00, 0x60, 0x7F, 0xF7, 0xFF, 0xE0, 0x30, 0xC0, 0x19, 0xC0, 0xF0, 0x30,
                        0x61, 0xB0, 0xE0, 0x33, 0xFE, 0x3F, 0xC0, 0x30, 0x06, 0x00, 0x30, 0x06, 0x07, 0xFF, 0x06, 0x00,
                        0x30, 0xFF, 0xF0, 0x30};
    
        public SerialPort serialPort;
    
        // 成员变量,用于判断是否收到应答
        private volatile bool isAckReceived = false;
    
        public MainWindow()
        {
            Encoding.RegisterProvider(CodePagesEncodingProvider.Instance);
            InitializeComponent();
            InitializeSerial();
            serialPort.DataReceived += new SerialDataReceivedEventHandler(SerialPortDataReceived);
        }
    
        //初始化串口
        private void InitializeSerial()
        {
            // 设置串口参数
            serialPort = new SerialPort
            {
                BaudRate = 9600, //波特率
                Parity = Parity.None, //校验位
                DataBits = 8, //数据位
                StopBits = StopBits.One //停止位
            };
    
            // 获取当前机器的串口并添加到下拉框中
            string[] ports = SerialPort.GetPortNames();
            cb_Ports.ItemsSource = ports;
            if (ports.Length > 0)
            {
                cb_Ports.SelectedItem = ports[0];
            }
        }
    
        // 串口数据接收事件处理函数
        private void SerialPortDataReceived(object sender, SerialDataReceivedEventArgs e)
        {
            // 处理接收到的数据
            SerialPort sp = (SerialPort)sender;
            string receivedData = sp.ReadExisting();
    
            // TODO: 在这里添加你想要做的处理逻辑
        }
    
        // 发送cCH_FreeTabB数组中的数据
        private void SendData()
        {
            if (serialPort.IsOpen)
            {
                serialPort.Write(cCH_FreeTabB, 0, cCH_FreeTabB.Length);
            }
        }
    
        // "发送数据"按钮点击事件
        private void btn_Send_Click(object sender, RoutedEventArgs e)
        {
            SendData();
        }
    }
    

    通过上述优化,我们可以完成以下功能:

    1. 实例化一个SerialPort对象并设置串口参数。
    2. 获取当前机器的串口并将其添加到下拉框中,同时设置默认选择第一个串口。
    3. 实现串口数据接收事件处理函数SerialPortDataReceived,在这里可以对接收到的数据进行处理。
    4. 添加了SendData方法,可用于发送cCH_FreeTabB数组中的数据。
    5. 在按钮点击事件中调用SendData方法以发送数据。

    请注意,这只是提供了代码的优化和示例,你需要根据具体需求进行修改和完善。


    如果你已经解决了该问题, 非常希望你能够分享一下解决方案, 写成博客, 将相关链接放在评论区, 以帮助更多的人 ^-^
    评论

报告相同问题?

问题事件

  • 创建了问题 1月6日

悬赏问题

  • ¥15 乌班图ip地址配置及远程SSH
  • ¥15 怎么让点阵屏显示静态爱心,用keiluVision5写出让点阵屏显示静态爱心的代码,越快越好
  • ¥15 PSPICE制作一个加法器
  • ¥15 javaweb项目无法正常跳转
  • ¥15 VMBox虚拟机无法访问
  • ¥15 skd显示找不到头文件
  • ¥15 机器视觉中图片中长度与真实长度的关系
  • ¥15 fastreport table 怎么只让每页的最下面和最顶部有横线
  • ¥15 R语言卸载之后无法重装,显示电脑存在下载某些较大二进制文件行为,怎么办
  • ¥15 java 的protected权限 ,问题在注释里