C#编写单片机上位机软件-串口通讯(BMS汽车动力电池管理系统)

C#编写单片机上位机软件-串口通讯(BMS汽车动力电池管理系统)上位机软件做了有一段时间,本人呕心沥血的作品。之前用python+pyQT5做,主线程特别特别容易闪退,数据重叠等问题,走了很多弯路;后来用VS的C#做,只能说上手很快,调试效果也不错,而且关键是非常非常简单易读,只希望大家不要像我一样,走这么多弯路–想要源码的小伙伴们,欢迎关注点赞三连+留言邮箱哦~华丽的分割线——————————————————————————————–

大家好,又见面了,我是你们的朋友全栈君。

485协议上位机软件做了有一段时间,
之前用python+pyQT5做,主线程特别特别容易闪退,数据重叠等问题,走了很多弯路;
后来用VS的C#做,只能说上手很快,多线程不卡顿,调试效果也不错,而且关键是非常非常简单易读,只希望大家不要像我一样,走这么多弯路 – –

正在持续优化中,欢迎关注点赞三连~
华丽的分割线——————————————————————————————–
废话不多说直接看效果图—-
在这里插入图片描述

在这里插入图片描述

其中串口数据的接收读取是最难的部分,因为下位机的特殊性(属于公司机密),传上来的都不知道是几进制的数据,还要根据特定的通讯协议分配显示槽,博主呕心沥血查阅各种资料, 才写出了字符串和数值的各种转换,高8位字节低8位字节读取、接收数据延迟显示、显示槽的定时刷新、时间显示、保存功能等等也是做好了的- – – ———————————

华丽的分割线—————————————————————————————
直接上最难的地方:
一、串口数据接收事件
区分数值接收与字符接收模式

        private void Form1_Load(object sender, EventArgs e)
        { 
   
            serialPort1.DataReceived += new SerialDataReceivedEventHandler(port_DataReceived);//必须手动添加事件处理程序
           
        }
        private void port_DataReceived(object sender, SerialDataReceivedEventArgs e)//串口数据接收事件
        { 
   
            Thread.Sleep(500);//休眠50ms
            try
            { 
   
                if (!hexshoufa6.Checked)//如果接收模式为字符模式
                { 
   
                    int ilen = serialPort1.BytesToRead;
                    byte[] bytes = new byte[ilen];
                    serialPort1.Read(bytes, 0, ilen);
                    string str = System.Text.Encoding.Default.GetString(bytes); //xx="中文";
                    if (time_flag == true)
                    { 
   
                        jiemiantext1.AppendText(GetTimeStamp() + " 电压: " + str + '\r' + '\n');//添加内容
                        Ubatfu.AppendText(str);
                        
                    }
                    else
                        jiemiantext1.AppendText(str + '\r' + '\n');//添加内容
                       
                }
                else
                { 
    //如果接收模式为数值接收
                    int count = serialPort1.BytesToRead;//判断接收数据的字节数
                    byte[] data = new byte[serialPort1.BytesToRead]; //定义缓冲区,因为串口事件触发时有可能收到不止一个字节
                    serialPort1.Read(data, 0, data.Length);//读取指定长度到serialPort1
                    buffer.AddRange(data);//缓存数据到buffer//把新接收的数据放入 buffer的末尾,开头定义了帧长为36个字节
                                         //2.完整性判断
                    serialPort1.DiscardInBuffer();
                    //foreach (byte Member in data) //遍历用法,不要用

                    { 
   
                     
                      这里直接写你的数据头检测,数据尾检测,命令码检测等串口检测语句,设计公司机密,就不放上来了
                            }




                            //此时已经找到一组完整数据,进行缓存
                            
                          string strbuffer = buffer.ToString();
                          //后面写你的串口通信协议就OK了
                          

二、保存功能
目前用的比较简单的保存功能,直接设定好路径保存,后面再做修改

        private void button4_Click(object sender, EventArgs e)
        { 
   
           // string[] STR_DATA1;
          // STR_DATA1 = System.IO.File.ReadAllLines(@"F:\Visual_Studio\恒温控制系统上位机\恒温系统上位机\数据保存\接收数据保存.txt");
          // string myStr = string.Join("", STR_DATA1);
          // textBox1.AppendText(myStr);
            System.IO.File.WriteAllText(@"F:\单片机上位机开发\lyb上位机\数据保存\接收数据保存.txt", jiemiantext1.Text);
            System.IO.File.WriteAllText(@"F:\单片机上位机开发\lyb上位机\数据保存\发送数据保存.txt", fasongjiemian2.Text);
            tishixinxi1.AppendText(" 数据保存完成!!! \r\n");
          
        }

三、时间调用功能

public static string GetTimeStamp()
        { 
   
           // TimeSpan ts = DateTime.UtcNow - new DateTime(1970, 1, 1, 0, 0, 0, 0);
          // return Convert.ToInt64(ts.TotalSeconds).ToString();

            // DateTime.Now.ToString(); // 2008-9-4 20:02:10
            return DateTime.Now.ToLocalTime().ToString();        // 2008-9-4 20:12:12
                            Application.DoEvents();
                System.Threading.Thread.Sleep(100);
        }

四、那么如何显示波形呢?

        private void timer1_Tick(object sender, EventArgs e)
        { 
   
            if (time_out == 0)
            { 
   
                time_out = Convert.ToInt16(huoqutime.Text);

                if (chuankoukongzhi.Checked)
                { 
   
                    try
                    { 
   //实现串口发送汉字
                        Ubatfu.Clear();
                        Encoding gb = System.Text.Encoding.GetEncoding("gb2312");
                        //byte[] bytes = gb.GetBytes("%");
                        //serialPort1.Write(bytes, 0, bytes.Length);
                    }
                    catch
                    { 
   
                        jiemiantext1.AppendText("串口数据写入错误\r\n");//出错提示
                        serialPort1.Close();
                        button1_Click(sender, e);
                    }
                }
            }
            if (time_out == 1)
            { 
   
                time_out --;
                boxing1.Series.Clear();
                boxing1.ChartAreas[0].AxisX.Maximum = 20;//设定x轴的最大值
                boxing1.ChartAreas[0].AxisY.Maximum = 100;//设定y轴的最大值

                boxing1.ChartAreas[0].AxisX.Minimum = 0;//设定x轴的最小值
                boxing1.ChartAreas[0].AxisY.Minimum =-10;//设定y轴的最小值

                //第一条数据
                Series series = new Series("实时电压");
                series.ChartType = SeriesChartType.Spline;  //设置为曲线模式
                series.BorderWidth = 1;
                series.ShadowOffset = 1;             // Populate new series with data 
                

                
                for (int i = 0; i < 19; i++)
                { 
   
                    myIntArray4[i] = myIntArray4[i + 1];
                         series.Points.AddY(myIntArray4[i]);//画线
                }

                try
                { 
   

                    string s = zifuchuan.Text;//Ubatfu.Text;
                    string strbat = s.Remove(0, 10);//s.Remove(0, 3);
                    strbat = strbat.Remove(4, strbat.Length - 4);//取字符串的前两个字符 str1

                    
                    // textBox13.Text = textBox15.Text.Substring(textBox15.Text.IndexOf("温度:") + 2, textBox15.Text.IndexOf("温度:") + 4);
                    test.Text = strbat;

                    //str1
                    myIntArray4[19] = Convert.ToInt32(test.Text);
                    //zifuchuan.Text = jiemiantext1.Text;
                    //string str1 = zifuchuan.Text.Remove(0, 5);
                    //str1 = str1.Remove(2, str1.Length - 2);
                   //IbatAN.Text = str1;
                }
                catch
                { 
   
                    myIntArray4[19] = 0;
                }
                series.Points.AddY(myIntArray4[19]);

                boxing1.Series.Add(series);
            }
            else time_out--;
        }

完事了 串口协议部分不能给大家, 大家看到上面也就差不多了,小白学习的话可以少走很多弯路,当然如果有更简便的方式,欢迎大神指正~~~
欢迎关注点赞三连哦~
你的支持就是我前进动力中的一部分呢~

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请联系我们举报,一经查实,本站将立刻删除。

发布者:全栈程序员-站长,转载请注明出处:https://javaforall.net/138340.html原文链接:https://javaforall.net

(0)
全栈程序员-站长的头像全栈程序员-站长


相关推荐

  • Laravel设置软删除及其恢复系列操作

    Laravel设置软删除及其恢复系列操作

    2021年11月8日
    39
  • 解决Deepin下qq无法显示图片「建议收藏」

    解决Deepin下qq无法显示图片「建议收藏」添加内核参数彻底禁用IPv6:执行:sudodedit/etc/default/grub开始编辑文件:在此行添加参数:GRUB_CMDLINE_LINUX=”ipv6.disable=1″保存退出后执行:sudoupdate-grub执行完命令之后,重新启动系统。亲测:可以接收图片…

    2022年8月10日
    8
  • onedrive免费版容量_onedrive永久1t申请

    onedrive免费版容量_onedrive永久1t申请1、打开:http://get365.pw在右上角可以看到临时邮箱的地址复制地址朋友们记得保存地址是登录的账号,(获得临时邮箱地址之后不要关闭页面等下还要获取验证码)2、然后打开https://signup.microsoft.com/signup?sku=student输入临时邮箱地址3、填写信息验证码(验证码打开临时邮箱的页面查看,第一步打开的那个界面,下方可以查看接收到的邮

    2025年10月16日
    1
  • db2排序rownumber函数讨论[通俗易懂]

    db2排序rownumber函数讨论[通俗易懂] 在我的应用中使用了Rownumber函数,由于我的非正常理解造成了排序混乱。现在晒出来讨论。一、初识rownumberrownumber()函数允许开发人员动态地将行号指定给结果集。如果去掉row_next子句(ROW_NEXTBETWEEN?and?),那么将返回所有匹配选择标准的行。上面使用的SELECT*FROM子句可以看作一个临时表,里面存有匹配选

    2022年6月6日
    146
  • 其实就是为了能有字幕特效,用MeGUI + AVS压制PSP MP4AVC视频01 – 基础知识篇

    其实就是为了能有字幕特效,用MeGUI + AVS压制PSP MP4AVC视频01 – 基础知识篇A、需要准备的软件: .netframework2.0运行库(下面两个软件都是.net写的)MeGUI(AVS等软件的集合GUI)LiteMP4Tool(批处理AVS转换的GUI)通用解码器包,能够播放各类视频文件即可,包括K-LiteCodec、完美解码甚至暴风影音(这个不推荐)之类。avisynth2.58,这个我自己用的完美解码附…

    2022年10月16日
    1
  • 车载以太网之 DHCP协议「建议收藏」

    车载以太网之 DHCP协议「建议收藏」车载以太网与传统以太网的主要区别在于二者的物理层,前者的物理层采用一对双绞线的100BASE-T1,而后者的物理层采用两对双绞线的方式,比如100BASE-TX。而二层以上的协议栈,车载网络则基本借鉴传统网络,区别并不大。下图是基于车载以太网的车载网络所使用的各种通信协议,在这篇文章中我将简要介绍一下位于7层上的DHCP协议。车载以太网涉包含的各种协议DHCP的全称是DynamicHostConfigurationProtocol,翻译作动态主机配置协议。它的用途是为网络节点自动配置I

    2022年5月23日
    120

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注

关注全栈程序员社区公众号