Winform 串口通讯之地磅
Posted 阿轩的BLOG
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Winform 串口通讯之地磅相关的知识,希望对你有一定的参考价值。
继上次的读卡之后,要做一个地磅的读取。
下面是我在读卡Demo上改的读取地磅的。
地磅是一直向串口发送数据的,所以需要截取数据来一直判断数据是否合法,然后计算出结果。
其中遇到了一个小问题,文末有介绍。
本人初学菜鸟,大牛们有意见欢迎评论。
1 using System; 2 using System.Collections.Generic; 3 using System.ComponentModel; 4 using System.Data; 5 using System.Drawing; 6 using System.Linq; 7 using System.Text; 8 using System.Windows.Forms; 9 using System.IO.Ports; 10 using System.IO; 11 using System.Threading; 12 13 namespace WindowsFormsApplicationcs 14 { 15 public partial class FormMain : Form 16 { 17 //声明端口对象 18 SerialPort myport = null; 19 //处理数据的数据数组 20 byte[] buf = new byte[50]; 21 //声明委托类型 22 public delegate void Displaydelegate(byte[] buf); 23 //委托变量 24 public Displaydelegate disp_delegate; 25 26 public FormMain() 27 { 28 InitializeComponent(); 29 //安全线程外更新空间 30 //Form.CheckForIllegalCrossThreadCalls = false; 31 } 32 33 //窗口加载 34 private void FormMain_Load(object sender, EventArgs e) 35 { 36 Form.CheckForIllegalCrossThreadCalls = false; 37 txtPort.Text = "COM3"; 38 myport = new SerialPort(); 39 disp_delegate = new Displaydelegate(DispUI); 40 } 41 42 //打开串口按钮 43 private void button1_Click(object sender, EventArgs e) 44 { 45 try 46 { 47 48 //设置串口端口 49 myport.PortName = txtPort.Text.ToString(); 50 //设置比特率 51 myport.BaudRate = Convert.ToInt32(cmbBaud.Text); 52 //设置数据位 53 myport.DataBits = Convert.ToInt32(cmbBits.Text); 54 //设置停止位 55 switch (cmbStopBits.SelectedIndex) 56 { 57 case 0: myport.StopBits = StopBits.None; break; 58 case 1: myport.StopBits = StopBits.One; break; 59 case 2: myport.StopBits = StopBits.OnePointFive; break; 60 case 3: myport.StopBits = StopBits.Two; break; 61 } 62 63 //设置奇偶校验位 64 switch (cmbParity.SelectedIndex) 65 { 66 case 0: myport.Parity = Parity.Even; break; 67 case 1: myport.Parity = Parity.Mark; break; 68 case 2: myport.Parity = Parity.None; break; 69 case 3: myport.Parity = Parity.Odd; break; 70 case 4: myport.Parity = Parity.Space; break; 71 } 72 73 //缓冲区只接受一个字符 74 myport.ReceivedBytesThreshold = 1; 75 //接收事件添加委托 76 myport.DataReceived += new SerialDataReceivedEventHandler(this.myport_DataReceived); 77 //打开串口 78 myport.Open(); 79 if (myport.IsOpen) 80 { 81 MessageBox.Show("端口已打开"); 82 this.tstldqzt.Text = "当前状态:端口已打开"; 83 } 84 else 85 { 86 MessageBox.Show("端口未能打开!"); 87 } 88 } 89 catch (Exception ex) 90 { 91 MessageBox.Show("端口打开出现错误!\n" + ex.Message.ToString()); 92 } 93 } 94 95 //委托方法 96 //接收数据 97 private void myport_DataReceived(object sender, SerialDataReceivedEventArgs e) 98 { 99 Thread.Sleep(100); 100 if (myport.BytesToRead > 0)//如果缓冲区内有数据 101 { 102 myport.Read(buf, 0, 1);//从缓冲区读取数据到buf暂存数组, 103 } 104 105 if (buf[0] == 0x02)//如果开头等于2,则表明是信息开始 0x02 106 { 107 try 108 { 109 while (myport.BytesToRead == 9); 110 myport.Read(buf, 0, 9);//从缓冲区读取一条正确数据到buf暂存数组 111 string s = string.Empty; 112 113 for (int i = 0; i < 9; i++) 114 { 115 s += (char)buf[i]; 116 } 117 118 StringBuilder b = new StringBuilder(""); 119 120 if (s.Substring(0, 1) == "-") 121 b.Append("-"); 122 123 int strint = Convert.ToInt32(s.Substring(1,7)); 124 int dianint = Convert.ToInt32(s.Substring(8,1)); 125 126 switch (dianint) 127 { 128 case 1: strint = strint / 10; break; 129 case 2: strint = strint / 100; break; 130 case 3: strint = strint / 1000; break; 131 case 4: strint = strint / 10000; break; 132 } 133 b.Append(strint); 134 txtReceive.Text += "开始" + b + "结束\r\n"; 135 136 //this.Invoke(disp_delegate, buf); 137 } 138 finally 139 { 140 myport.DiscardInBuffer();//清空缓冲区 141 } 142 } 143 } 144 145 //更新ui方法 146 public void DispUI(byte[] buf) 147 { 148 149 } 150 151 152 //关闭方法 153 private void button2_Click(object sender, EventArgs e) 154 { 155 myport.Close(); 156 if (!myport.IsOpen) 157 { 158 this.tstldqzt.Text = "当前状态:端口已关闭"; 159 MessageBox.Show("端口已关闭"); 160 } 161 } 162 163 //清屏按钮 164 private void button3_Click(object sender, EventArgs e) 165 { 166 this.txtReceive.Clear(); 167 } 168 169 //菜单栏关于 170 private void tsmiabout_Click(object sender, EventArgs e) 171 { 172 frmAbout frmabout = new frmAbout(); 173 frmabout.ShowDialog(); 174 } 175 176 //菜单栏保存结果 177 private void tsmisave_Click(object sender, EventArgs e) 178 { 179 if (this.txtReceive.Text == "") 180 { MessageBox.Show("当前结果为空,请先测试"); } 181 string path = Directory.GetCurrentDirectory() + "\\端口测试结果.txt"; 182 File.WriteAllText(path, this.txtReceive.Text.ToString(), Encoding.ASCII); 183 } 184 185 } 186 }
这里其实有个问题,就是一个窗口一般会涉及到多个串口设备的通讯,
公司目前的需求也不例外,可以看到我使用了一个thread.sleep,
这样虽然当时解决了问题,但是当一个窗口有多个串口通讯更新ui的时候应该会出现问题,
但因为当时手头没有设备也没做进一步的测试,。
因为不加这句话就会无法实时更新ui,当时打了一个多小时的短点记了好多数据,
才确定了不是数据处理那部分的问题,思考一下原因应该是while把线程堵死了,一直在做运算。
但是使用invoke不是新开线程委托吗?为什么也是更新不了ui。
百度了发现如下解释
invoke是在拥有此控件的基础窗口句柄的线程上指定指定的委托
begininvoke是在创建此控件的基础窗口句柄的线程上异步执行指定的委托
使用begininvoke应该就可以不干扰其他的串口通讯更新ui了
以上是关于Winform 串口通讯之地磅的主要内容,如果未能解决你的问题,请参考以下文章