赞
踩
假设现在我们要实现这样一个功能:我们需要让电机某轴(或几轴)循环往复运动,并每次循环获取电机运动结束位置,记录到csv文件中,每个循环结束后(即到达起点),我们要在textBox上写入循环次数。
我们有toPoint(axis,point,velocity),waitMotorEnd(axis,timeout);getMotorPos(axis),
killMotor(axis)
一. 第一种方法是添加一个Timer控件,设置Interval间隔,添加tick事件,在这个事件中编程和调用其他函数,用两个按钮和几个变量控制tick是否开启和关闭。
点评:这种方法简单易行,它可以访问任何控件,但是主线程已经有一个timer控件实时读取电机位置并显示出来,导致主界面在电机运动期间是卡死状态,包括最小化等界面图标均无法选中,因为这个timer控件本质上是主线程上的
二. 通过 system.Timers使用系统timer,这种方法不用在界面上拖拽控件,相应的需要在代码中设置属性。
首先我们先考虑主循环的事件处理,然后再考虑主线程控件调用问题,因为是线程安全的,这个线程是不能直接读取主线程中的控件,需要启用委托。
代码简单如下,仔细弄明白以便在自己的代码中进行移植。
- using Systems.Timers;
- using System.Threading;
- namespace demo_np
- {
- public partial class MainForm : Form
- {
- private int count_cycle=0; //循环次数要填入textBox中,全局变量。
- private string path = @"D:\MOTOR_CSV\info.csv";//写入csv的目录,文件在代码中建立。
-
- public MainForm()
- {
- InitializeComponent();
- }
-
- private void Form1_Load(object sender, EventArgs e)
- {
- InitTimer(); //这个是我们设置的timer属性初始化函数。
- }
-
- System.Timers.Timer timer;//实例化一个计时器
-
- private void InitTimer()
- {
- //设置定时间隔,本例较大,因为太小的话代码执行太快,电机还没动起来导致程序总是认为你电机已经循环过。
- int interval = 2000;
- timer = new System.Timers.Timer(interval);
- //设置执行一次(false)还是一直执行(true)
- timer.AutoReset = true;
- timer.Enabled = false;
- //绑定Elapsed事件,让计时器能够不断执行这个TimerCycle事件
- timer.Elapsed += new System.Timers.ElapsedEventHandler(TimerCycle);
- }
-
- private void TimerCycle(object sender, System.Timers.ElapsedEventArgs e)
- {
- try
- {
- timer.Enabled = false;//这里先关闭计时器,事件结尾再打开
- int timeout = 1000000;
- waitMotorEnd(0,timeout);代表0轴
- write_csv();
- toPoint(0,100.0f);
- toPoint(0,0.0f);//代表一个往复循环
- count_cycle = (count_cycle + 1) % 1000000;
- //text_count.Text=count_cycle.ToString();非法调用主线程控件。
- timer.Enabled = true;
-
- }
- catch(Exception ex)
- {
- MessageBox.Show(ex.Message, "ERROR", MessageBoxButtons.OK, MessageBoxIcon.Error);
- System.Diagnostics.Debug.WriteLine(ex.Message);
- }
- //接下来是按钮控制开关及写入csv方法
- private void btnCycleStart_Click(object sender, EventArgs e)
- {
- count_cycle=0;
- timer.Enabled = true;
- if (!File.Exists(path))
- File.Create(path).Close();//创建csv文件。
- }
- private void button10_Click(object sender, EventArgs e)
- {
- killMotor(0);
- timer.Enabled = false;
- }
- private void write_csv()
- {
- StreamWriter sw = new StreamWriter(path, true, Encoding.UTF8);
- sw.Write("\r\n");
- sw.Write(String.Format("{0:0.0000}", getMotorPos(0) + ",");
- sw.Write(String.Format("{0:0.0000}", getMotorPos(0)) + ",");
- sw.Flush();
- sw.Close();
- }
- }
- }
上述代码非法调用控件,接下来通过委托实现访问,注意和上面代码对照需要加到哪里?
- delegate void text_countDelegate();
- private void text_count()
- {
- this.text_count.Text = cycle_count.ToString();
- }
-
- //这里只是定义了这个委托,名字叫text_countDelegate,既没有运行也没有和咱们这个textcount事件联系起来,那怎么办呢?
textBox4.Invoke((txb4countDelegate)txb4count);
我们需要将这行代码加到TimerCycle非法调用那里,就可以成功访问啦
上面这种多线程访问控件的方法好处是可以选择加参数,但是这个例子中并没有参数传递,c#给了我们这样一种方法,MethodInvoker,表示一个委托,该委托可以执行托管代码中(声明为void且不接受任何参数的)任何方法!
- this.Invoke((MethodInvoker)delegate
- {
- textCount.Text=cycle_count.ToString();
- }
欢迎任何评论,有不当的地方欢迎提出来,共同交流共同进步!
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。