自己写C#用汽车诊断卡对MIT电机做调试

国内现在做MIT电机的工厂很多,有台州海泰(HT),深圳智擎(Dogi),江西老虎(T-MOTOR),江苏伺泰(SteadyWin),
自MIT去年下半年开源了猎豹机器人以及对应的mini-Cheetah actuator(MIT电机)以后,国内有不少做BLDC电机的厂商都开始做这玩意儿了,不过这些企业都是面向无人机市场或者高校研发之类的,
国内做工业伺服的工厂比如汇川伺服,就没有折腾这个

然后我买了个电机来研究一下……

我有两台MIT电机,一台是智擎的
在这里插入图片描述
智擎的会附带发你一个专门的驱动板,可以用这个跟电机做速度控制通信,但是,感觉对开发者而言没用,我无法直接用CAN发送报文。
在这里插入图片描述

另一个是海泰HT-03规格的MIT电机,同时也买了他们的USB2CAN模块
在这里插入图片描述

海泰客服发了我资料,我可以用USB2CAN模块对应的上位机来驱动MIT电机,但他们自己的上位机代码有问题无法实现速度控制只能位置控制,然后,他们拒绝给对应的上位机源码,所以只好自己用其他方式来驱动这个MIT电机。

最终用这个CAN卡来成功驱动了:
在这里插入图片描述
店家发CAN卡的时候,还附赠了一对汽车仪表还有发动机接口的线,看来这玩意儿主要是用于汽车维修行业做检测用的。

可以看到HT电机的绿灯亮了。如果CAN没有通信成功,FC命令不发的话,默认是进入RESET模式,只有黄灯亮
这是在店家发过来的资料里,自带的C#示例代码的基础上做的
用这种方式来控制电机,比另一位CSDN网友用STM32开发板来控制,我觉得会方便很多,毕竟嵌入式开发有点难,C#简单点……
在这里插入图片描述
CSDN惯例贴代码:

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Text;
using System.Windows.Forms;
using System.Runtime.InteropServices;

/*------------兼容ZLG的数据类型---------------------------------*/

//1.ZLGCAN系列接口卡信息的数据类型。
public struct VCI_BOARD_INFO 
{ 
	public UInt16 hw_Version;
    public UInt16 fw_Version;
    public UInt16 dr_Version;
    public UInt16 in_Version;
    public UInt16 irq_Num;
    public byte   can_Num;
    [MarshalAs(UnmanagedType.ByValArray, SizeConst=20)] public byte []str_Serial_Num;
    [MarshalAs(UnmanagedType.ByValArray, SizeConst = 40)]
    public byte[] str_hw_Type;
    [MarshalAs(UnmanagedType.ByValArray, SizeConst = 4)]
    public byte[] Reserved;
}

/
//2.定义CAN信息帧的数据类型。
unsafe public struct VCI_CAN_OBJ  //使用不安全代码
{
    public uint ID;
    public uint TimeStamp;        //时间标识
    public byte TimeFlag;         //是否使用时间标识
    public byte SendType;         //发送标志。保留,未用
    public byte RemoteFlag;       //是否是远程帧
    public byte ExternFlag;       //是否是扩展帧
    public byte DataLen;          //数据长度
    public fixed byte Data[8];    //数据
    public fixed byte Reserved[3];//保留位

}

//3.定义初始化CAN的数据类型
public struct VCI_INIT_CONFIG 
{
    public UInt32 AccCode;
    public UInt32 AccMask;
    public UInt32 Reserved;
    public byte Filter;   //0或1接收所有帧。2标准帧滤波,3是扩展帧滤波。
    public byte Timing0;  //波特率参数,具体配置,请查看二次开发库函数说明书。
    public byte Timing1;
    public byte Mode;     //模式,0表示正常模式,1表示只听模式,2自测模式
}

/*------------其他数据结构描述---------------------------------*/
//4.USB-CAN总线适配器板卡信息的数据类型1,该类型为VCI_FindUsbDevice函数的返回参数。
public struct VCI_BOARD_INFO1
{
    public UInt16 hw_Version;
    public UInt16 fw_Version;
    public UInt16 dr_Version;
    public UInt16 in_Version;
    public UInt16 irq_Num;
    public byte can_Num;
    public byte Reserved;
    [MarshalAs(UnmanagedType.ByValArray, SizeConst=8)] public byte []str_Serial_Num;
    [MarshalAs(UnmanagedType.ByValArray, SizeConst = 16)]
    public byte[] str_hw_Type;
    [MarshalAs(UnmanagedType.ByValArray, SizeConst = 16)]
    public byte[] str_Usb_Serial;
}

/*------------数据结构描述完成---------------------------------*/

public struct CHGDESIPANDPORT 
{
    [MarshalAs(UnmanagedType.ByValArray, SizeConst = 10)]
    public byte[] szpwd;
    [MarshalAs(UnmanagedType.ByValArray, SizeConst = 20)]
    public byte[] szdesip;
    public Int32 desport;

    public void Init()
    {
        szpwd = new byte[10];
        szdesip = new byte[20];
    }
}


namespace WindowsApplication1
{
    public partial class Form1 : Form
    {
        const int DEV_USBCAN = 3;
        const int DEV_USBCAN2 = 4;
         /// <summary>
        /// 
        /// </summary>
        /// <param name="DeviceType"></param>
        /// <param name="DeviceInd"></param>
        /// <param name="Reserved"></param>
        /// <returns></returns>
        /*------------兼容ZLG的函数描述---------------------------------*/
        [DllImport("controlcan.dll")]
        static extern UInt32 VCI_OpenDevice(UInt32 DeviceType, UInt32 DeviceInd, UInt32 Reserved);
        [DllImport("controlcan.dll")]
        static extern UInt32 VCI_CloseDevice(UInt32 DeviceType, UInt32 DeviceInd);
        [DllImport("controlcan.dll")]
        static extern UInt32 VCI_InitCAN(UInt32 DeviceType, UInt32 DeviceInd, UInt32 CANInd, ref VCI_INIT_CONFIG pInitConfig);

        [DllImport("controlcan.dll")]
        static extern UInt32 VCI_ReadBoardInfo(UInt32 DeviceType, UInt32 DeviceInd, ref VCI_BOARD_INFO pInfo);

        [DllImport("controlcan.dll")]
        static extern UInt32 VCI_GetReceiveNum(UInt32 DeviceType, UInt32 DeviceInd, UInt32 CANInd);
        [DllImport("controlcan.dll")]
        static extern UInt32 VCI_ClearBuffer(UInt32 DeviceType, UInt32 DeviceInd, UInt32 CANInd);

        [DllImport("controlcan.dll")]
        static extern UInt32 VCI_StartCAN(UInt32 DeviceType, UInt32 DeviceInd, UInt32 CANInd);
        [DllImport("controlcan.dll")]
        static extern UInt32 VCI_ResetCAN(UInt32 DeviceType, UInt32 DeviceInd, UInt32 CANInd);

        [DllImport("controlcan.dll")]
        static extern UInt32 VCI_Transmit(UInt32 DeviceType, UInt32 DeviceInd, UInt32 CANInd, ref VCI_CAN_OBJ pSend, UInt32 Len);

        [DllImport("controlcan.dll")]
        static extern UInt32 VCI_Receive(UInt32 DeviceType, UInt32 DeviceInd, UInt32 CANInd, ref VCI_CAN_OBJ pReceive, UInt32 Len, Int32 WaitTime);
        
        /*------------其他函数描述---------------------------------*/

        [DllImport("controlcan.dll")]
        static extern UInt32 VCI_ConnectDevice(UInt32 DevType,UInt32 DevIndex);
        [DllImport("controlcan.dll")]
        static extern UInt32 VCI_UsbDeviceReset(UInt32 DevType,UInt32 DevIndex,UInt32 Reserved);
        [DllImport("controlcan.dll")]
        static extern UInt32 VCI_FindUsbDevice(ref VCI_BOARD_INFO1 pInfo);
        /*------------函数描述结束---------------------------------*/

        static UInt32 m_devtype = 4;//USBCAN2

        UInt32 m_bOpen = 0;
        UInt32 m_devind = 0;
        UInt32 m_canind = 0;

        VCI_CAN_OBJ[] m_recobj = new VCI_CAN_OBJ[1000];

        UInt32[] m_arrdevtype = new UInt32[20];

        public Form1()
        {
            InitializeComponent();
        }

        private void Form1_Load(object sender, EventArgs e)
        {
            comboBox_DevIndex.SelectedIndex = 0;
            comboBox_CANIndex.SelectedIndex = 0;
            textBox_AccCode.Text = "00000000";
            textBox_AccMask.Text = "FFFFFFFF";
            textBox_Time0.Text = "00";
            textBox_Time1.Text = "14";
            comboBox_Filter.SelectedIndex = 0;              //接收所有类型
            comboBox_Mode.SelectedIndex = 0;                //还回测试模式
            comboBox_FrameFormat.SelectedIndex = 0;
            comboBox_FrameType.SelectedIndex = 0;
            textBox_ID.Text = "1";
            textBox_Data.Text = "FF FF FF FF FF FF FF FC ";

            //
            Int32 curindex = 0;
            comboBox_devtype.Items.Clear();

            curindex = comboBox_devtype.Items.Add("DEV_USBCAN");
            m_arrdevtype[curindex] =  DEV_USBCAN;
            //comboBox_devtype.Items[2] = "VCI_USBCAN1";
            //m_arrdevtype[2]=  VCI_USBCAN1 ;

            curindex = comboBox_devtype.Items.Add("DEV_USBCAN2");
            m_arrdevtype[curindex] = DEV_USBCAN2 ;
            //comboBox_devtype.Items[3] = "VCI_USBCAN2";
            //m_arrdevtype[3]=  VCI_USBCAN2 ;

             comboBox_devtype.SelectedIndex = 1;
            comboBox_devtype.MaxDropDownItems = comboBox_devtype.Items.Count;

        }

        private void Form1_FormClosed(object sender, FormClosedEventArgs e)
        {
            if (m_bOpen==1)
            {
                VCI_CloseDevice(m_devtype, m_devind);
            }
        }

        private void buttonConnect_Click(object sender, EventArgs e)
        {
            if (m_bOpen==1)
            {
                VCI_CloseDevice(m_devtype, m_devind);
                m_bOpen = 0;
            }
            else
            {
                m_devtype = m_arrdevtype[comboBox_devtype.SelectedIndex];

                m_devind=(UInt32)comboBox_DevIndex.SelectedIndex;
                m_canind = (UInt32)comboBox_CANIndex.SelectedIndex;
                if (VCI_OpenDevice(m_devtype, m_devind, 0) == 0)
                {
                    MessageBox.Show("打开设备失败,请检查设备类型和设备索引号是否正确", "错误",
                            MessageBoxButtons.OK, MessageBoxIcon.Exclamation);
                    return;
                }

                m_bOpen = 1;
                VCI_INIT_CONFIG config=new VCI_INIT_CONFIG();
                config.AccCode=System.Convert.ToUInt32("0x" + textBox_AccCode.Text,16);
                config.AccMask = System.Convert.ToUInt32("0x" + textBox_AccMask.Text, 16);
                config.Timing0 = 0x00;// System.Convert.ToByte("0x" + textBox_Time0.Text, 16);
                config.Timing1 = 0x14;// System.Convert.ToByte("0x" + textBox_Time1.Text, 16);
                config.Filter = (Byte)(comboBox_Filter.SelectedIndex+1);
                config.Mode = (Byte)comboBox_Mode.SelectedIndex;
                VCI_InitCAN(m_devtype, m_devind, m_canind, ref config);
            }
            buttonConnect.Text = m_bOpen==1?"断开":"连接";
            timer_rec.Enabled = m_bOpen==1?true:false;
        }

        unsafe private void timer_rec_Tick(object sender, EventArgs e)
        {
            UInt32 res = new UInt32();

            res = VCI_Receive(m_devtype, m_devind, m_canind, ref m_recobj[0],1000, 100);

            /
            //IntPtr[] ptArray = new IntPtr[1];
            //ptArray[0] = Marshal.AllocHGlobal(Marshal.SizeOf(typeof(VCI_CAN_OBJ)) * 50);
            //IntPtr pt = Marshal.AllocHGlobal(Marshal.SizeOf(typeof(IntPtr)) * 1);

            //Marshal.Copy(ptArray, 0, pt, 1);


            //res = VCI_Receive(m_devtype, m_devind, m_canind, pt, 50/*50*/, 100);
            
            if (res == 0xFFFFFFFF) res = 0;//当设备未初始化时,返回0xFFFFFFFF,不进行列表显示。
            String str = "";
            for (UInt32 i = 0; i < res; i++)
            {
                //VCI_CAN_OBJ obj = (VCI_CAN_OBJ)Marshal.PtrToStructure((IntPtr)((UInt32)pt + i * Marshal.SizeOf(typeof(VCI_CAN_OBJ))), typeof(VCI_CAN_OBJ));

                str = "接收到数据: ";
                str += "  帧ID:0x" + System.Convert.ToString(m_recobj[i].ID, 16);
                str += "  帧格式:";
                if (m_recobj[i].RemoteFlag == 0)
                    str += "数据帧 ";
                else
                    str += "远程帧 ";
                if (m_recobj[i].ExternFlag == 0)
                    str += "标准帧 ";
                else
                    str += "扩展帧 ";

                //
                if (m_recobj[i].RemoteFlag == 0)
                {
                    str += "数据: ";
                    byte len = (byte)(m_recobj[i].DataLen % 9);
                    byte j = 0;
                    fixed (VCI_CAN_OBJ* m_recobj1 = &m_recobj[i])
                    {
                        if (j++ < len)
                            str += " " + System.Convert.ToString(m_recobj1->Data[0], 16);
                        if (j++ < len)
                            str += " " + System.Convert.ToString(m_recobj1->Data[1], 16);
                        if (j++ < len)
                            str += " " + System.Convert.ToString(m_recobj1->Data[2], 16);
                        if (j++ < len)
                            str += " " + System.Convert.ToString(m_recobj1->Data[3], 16);
                        if (j++ < len)
                            str += " " + System.Convert.ToString(m_recobj1->Data[4], 16);
                        if (j++ < len)
                            str += " " + System.Convert.ToString(m_recobj1->Data[5], 16);
                        if (j++ < len)
                            str += " " + System.Convert.ToString(m_recobj1->Data[6], 16);
                        if (j++ < len)
                            str += " " + System.Convert.ToString(m_recobj1->Data[7], 16);
                    }
                }

                listBox_Info.Items.Add(str);
                listBox_Info.SelectedIndex = listBox_Info.Items.Count - 1;
            }
            //Marshal.FreeHGlobal(ptArray[0]);
            //Marshal.FreeHGlobal(pt);
        }

        private void button_StartCAN_Click(object sender, EventArgs e)
        {
            if (m_bOpen == 0)
                return;
            VCI_StartCAN(m_devtype, m_devind, m_canind);
        }

        private void button_StopCAN_Click(object sender, EventArgs e)
        {
            if (m_bOpen == 0)
                return;
            VCI_ResetCAN(m_devtype, m_devind, m_canind);
        }

        unsafe private void button_Send_Click(object sender, EventArgs e)
        {
            if(m_bOpen==0)
                return;

            VCI_CAN_OBJ sendobj = new VCI_CAN_OBJ();
            //sendobj.Init();
            sendobj.RemoteFlag = (byte)comboBox_FrameFormat.SelectedIndex;
            sendobj.ExternFlag = (byte)comboBox_FrameType.SelectedIndex;
            sendobj.ID = System.Convert.ToUInt32("0x"+textBox_ID.Text,16);
            int len = (textBox_Data.Text.Length+1) / 3;
            sendobj.DataLen =System.Convert.ToByte(len);
            String strdata = textBox_Data.Text;
            int i=-1;
            if(i++<len-1)
                sendobj.Data[0]=System.Convert.ToByte("0x" +strdata.Substring(i * 3, 2),16);
            if (i++ < len - 1)
                sendobj.Data[1]=System.Convert.ToByte("0x" +strdata.Substring(i * 3, 2),16);
            if (i++ < len - 1)
                sendobj.Data[2]=System.Convert.ToByte("0x" +strdata.Substring(i * 3, 2),16);
            if (i++ < len - 1)
                sendobj.Data[3]=System.Convert.ToByte("0x" +strdata.Substring(i * 3, 2),16);
            if (i++ < len - 1)
                sendobj.Data[4]=System.Convert.ToByte("0x" +strdata.Substring(i * 3, 2),16);
            if (i++ < len - 1)
                sendobj.Data[5]=System.Convert.ToByte("0x" +strdata.Substring(i * 3, 2),16);
            if (i++ < len - 1)
                sendobj.Data[6]=System.Convert.ToByte("0x" +strdata.Substring(i * 3, 2),16);
            if (i++ < len - 1)
                sendobj.Data[7] = System.Convert.ToByte("0x" + strdata.Substring(i * 3, 2), 16);

            if(VCI_Transmit(m_devtype,m_devind,m_canind,ref sendobj,1)==0)
            {
                MessageBox.Show("发送失败", "错误",
                        MessageBoxButtons.OK, MessageBoxIcon.Exclamation);
            }
        }

        private void button_Clear_Click(object sender, EventArgs e)
        {
            listBox_Info.Items.Clear();
        }

        unsafe private void button3_Click(object sender, EventArgs e)
        {
            if (m_bOpen == 0)
                return;

            VCI_CAN_OBJ sendobj = new VCI_CAN_OBJ();
            //sendobj.Init();
            sendobj.RemoteFlag = (byte)comboBox_FrameFormat.SelectedIndex;
            sendobj.ExternFlag = (byte)comboBox_FrameType.SelectedIndex;
            sendobj.ID = System.Convert.ToUInt32("0x" + textBox_ID.Text, 16);
            int len = (textBox_Data.Text.Length + 1) / 3;
            sendobj.DataLen = System.Convert.ToByte(len);
            String strdata = textBox_Data.Text;
            int i = -1;
            if (i++ < len - 1)
                sendobj.Data[0] = 0xff;
            if (i++ < len - 1)
                sendobj.Data[1] = 0xff;
            if (i++ < len - 1)
                sendobj.Data[2] = 0xff;
            if (i++ < len - 1)
                sendobj.Data[3] = 0xff;
            if (i++ < len - 1)
                sendobj.Data[4] = 0xff;
            if (i++ < len - 1)
                sendobj.Data[5] = 0xff;
            if (i++ < len - 1)
                sendobj.Data[6] = 0xff;
            if (i++ < len - 1)
                sendobj.Data[7] = 0xfc;

            if (VCI_Transmit(m_devtype, m_devind, m_canind, ref sendobj, 1) == 0)
            {
                MessageBox.Show("发送失败", "错误",
                        MessageBoxButtons.OK, MessageBoxIcon.Exclamation);
            }
        }

        unsafe private void button4_Click(object sender, EventArgs e)
        {
            if (m_bOpen == 0)
                return;

            VCI_CAN_OBJ sendobj = new VCI_CAN_OBJ();
            //sendobj.Init();
            sendobj.RemoteFlag = (byte)comboBox_FrameFormat.SelectedIndex;
            sendobj.ExternFlag = (byte)comboBox_FrameType.SelectedIndex;
            sendobj.ID = System.Convert.ToUInt32("0x" + textBox_ID.Text, 16);
            int len = (textBox_Data.Text.Length + 1) / 3;
            sendobj.DataLen = System.Convert.ToByte(len);
            String strdata = textBox_Data.Text;
            int i = -1;
            if (i++ < len - 1)
                sendobj.Data[0] = 0xff;
            if (i++ < len - 1)
                sendobj.Data[1] = 0xff;
            if (i++ < len - 1)
                sendobj.Data[2] = 0xff;
            if (i++ < len - 1)
                sendobj.Data[3] = 0xff;
            if (i++ < len - 1)
                sendobj.Data[4] = 0xff;
            if (i++ < len - 1)
                sendobj.Data[5] = 0xff;
            if (i++ < len - 1)
                sendobj.Data[6] = 0xff;
            if (i++ < len - 1)
                sendobj.Data[7] = 0xfd;

            if (VCI_Transmit(m_devtype, m_devind, m_canind, ref sendobj, 1) == 0)
            {
                MessageBox.Show("发送失败", "错误",
                        MessageBoxButtons.OK, MessageBoxIcon.Exclamation);
            }
        }
    }
}

代码里注意, CAN的传输速度必须设置为 1000K。只要速度设对了就可以通信上

使用这个汽车诊断卡,是可以接两路CAN信号的。所以虽然这两个电机的slave id 都是1,但我可以用不同的两个CAN通道来控制,两对CAN线。
在这里插入图片描述


记录一下自己踩过的坑:

ARDUINO 坑!
一开始参考的youtube上的瑞士网友skyentific的视频,使用arduin+can shield来做的:
在这里插入图片描述
我参照他的方式,买了几张 arduino can shield (因为买错了 can shield) ,都没有成功:
在这里插入图片描述
这张卡买来后,一不小心漏焊了SPI的排母,然后排母丢了,就一直都没用上,然后自己费了好大劲把SPI口给焊上:
在这里插入图片描述
结果还是不能用!

这是国内改造版本的 arduino seeedio studio 的 CAN shield v1.2 ,非官方原版,它的电子元件跟官方的不一样,我以为是我的焊接问题或国产版电子元件擅自改动的原因,所以又去淘宝买了其他的can shield
在这里插入图片描述
这个是skyentific网友在视频里用的sparkfun牌子的can-shield v2.0,拿到手焊接好调试了一个晚上还是没成功,最后发现这板子里的joystick针脚里的left up竟然是短接的,怒,找店家争论,店家说自己的板子绝对没问题,还说让我邮寄退回去,算了先放放,万一我自己把它修好了呢,毕竟只是短接而已……

在这里插入图片描述
然后又买了这块板子,依旧是 seeedstudio 的 can-shield v1.2 , 本来就是焊好针脚的,不需要我再焊(我焊接水平不好,另外我只有简单便宜的尖焊头没有刀焊头,所以这个排针对我而言还真不好焊)

这一次使用的时候,发现依然无法跟MIT电机通信,然后终于在seeedstdio官网找到了原因: can-shield v1.2 不支持 1000K的传输速度,

然后又查到了用sparkfun can shield v2.0 不能用的原因,当然有可能是板子本身哪里短接了,但另一方面是国内的大多数 arduino uno , 都是国内简化过的, 擅自把原来的ATMEGA16改成了CH340芯片
CH340芯片属于低速串口芯片,所以我调试不通。
CH340的arduino uno 才16块钱一块,而意大利原版的 ATMEGA16 的 arduino 要100多 , 哎, 心酸……

我放弃了用 arduino 驱动 MIT 电机的这种方式, 鬼知道还有其他哪些坑在这条道路上

2 USB串口调试坑
因为我并不是主职电子领域的,所以对串口不是很懂……
串口的什么 TTL SPI 232 485 协议区别我不太懂,我只知道硬件接线上的区别

智擎的电机,他们的串口我到现在都还没有接通,哎……
反正我调通了海泰电机的串口,就对智擎的放弃了。
他们的串口,搞成了一个USB口,然后发货的时候也没有附带USB线,我向智擎店家要USB口,他们竟然不给,甚至都不卖!我真服了! 然后我自己在淘宝上找了半天也找不到对应的USB口是啥样的,
于是我拆开了他们家的电机,打算自己焊线上去接,
在这里插入图片描述
看了一眼,放弃,就我这焊接水平,原指望着能找到一个很大的焊接区域去接线。
但这驱动板上,主控STM32的针脚跟旁边的串口针脚这么近,我要是不小心把主控针脚给连焊了那就完了……

调海泰电机串口时,我先用的 RS232 线来接, 呵呵,当然不行,
店家告诉我这个串口要用 USB2TTL,
然后就去买 USB2TTL,
在这里插入图片描述
这两个,便宜的那个是不能用的,因为CH340的速度太慢,无法支持. CP2102 的才行。

最终用 CP2102 的 USB2TTL 调试,才成功。 电机一上电,就会发 mini cheetah 的报文过来, 感动!
毕竟折腾我这么久

3 USB2CAN 的坑
淘宝上就有卖USB2CAN的模块,
在这里插入图片描述
这玩意儿是不行的,因为用的CH340芯片,最高速度只能5K,但是MIT电机的需要1000K

后来我买了这个, 还没到货,等到了之后再试试

在这里插入图片描述

  • 1
    点赞
  • 12
    收藏
    觉得还不错? 一键收藏
  • 10
    评论
以下是用C#串口调试助手的基本代码: ``` using System; using System.IO.Ports; using System.Windows.Forms; namespace SerialPortAssistant { public partial class MainForm : Form { private SerialPort serialPort; public MainForm() { InitializeComponent(); serialPort = new SerialPort(); serialPort.DataReceived += new SerialDataReceivedEventHandler(serialPort_DataReceived); } private void MainForm_Load(object sender, EventArgs e) { string[] portNames = SerialPort.GetPortNames(); foreach (string portName in portNames) { comboBoxPortName.Items.Add(portName); } if (portNames.Length > 0) { comboBoxPortName.SelectedIndex = 0; } } private void buttonOpen_Click(object sender, EventArgs e) { if (serialPort.IsOpen) { serialPort.Close(); } serialPort.PortName = comboBoxPortName.SelectedItem.ToString(); serialPort.BaudRate = int.Parse(comboBoxBaudRate.SelectedItem.ToString()); serialPort.Parity = (Parity)Enum.Parse(typeof(Parity), comboBoxParity.SelectedItem.ToString()); serialPort.DataBits = int.Parse(comboBoxDataBits.SelectedItem.ToString()); serialPort.StopBits = (StopBits)Enum.Parse(typeof(StopBits), comboBoxStopBits.SelectedItem.ToString()); serialPort.Open(); buttonOpen.Enabled = false; buttonClose.Enabled = true; } private void buttonClose_Click(object sender, EventArgs e) { if (serialPort.IsOpen) { serialPort.Close(); } buttonOpen.Enabled = true; buttonClose.Enabled = false; } private void buttonSend_Click(object sender, EventArgs e) { if (serialPort.IsOpen) { string data = textBoxSend.Text; serialPort.Write(data); } } private void serialPort_DataReceived(object sender, SerialDataReceivedEventArgs e) { string data = serialPort.ReadExisting(); this.Invoke(new Action(() => { textBoxReceive.AppendText(data); })); } } } ``` 此程序包括以下功能: 1. 打开和关闭串口 2. 发送数据到串口 3. 接收串口数据并显示在文本框中 你可以通过添加其他控件和功能来扩展它,例如: 1. 添加一个清除接收文本框的按钮 2. 显示串口的状态(开启/关闭) 3. 添加错误处理和异常处理 4. 支持不同的编码格式(例如UTF-8,ASCII等) 5. 支持自定义串口设置 6. 添加一个日志记录功能 7. 等等 以上仅为基本代码,您可以根据自己的需求进行修改和扩展。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 10
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值