串口传输文件(YModem协议)

需求:通过串口线实现应用程序固件烧录到单片机的flash中
开发语言:C#
串口设置:串口号,波特率:115200;

文件传输函数如下:

        //烧录文件函数
        public bool YmodemUploadFile()
        {
            /* control signals */
            const byte STX = 2;  // Start of TeXt 
            const byte EOT = 4;  // End Of Transmission
            const byte ACK = 6;  // Positive ACknowledgement
            const byte C = 67;   // capital letter C
            /* sizes */
            const int dataSize = 1024;
            const int crcSize = 2;
            /* THE PACKET: 1029 bytes */
            /* header: 3 bytes */
            // STX        
            int invertedPacketNumber = 255;
            /* data: 1024 bytes */
            byte[] data = new byte[dataSize];
            /* footer: 2 bytes */
            byte[] CRC = new byte[crcSize];
            /* get the file */
            //string strfilepath = m_configData.ini_burningfilespath;
            FileStream fileStream = new FileStream(@path, FileMode.Open, FileAccess.Read);//读取bin文件的path           
            m_strMsglogString += ("\r\nreading buring files...\r\n");
            ShowExcuteProcessInfo();            
            DateTime dt = DateTime.Now;
            byte[] ack;
            ack = new byte[] { 0x31 };
            try
            {
                serialPort1.Write(ack, 0, 1);
            }
            catch
            {
                MessageBox.Show("Exception");
            }
            Thread.Sleep(300);            
            try
            {
                ///* send the initial packet with filename and filesize */
                m_strMsglogString += ("waiting for the serial response...\r\n");
                ShowExcuteProcessInfo(); 
                int AAA = serialPort1.ReadByte();
                //pictureBoxResult.BackgroundImage = Properties.Resources.faillight;
                if (serialPort1.ReadByte() != C)
                {
                    MessageBox.Show("Can't begin the transfer.");
                    //Console.WriteLine("Can't begin the transfer.");
                    //pictureBoxResult.BackgroundImage = Properties.Resources.faillight;
                    ShowTestFailResult();
                    return false;
                }
                m_strMsglogString += ("send the initial packet with filename and filesize ...\r\n");
                ShowExcuteProcessInfo(); 
                sendYmodemInitialPacket(STX, packetNumber, invertedPacketNumber, data, dataSize, path, fileStream, CRC, crcSize);
                if (serialPort1.ReadByte() != ACK)
                {
                    MessageBox.Show("Can't send the initial packet.");
                    ShowTestFailResult();
                    return false;
                }

                if (serialPort1.ReadByte() != C)
                {
                    MessageBox.Show("22Can't send the initial packet.");
                    ShowTestFailResult();
                    return false;
                }
                btn_download.Invoke
           (
                    //委托,托管无参数的任何方法
               new MethodInvoker
               (
                   delegate
                   {
                       btn_download.Text = "正在烧录";
                   }
               )
            );
                /* send packets with a cycle until we send the last byte */
                m_strMsglogString += ("\r\nsending packets...\r\n");
                ShowExcuteProcessInfo(); 
                int fileReadCount;
                do
                {
                    /* if this is the last packet fill the remaining bytes with 0 */
                    fileReadCount = fileStream.Read(data, 0, dataSize);

                    if (fileReadCount == 0) break;
                    if (fileReadCount != dataSize)
                        for (int i = fileReadCount; i < dataSize; i++)
                            data[i] = 0;
                    /*calculate packetNumber */
                    packetNumber++;
                    //if (packetNumber > 255)
                    //    packetNumber -= 256;
                    ThreadFunction();
                    Console.WriteLine(packetNumber);
                    //Thread.Sleep(300);
                    /* calculate invertedPacketNumber */
                    invertedPacketNumber = 255 - packetNumber % 256;

                    /* calculate CRC */
                    Crc16Ccitt crc16Ccitt = new Crc16Ccitt(InitialCrcValue.Zeros);
                    CRC = crc16Ccitt.ComputeChecksumBytes(data);

                    /* send the packet */
                    sendYmodemPacket(STX, packetNumber, invertedPacketNumber, data, dataSize, CRC, crcSize);

                    int iii = serialPort1.ReadByte();
                    /* wait for ACK */
                    if (iii != (int)ACK)
                    {
                        MessageBox.Show("Couldn't send a packet.");
                        //Console.WriteLine("Couldn't send a packet.");
                        ShowTestFailResult();
                        return false;
                    }
                } while (dataSize == fileReadCount);

                /* send EOT (tell the downloader we are finished) */
                serialPort1.Write(new byte[] { EOT }, 0, 1);
                /* send closing packet */
                packetNumber = 0;
                invertedPacketNumber = 255;
                data = new byte[dataSize];
                CRC = new byte[crcSize];
                m_strMsglogString += ("\r\nsend closing packet...\r\n");
                ShowExcuteProcessInfo(); 
                sendYmodemClosingPacket(STX, packetNumber, invertedPacketNumber, data, dataSize, CRC, crcSize);
                /* get ACK (downloader acknowledge the EOT) */
                if (serialPort1.ReadByte() != ACK)
                {
                    Console.WriteLine("Can't complete the transfer.");
                    ShowTestFailResult();
                    return false;
                }
            }
            catch (TimeoutException)
            {
                throw new Exception("Eductor does not answering");
            }
            finally
            {
                fileStream.Close();
            }
            packetNumber = fsLen;
            ThreadFunction();            
            Console.WriteLine("File transfer is succesful");
            TimeSpan span = DateTime.Now - dt;
            btn_download.Invoke
           (
                //委托,托管无参数的任何方法
               new MethodInvoker
               (
                   delegate
                   {
                       btn_download.Text = "开始烧录";
                   }
               )
            );          
            m_strMsglogString += ("\r\n烧录完成,耗时:" + span.ToString() + "\r\n");
            ShowExcuteProcessInfo(); 
            txb_section.Invoke
           (
                //委托,托管无参数的任何方法
               new MethodInvoker
               (
                   delegate
                   {
                       txb_section.Text = "0";
                   }
               )
            );
            Thread.Sleep(2000);            
            return true;
        }

文件传输函数包含了YModem协议文件传输的过程,根据YModem协议,发送数据之前和之后都需建立握手通信,

        //YModem协议 初始化包
        private void sendYmodemInitialPacket(byte STX, int packetNumber, int invertedPacketNumber, byte[] data, int dataSize, string path, FileStream fileStream, byte[] CRC, int crcSize)
        {
            string fileName = System.IO.Path.GetFileName(path);
            string fileSize = fileStream.Length.ToString();

            /* add filename to data */
            int i;
            for (i = 0; i < fileName.Length && (fileName.ToCharArray()[i] != 0); i++)
            {
                data[i] = (byte)fileName.ToCharArray()[i];
            }
            data[i] = 0;

            /* add filesize to data */
            int j;
            for (j = 0; j < fileSize.Length && (fileSize.ToCharArray()[j] != 0); j++)
            {
                data[(i + 1) + j] = (byte)fileSize.ToCharArray()[j];
            }
            data[(i + 1) + j] = 0;

            /* fill the remaining data bytes with 0 */
            for (int k = ((i + 1) + j) + 1; k < dataSize; k++)
            {
                data[k] = 0;
            }

            /* calculate CRC */
            Crc16Ccitt crc16Ccitt = new Crc16Ccitt(InitialCrcValue.Zeros);
            CRC = crc16Ccitt.ComputeChecksumBytes(data);

            /* send the packet */
            sendYmodemPacket(STX, packetNumber, invertedPacketNumber, data, dataSize, CRC, crcSize);
        }
       
        //YModem协议 尾包
        private void sendYmodemClosingPacket(byte STX, int packetNumber, int invertedPacketNumber, byte[] data, int dataSize, byte[] CRC, int crcSize)
        {
            /* calculate CRC */
            Crc16Ccitt crc16Ccitt = new Crc16Ccitt(InitialCrcValue.Zeros);
            CRC = crc16Ccitt.ComputeChecksumBytes(data);

            /* send the packet */
            sendYmodemPacket(STX, packetNumber, invertedPacketNumber, data, dataSize, CRC, crcSize);
        }
        

以上是YModem协议进行文件传输的大致过程。由于YModem协议每次传输1024字节的数据,整个烧录文件是预加载的,可以根据具体情况加上进度条信息。

实现源码可参考:https://download.csdn.net/download/shufac/10308977




  • 2
    点赞
  • 47
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 3
    评论
### 回答1: LabVIEW是一种图形化编程环境和开发平台,用于与各种硬件设备和传感器进行交互和控制。Ymodem是一种通信协议,用于在串行通信中传输文件。 在LabVIEW中,可以使用内置的函数和工具箱来实现Ymodem协议的功能。首先,需要通过串行通信接口与外部设备进行通信。可以使用LabVIEW的VISA(Virtual Instrument Software Architecture)函数来建立串行连接和通信通道。 一旦建立了通信连接,就可以使用LabVIEW中的Ymodem协议相关函数来实现文件传输。可以使用VISA函数读取外部设备发送的Ymodem协议数据包,并将其解析为文件。同时,也可以使用VISA函数将文件数据打包成Ymodem数据包发送给外部设备。 LabVIEW提供了一系列的函数和工具箱,用于处理文件传输过程中可能遇到的错误或异常情况。例如,可以使用相关函数来检测丢失的数据包、修复错误的数据包、实现数据的重传等。 此外,LabVIEW还可以使用其图形化界面来构建用户友好的界面,以便用户可以直观地操作和监控Ymodem文件传输过程。可以通过面板和控件的设计来显示传输进度、传输速度以及传输结果等信息。 总之,LabVIEW提供了丰富的功能和工具来实现Ymodem协议文件传输。使用LabVIEW,可以方便地通过图形化编程来构建实时、高效且稳定的Ymodem协议通信系统。 ### 回答2: LabVIEW是一种图形化编程语言和开发平台,通常用于控制、测量和数据采集等应用。Ymodem协议是一种常用的通信协议,通常用于在计算机之间传输文件。下面我将用300字来解释一下LabVIEW和Ymodem协议。 LabVIEW是由美国国家仪器公司(National Instruments)开发的一种图形化编程语言和开发平台。它采用了数据流图的形式,用户可以通过将不同的功能模块拖拽在一个主程序框图中来设计程序。这些功能模块可以代表不同的传感器、仪器或控制设备,通过连接线将它们连接在一起,形成一个完整的程序。 而Ymodem协议是一种常用的通信协议,它主要用于在计算机之间可靠地传输文件。Ymodem协议通过发送和确认数据包的方式来实现文件传输。发送端将要传输文件分成一个个固定大小的数据包,并逐个发送给接收端。接收端在接收到一个数据包后,会向发送端发送一个确认信号,表示已经成功接收。如果发送端在规定的时间内没有收到确认信号,就会重新发送该数据包。 在LabVIEW中使用Ymodem协议进行文件传输是非常方便的。LabVIEW提供了丰富的通信库函数和工具箱,用户可以直接调用这些函数来实现Ymodem协议的功能。用户可以通过编写LabVIEW程序来实现发送文件和接收文件的功能。通过使用LabVIEW的图形化编程界面,用户可以直观地设计程序,而不需要编写繁琐的代码。 总之,LabVIEW是一种图形化编程语言和开发平台,用于控制、测量和数据采集等应用。Ymodem协议是一种常用的通信协议,用于可靠地在计算机之间传输文件。在LabVIEW中使用Ymodem协议是非常方便的,只需要调用相应的函数和工具箱即可实现文件传输的功能。 ### 回答3: LabVIEW是一种由National Instruments开发的图形化编程语言和开发环境。而Ymodem协议则是一种文件传输协议,主要用于在计算机之间进行文件传输。 LabVIEW中可以通过使用串口通信模块来实现通过Ymodem协议进行文件传输。首先,需要使用LabVIEW内置的串口通信函数来建立与目标设备之间的连接。然后,可以使用LabVIEW提供的功能来实现Ymodem文件传输方法。 Ymodem协议文件传输主要分为三个阶段:文件名发送、文件数据发送和文件信息确认。在LabVIEW中,可以通过序列的方式逐一发送这些阶段所需的信息。 首先,在文件传输之前,发送端需要先发送文件的名称和大小等信息给接收端。发送端可以通过LabVIEW中的串口通信函数来发送这些文件信息。 接着,在文件数据传输阶段,通过LabVIEW中的循环结构来不断发送数据帧给接收端。可以使用LabVIEW提供的文件读取功能来读取本地文件的数据,然后按照Ymodem协议的格式发送给接收端。 最后,在接收端接收到数据后,需要发送确认信号给发送端以告知已成功接收到数据。在LabVIEW中,可以使用条件语句来判断接收到的数据是否正确,若正确则发送确认信号。而在发送端,使用循环结构来等待接收端的确认信号,确保数据传输的完整性。 总之,通过LabVIEW可以实现Ymodem协议文件传输。利用LabVIEW的串口通信功能和文件处理功能,可以方便地实现在计算机之间进行文件的可靠传输

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

法哥2012

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值