串口通信--控制舵机运动_.NET_编程开发_程序员俱乐部

中国优秀的程序员网站程序员频道CXYCLUB技术地图
热搜:
更多>>
 
您所在的位置: 程序员俱乐部 > 编程开发 > .NET > 串口通信--控制舵机运动

串口通信--控制舵机运动

 2014/4/25 16:18:44  ZhongJieKing  博客园  我要评论(0)
  • 摘要:界面部分使用krytonToolKit开发,整个软件实现了串口通信,并且控制四个自由度的舵机运动。整个软件使用多线程开发,采集舵机指令保存到TXT文档中,然后调用TXT文档再现舵机运动过程,软件界面如下:优化之后的界面如下:usingSystem;usingSystem.Collections.Generic;usingSystem.ComponentModel;usingSystem.Data;usingSystem.Drawing;usingSystem.Linq;usingSystem
  • 标签:

界面部分使用krytonToolKit开发,整个软件实现了串口通信,并且控制四个自由度的舵机运动。

整个软件使用多线程开发,采集舵机指令保存到TXT文档中,然后调用TXT文档再现舵机运动过程,软件界面如下:


优化之后的界面 如下:



using System; using System.Collections.Generic; using System.ComponentModel; using System.Data; using System.Drawing; using System.Linq; using System.Text; using System.IO.Ports; using System.Windows.Forms; using System.Text.RegularExpressions; using System.Threading; using System.IO; //DotNetMagic using Crownwood.DotNetMagic; using Crownwood.DotNetMagic.Common; using Crownwood.DotNetMagic.Controls; using Crownwood.DotNetMagic.Docking; using Crownwood.DotNetMagic.Forms; using System.Runtime.InteropServices; using System.Collections;   namespace ComAssistant {     public partial class ComAssistantForm : DotNetMagicForm     {         private int received_count = 0;//接收计数           private long send_count = 0;//发送计数         private bool Listening = false;//是否没有执行完invoke相关操作           //private bool Closing = false;//是否正在关闭串口,执行Application.DoEvents,并阻止再次invoke           private bool Closing = false;//是否正在关闭串口,执行Application.DoEvents,并阻止再次invoke           private bool Query = false;//查询状态          private List<byte> buffer = new List<byte>(4096);//默认分配1页内存,并始终限制不允许超过           private byte[] binary_data_1 = new byte[10];//FF FF 01 06 00 B1 0A 00 00 3D          List<Array> dataList = new List<Array>();  //数据再现         string FILE_INFO_NAME = "FileInfo.txt";         private bool kaiguan = true;         private bool openClose = true;             string strShow = "";           public ComAssistantForm()         {             InitializeComponent();         }           private void serialPort1_DataReceived(object sender, SerialDataReceivedEventArgs e)         {             //返回指令格式:FF FF 01 06 00 B1 0A 00 00 3D   ,   其中B1 0A为ID为1的舵机当前位置,00 00为其当前速度             // 第2位是舵机,5、6位是位置,7、8位为速度               if (Closing) return;//如果正在关闭,忽略操作,直接返回,尽快的完成串口监听线程的一次循环             try             {                 Listening = true;//设置标记,说明我已经开始处理数据,一会儿要使用系统UI的。                 int n = serialPort1.BytesToRead;//先记录下来,避免某种原因,人为的原因,操作几次之间时间长,缓存不一致                 byte[] buf = new byte[n];//声明一个临时数组存储当前来的串口数据                 serialPort1.Read(buf, 0, n);//读取缓冲数据                   /////////////////////////////////////////////////////////////////////////////////////////////////////////////                 //<协议解析>                 //1.缓存数据                 buffer.AddRange(buf);                 //2.完整性判断                 while (buffer.Count >= 10)//至少要包含头(2字节)+长度(7字节)+校验(1字节)                 {                     if (buffer[0] == 0xFF && buffer[1] == 0xFF && buffer[2] == 0xFF)                     {                         buffer.RemoveRange(0, 10);//从缓存中移除数据。                         continue;                     }                           //2.1 查找数据头                         if (buffer[0] == 0xFF && buffer[1] == 0xFF&& buffer[2] != 0xFF)                         {                             received_count++;                             //至此,已经被找到了一条完整数据。我们将数据直接分析,或是缓存起来一起分析                             buffer.CopyTo(0, binary_data_1, 0, 9);//复制一条完整数据到具体的数据缓存                             //3.分析数据                               //根据舵机编号分类并存入TXT文件                             string zhuanbian = binary_data_1[7].ToString("X2");                             if (zhuanbian == "00")                             {                                 zhuanbian = "01";                             }                               //我们的数据都是定好格式的,所以当我们找到分析出的数据1,就知道固定位置一定是这些数据,我们只要显示就可以了                             string data = binary_data_1[2].ToString("X2") + " " +                                 binary_data_1[5].ToString("X2") + " " + binary_data_1[6].ToString("X2") + " " +                                 zhuanbian + " " + binary_data_1[8].ToString("X2");                               //更新界面                             this.Invoke((EventHandler)(delegate                             {                                 kryptonRichTextBox1.Text += data + "**";                                 WriteFile(data);                               }));                             if (received_count == 4)                             {                                 WriteFileLine();                                 received_count = 0;                                 //更新界面                                 this.Invoke((EventHandler)(delegate                                 {                                     kryptonRichTextBox1.Text += "\r\n";                                 }));                             }                             buffer.RemoveRange(0, 10);//正确分析一条数据,从缓存中移除数据。                         }                         else                         {                             //这里是很重要的,如果数据开始不是头,则删除数据                             buffer.RemoveAt(0);                         }                 }             }             catch (Exception)             {                   MessageBox.Show("串口接收数据出错,请查看串口接收指令!", "软件提醒", MessageBoxButtons.OKCancel, MessageBoxIcon.Error);             }             finally             {                 Listening = false;//我用完了,ui可以关闭串口了。             }         }           //初始化         private void ComAssistantForm_Load(object sender, EventArgs e)         {             int ii = 0;             foreach (string s in SerialPort.GetPortNames())             {                 if (ii >= 1)                 {                     ktComboBoxCom.Items.Add(s);                 }                 ii++;             }               if (SerialPort.GetPortNames().Length != 0)             {                 ktComboBoxCom.Text = (string)ktComboBoxCom.Items[0];             }               //string[] strCom = new string[] { "COM1", "COM2", "COM3", "COM4" };             //ktComboBoxCom.DataSource = strCom;                 string[] ss = new string[] {"2000000" , "9600", "19200", "57600" };             ktComboBoxBount.DataSource = ss;               ktComboBoxJiaoyan.DataSource = Enum.GetNames(typeof(Parity));               ss = new string[] { "5", "6", "7", "8" };             ktComboBoxData.DataSource = ss;             ktComboBoxData.Text = "8";               ktComboBoxStop.DataSource = Enum.GetNames(typeof(StopBits));             ktComboBoxStop.Text = Enum.Format(typeof(StopBits), StopBits.One, "G");             kryptonTextBox1.Text = "FF FF 04 04 03 18 00 DC";               try             {                 if (!serialPort1.IsOpen)                 {                     serialPort1.PortName = ktComboBoxCom.Text;                     serialPort1.BaudRate = Convert.ToInt32(ktComboBoxBount.Text);                     serialPort1.Parity = (Parity)Enum.Parse(typeof(Parity), ktComboBoxJiaoyan.Text);                     serialPort1.DataBits = Int32.Parse(ktComboBoxData.Text);                     serialPort1.StopBits = (StopBits)Enum.Parse(typeof(StopBits), ktComboBoxStop.Text);                     serialPort1.Encoding = Encoding.GetEncoding("Gb2312");                     serialPort1.Open();                     pictureBox1.Image = Image.FromFile(Application.StartupPath + "\\kai.jpg");                 }             }             catch (Exception)             {                   MessageBox.Show("初始化出问题,请检查串口设备", "软件提醒", MessageBoxButtons.OKCancel, MessageBoxIcon.Error);             }         }           //连接串口         private void ktBtnLink_Click(object sender, EventArgs e)         {             try             {                 if (!serialPort1.IsOpen)                 {                     serialPort1.PortName = ktComboBoxCom.Text;                     serialPort1.BaudRate = Convert.ToInt32(ktComboBoxBount.Text);                     serialPort1.Parity = (Parity)Enum.Parse(typeof(Parity), ktComboBoxJiaoyan.Text);                     serialPort1.DataBits = Int32.Parse(ktComboBoxData.Text);                     serialPort1.StopBits = (StopBits)Enum.Parse(typeof(StopBits), ktComboBoxStop.Text);                     serialPort1.Encoding = Encoding.GetEncoding("Gb2312");                     serialPort1.Open();                     pictureBox1.Image = Image.FromFile(Application.StartupPath + "\\kai.jpg");                 }             }             catch (Exception)             {                   MessageBox.Show("初始化出问题,请检查串口设备", "软件提醒", MessageBoxButtons.OKCancel, MessageBoxIcon.Error);             }         }           //关闭串口         private void ktBtnClose_Click(object sender, EventArgs e)         {             try             {                 if (serialPort1.IsOpen)                 {                     Closing = true;                     while (Listening) Application.DoEvents();                     serialPort1.Close();                     pictureBox1.Image = Image.FromFile(Application.StartupPath + "\\guan.jpg");                     //打开时点击,则关闭串口                       Closing = false;                 }             }             catch (System.Exception ex)             {                 MessageBox.Show("串口关闭出错,请检查串口连接!", "软件提醒", MessageBoxButtons.OKCancel, MessageBoxIcon.Exclamation);             }         }           //发送数据         private void ktBtnSend_Click(object sender, EventArgs e)         {             if (!serialPort1.IsOpen)             {                 MessageBox.Show("请打开串口!", "软件提醒", MessageBoxButtons.OKCancel, MessageBoxIcon.Exclamation);             }             else             {                 string content = kryptonTextBox1.Text;                 byte[] bytes = MyClass.StringToHex(content);                 serialPort1.Write(bytes, 0, bytes.Length);             }         }           //接收数据         private void ktBtnAccept_Click(object sender, EventArgs e)         {             //Closing = false;               int n = serialPort1.BytesToRead;             byte[] dbs = new byte[n];             int len = serialPort1.Read(dbs, 0, n);             int[] num = new int[len];               string show = "";             show = MyClass.byteToHexStr(dbs);             kryptonRichTextBox1.Text += show;         }           //清空数据         private void ktBtnClear_Click(object sender, EventArgs e)         {             strShow = "";             kryptonRichTextBox1.Text = "";         }           //急停指令         private void ktBtnStop_Click(object sender, EventArgs e)         {             try             {                 if (serialPort1.IsOpen)                 {                     Closing = true;                     while (Listening) Application.DoEvents();                     serialPort1.Close();                     pictureBox1.Image = Image.FromFile(Application.StartupPath + "\\guan.jpg");                     //打开时点击,则关闭串口                       Closing = false;                 }             }             catch (System.Exception ex)             {                 MessageBox.Show("串口紧急关闭!", "软件提醒", MessageBoxButtons.OKCancel, MessageBoxIcon.Exclamation);             }         }           //查询舵机状态         private void ktBtnQuery_Click(object sender, EventArgs e)         {               try             {                 FileStream stream2 = File.Open(FILE_INFO_NAME, FileMode.OpenOrCreate, FileAccess.Write);                 stream2.Seek(0, SeekOrigin.Begin);                 stream2.SetLength(0); //清空txt文件                 stream2.Close();             }             catch (System.Exception ex)             {                         }             finally             {                 MessageBox.Show("缓存数据已经清空!", "软件提醒", MessageBoxButtons.OKCancel, MessageBoxIcon.Exclamation);             }                 //if (!Query)             //{             //    ktBtnQuery.Text = "停止查询舵机";             //    Query = true;               //    if (!serialPort1.IsOpen)             //    {             //        MessageBox.Show("请打开串口!", "软件提醒", MessageBoxButtons.OKCancel, MessageBoxIcon.Exclamation);             //    }             //    else             //    {             //        for (int i = 0; i < 10; i++)             //        {             //            //这是舵机返回指令,发送指令没有加入             //            //舵机1             //            byte[] bytes = MyClass.StringToHex("FF FF 01 06 00 B1 0A 01 01 3D");             //            serialPort1.Write(bytes, 0, bytes.Length);               //            //舵机2             //            bytes = MyClass.StringToHex("FF FF 02 06 00 B1 0A 02 02 3D");             //            serialPort1.Write(bytes, 0, bytes.Length);               //            //舵机3             //            bytes = MyClass.StringToHex("FF FF 03 06 00 B1 03 03 03 3D");             //            serialPort1.Write(bytes, 0, bytes.Length);               //            //舵机4             //            bytes = MyClass.StringToHex("FF FF 04 06 00 B1 04 04 04 3D");             //            serialPort1.Write(bytes, 0, bytes.Length);             //            //Thread.Sleep(5000);               //        }               //    }               //}             //else             //{             //    ktBtnQuery.Text = "查询舵机状态";             //    Query = false;             //}         }           /// <summary>         /// 写入舵机位置速度信息         /// </summary>         private void WriteFile(string input)         {             using (StreamWriter sw = File.AppendText("FileInfo.txt"))             {                 sw.Write(input + " ** ");             }               ///文件目录             //FileStream fs = new FileStream("FileInfo.txt", FileMode.Create);             //StreamWriter sw = new StreamWriter(fs);             //sw.WriteLine(input + "\n");             ////清空缓冲区             //sw.Flush();             ////关闭流             //sw.Close();             //fs.Close();             ///写入内容并换行         }           /// <summary>         /// 换行         /// </summary>         private void WriteFileLine()         {             using (StreamWriter sw = File.AppendText(FILE_INFO_NAME))             {                 sw.WriteLine();             }         }                       //采集指令         private void ktBtnCollection_Click(object sender, EventArgs e)         {             if (kaiguan)             {                  Closing = false;                 //这里创建一个线程,使之执行Alpha类的Beta()方法                 Thread newThread = new Thread(new ThreadStart(caijiThread));                 newThread.Start();                 ktBtnCollection.Text = "停  止";                 kaiguan = false;               }             else             {                 kaiguan = true;                 ktBtnCollection.Text = "采  集";               }         }           //创建采集新线程         public void caijiThread()         {             if (!serialPort1.IsOpen)             {                 MessageBox.Show("请打开串口!", "软件提醒", MessageBoxButtons.OKCancel, MessageBoxIcon.Exclamation);             }             else             {                 try                 {                       while (true)                     {                         if (kaiguan == true)                         {                             break;                         }                           //采集[指令固定]                         byte[] bytes = MyClass.StringToHex("FF FF FE 14 83 18 01 01 00 02 00 03 00 04 00 05 00 06 00 07 00 08 00 2D");                         serialPort1.Write(bytes, 0, bytes.Length);                           //舵机01的指令FF FF 01 04 02 24 04 D0                         byte checksum = 0;                         for (int QueryNum = 1; QueryNum < 5; QueryNum++)                         {                             //求校验和,方法一                             checksum = ((byte)(QueryNum + 0X04 + 0X02 + 0X24 + 0X04));                             byte[] ab = new byte[1];                             ab[0] = (byte)~(0xff & checksum);                             string mySum = MyClass.byteToHexStr(ab);                               //////求校验和,方法二                             //byte[] tempab = new byte[] { 0X01, 0X04, 0X02, 0X24, 0X04 };                             //byte strab = MyClass.CheckSum(tempab);                               byte[] bytesCaiji = MyClass.StringToHex("FF FF " + QueryNum.ToString("X2") + " 04 02 24 04 " + mySum.Trim());                             serialPort1.Write(bytesCaiji, 0, bytesCaiji.Length);                             Thread.Sleep(1 / 50);                         }                         Thread.Sleep(50);                     }                 }                 catch (System.Exception ex)                 {                     MessageBox.Show("采集过程中出错!", "软件提醒", MessageBoxButtons.OKCancel, MessageBoxIcon.Exclamation);                                 }             }         }             //再现过程         private void ktBtnAgain_Click(object sender, EventArgs e)         {             if (openClose)             {                 //这里创建一个线程,使之执行Alpha类的Beta()方法                 Thread newThread = new Thread(new ThreadStart(zaixianThread));                 newThread.Start();                 ktBtnAgain.Text = "执行中 • • •";                 openClose = false;               }             else             {                 openClose = true;                 ktBtnAgain.Text = "再  现";               }           }             //创建再现新线程         public void zaixianThread()         {             if (!serialPort1.IsOpen)             {                 MessageBox.Show("请打开串口!", "软件提醒", MessageBoxButtons.OKCancel, MessageBoxIcon.Exclamation);             }             else             {                 try                 {                     //获取数据                     dataList = ReadFile();                       //FF FF FE 18 83 1E 04 01 00 00 11 11 02 22 22 33 33 03 44 44 55 55 04 66 66 77 99 18                      foreach (Array ar in dataList) //获取一条四个舵机数据                     {                           string zuhe = "";                         byte[] xiafa = new byte[28];                         foreach (string str in ar)   //获取一个舵机数据                         {                             zuhe += str.Trim() + " ";                         }                         string hh = zuhe.Trim();                         byte[] temp = MyClass.StringToHex(hh);                           byte[] tempOne = new byte[26];                         for (int i = 0; i < 20; i++)                         {                             xiafa[i + 7] = temp[i];                         }                         xiafa[0] = 0XFF;                         xiafa[1] = 0XFF;                         xiafa[2] = 0XFE;                         xiafa[3] = 0X18;                         xiafa[4] = 0X83;                         xiafa[5] = 0X1E;                         xiafa[6] = 0X04;                           Array.Copy(xiafa, 2, tempOne, 0, 26);//复制数组                         xiafa[27] = MyClass.CheckSum(tempOne);                         serialPort1.Write(xiafa, 0, xiafa.Length);                         Thread.Sleep(65);                     }                     if (openClose == false)                     {                         openClose = true;                         ktBtnAgain.Text = "再  现";                     }                 }                 catch (System.Exception ex)                 {                     MessageBox.Show("串口紧急关闭!", "软件提醒", MessageBoxButtons.OKCancel, MessageBoxIcon.Exclamation);                 }                 }         }           //读取文件         private List<Array> ReadFile()         {             List<Array> myArray = new List<Array>();             if (File.Exists(FILE_INFO_NAME))             {                 FileStream myFile = new FileStream(FILE_INFO_NAME, FileMode.Open, FileAccess.Read);                           using (StreamReader sr = new StreamReader(FILE_INFO_NAME, UnicodeEncoding.GetEncoding("GB2312")))                 {                     string Line = null;                     string[] duoji = new string[4];  //存储一条数据                      for (Line = sr.ReadLine(); Line != null; Line = sr.ReadLine())                     {                         if (!(Line.Trim() == ""))                         {                             duoji = Line.Trim().Split(new string[] { "**" }, StringSplitOptions.RemoveEmptyEntries);                             myArray.Add(duoji);                         }                     }                   }             }             return myArray;             #region             //备份读取文件的执行过程                 //using (StreamReader sr = new StreamReader(FILE_INFO_NAME, UnicodeEncoding.GetEncoding("GB2312")))                 //{                 //    string Line = null;                 //    string[] duoji = new string[4];  //存储一条数据                  //    for (Line = sr.ReadLine(); Line != null; Line = sr.ReadLine())                 //    {                 //        if (!(Line.Trim() == ""))                 //        {                 //            duoji = Line.Trim().Split(new string[] { "**" }, StringSplitOptions.RemoveEmptyEntries);                 //            myArray.Add(duoji);                 //        }                 //    }                   //}                     //使用每次读取固定长度的字节,遇到 问题是加车符号的处理                 //int FileSize = 172;                   //if (FileSize < myFile.Length)                 //{                 //    byte[] buffer = new byte[FileSize];                 //    int copy = 0;                 //    string[] duoji = new string[4];  //存储一条数据                  //    string temp1;                 //    ArrayList myAL = new ArrayList();                   //    while (copy <= myFile.Length)                 //    {                 //        myFile.Read(buffer, 0, FileSize);                 //        myFile.Flush();                 //        copy += FileSize;                 //        myFile.Position = copy;                 //        temp1 = System.Text.Encoding.Default.GetString(buffer);                 //        //myAL = MyClass.Str16ToArrayList(temp1);                 //        //duoji = MyClass.byteToHexStr(buffer).Trim().Split(new string[] { "**" }, StringSplitOptions.RemoveEmptyEntries);                 //        string jiequ = temp1.Replace("\r\n", "");                 //        duoji = jiequ.Trim().Split(new string[] { "**" }, StringSplitOptions.RemoveEmptyEntries);                 //        myArray.Add(duoji);                 //    }             //}             #endregion         }             //复位选择         private void ktBtnFuwei_Click(object sender, EventArgs e)         {             if (!serialPort1.IsOpen)             {                 MessageBox.Show("请打开串口!", "软件提醒", MessageBoxButtons.OKCancel, MessageBoxIcon.Exclamation);             }             else             {                 Closing = true;                 byte[] bytes = MyClass.StringToHex("FF FF FE 18 83 1E 04 01 00 08 0A 00 02 00 08 0A 00 03 00 08 0A 00 04 00 08 0A 00 F2");                 serialPort1.Write(bytes, 0, bytes.Length);             }         }     } }
********************************************************************************************************************************************************
 using System; using System.Collections.Generic; using System.Text; using System.Windows.Forms; using System.Collections; namespace System {     class MyClass     {         public MyClass()         {         }           /// <summary>         /// 字符串转16进制字节数组         /// </summary>         /// <param name="hexString"></param>         /// <returns></returns>         public static byte[] StringToHex(string str)         {             string[] strs = str.Split(' ');             byte[] bytes = new byte[strs.Length];             int index = 0;             foreach (string s in strs)             {                 int hex = Convert.ToInt32(s, 16);                 bytes[index++] = (byte)hex;             }             return bytes;         }           /// <summary>         /// 字节数组转16进制字符串         /// </summary>         /// <param name="bytes"></param>         /// <returns></returns>         public static string byteToHexStr(byte[] bytes)         {             string returnStr = "";             if (bytes != null)             {                 for (int i = 0; i < bytes.Length; i++)                 {                     //ToString("X2") 为C#中的字符串格式控制符                     //假设有两个数10和26,正常情况十六进制显示0xA、0x1A,这样看起来不整齐,为了好看,可以指定"X2",这样显示出来就是:0x0A、0x1A。                     returnStr += bytes[i].ToString("X2");                     returnStr += " ";                 }             }             return returnStr;         }           public static byte CheckSum(byte[] temp)         {             byte sum;             byte jia=0X00;             for (int i = 0; i < temp.Length;i++ )             {                 jia += temp[i];             }             sum= (byte)~(0xff & jia);             return sum;         }           public static ArrayList Str16ToArrayList(string strIn)         {             string sParse = "";             ArrayList myAL = new ArrayList();               int i = 0;             foreach (char cc in strIn)             {                 i++;                 if (cc == ' ' || sParse.Length == 2)                 {                     myAL.Add(sParse);                     if (sParse.Length == 2 && cc != ' ')                     {                         sParse = Convert.ToString(cc);                     }                     else                     {                         sParse = "";                     }                 }                 else                 {                     sParse += Convert.ToString(cc);                     if (i == strIn.Length && cc != ' ')                     {                         myAL.Add(sParse);                     }                 }             }             return myAL;         }         }   } ******************************************************************************************************************************************************** 



第一次软件界面:





软件由主程序 和myClass类两部分组成,其中myClass 类主要处理字符与字节之间转换及求取校验位。

主程序:

using System; using System.Collections.Generic; using System.ComponentModel; using System.Data; using System.Drawing; using System.Linq; using System.Text; using System.IO.Ports; using System.Windows.Forms; using System.Text.RegularExpressions; using System.Threading; using System.IO; //DotNetMagic using Crownwood.DotNetMagic; using Crownwood.DotNetMagic.Common; using Crownwood.DotNetMagic.Controls; using Crownwood.DotNetMagic.Docking; using Crownwood.DotNetMagic.Forms; using System.Runtime.InteropServices;   namespace ComAssistant {     public partial class ComAssistantForm : DotNetMagicForm     {         private StringBuilder builder = new StringBuilder();//避免在事件处理方法中反复的创建,定义到外面。           private int received_count = 0;//接收计数           private long send_count = 0;//发送计数         private bool Listening = false;//是否没有执行完invoke相关操作           private bool Closing = false;//是否正在关闭串口,执行Application.DoEvents,并阻止再次invoke           private bool Query = false;//查询状态          private List<byte> buffer = new List<byte>(4096);//默认分配1页内存,并始终限制不允许超过           private byte[] binary_data_1 = new byte[10];//FF FF 01 06 00 B1 0A 00 00 3D          List<Array> dataList = new List<Array>();  //数据再现         string FILE_INFO_NAME = "FileInfo.txt";         private bool kaiguan = true;         private bool openClose = true;             string strShow = "";           public ComAssistantForm()         {             InitializeComponent();         }           private void serialPort1_DataReceived(object sender, SerialDataReceivedEventArgs e)         {             //返回指令格式:FF FF 01 06 00 B1 0A 00 00 3D   ,   其中B1 0A为ID为1的舵机当前位置,00 00为其当前速度             // 第2位是舵机,5、6位是位置,7、8位为速度               if (Closing) return;//如果正在关闭,忽略操作,直接返回,尽快的完成串口监听线程的一次循环             try             {                 Listening = true;//设置标记,说明我已经开始处理数据,一会儿要使用系统UI的。                 int n = serialPort1.BytesToRead;//先记录下来,避免某种原因,人为的原因,操作几次之间时间长,缓存不一致                 byte[] buf = new byte[n];//声明一个临时数组存储当前来的串口数据                 serialPort1.Read(buf, 0, n);//读取缓冲数据                   /////////////////////////////////////////////////////////////////////////////////////////////////////////////                 //<协议解析>                 //1.缓存数据                 buffer.AddRange(buf);                 //2.完整性判断                 while (buffer.Count >= 10)//至少要包含头(2字节)+长度(7字节)+校验(1字节)                 {                     //2.1 查找数据头                     if (buffer[0] == 0xFF && buffer[1] == 0xFF)                     {                         received_count++;                         /*                         //校验                         byte checksum = 0;                         for (int i = 0; i < len + 3; i++)//len+3表示校验之前的位置                         {                             checksum ^= buffer[i];                         }                         if (checksum != buffer[len + 3]) //如果数据校验失败,丢弃这一包数据                         {                             buffer.RemoveRange(0, len + 4);//从缓存中删除错误数据                             continue;//继续下一次循环                         }                         */                           //至此,已经被找到了一条完整数据。我们将数据直接分析,或是缓存起来一起分析                         buffer.CopyTo(0, binary_data_1, 0, 9);//复制一条完整数据到具体的数据缓存                         //3.分析数据                           //根据舵机编号分类并存入TXT文件                         string zhuanbian = binary_data_1[7].ToString("X2");                         if (zhuanbian == "00")                         {                             zhuanbian = "01";                         }                           //我们的数据都是定好格式的,所以当我们找到分析出的数据1,就知道固定位置一定是这些数据,我们只要显示就可以了                         string data = binary_data_1[2].ToString("X2") + " " +                             binary_data_1[5].ToString("X2") + " " + binary_data_1[6].ToString("X2") + " " +                             zhuanbian + " " + binary_data_1[8].ToString("X2");                               //更新界面                         this.Invoke((EventHandler)(delegate                         {                             kryptonRichTextBox1.Text += data + "**";                             WriteFile(data);                           }));                         if (received_count == 4)                         {                             WriteFileLine();                             received_count = 0;                             //更新界面                             this.Invoke((EventHandler)(delegate                             {                                 kryptonRichTextBox1.Text += "\r\n";                             }));                         }                         buffer.RemoveRange(0, 10);//正确分析一条数据,从缓存中移除数据。                     }                     else                     {                         //这里是很重要的,如果数据开始不是头,则删除数据                         buffer.RemoveAt(0);                     }                 }             }             finally             {                 //写入文档                 Listening = false;//我用完了,ui可以关闭串口了。             }                     #region             /*             //接收指令函数             int n = serialPort1.BytesToRead;             byte[] dbs = new byte[n];             int len = serialPort1.Read(dbs, 0, n);             int[] num = new int[len];             string show = "";             show = MyClass.byteToHexStr(dbs);             strShow += show + "\r\n";             this.Invoke((EventHandler)delegate { kryptonRichTextBox1.Text = strShow; });             */                 /*             //查询01舵机             //try             //{             Listening = true;//设置标记,说明我已经开始处理数据,一会儿要使用系统UI的。               int nn = serialPort1.BytesToRead;//先记录下来,避免某种原因,人为的原因,操作几次之间时间长,缓存不一致               byte[] buf = new byte[nn];//声明一个临时数组存储当前来的串口数据               received_count += nn;//增加接收计数               serialPort1.Read(buf, 0, nn);//读取缓冲数据               /////////////////////////////////////////////////////////////////////////////////////////////////////////////               //<协议解析>               bool data_1_catched = false;//缓存记录数据是否捕获到               //1.缓存数据               buffer.AddRange(buf);             //2.完整性判断               //while (buffer.Count >= 5)//至少要包含头(2字节)+长度(1字节)+校验(1字节)               //{             //请不要担心使用>=,因为>=已经和>,<,=一样,是独立caozuofu.html" target="_blank">操作符,并不是解析成>和=2个符号               //2.1 查找数据头               if (buf[0] == 0xFF && buf[1] == 0xFF)             {                 int len = buf[2];//数据长度                     if (1 == len)                 {                     binary_data_1[0] = buffer[5];                     binary_data_1[1] = buffer[6];                     binary_data_1[2] = buffer[7];                     binary_data_1[3] = buffer[8];                 }                   //更新界面                    this.Invoke((EventHandler)delegate { kryptonRichTextBox1.Text = MyClass.byteToHexStr(binary_data_1); });             }                 */                   // this.Invoke((EventHandler)(delegate { txData.Text = data; }));               //strShow = ;             //strShow = "舵机1接收到的指令:" + binary_data_1[0].ToString() + " " + binary_data_1[1].ToString() + " " + binary_data_1[2].ToString() + " " + binary_data_1[3].ToString();             //    buffer.CopyTo(0,binary_data_1,0,4);//复制一条完整数据到具体的数据缓存               //    buffer.CopyTo(0, binary_data_1, 5, 4);//复制一条完整数据到具体的数据缓存               //data_1_catched = true;             //buffer.RemoveRange(0, len + 4);//正确分析一条数据,从缓存中移除数据。                 //                   }             //                   else             //                   {             //                       //这里是很重要的,如果数据开始不是头,则删除数据               //                       buffer.RemoveAt(0);             //                   }             //               }             //               //分析数据               //               if (data_1_catched)             //               {             //                   //我们的数据都是定好格式的,所以当我们找到分析出的数据1,就知道固定位置一定是这些数据,我们只要显示就可以了               //                   string data = binary_data_1[5].ToString("X2") + " " + binary_data_1[6].ToString("X2") + " " +             //                       binary_data_1[7].ToString("X2") + " " + binary_data_1[8].ToString("X2");             //                   //更新界面               //                   this.Invoke((EventHandler)(delegate { kryptonRichTextBox1.Text = data; }));             //               }             //               //如果需要别的协议,只要扩展这个data_n_catched就可以了。往往我们协议多的情况下,还会包含数据编号,给来的数据进行               //               //编号,协议优化后就是: 头+编号+长度+数据+校验               //               //</协议解析>               //               /////////////////////////////////////////////////////////////////////////////////////////////////////////////               //               //因为要访问ui资源,所以需要使用invoke方式同步ui。               //               this.Invoke((EventHandler)(delegate             //               {             //                   //判断是否是显示为16禁止               ////依次的拼接出16进制字符串               //                       foreach (byte b in buf)             //                       {             //                           builder.Append(b.ToString("X2") + " ");             //                       }               //                   //追加的形式添加到文本框末端,并滚动到最后。               //                   this.kryptonRichTextBox1.AppendText(builder.ToString());             //                   //修改接收计数               //               }));             //           }             //           finally             //           {             //               Listening = false;//我用完了,ui可以关闭串口了。               //           }               #endregion           }           //初始化         private void ComAssistantForm_Load(object sender, EventArgs e)         {             int ii = 0;             foreach (string s in SerialPort.GetPortNames())             {                 if (ii >= 1)                 {                     ktComboBoxCom.Items.Add(s);                 }                 ii++;             }               if (SerialPort.GetPortNames().Length != 0)             {                 ktComboBoxCom.Text = (string)ktComboBoxCom.Items[0];             }               //string[] strCom = new string[] { "COM1", "COM2", "COM3", "COM4" };             //ktComboBoxCom.DataSource = strCom;                 string[] ss = new string[] {"1000000" , "9600", "19200", "57600" };             ktComboBoxBount.DataSource = ss;               ktComboBoxJiaoyan.DataSource = Enum.GetNames(typeof(Parity));               ss = new string[] { "5", "6", "7", "8" };             ktComboBoxData.DataSource = ss;             ktComboBoxData.Text = "8";               ktComboBoxStop.DataSource = Enum.GetNames(typeof(StopBits));             ktComboBoxStop.Text = Enum.Format(typeof(StopBits), StopBits.One, "G");             kryptonTextBox1.Text = "FF FF 04 04 03 18 00 DC";               //打开串口             try             {                 if (!serialPort1.IsOpen)                 {                     serialPort1.PortName = ktComboBoxCom.Text;                     serialPort1.BaudRate = Convert.ToInt32(ktComboBoxBount.Text);                     serialPort1.Parity = (Parity)Enum.Parse(typeof(Parity), ktComboBoxJiaoyan.Text);                     serialPort1.DataBits = Int32.Parse(ktComboBoxData.Text);                     serialPort1.StopBits = (StopBits)Enum.Parse(typeof(StopBits), ktComboBoxStop.Text);                     serialPort1.Encoding = Encoding.GetEncoding("Gb2312");                     serialPort1.Open();                     ktLabMessage.Text = "当前连接状态: 已经连接";                 }             }             catch (Exception)             {                   MessageBox.Show("初始化出问题,请检查串口设备", "软件提醒", MessageBoxButtons.OKCancel, MessageBoxIcon.Error);             }               }           //连接串口         private void ktBtnLink_Click(object sender, EventArgs e)         {             try             {                 if (!serialPort1.IsOpen)                 {                     serialPort1.PortName = ktComboBoxCom.Text;                     serialPort1.BaudRate = Convert.ToInt32(ktComboBoxBount.Text);                     serialPort1.Parity = (Parity)Enum.Parse(typeof(Parity), ktComboBoxJiaoyan.Text);                     serialPort1.DataBits = Int32.Parse(ktComboBoxData.Text);                     serialPort1.StopBits = (StopBits)Enum.Parse(typeof(StopBits), ktComboBoxStop.Text);                     serialPort1.Encoding = Encoding.GetEncoding("Gb2312");                     serialPort1.Open();                     ktLabMessage.Text = "当前连接状态: 已经连接";                 }             }             catch (Exception)             {                   MessageBox.Show("初始化出问题,请检查串口设备", "软件提醒", MessageBoxButtons.OKCancel, MessageBoxIcon.Error);             }         }           //关闭串口         private void ktBtnClose_Click(object sender, EventArgs e)         {             if (serialPort1.IsOpen)             {                 serialPort1.Close();                 ktLabMessage.Text = "当前连接状态: 已经关闭";             }         }           //发送数据         private void ktBtnSend_Click(object sender, EventArgs e)         {             if (!serialPort1.IsOpen)             {                 MessageBox.Show("请打开串口!", "软件提醒", MessageBoxButtons.OKCancel, MessageBoxIcon.Exclamation);             }             else             {                 string content = kryptonTextBox1.Text;                 byte[] bytes = MyClass.StringToHex(content);                 serialPort1.Write(bytes, 0, bytes.Length);               }         }           //接收数据         private void ktBtnAccept_Click(object sender, EventArgs e)         {             int n = serialPort1.BytesToRead;             byte[] dbs = new byte[n];             int len = serialPort1.Read(dbs, 0, n);             int[] num = new int[len];               string show = "";             show = MyClass.byteToHexStr(dbs);             kryptonRichTextBox1.Text += show;         }           //清空数据         private void ktBtnClear_Click(object sender, EventArgs e)         {             strShow = "";             kryptonRichTextBox1.Text = "";         }               private void timer1_Tick(object sender, EventArgs e)         {             kryptonRichTextBox1.Text = strShow;         }               //急停指令         private void ktBtnStop_Click(object sender, EventArgs e)         {             if (!serialPort1.IsOpen)             {                 MessageBox.Show("请打开串口!", "软件提醒", MessageBoxButtons.OKCancel, MessageBoxIcon.Exclamation);             }             else             {                 byte[] bytes = MyClass.StringToHex("FF FF FE 1C 83 20 02 01 01 00 02 01 00 03 01 00 04 01 00 05 01 00 06 01 00 07 01 00 08 01 00 14");                 serialPort1.Write(bytes, 0, bytes.Length);             }         }           //查询舵机状态         private void ktBtnQuery_Click(object sender, EventArgs e)         {               try             {                 FileStream stream2 = File.Open(FILE_INFO_NAME, FileMode.OpenOrCreate, FileAccess.Write);                 stream2.Seek(0, SeekOrigin.Begin);                 stream2.SetLength(0); //清空txt文件                 stream2.Close();             }             catch (System.Exception ex)             {                         }             finally             {                 MessageBox.Show("缓存数据已经清空!", "软件提醒", MessageBoxButtons.OKCancel, MessageBoxIcon.Exclamation);             }                 //if (!Query)             //{             //    ktBtnQuery.Text = "停止查询舵机";             //    Query = true;               //    if (!serialPort1.IsOpen)             //    {             //        MessageBox.Show("请打开串口!", "软件提醒", MessageBoxButtons.OKCancel, MessageBoxIcon.Exclamation);             //    }             //    else             //    {             //        for (int i = 0; i < 10; i++)             //        {             //            //这是舵机返回指令,发送指令没有加入             //            //舵机1             //            byte[] bytes = MyClass.StringToHex("FF FF 01 06 00 B1 0A 01 01 3D");             //            serialPort1.Write(bytes, 0, bytes.Length);               //            //舵机2             //            bytes = MyClass.StringToHex("FF FF 02 06 00 B1 0A 02 02 3D");             //            serialPort1.Write(bytes, 0, bytes.Length);               //            //舵机3             //            bytes = MyClass.StringToHex("FF FF 03 06 00 B1 03 03 03 3D");             //            serialPort1.Write(bytes, 0, bytes.Length);               //            //舵机4             //            bytes = MyClass.StringToHex("FF FF 04 06 00 B1 04 04 04 3D");             //            serialPort1.Write(bytes, 0, bytes.Length);             //            //Thread.Sleep(5000);               //        }               //    }               //}             //else             //{             //    ktBtnQuery.Text = "查询舵机状态";             //    Query = false;             //}         }           /// <summary>         /// 写入舵机位置速度信息         /// </summary>         private void WriteFile(string input)         {             using (StreamWriter sw = File.AppendText("FileInfo.txt"))             {                 sw.Write(input + " ** ");             }               ///文件目录             //FileStream fs = new FileStream("FileInfo.txt", FileMode.Create);             //StreamWriter sw = new StreamWriter(fs);             //sw.WriteLine(input + "\n");             ////清空缓冲区             //sw.Flush();             ////关闭流             //sw.Close();             //fs.Close();             ///写入内容并换行         }           /// <summary>         /// 换行         /// </summary>         private void WriteFileLine()         {             using (StreamWriter sw = File.AppendText(FILE_INFO_NAME))             {                 sw.WriteLine();             }         }           //读取文件         private List<Array> ReadFile()         {             List<Array> myArray = new List<Array>();             if (File.Exists(FILE_INFO_NAME))             {                 using (StreamReader sr = new StreamReader(FILE_INFO_NAME, UnicodeEncoding.GetEncoding("GB2312")))                 {                     string Line = null;                     string[] duoji = new string[4];  //存储一条数据                      for (Line = sr.ReadLine(); Line != null; Line = sr.ReadLine())                     {                         if (!(Line.Trim() == ""))                         {                             duoji = Line.Trim().Split(new string[] { "**" }, StringSplitOptions.RemoveEmptyEntries);                             myArray.Add(duoji);                         }                     }                                      }               }               return myArray;         }               //再现过程         private void ktBtnAgain_Click(object sender, EventArgs e)         {             if (openClose)             {                 //这里创建一个线程,使之执行Alpha类的Beta()方法                 Thread newThread = new Thread(new ThreadStart(zaixianThread));                 newThread.Start();                 ktBtnAgain.Text = "停  止";                 openClose = false;               }             else             {                 openClose = true;                 ktBtnAgain.Text = "再  现";               }         }             //创建再现新线程         public void zaixianThread()         {             if (!serialPort1.IsOpen)             {                 MessageBox.Show("请打开串口!", "软件提醒", MessageBoxButtons.OKCancel, MessageBoxIcon.Exclamation);             }             else             {                 while (true)                 {                     if (openClose == true)                     {                         break;                     }                     //获取数据                 dataList = ReadFile();                   //FF FF FE 18 83 1E 04 01 00 00 11 11 02 22 22 33 33 03 44 44 55 55 04 66 66 77 99 18                  foreach (Array ar in dataList) //获取一条四个舵机数据                 {                                          string zuhe = "";                     byte[] xiafa = new byte[28];                     foreach (string str in ar)   //获取一个舵机数据                     {                         zuhe += str.Trim() + " ";                     }                     string hh = zuhe.Trim();                     byte[] temp = MyClass.StringToHex(hh);                       byte[] tempOne=new byte[26];                     for (int i = 0; i < 20; i++)                     {                         xiafa[i + 7] = temp[i];                         //tempOne[i+5]=temp[i];                     }                     xiafa[0] = 0XFF;                     xiafa[1] = 0XFF;                     xiafa[2] = 0XFE;                     xiafa[3] = 0X18;                     xiafa[4] = 0X83;                     xiafa[5] = 0X1E;                     xiafa[6] = 0X04;                       Array.Copy(xiafa, 2, tempOne, 0, 26);//复制数组                     xiafa[27] = MyClass.CheckSum(tempOne);                        serialPort1.Write(xiafa, 0, xiafa.Length);                     Thread.Sleep(100);                   }                   }             }         }             //采集指令         private void ktBtnCollection_Click(object sender, EventArgs e)         {             if (kaiguan)             {                 //这里创建一个线程,使之执行Alpha类的Beta()方法                 Thread newThread = new Thread(new ThreadStart(caijiThread));                 newThread.Start();                 ktBtnCollection.Text = "停  止";                 kaiguan = false;               }             else             {                 kaiguan = true;                 ktBtnCollection.Text = "采  集";               }         }           //创建采集新线程         public void caijiThread()         {             if (!serialPort1.IsOpen)             {                 MessageBox.Show("请打开串口!", "软件提醒", MessageBoxButtons.OKCancel, MessageBoxIcon.Exclamation);             }             else             {                 while (true)                 {                     if (kaiguan == true)                     {                         break;                     }                       //采集[指令固定]                     byte[] bytes = MyClass.StringToHex("FF FF FE 14 83 18 01 01 00 02 00 03 00 04 00 05 00 06 00 07 00 08 00 2D");                     serialPort1.Write(bytes, 0, bytes.Length);                       //舵机01的指令FF FF 01 04 02 24 04 D0                     byte checksum = 0;                     for (int QueryNum = 1; QueryNum < 5; QueryNum++)                     {                         //求校验和,方法一                         checksum = ((byte)(QueryNum + 0X04 + 0X02 + 0X24 + 0X04));                         byte[] ab = new byte[1];                         ab[0] = (byte)~(0xff & checksum);                         string mySum = MyClass.byteToHexStr(ab);                           //////求校验和,方法二                         //byte[] tempab = new byte[] { 0X01, 0X04, 0X02, 0X24, 0X04 };                         //byte strab = MyClass.CheckSum(tempab);                           byte[] bytesCaiji = MyClass.StringToHex("FF FF " + QueryNum.ToString("X2") + " 04 02 24 04 " + mySum.Trim());                         serialPort1.Write(bytesCaiji, 0, bytesCaiji.Length);                         Thread.Sleep(6);                     }                     Thread.Sleep(100);                 }             }         }     } }  


*******************************************************************************************************************************************************
myClass类:

using System; using System.Collections.Generic; using System.Text; using System.Windows.Forms; using System.Collections; namespace System {     class MyClass     {         public MyClass()         {         }           /// <summary>         /// 字符串转16进制字节数组         /// </summary>         /// <param name="hexString"></param>         /// <returns></returns>         public static byte[] StringToHex(string str)         {             string[] strs = str.Split(' ');             byte[] bytes = new byte[strs.Length];             int index = 0;             foreach (string s in strs)             {                 int hex = Convert.ToInt32(s, 16);                 bytes[index++] = (byte)hex;             }             return bytes;         }           /// <summary>         /// 字节数组转16进制字符串         /// </summary>         /// <param name="bytes"></param>         /// <returns></returns>         public static string byteToHexStr(byte[] bytes)         {             string returnStr = "";             if (bytes != null)             {                 for (int i = 0; i < bytes.Length; i++)                 {                     //ToString("X2") 为C#中的字符串格式控制符                     //假设有两个数10和26,正常情况十六进制显示0xA、0x1A,这样看起来不整齐,为了好看,可以指定"X2",这样显示出来就是:0x0A、0x1A。                     returnStr += bytes[i].ToString("X2");                     returnStr += " ";                 }             }             return returnStr;         }           public static byte CheckSum(byte[] temp)         {             byte sum;             byte jia=0X00;             for (int i = 0; i < temp.Length;i++ )             {                 jia += temp[i];             }             sum= (byte)~(0xff & jia);             return sum;         }           public static ArrayList Str16ToArrayList(string strIn)         {             string sParse = "";             ArrayList myAL = new ArrayList();               int i = 0;             foreach (char cc in strIn)             {                 i++;                 if (cc == ' ' || sParse.Length == 2)                 {                     myAL.Add(sParse);                     if (sParse.Length == 2 && cc != ' ')                     {                         sParse = Convert.ToString(cc);                     }                     else                     {                         sParse = "";                     }                 }                 else                 {                     sParse += Convert.ToString(cc);                     if (i == strIn.Length && cc != ' ')                     {                         myAL.Add(sParse);                     }                 }             }             return myAL;         }         }   }  

 

  • 相关文章
发表评论
用户名: 匿名