C#学习笔记 , 好记性不如烂笔头 (自己用的,请无视我)
串口号获取方法:
private void Form1_Load(object sender, EventArgs e)
{
string[] str;//定义一个字符型数组
str = System.IO.Ports.SerialPort.GetPortNames();//获取系统串口号数组
comboBox1.Items.AddRange(System.IO.Ports.SerialPort.GetPortNames());
//分别添加到下拉菜单中
if (str.Length != 0)//若数组长度不为0
comboBox1.Text = str;//将数组第一个数据送给下拉框text显示
else comboBox1.Text = "";//否则空着
}
9 个回复
admin
赞同来自:
uint16 com_open;
private void button1_Click(object sender, EventArgs e)
{
try
{
if (com_open == 1)
{
serialPort1.Close();
button1.Text = "开启";
com_open = 0;
return;
}
serialPort1.PortName = comboBox1.Text;
serialPort1.BaudRate = Convert.ToInt32(comboBox2.Text);
serialPort1.Open();
button1.Text = "关闭";
com_open = 1;
}
catch
{
if (com_open == 1)
MessageBox.Show("关闭失败!", "警告");
else
MessageBox.Show("开启失败", "警告");
}
}
如果发送的有中文字符,
则需要在打开串口之前设置字符集
serialPort1.PortName = comboBox1.Text;
serialPort1.BaudRate = Convert.ToInt32(comboBox2.Text);
serialPort1.Encoding = System.Text.Encoding.GetEncoding("gb2312");
serialPort1.Open();
以下再记录一个代码:转Unicode格式
admin
赞同来自:
这个里面有个问题,假如将下面的代码中的最后一句改成
textBox2.AppendText(str);
不使用delegate继承的话,会报错
:线程间操作无效: 从不是创建控件“textBox2”的线程访问它。
说明串口处理事件是在其他线程进行的,直接在串口事件里面直接调用TEXtbox显示
是不行的,TEXTbox用的事主线程,
可以取消线程间检查:
System.Windows.Forms.Control.CheckForIllegalCrossThreadCalls = false;
也可以将串口事件中的TEXTbox定义为继承即可.
如下:
注意:我把原来最后一句中的Invoke改成了BeginInvoke,前面一个是在拥有此控件的基础窗口句柄的线程上执行指定的委托。后面一个是:在创建控件的基础句柄所在线程上异步执行指定委托。
两者的区别去看下面额文章:
http://www.cnblogs.com/mashang ... .html
admin
赞同来自:
官网说明地址:
https://msdn.microsoft.com/zh- ... .aspx
貌似可以代替Thread线程操作.
里面包含了三个Callback
backgroundWorker1_DoWork() //调用 RunWorkerAsync 时发生
backgroundWorker1_ProgressChanged() //调用 ReportProgress 时发生。
backgroundWorker1_RunWorkerCompleted() //当后台操作已完成、被取消或引发异常时发生
根据官方第一个例子:
我自己添加了个ctime记录按键按下次数
private void startAsyncButton_Click(object sender, EventArgs e)
{
//ctime++;
if (backgroundWorker1.IsBusy != true)
{
ctime++;
// Start the asynchronous operation.
backgroundWorker1.RunWorkerAsync();//开启线程
}
label1.Text = ctime.ToString ();
}
可以看出,为了不在BW启动后运行过程中被再次开启导致出错,所以粗体部分很重要
这样就算你在开启后运行中再次点击按钮,开启操作是不会再次执行的,因为此时
backgroundWorker1.IsBusy = busy
看下面的:
private void cancelAsyncButton_Click(object sender, EventArgs e)
{
if (backgroundWorker1.WorkerSupportsCancellation == true)
{
// Cancel the asynchronous operation.
backgroundWorker1.CancelAsync();//取消线程
}
}
其实判断backgroundWorker1.WorkerSupportsCancellation == true这个完全没有必要,因为我们确实开启了,可以删掉..
继续看:
private void backgroundWorker1_DoWork/b
{
[b]BackgroundWorker worker = sender as BackgroundWorker;
for (int i = 1; i <= 10; i++)
{
if (worker.CancellationPending == true)
{
e.Cancel = true;
break;
}
else
{
// Perform a time consuming operation and report progress.
System.Threading.Thread.Sleep(500);
//这个应该就是sleep了吧?和VC有啥区别?线程延时休眠500ms???
//貌似是将当前线程休眠........就是这个BW线程?
//休眠的时间可以用于让其他线程完成当前工作,亦可以减少CPU占用时间
worker.ReportProgress(i * 10);
}
}
}
这个是DoWork的事件,注意后面的 e,后面会用到
这个线程的任务是产生一个过程量
admin
赞同来自: L
private void backgroundWorker1_ProgressChanged/b
{
resultLabel.Text = ([b]e.ProgressPercentage.ToString() + "%");
}
注意到粗体部分,意思是获取异步任务的进度百分比,这个百分比来自上面的
worker.ReportProgress(i * 10);传递来的....
紧接着事件处理完成事件触发了
private void backgroundWorker1_RunWorkerCompleted/b
{
if (e.Cancelled == true)
{
resultLabel.Text = "Canceled!";
}
else if (e.Error != null)
{
resultLabel.Text = "Error: " + e.Error.Message;
}
else
{
resultLabel.Text = "Done!";
}
}
完成函数尽量要这样写,要判断是自主取消还是错误导致,或者是事件完成了.
这里还有一个要重点知道的 resultLabel.Text = [b]e.Result.ToString();
表示获取异步操作结果的值.....
admin
赞同来自: L
比如:开启函数可以这样
backgroundWorker1.RunWorkerAsync(test);//开启线程
但是其中test只能有一个,即参数只能是一个!
如果想传递多个参数,那么可以将test封装成结构体或者object,例如
先定义一个类:
然后全局初始化一下:
然后初始化开启BW的时候,用
}
这样多个参数就传递过去了.
应用的时候这样用:
也可以这样用来传递两个参数到ReportProgress
worker.ReportProgress(str.onevalue,str.twovalue );
如果这样到时候获取就用
label1.Text = e.ProgressPercentage.ToString ()+e.UserState .ToString() ;
本来是:一个作为进度量,一个作为状态量的,现在都用来传递参数了.
最后: 完成事件里面用backgroundWorker1.Dispose();来释放资源
admin
赞同来自:
比如 AD采集了8个通道的数据,那么应该怎么在采集完成后返回这些数据呢?
显然用ReportProgress不行,必须使用完成事件了,
完成事件同样可以将这个参数封装成一个结构体来用.
如下;
封装还是如楼上那样
public class Testobj
{
public int onevalue { get; set; }
public int twovalue { get; set; }
}
在Dowork声明,例如
Testobj ccstr = new Testobj { };//注意必须这样写
然后可以将采集的AD分别赋给这些变量,最后将这个变量提交给 e.Result 如:
ccstr.onevalue = 88;
ccstr.twovalue = 55;
e.Result = ccstr;
最后一个就是当BW完成后,调用完成事件,会自动将上面的参数传递
private void backgroundWorker1_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
{
Testobj ctest = e.Result as Testobj;//必须有这个
if (e.Error != null)
label1.Text = e.Error.Message;
else if (e.Cancelled == true)
label1.Text = "user cancel.";
else label1.Text = ctest.onevalue.ToString() + ctest.twovalue.ToString();
backgroundWorker1.Dispose();
}
ok,结果可以取出了.........
admin
赞同来自:
无语用分析
赞同来自: L
admin
赞同来自: L
上面的是先显示Control returned to startButton_Click.然后才慢慢逐条的显示采集到的数据长度