IAP上位机开发

IAP上位机开发

串口类型和串口名

由于使用到的串口类型和串口名都是系统自带的,我们所能做的只是将电脑中可用的串口搜索出来,并且在上位机上面显示出来供我们使用。因此,我们是没办法自己编辑串口名和串口类型来使用的。因此在设置这两个功能的combo Box的时候,需要修改一下他们的DropDownStyle属性,将其修改为DropDownList,就可以让这两个下拉列表只能够使用提供的选项,而不能由用户自定义编辑。

而串口的波特率有些时候由于预设的波特率不满足需求,需要用户自定义波特率,因此这个时候,下拉列表的DropDownStyle属性就不需要修改,保持为DropDown就行了。

传输文件的打开

我们需要一个button来打开所需要传输的文件,并且将打开了的文件路径显示在一个text box中。但是由于IAP串口升级固件不是所有的文件都能够传输的,因此需要进行判断,不能够传输的文件就无法打开。通过messagebox报告错误信息.

控制编辑的数据内容

由于波特率和下载的初始地址是用户自定义编辑的,因此我们需要控制用户编辑的内容是符合要求的. 比方说波特率的输入只能是数字,不能有其他的内容. 否则波特率就是不合法的,会导致程序错误. 同样的,文件传输的开始地址也是如此. 而要要控制编辑的内容,需要添加keypress事件,在添加的keypress事件函数中添加我们所需要规定的内容就可以了. 具体的实现函数如下所示:

// 传输开始地址编辑内容控制 
private void textBox2_KeyPress(object sender, KeyPressEventArgs e)
 {
     e.Handled = "0123456789ABCDEFabcdef\b".IndexOf(char.ToUpper(e.KeyChar)) < 0;
 }
// 波特率编辑内容控制
 private void comboBox3_KeyPress(object sender, KeyPressEventArgs e)
 {
     e.Handled = "0123456789\b".IndexOf(char.ToUpper(e.KeyChar)) < 0;
 }

要想添加keypress事件可以通过属性边上的闪电标志进行添加.

串口RS232下载

这是整个IAP通过USART串口升级最重要的部分

这个部分可以分为几个部分,我分别进行介绍

获取所需传输的文件信息

要通过串口升级固件,首先就是要知道我们需要发送的文件是什么,内容如何.

这里我们通过一个class类将文件所需的一些基本信息包括进来

public class FilePartInfo
{
    public uint PartStartAddress; //开始地址
    public int PartEndAddress; //结束地址
    public int PartSize; //大小
    public int PartChecksum; //校验位
    public byte[] PartData; //数据
}

由于一个文件太大,不可能一次性发送完成,因此我们的基本信息是一部分一部分的进行收集的.

这个class是将每个部分的信息保存起来,然后将所有部分的信心,统一保存在一个list<FilePartInfo>中.

而要获取所需传输文件的信息,在串口下载的时候还需要进行判断获取信息的过程是否成功,如果失败了,则串口升级就失败了,就需要停止串口下载升级固件.因此,我们需要这个函数返回一个bool类型的值 . 但也需要将所需文件的信息也返回出来,在c#中有一个关键词可以让一个函数返回多个值,就是out. 我们让整个函数返回bool类型的值,然后通过out修饰函数的参数,在函数中对out所修饰的值进行修改,就可以达到返回多个值的目的. 只是out修饰的参数并不是函数的返回值,但是已经在函数中被修改了.

获取所需文件的函数具体实现如下:

private bool GetFileInfo(out uint StartAddr, out List<FilePartInfo> FIleInfo, string filePath)
{
    StartAddr = 0;
    FIleInfo = null;
    if (filePath == string.Empty)
    {
        return false;
    }
    string tempType = filePath.Substring(filePath.LastIndexOf(@"\")).ToUpper();
    if (tempType.Substring(tempType.Length - 3, 3) == "BIN")
    {
        FIleInfo = AddValue(filePath);
        string strAddr = textBox2.Text;
        StartAddr = StringToUInt32(strAddr, 16);
    }
    else
    {
        MessageBox.Show("下载文件格式错误", "Error", MessageBoxButtons.OK, MessageBoxIcon.Error,
                                               MessageBoxDefaultButton.Button1, MessageBoxOptions.ServiceNotification);
        return false;
    }
    if (FIleInfo == null)
    {
        MessageBox.Show("下载文件错误,file information为null", "Error", MessageBoxButtons.OK, MessageBoxIcon.Error,
                                               MessageBoxDefaultButton.Button1, MessageBoxOptions.ServiceNotification);
        CloseProgress();
        return false;
    }
    if (FIleInfo.Count == 0)
    {
        MessageBox.Show("下载文件错误,file information.count为0", "Error", MessageBoxButtons.OK, MessageBoxIcon.Error,
                                               MessageBoxDefaultButton.Button1, MessageBoxOptions.ServiceNotification);
        CloseProgress();
        return false;
    }
    return true;
}

首先是判断是否有文件打开,如果filePath为空,则返回false,文件的信息则还是为null. 如果filePath不为空,则继续判断格式是否复合要求, 不符合的报错,符合的再将文件的基本信息通过AddValue函数保存到事先声明好的列表中. AddValue后,再对列表进行判断,来最后决定是否成功的将所需的文件信息保存到了列表中.

其中AddValue函数的具体实现为:

public List<FilePartInfo> AddValue(string FilePath)
{
    if (!File.Exists(FilePath))
    {
        return null;
    }
    List<FilePartInfo> partInfo = new List<FilePartInfo>();
    FileStream fs = new FileStream(FilePath, FileMode.Open, FileAccess.Read);
    BinaryReader br = new BinaryReader(fs);
    int fullLength = (int)fs.Length;
    if (fullLength == 0)
    {
        return null ;
    }
    int partLength = 0;
    FilePartInfo tempInfo = new FilePartInfo();
    tempInfo.PartStartAddress = 0;
    tempInfo.PartEndAddress = 0;
    tempInfo.PartSize = 2048;
    tempInfo.PartData = new byte[2048];
    for (int k = 0; k < 2048; k++)
        tempInfo.PartData[k] = 0xFF;
    partInfo.Add(tempInfo);
    partLength = 0;
    for(int i = 0; i < fullLength; i++)
    {
        partInfo[partInfo.Count - 1].PartData[partLength] = br.ReadByte();
        partLength++;
        if ((partLength == 0x0800) && (i + 1 < fullLength))
        {
            tempInfo = new FilePartInfo();
            tempInfo.PartStartAddress = partInfo[partInfo.Count - 1].PartStartAddress + 0x0800;
            tempInfo.PartEndAddress = 0;
            tempInfo.PartSize = 2048;
            tempInfo.PartData = new byte[2048];
            for (int k = 0; k < 2048; k++)
                tempInfo.PartData[k] = 0xFF;
            partInfo.Add(tempInfo);
            partLength = 0;
        }
    }

    return partInfo;
}

同样的,首先是对filePath进行判断,只有文件路径存在,才说明有文件的信息需要保存.

当文件路径存在的时候,再通过文件流filestream对文件进行打开,并且使用binaryreader进行对文件进行读取.(因此文件我们规定只有二进制文件能够传输) 然后通过tempInfo将文件的信息一部分一部分的保存在声明的列表中. 由于串口通信协议规定不满足2k的数据用0xFF填充,因此我们先将所有的数据都填充为0xFF,然后再对实际的数据进行更改. 最后将所有的 数据都保存到列表后,返回列表.

串口通信

串口通信其实就是根据串口通信协议,对上位机面对不同情况的时候所需要做出的反应进行设置就可以了.

由于串口通信协议中对于超时的情况认定为通信失败,因此我们需要获取时间来判断是否超时. 而计算机中一个经典的获取时间的方法为:

private long GetCurrentTimeSeconds()
{
    long currentTicks = System.DateTime.Now.Ticks;
    System.DateTime dtFrom = new System.DateTime(1970, 1, 1, 0, 0, 0, 0);
    long currentMillis = (currentTicks - dtFrom.Ticks) / 1000 / 1000 / 10;
    return currentMillis;
}

1970年一月一日00:00:00是Unix纪元时间. 这个函数通过获取当前时间距离Unix纪元时间的时间来确定当前的时候. 两次调用这个函数得到的结果的差值就是我们所需要的时间间隔,当时间间隔大于我们通信协议中规定的时间时,就认为是超时了,则串口通信失败,停止串口升级.

串口通信函数有两个,一个是IAP固件刚开始升级的时候,用来判断0x5A 0xA5是否正常通信的,另一个是,进入IAP升级的时候,用来判断是否正常升级的函数.

两个函数之间的主要区别在于:

  1. 功能目的不同:
    • PortCommunicationRS232Begin的主要目的是建立串口通信连接,并等待设备返回特定的应答字节序列(0xCC 0xDD),以确认连接已建立。
    • PortCommunicationRS232的主要目的是通过已建立的串口连接发送和接收数据。
  2. 接收数据处理逻辑不同:
    • PortCommunicationRS232Begin在接收数据时,专门寻找特定的应答字节序列(0xCC 0xDD),并根据是否收到该序列来判断是否连接成功。
    • PortCommunicationRS232在接收数据时,只是简单地将接收到的字节存储到提供的接收缓冲区中,不做特殊处理。
  3. 超时处理逻辑不同:
    • PortCommunicationRS232Begin在等待应答时,如果超过5秒钟没有收到期望的应答序列,就会退出循环并返回失败。
    • PortCommunicationRS232在接收数据时,如果连续5次读取操作失败,就会认为超时并返回失败。
  • 14
    点赞
  • 26
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
STM32 IAP(In-Application Programming)上位机是指通过串口及相关协议,在硬件级别上实现对STM32单片机程序的在线升级或更新,使得在不连接到调试器或者烧录器的情况下,可以实现固件的更新与修改。同时采用IAP上位机的方法可以避免反复插拔ST单片机导致的损坏风险和便于远程升级。 STM32 IAP上位机方案的实现总体上需要实现以下几个步骤: 1.编写软件升级程序:需要选择合适的编译器,并选择合适的STM32芯片型号。在编写程序的过程中需要实现串口初始化、将程序固化在Flash中、检测程序更新、回复ACK或NAK指令等操作。 2.升级文件的生成:编写程序后需要将其进行编译,并生成HEX格式的升级文件。升级文件的生成需要注意程序image在Flash中的大小是否超出芯片Flash容量,否则将无法固化程序。 3.STM32与上位机连接:将STM32芯片与上位机通过串口进行连接,并需要对串口进行初始化(波特率等)。 4.进行数据传输:数据传输需要根据指定协议进行传输,如启动指令、升级指令等。 5.数据接收及处理:数据传输完成后,需要接收上位机发送过来的升级文件,并进行相关的处理既写入flash。 总的来说,STM32 IAP上位机可以提高固件升级的效率、方便性,并降低了无意中损坏设备的风险。但由于实现需要较长的过程,并且相对较为复杂,需要进行一定的开发经验与技能才能实现。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值