精华内容
下载资源
问答
  • STM32 IAP固件升级程序源代码。 STM32通过串口,接 收上位机、APP、或者服务器来的数据,更新设备的固件,...
    千次阅读
    2022-04-07 09:41:33

    STM32 IAP固件升级程序源代码。
    STM32通过串口,接 收上位机、APP、或者服务器来的数据,更新设备的固件,也就是说上位机端(需用户自己编写)可以通过wifi转串口,网口转串口,GPRS转串口模块等,给这个STM32设备端发送设备要升级的固件程序(BIN文件)。
    这是一个设备端(客户端)固件程序。
    串口采用环形队列接收模式,超强处理。
    :86100626557937528dgkghkgj

    请添加图片描述

    更多相关内容
  • 该软件用于串口升级,使用YModem协议,通过串口对产片进行升级,方便调试测试自己所写的升级程序,也可以直接作为升级工具使用
  • 4.支持一键升级(在主程序运行状态下直接更新固件) 资料内容: 1.包含单片机运行程序及Bootloader源码; 2.包含C#上位机源码【VS2019】 3.包含QT上位机源码(C++) 4.包含exe可直接运行上位机 答疑: 问:我用的...

    这套IAP升级代码是用在产品中的,稳定可靠!!!

    更新日志:

    2020.10.30

    1.增加QT版上位机【QT版本V4.11.1】;

    2.重构升级逻辑,避免升级过程因干扰或中断造成失败;

    3.优化代码逻辑;

    4.支持一键升级(在主程序运行状态下直接更新固件)

    资料内容:

    1.包含单片机运行程序及Bootloader源码;

    2.包含C#上位机源码【VS2019】

    3.包含QT上位机源码(C++)

    4.包含exe可直接运行上位机

    答疑:

    问:我用的硬件是485,可以直接用吗?

    答:不论是232还是485,本质都是单片机的串口协议,都可以使用,485需要配置收发引脚

    请添加图片描述
    请添加图片描述
    请添加图片描述
    请添加图片描述
    请添加图片描述
    请添加图片描述

    展开全文
  • 基于YMODEM协议,实现串口IAP程序升级
  • 上位机用于给STM32进行串口IAP固件升级上位机升级原理可以移植到其他控制器实现STM32单片机远程固件升级,亲测稳定可用
  • 采用MFC+winapi编写的一个串口调试工具,支持程序升级,以及shell命令调试,日志保存等功能。采用多线程通信机制来控制升级过程界面刷新以及后台升级数据包发送解析等,对于想要做C++上位机工具的同学来说可以从种学...
  • QT编写的IAP升级上位机 ,学习QT,带校验和重传。
  • IAP更新操作说明第一个文件夹:bootloader程序第二个文件夹:上位机下载程序源码第三个文件夹:需要更新下载的代码第四个文件:下载工具可执行文件第五个文件:生成的pbdr.bin文件,用于更新。一、硬件设计:升级...

    IAP更新操作说明

    第一个文件夹:bootloader程序

    第二个文件夹:上位机下载程序源码

    第三个文件夹:需要更新下载的代码

    第四个文件:下载工具可执行文件

    第五个文件:生成的pbdr.bin文件,用于更新。一、硬件设计:

    升级下载程序采用外部硬件触发的方式。

    PB-20M4硬件板 预留一个IO口处理代码下载及更新的功能。

    功能简介:开机前若将 PB4接口与GND用杜邦线(改进硬件后可用跳帽)短接, LED6闪烁状态,即可进入固件下载功能程序,然后等待串口输入接收APP程序(.bin文件,生成方法见后面说明、分段接收每包2K数据,进行CRC校验),在接收完APP程序包后,断开PB4与地线的连接即可进入用户程序。

    用到的资源:指示灯DS6

    一根短接线,优化硬件后可用跳帽

    串口(共地)

    图一  硬件指示图

    图二  串口连接

    二、软件设计

    总共涉及三部分代码:1、Bootloader;2、Flash App;3、上位机程序

    1.Bootloader;

    主函数进行任务判断,以及IAP更新和跳转等各项操作。串口中断中运行数据处理,数据检测,与上位机及握手校验等任务。Bootloader大小仅16K左右。

    2、Flash App;

    需要下载的程序,设置flash起始地址偏移量,由bootloader串口中断中写到flash中去。在初始化的时候执行跳转,运行该代码程序。

    3、上位机发送校验程序

    协议如下:

    /*---------------------------------------------------------------------

    protocol-----|#|remainSend|#|length|data[]|CRC_check

    ---------------------------------------------------------------------*/

    IAP不是一下子把所有BIN文件都接收过来写入FLASH,而是根据自己硬件的RAM空间,把BIN文件分成若干包,如每1K,2K等传送一次,传送当中加上帧头,帧尾,CRC,及总共多少包,及这是第几包等信息封装好的数据包,每接收一包写相应FLASH,下一包对应的FLASH地址++,如此完成固件更新。三、上位机设计:

    打开应用程序IAP_Download_USART\IAP_Download_USART\obj\Debug中exe文件。

    或直接打开附件中IAP_Download_USART.exe应用程序

    运行界面

    烧录过程:

    开发环境如下:

    VS2013上用C#设计的简单的串口应用程序,基于.net4.5。

    主要代码:

    详见附件。

    四、IAP说明

    IAP(In Application Programming)即应用编程,IAP是用户自己的程序在运行过程中对User Flash的部分区域进行烧写,后期可以方便的通过预留通信口对产品进行更新升级。在实现IAP功能时,需要在设计固件程序时编写两个项目的代码,第一个项目程序(bootloader程序)不执行正常的功能操作,而是只通过某种通信方式接收程序和数据,执行对第二部分代码的更新;第二个项目代码是功能代码(APP程序)。这两部分项目代码都同时烧录在User Flash中,在芯片上电后,首先执行第一个项目的代码,进行如下操作:检查是否需要对第二部分代码进行更新

    如果不需要更新,则运行第二部分代码

    若需要更新,执行更新操

    更新完成,执行第二部分代码

    Bootloader代码必须通过其他手段,如JTAG或ISP烧录;第二部分代码使用Bootloader程序IAP功能烧录,也可以通过JTAG烧录,以后需要更新时可以通过IAP代码进行烧录。

    两部分代码存放在flash不同的地址位置,从最低地址区开始存放Bootloader,在其后指定位置存放APP程序。

    STM32F4的内部闪存(flash)地址起始于0x08000000,一般情况下,程序文就从此地址开始写入。此外STM32是基于Cortex-M4 内核的微控制器,其内部通过一张“中断向量表”来响应中断,程序启动后,将首先从“中断向量表”取出复位中断向量执行复位中断程序完成启动,而这张“中断向量表”的起始地址是0x08000004,当中断来临,STM32F4 的内部硬件机制亦会自动将PC 指针定位到“中断向量表”处,并根据中断源取出对应的中断向量执行中断服务程序。

    IAP程序满足的要求:新程序必须在IAP程序之后的某个偏移量为x的地址开始;

    必须将新程序的中断向量表相应的移动,移动的偏移量为x;

    1.程序起始地址设置方法

    打开pbdr_v110工程,点击Options for Target /Target选项卡,如图一所示:

    图一 Flash app target 选项卡设置

    默认条件下,图中IROM1的起始地址(Start)一般为0x08000000,大小1M(Size)为0x100000。而我们设置APP程序起始地址为0X08010000,即偏移量为0x10000(64K字节),留给用户flash空间(size)是1024k-64k=960K。偏移量是定义留给bootloader程序的地址空间大小。发布者可以定义bootloader空间的大小这里我定义的是64K,偏移量为0x200的倍数即可。(本设计的bootloader只有16K左右),这里留有余量,方便bootloader以后的升级修改。

    1.中断向量表的偏移设置方法

    在pbdr_v110版本中在mian.c中设置如下:

    完成中断向量表偏移量的设置

    MDK编译默认生成.hex文件,而升级程序需要生成.bin文件。MDK自带的格式转换工具fromelf.exe,来实现.axf文件到.bin文件的转换。该工具在MDK的安装目录\ARM\BIN40文件夹下。通过下一步设置,可以在MDK编译成功之后,调用fromelf.exe (注意,MDK的安装路径,我的路径D:\Keil_v5\ARM\ARMCC\bin),根据当前工程pbdr.axf,生成一个pbdr.bin文件。存放在OBJ文件夹下。在得到.bin文件后,我们只需要将这个bin文件通过串口传送给单片机,即可执行代码的下载以及升级。

    五、下载验证:

    将JTDO(PB4)与GND短接,上电后,LED灯D6开始闪烁,说明进入下载更新状态。

    丝印见PB-20背面。

    通过TTL转usb连上电脑端串口,打开IAP更新软件(打开应用程序IAP_Download_USART\IAP_Download_USART\obj\Debug文件夹中IAP_Download_USART.exe文件或直接打开附件中IAP_Download_USART.exe应用程序),打开串口即可选则发送BIN文件进行代码下载。

    关闭下载窗口,断开短接线即可运行更新后的程序。

    stm32 IAP Bootloader V1.4源码:

    /*--------------------------------------------------------------------------------------

    @file:    IAP_Serial

    @version: V1.0

    @author:  Shanwu.5_W && Potter_lv

    @Introduction : Unlock flash   load_app from serial

    --------------------------------------------------------------------------------------*/

    #include "sys.h"

    #include "delay.h"

    #include "usart.h"

    #include "led.h"

    #include "stmflash.h"

    #include "iap.h"

    void Button_Switch_DFU_Init(void)    //按键升级初始化

    {

    GPIO_InitTypeDef GPIO_InitStructure;

    RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOB, ENABLE);

    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN;

    GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_NOPULL;

    GPIO_InitStructure.GPIO_Pin = GPIO_Pin_3;

    GPIO_Init(GPIOB, &GPIO_InitStructure);

    }

    #define  GET_BUTTON_STATE   GPIO_ReadInputDataBit(GPIOB, GPIO_Pin_3)

    int main(void)

    {

    u8 t;

    NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);//设置系统中断优先级分组2

    delay_init(168);  //初始化延时函数

    uart_init(115200);                //初始化串口波特率为115200

    LED_Init();                                        //初始化LED

    Button_Switch_DFU_Init();                //初始化跳转APP程序接口

    while(1)

    {

    t++;

    delay_ms(10);

    if(t==30)

    {

    LED0=!LED0;                  //D6闪烁 等待更新状态

    t=0;

    }

    if(GET_BUTTON_STATE != 0x00)        //悬空进入更新进程

    {

    if(((*(vu32*)(FLASH_APP1_ADDR+4))&0xFF000000)==0x08000000)   //判断是否为0X08XXXXXX.

    {

    USART_Cmd(USART2, DISABLE);                                //失能串口2 ,防止跳转到App程序时死机

    iap_load_app(FLASH_APP1_ADDR);                             //执行FLASH APP代码

    }else

    {

    printf("非FLASH应用程序,无法执行!\r\n");

    }

    }

    }

    }复制代码

    0.png (45.22 KB, 下载次数: 35)

    2018-10-18 14:32 上传

    全部资料51hei下载地址:

    IAP_release.rar

    (2.24 MB, 下载次数: 660)

    2018-10-18 14:39 上传

    点击文件名下载附件

    iap升级的例子

    下载积分: 黑币 -5

    展开全文
  • 与我博客里面写的STM32串口iap升级相关博文关联,单片机下载iap和app固件后,通过QT上位机连接STM32设备串口可实现单片机固件的交替升级功能,亲测稳定可用
  • STM32 IAP升级固件 + 上位机 例程

    千次阅读 2020-05-17 16:18:59
    2、APP固件程序实现自定义功能,接收上位机下发的bin文件 3、上位机加载APPbin文件,分割下发至APP固件程序(本例程使用QT开发) 一、IAP升级简单介绍 原理参见: 两种方式: 本例程采用方式二升级 二、 ...

    本例程实现功能:

    1、IAP固件程序实现固件APP搬移,跳转至APP

    2、APP固件程序实现自定义功能,接收上位机下发的bin文件

    3、上位机加载APPbin文件,分割下发至APP固件程序(本例程使用QT开发)

    一、IAP升级简单介绍

    基本原理不做赘述,参见:https://blog.csdn.net/wzy15965343032/article/details/88545225

    两种方式:

    方式1:  IAP固件直接接收上位机下发的程序,将程序写入APP区域,完成后跳转至APP部分。这种方法正点原子有相应的例程;

    方式2:

    FALSH区域分为4部分:IAP区、APP运行区、APP下载区、参数区域

    1、IAP部分检测APP程序是否有更新,有更新需从APP下载区搬运程序至APP运行区,完成后跳转至APP区域;如无更新,直接跳转。

    2、APP区域负责运行程序主流程,如是APP升级数据包,则将此包写入APP下载区,同时更新参数区升级标志

    3、APP下载区主要存放更新程序

    4、参数区域存放升级标志以及其他参数

    本例程采用方式二升级

    二、固件程序

    STM32F103CBT6芯片使用HAL库开发

    1、flash区域划分

    分区大小扇区地址
    IAP10k0-90x08000000-0x080027FF
    APP运行区58k10-570x08002800-0x08010FFF
    APP下载区58k58-1260x08011000-0x0801F7FF
    参数区2k127-1280x0801F800-0x0801FFFF

    2、IAP程序开发

    根据需求,IAP程根据参数区标志位判定是否要升级,只需要完成flash读写即可,为方便调试附带串口打印功能;

    跳转APP部分程序一为固定代码,如下程序流程图如下:

    程序例程:

    //跳转到应用程序段
    //ulAddr_App:APP运行区地址.
    void IAP_ExecuteApp ( uint32_t ulAddr_App )
    {
        pIapFun_TypeDef pJump2App;
        //检查栈顶地址是否合法.
        if ( ( ( * ( __IO uint32_t * ) ulAddr_App ) & 0x2FFE0000 ) == 0x20000000 )    
        {
             pJump2App = ( pIapFun_TypeDef ) * ( __IO uint32_t * ) ( ulAddr_App + 4 );    
             //用户代码区第二个字为程序开始地址(复位地址)        
             MSR_MSP( * ( __IO uint32_t * ) ulAddr_App );
             //初始化APP堆栈指针(用户代码区的第一个字用于存放栈顶地址)
             pJump2App ();                                                                        
             //跳转到APP.
        }
    }       
    
    void IAP_Copy_App(void)
    {
        uint8_t i;
        uint8_t buf[2] = {0x96,0x69};
        //擦除App扇区
        Flash_EraseSector(10,67);
        
        for(i = 0;i < 58;i++)
        {
             FLASH_ReadPage(68 + i,FLASH_BUFF);
             HAL_Delay(10);
             FLASH_WritePage(10 + i,FLASH_BUFF);
        }
        
        FLASH_WriteNData(FLASH_APP_UPTADE,buf,2);
    }
    
    int main(void)
    {
    
      /* USER CODE BEGIN 1 */
      /* USER CODE END 1 */
      /* MCU Configuration----------------------------------------------------------*/
      /* Reset of all peripherals, Initializes the Flash interface and the Systick. */
      HAL_Init();
      /* USER CODE BEGIN Init */
      /* USER CODE END Init */
      /* Configure the system clock */
      SystemClock_Config();
      /* USER CODE BEGIN SysInit */
      /* USER CODE END SysInit */
      /* Initialize all configured peripherals */
      MX_GPIO_Init();
      MX_DMA_Init();
      MX_USART3_UART_Init();
      /* USER CODE BEGIN 2 */
      USER_UART_Init();
      /* USER CODE END 2 */
      /* Infinite loop */
      /* USER CODE BEGIN WHILE */
            HAL_Delay(100);
          printf("IAP start\r\n");    
       while(1){
               uint16_t ret = FLASH_ReadHalfWord(FLASH_APP_UPTADE);
               printf("update = %04x \n",ret);    
           if(ret == UPTADE_FALG)
           {
               printf("Updata App...\r\n");
                   IAP_Copy_App();
               printf("Updata App Succeed...\r\n");
           }
           IAP_ExecuteApp(FLASH_APP_START);
         }
      /* USER CODE END 3 */
    }

     

    3、APP程序开发

    APP程序需要:1、flash读写;2、串口接收,发送;3、中断向量表重定义;4、程序重启

    程序主流程:串口接收数据包(1024byte)直接写入flash(58扇区开始,往后写),为方便方便理解移植,本demo接收16K文件然后重启。(正式版本可以通过通信协议控制

    void IAP_WriteBin(int ii,uint8_t *pBuff,uint32_t Len)
    {
        uint8_t buf[2] = {0xAA,0x55};
        //擦除DOWNLOAD扇区
        Flash_EraseSector(68+ii,68+ii+1);
        //写入程序
        FLASH_WritePage(68+ ii,pBuff);
        if (ii > 15){
              //更新标记
              FLASH_WriteNData(FLASH_APP_UPTADE,buf,2);
              //复位单片机
             NVIC_SystemReset();
         }
    }
    
    
    void cmdProcess()
    {
        if(g_rx232_end_flag == 1)
        {        
            IAP_WriteBin(current,g_rx232_buffer,g_rx232_len);
                  current ++;
                    HAL_Delay(10);
                  memset(g_rx232_buffer,0,g_rx232_len);/*清接收缓存 */
                  g_rx232_len=0;                       /*清除计数 */
            g_rx232_end_flag=0;                  /*清除接收结束标志位*/
            HAL_UART_Receive_DMA(&huart3,g_rx232_buffer,BUFFER_SIZE);/*重新打开DMA接收*/
        }
        
            if(g_rx485_len)
        {        
                  IAP_WriteBin(current,g_rx232_buffer,g_rx232_len);
                  current ++;
                   HAL_Delay(10);
                   memset(g_rx485_buffer,0,g_rx485_len);/*清接收缓存 */
                  HAL_UART_Receive_DMA(&huart1,g_rx485_buffer,BUFFER_SIZE);
                  g_rx485_len = 0;
        }
    }

    三、上位机程序

    使用QT进行开发

    1、加载BIN文件

    2、串口操作

    3、程序分割下载(1024字节bin文件数据包)

    void MainWindow::on_pushButton_loadfile_clicked()
    {            
           QString fileName=QFileDialog::getOpenFileName(this,QString::fromLocal8Bit("bin file"),qApp->applicationDirPath(),
    
        QString::fromLocal8Bit("bin File(*.bin)"));//新建文件打开窗口
         if (fileName.isEmpty())//如果未选择文件便确认,即返回
        return;
    
         QFile file(fileName);
         if(!file.open(QIODevice::ReadOnly)
         ui->label_filepath->setText(file.errorString());//文件打开错误显示错误信息
         arry=file.readAll();//读取文件
         ui->label_filepath->setText(fileName);
         ui->textEdit_3->append(arry.toHex());
         qDebug()<<arry.length();
         file.close();
    }
    
    void MainWindow::on_pushButton_download_clicked()
    
     {
    
         if (arry.length() <= 0){
    
             qDebug()<<"part num = 0 ";
    
             return;
    
         }
    
    
         unsigned char temp[1200];
    
         unsigned char crc[2];
    
         QString string;
    
         int j = 0;
    
         QByteArray partbuff;
    
         partbuff.resize(1200);
    
         partbuff.clear();
    
         upgrade.sum_part = arry.length()/1024;
    
         for(int i = 1 ;i <= upgrade.sum_part; i++)
    
         {
    
             partbuff.clear();
    
             partbuff.append(arry.mid(j,1024));
    
             memcpy( temp,partbuff,1024);
    
             myCom->write(partbuff,1024);
    
             delay_MSec(3000);
    
             //升级判定返回
    
             ui->progressBar->setValue(0);
    
             j = j + 1024;
    
             string = "\n" + QString::number(i) + "\n" +partbuff.toHex() +ui->textEdit_4->toPlainText();
    
             ui->textEdit_4->clear();
    
             ui->textEdit_4->setText(string);
    
             delay_MSec(100);
    
         }
    
     }

    本例程源码:

     

    展开全文
  • DSP软件串口升级

    2015-04-21 22:16:35
    介绍了DSP 的一种程序烧录方案,此方案可行性,已测试过
  • Ymodem固件更新上位机串口程序(c++),qt5.11.0 mingw32位. 实现的上位机,没有在正规的Ymodem下位机上尝试过。看网络资料,起始包的里的文件长度是16进制字符串,本程序用的是10进制字符串。有点类似超级终端。
  • 在实际工程项目中使用的STM32F2xx的通过串口升级程序的源码,串口通信协议采用常见的ymodem。注意传输块大小选择1024字节,带crc16校验。如采用的是该系列单片机,可直接使用(非常稳定)。其它系列的单片机也有极大...
  • stm32在线升级程序,加VB做的上位机

    热门讨论 2011-12-24 14:10:47
    STM32在线升级程序,和VB做的上位机,调试可以将bin文件下载进STM32的flash指定位置
  • QT上位机给STM32设备串口IAP升级固件

    千次阅读 2018-07-30 15:47:45
    QT上位机给STM32设备串口IAP升级固件 目录 QT上位机给STM32设备串口IAP升级固件 1,实现原理 2,程序流程 3,关键代码解析 4,相关工具及代码 废话不多说看看效果先 上位机源码连接:...
  • ISP:In System Programming (在系统中编程),通过芯片专用的串行编程接口对其内部的程序存储器进行擦写。 IAP:In Application Programming(在应用中编程),通过调用特定的bootloader程序,...
  • 通过使用STM32F103C8T6串口1,采用YModem协议对固件进行IAP升级,手工编写,测试有效。IAP程序大小12K,因此APP程序其实地址为0x8003000,同时中断偏移量也需要修改。
  • 开发环境:Window 7 开发工具:Keil uVision4 ...1.PC端下载一个上位机Flash Loader Demo 2.芯片的串口引脚Tx、Rx(PA.9、PA.10)通过USB>TTL连接到电脑上 3.将芯片的boot0引脚接高电平、boot1引脚接低电平。
  • 开源串口 Ymodem 上位机软件

    千次阅读 2019-09-28 02:45:49
    上位机使用Qt开发,计划整合多个工具为一体,用作以后的调试工具。 当前完成功能: 1、串口调试 支持hex和ascii 码发送,接受. 支持自动添加回车换行. 支持定时发送,最短间隔100ms,最大2000ms。 2、Ymodem-IAP...
  • STM32_IAP上位机程序

    热门讨论 2011-03-08 19:24:17
    STM32_IAP上位机程序,通过·串口更新升级基于stm32系列单片机应用程序,可以配合官方的例程使用,替代超级终端,本程序和ST官方的单片机IAP例程一样采用YMODEM协议。
  • 基于STM32F103C8T6的IAP固件升级程序,使用USART升级,协议为YMODEM,同时附带上位机及其源码 :4320657106112716NINGO
  • 1.内含avr单片机下位机源码c程序,本人在atmega128单片机上已经成功运行,能够和资源内的上位机程序配合进行程序升级。 2.c程序里有修改指南;大家根据自己的cpu型号,对c程序进行相应的修改。 3.c程序的运行环境为...
  • 上位机工具通过串口发送.bin文件,走的是Modbus协议,一帧数据里包含200Byte的升级包。stm32接收到数据校验没问题后,将升级包写入Flash。
  • 欢迎转载,请注明出处! ©MrWang_tju 2019.8.1 BootLoader是在操作系统内核运行之前运行的,主要功能是初始化硬件设备、建立内存空间映射图,从而将系统的软硬件环境带到一...ARM内核芯片下载程序方式可分为三类;...
  • 网络升级的优点传输速度快,但是驱动复杂,升级场地局限(必须要有上位机)。U 盘升级的优点不受场地限制,传输速度快,但是驱动有点复杂。不过 ST官方已经将 USB 的驱动提供给大家,这样我们需要的编写的就更集中在...
  • 针对电动舵系统批次性修改控制程序需要从整弹拆下工序复杂的现状,提出了利用422串行通信接口进行程序在线加载的方案。设计了基于STM32控制器中的用户bootloader程序和电动舵机控制程序,通过电动舵机控制程序实现...
  • STM32 IAP 在线升级在应用编程 功能 实验,包括代码,实验教程文档,IAP程序,应用程序以及上位机VB源代码
  • 上位机串口通信分发升级包部分 上位机与STM32之间的串口数据通信协议约定 包头 包长度 命令 0~n字节数据 校验和 0xff 0x** 0x** 0x**....0x** 0x** 校验和计算方法 从...
  • 【自己动手写上位机串口通信

    万次阅读 2015-09-22 22:54:42
    【自己动手写上位机串口通信 C#编写 本篇主要内容: 介绍C#串口类:SerialPort 封装串口类   名称 描述 Ser

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 1,257
精华内容 502
关键字:

串口升级上位机程序

友情链接: ucnvhz.rar