历史上的今天
返回首页

历史上的今天

今天是:2024年10月14日(星期一)

正在发生

2019年10月14日 | LPC1768 IAP升级方法

2019-10-14 来源:eefocus

1、IAP介绍

IAP即“in applicatinprogramming”在应用编程的缩写,指MCU可以在系统中获取新代码并对自己重新编程,即改变应用程序。它与我们所熟悉的ISP编程不同,      

LPC1768 的ISP编程接口为串口1,如果使用其他的串口或其他总线则不能对其进行编程。而我们这里所说的IAP通过下载一段引导程序Bootloader程序,如果我们想要从串口2或网口更新应用程序,在Bootloader中初始化相应的串口或网口,使其接收应用程序,将接收到的应用程序写入到Flash里面,IAP完成后跳转到应用程序入口执行应用程序。所以现在的IAP程序涉及到两个概念:Bootloader和应用程序。


Bootloader:BootLoader就是在操作系统内核运行之前运行的一段小程序。通过这段小程序,我们可以初始化硬件设备、建立内存空间映射图,从而将系统的软硬件环境带到一个合适状态,以便为最终调用操作系统内核准备好正确的环境。这里我们所说的Bootloader也是系统开机前的一段小程序,其主要任务是用来初始化串口和IAP端口(网口CAN接口等)的,通过判断状态是否需要从IAP端口进行更新应用程序,若需要更新则从端口接收应用程序,并存放到指定的Flash里面,更新完成后则跳入到指定的Flash里面执行应用程序。


应用程序:即我们需要开发板实现功能的程序,其中应用程序主要分为两种:hex文件和bin文件。在我们经常使用的KEIL中默认编译生成的可执行文件(应用程序)为hex格式的,若需要编译生成bin格式需要做如下修改,加入“D:KeilARMARMCCbinfromelf.exe --bin --output ./Obj/Can_Updata.bin ./Obj/test.axf”,重新编译生成的Can_Updata.bin文件存放在Obj文件夹下。


2、bin格式文件与hex格式文件的区别

bin格式文件是纯粹的二进制文件,使用下载其将其下载到开发板时其内容完全不变,所以对于IAP下载使用bin格式文件是比较方便的,如下图是bin文件的内容与写入到开发板后使用仿真器观察到Flash存放的内容(这段程序当然是可以执行的)。


Hex格式文件:Hex全称(Intel HEX)文件是由一行行符合Intel HEX文件格式的文本所构成的ASCII文本文件。在Intel HEX文件中,每一行包含一个HEX记录。这些记录由对应机器语言码和/或常量数据的十六进制数数字组成。如下图是hex文件的部分数据,其组成由“:CCAAAARR...ZZ ”,CC=10代表长度为16字节,AAAA=0000本条记录中的数据在存储区中的起始地址,RR=00,数据区,ZZ=38为校验,这里就不做仔细说明了。


3、LPC1768 IAP原理

LPC1768复位后开始执行Boot代码,Boot代码可以执行ISP程序或用户的应用代码。发生硬件复位后,P2.10 引脚为低电平,这就被当作启动ISP命令处理器的外部硬件请求。假定在/RESET 引脚上出现上升沿时,电源引脚出现正确的信号,那么在采样P2.10 之前有3ms的时间决定是执行用户代码还是ISP 处理程序。如果P2.10 为低电平且看门狗溢出标志置位,那么忽略启动ISP 命令处理器的外部硬件请求。在没有ISP 命令处理器的请求(硬件复位后P2.10引脚为高电平)时,将搜索有效的用户程序。若发现有效的用户程序,执行控制权就被转移给用户程序。若没有找到有效的用户程序,就将调用自动波特率程序。这里不讨论ISP下载及命令,有兴趣的朋友可以查看LPC1768技术手册第三十二章ISP命令。


在IAP升级中,程序正常执行即用户代码(这里的用户代码是我们所说的IAP引导程序),如下是IAP升级流程图,程序将预留端口(这里提供有串口和CAN总线接口两种)接收到的APP程序bin文件,将接收到的数据写入到指定的Flash区域(例程APP地址为0x0001 0000),程序通过IAP命令将数据写入到Flash里面,LPC1768提供了一系列IAP命令对片内Flash进行擦除编写等


4、IAP命令

LPC1768通过IAP函数对片内Flash进行操作,IAP函数是固化在0x1FFF1FF1处的一个有传入参数和返回参数的一个函数,在LPC1768技术手册第三十二章IAP命令中有有详细的说明。主要提供有如下命令:准备下操作扇区、将RAM内容复制到Flash、清除扇区、扇区查空、读器件ID、读boot版本、比较、重新调用ISP等。


5、串口IAP升级

本例程是根据官方提供的串口IAP更新图片进行修改而来,直接使用官方的IAP.c文件,该文件中提供了如上图IAP命令的各种函数,其具体参数可以参考IAP命令。根据官方例程里面将bmp图片经过串口采用Xmodem1K协议发送到开发板存放在地址0x0001 0000,如下图是LPC1768 Flash分配地址,第16~21扇区为应用程序存放空间。这里我们将要传送的bmp图片改为传输应用程序bin文件


6、串口IAP程序分析

例程通过按键对开发板进行控制,INT0键擦除Flash,确认键等待串口IAP,向上键显示菜单,向下键执行应用程序,使用LCD来开发板状态


当程序全部写入到Flash后,按下向下按键,跳转到应用程序,首先修改中断向量表然后进入应用程序

void Boot( void )

{

        SCB->VTOR = IMG_START_SECTOR & 0x1FFFFF80;        //修改中断向量表

        JMP_Boot(IMG_START_SECTOR);

}

堆栈地址更新,PC地址更新

__asm void JMP_Boot( uint32_t address ){

   LDR SP, [R0]                ;堆栈地址更新

   LDR PC, [R0, #4]        ;进入应用程序

}

7、操作步骤及实验现象

1、下载“宝马开发板串口IAP升级”例程,插上USB转串口线,打开超级终端,复位开发板。

2、按下按键INT0按键--擦除扇区

3、按下方向键确认键(即向下按)--等待接收串口程序

4、串口打印’C’字符等待接收数据

5、串口发送文件,选择“1K Xmodem”协议,选择要下载的应用程序bin文件,这里使用DAC例程作为测试。

6、点击“发送”,发送文件

7、发送完成

8、按下方向键向下键开始执行应用程序,这时我们可以使用示波器测试P0.26口输出正弦波信号


bin文件生成方法及设置:

打开要更新应用程序工程,这里使用“IAP升级DAC转换”程序,设置ROM空间地址(程序下载到Flash的地址),这里也是我们应用程序的入口地址0x10000

打开User选项,利用Keil自带的fromelf.exe生成bin文件,bin文件保存在Obj文件夹中,如下图添加“D:KeilARMARMCCbinfromelf.exe --bin --output ./Obj/app.bin ./Obj/app.axf”,输入文件为app.axf,所以工程编译生成输出文件名设置为app,命令执行生成app.bin文件

打开Asm选项,定义“NO_CRP”,我们可以打开启动文件,当定义了“NO_CRP”后,那么我们后面的代码也就不起作用了,所以在需要加密的时候前面就一定不能再定义了代码读保护,也就是加密的关键字,经过加密后芯片再也无法擦除,由于我们这里程序需要使用到IAP升级,因此添加此定义


编译即可生成app.bin


lpc1768 IAP疑点全解释


IAP简介:

       IAP为在应用编程的简称,其作用是用户自己的程序在运行过程中对用户程序所在的部分区域进行烧写,目的是为了在产品发布后可以方便地通过预留的通信口对产品中的程序进行更新升级。

Lpc1768存储器空间分配:

整体Flash布局:     

地址范围

地址说明

0x1000_0000 ~0x1000_7FFF

片上32K通用SRAM

0x2007_C000 ~0x2007_FFFF

片上16K以太网/USB静态SRAM,可用作通用SRAM

0x2008_0000 ~0x2008_3FFF

片上16K以太网/USB静态SRAM,可用作通用SRAM

0x1FFF_0000 ~0x1FFF_1FFF

片上 8K启动代码区

0x0000_0000 ~0x0007_FFFF

片上512K Flash存储器

其他地址

APB、AHB等寄存器映射区

分散加载描述文件:

分散加载描述文件是arm连接器提供的可以将程序中的代码段、数据段定位到flash中特定的物理地址的一种机制。通过此机制我们可以把给IAP程序和用户程序分别分配一部分空间并制定各自的起始地址以保证IAP程序和用户程序不会重叠。关于分散加载描述文件详细文档,请参考《RealView编译工具----链接器参考指南》第三章,对于IAP涉及到的分散加载文件的知识,我们只需知道以下几点。以本次IAP工程为例,我们给IAP升级代码留32K的空间(0x0000_0000~0x0000_7FFFF),剩余的给用户程序空间(即用户程序从地址0x0000_8000开始)。对于IAP程序部分的分散加载文件不做修改,对于用户程序部分修改如下:

我们仅仅对第5行和第6行做了修改,改动的地方做出了标注,其具体表示意思是:

Line5:0x0000_8000表示加载域的起始地址,即放在flash0x0000_8000地址处开始放置,0x0008_0000表示代码区、数据区的总共大小的最大值,程序文件超过此值将会报错,这里取默认值0x0008_0000即可。


Line6: 0x0000_8000表示执行域的起始地址,即程序从0x0000_8000地址处开始执行,0x0008_0000代表的意思参考上一行。


Line7:此行的作用是把中断向量表定位在起始地址处(这里是0x0000_8000).

要使用此分散加载描述文件,还需要将Target Opitions…->Linker下的Use Memory Layout from Target Dialog前的“√”去掉。

 

IAP函数的使用

Iap函数是固化在Boot Rom中地址0x1FFF1FF1处的一个有传入参数和返回参数的一个函数。对于不同的传入参数,iap函数实现不同的功能。关于这些功能的详细介绍,《LPC1768 user manual》32章第8节IAP commands一节中有详细介绍,这里不赘述。远程升级中我们常用到的几个iap命令是:读器件标识号、准备写操作扇区、擦除扇区、扇区查空、将RAM内容复制到Flash、比较<地址1><地址2><字节数>。


以准备写操作扇区为例说明iap函数的写法。首先定义iap函数的入口地址:

1

#define  IAP_ENTER_ADR  0x1FFF1FF1/*IAP函数入口地址*/

接着声明函数类型指针IAP_Entry:

1

void (*IAP_Entry)(uint32  paramin[ ],uint32  paramout[ ]) ;

初始化IAP函数指针使其指向IAP函数入口地址:

1

2

3

4

void  IAP_EntryInit(void)

{

   IAP_Entry  =( void(*)() )IAP_ENTER_ADR ;

}

由用户手册可知iap命令汇总如下图:

 

Iap状态码汇总如下图:

据此写出IAP命令字和状态码宏定义如下:(PS:Command Code中的数字10表示十进制,如:Read part ID的命令字为5410,表示其命令字为十进制的54,见上图)

准备写操作扇区的命令解释如下图:

由上图可知准备写操作扇区需要三个参数,分别是Command code、Param0、Param1,返回状态码的可能取值为CMD_SUCCESS、BUSY、INVALID_SECTOR。据此我们写处准备写操作扇区的命令函数如下:

1

2

3

4

5

6

7

8

9

uint32  PreSector(uint8  arg1,uint8  arg2)

{

    paramin[0] = IAP_SELECTOR ;    //设置命令字

    paramin[1] = arg1 ;        //设置参数

    paramin[2] = arg2 ;

    (*IAP_Entry)(paramin, paramout) ; //调用IAP服务程序

    Return (paramout[0]) ;      // 返回状态码

}

其中paramin[]、paramout[]为定义的uint32型全局数组。调用此函数时只需将起始扇区号传给arg1,结束扇区号传给arg2即可。其他命令的函数书写于此大同小异。


这里给出一个远程升级的iap流程:读取器件标识码确定是当前芯片→确定待升级程序(用户程序)占用的起始扇区号与结束扇区号→准备需占用扇区→擦除需占用扇区→扇区查空确定需占用扇区已成功擦除→执行将RAM复制到Flash命令将数据块复制到Flash→执行比较命令校验数据是否正确→如果正确执行下一数据块的复制。


需要说明的一点是:在还行IAP命令的时候,需要关闭中断以保证IAP命令的正确执行。幸运的是Cortex-M3提供了关闭/打开中断的指令CPSID I 和CPSIE I,而且在core_cm3.h中也提供这样的开关中断的函数__enable_irq()和__disable_irq(),需要的时候直接去调用就可以。

从bootloader到UsrApp的跳转:

这里我们把引导cpu进入用户代码区的程序称作bootloader,把用户实际实现相应功能的程序称作UsrApp,它们是一个完整的程序,下文提到的bootloader、UsrApp均指这些。


bootloader到UsrApp的跳转需要熟知两方面的知识:一个是中断向量表的重映射,另一个是一段完整的程序的入口是如何定义的。


中断向量表重映射:

在LPC1768中,位于地址0xE000_ED08处有一个向量表偏移寄存器VTOR,通过修改此寄存器可以设定向量表基址位于Code区或是RAM区以及向量表的基址偏移域,以此达到中断向量表重映射的目的。比如我们的UsrApp起始地址为0x8000;为使UsrApp在发生中断行为时不会产生错误或异常,我们可以通过以下代码段将中断向量表重映射到地址0x8000处Code区。

1

SCB->VTOR = USR_APP_START_ADDR &0x1FFFFF80;

SCB->VTOR由core_cm3.c提供,对应向量表偏移寄存器地址0xE000_ED08。USR_APP_START_ADDR为用户代码区的起始地址,和数值0x1FFFFF80按位与是保证寄存器的保留位为0和向量表基址位于Code区。此寄存器的详细说明请参考《cortex-M3技术参考手册》第八章第二节的NVIC寄存器描述或《LPC17XX User manual》英文版34.4.3.5章节。,此处不再贴出。对于用户程序,在bootloader中的向量表偏移设置并不起作用,需要在用户程序中重新设置向量表偏移寄存器。原因是CM3器件进入main()函数即要求调用SystemInit(void)进行系统初始化,系统初始化的时候将向量表偏移寄存器清零了,所以需要在调用SystemInit()之后重新设置向量表偏移寄存器。有网文称对于应用了OS的用户程序需要这样做,其实对于开启了中断的的用户程序都需要这样,你的简单的IAP测试程序之所以在没有这样做的情况下通过了测试,是因为你的用户程序测试代码中并没有用到中断。


一个完整镜像的程序入口:

对于在flash中存储的一个完整的程序代码,其起始部分应该为向量表,向量表的内容格式固定如下表(参考《cortex-M3权威指南》7.3节)

上电后的向量表:

由表可知,对于起始存储地址为0的一段完整程序,其首地址处存放的是MSP的初始值,偏移4字节的地址处存放的是PC指针的初始值,我们要运行这段完整的程序,只需将这段完整程序的SP、PC初始值赋给SP和PC寄存器即可,具体实现的函数如下:

1

2

3

4

5

__asm void boot_jump(uint32 address)

{

   LDR  SP, [R0]

LDR  PC ,[R0, #4]

}

对于此函数的解释:__asm是MDK的编译器提供的嵌入汇编的指令(RealView C编译器3.0以上版本提供)。函数体中两行汇编代码的功能分别为:

LDR  SP, [R0]:把R0中的值作为地址,将此地址中的值赋给SP

LDR  PC ,[R0, #4]:把R0中的值加4作为地址,将此地址中的值赋给SP

这里涉及到一个问题,r0中的值是什么?我们根据ATPCS(ARM-THUMBprocedure call standard)可知,对于参数少于等于4的函数,参数是通过R0~R3传递的,第一个参数放在R0中,依次类推。所以这里的R0存放的正式UsrApp的起始地址,回过头再看前面的两行汇编代码,它们做的事正是将UsrApp的SP、PC初始值赋给相应寄存器,达到开始运行UsrApp的目的。


UsrApp的烧写:

因为在片内flash的起始地址处烧写的是我们的iap处理程序,用户程序的起始地址不是0x0000_0000,在通过keil用jlink下载程序的时候,还需做一个设置。在Option for Target→Debug→Settings→Flash Download中,设置下载程序时的起始地址为用户程序的起始地址。如本例中用户程序的起始地址是0x0000_8000,我们设置下载程序的起始地址为0x0000_8000,如下图。如果不这么做的话,通过jlink下载程序的时候会从地址0x0000_0000开始擦除。

遗留的问题:

疑问1:《lpc1768 user manual》34.4.3.5章节指出中断向量表偏移寄存器的向量表基址偏移域为[28:8]位,为什么将偏移量实际赋值给此寄存器的时候没有做’<<8’的处理而是直接赋值过来?PS:《Cortex-M3技术参考手册》第8章的表8-15指出中断向量偏移寄存器的向量表基址偏移域为[28:7]


疑问2:手册中指出使用iap的时候RAM顶部32字节空出,这该怎么理解?iap占用ram顶端32字节,即使我不去刻意留出也不影响iap使用这32字节的空间,我能想到的唯一解释是编译器可能会把程序中的全局变量放到ram顶端32字节区域进而调用iap函数会引起全局变量被修改,是这样么?


  如果你读到了这里并且你知道这些答案,敬请告知解惑。

参考过的文献:

《arm汇编指令集》--------网文

《arm启动代码的探究-郑远超》

《arm体系结构与编程》------杜春雷(PS:重点第11章)

《map文件认识初步》-------网文

《汇编器指南》------RealviewMDK

《链接器指南》------RealviewMDK

《中断向量表重映射与复制》------网文

《cortex-m3技术参考手册》


  之前说了stm32的iap编程,今天天气真好,顺手就来说说lpc1788的iap编程(没看前面的请查看stm笔记下的内容)


  首先是flash的算法,lpc1768并没有寄存器来让我们操作flash,他内置了iap的flash算法,在技术手册的525页有如下说明

  

  其支持的iap命令有这些

这样我们就能够做出相关的flash读写借口呢(具体请查看lpc1768的技术手册)

unsigned param_table[5];//传递参数列表

unsigned result_table[5];//返回结果列表

//调用iap命令

void iap_entry(unsigned param_tab[],unsigned result_tab[])

{

    void (*iap)(unsigned [],unsigned []);

    iap = (void (*)(unsigned [],unsigned []))IAP_ADDRESS;

    iap(param_tab,result_tab);

}

  通过这种手段就能够调用iap命令,我们演示性的看一个命令

//扇区准备好指令

//起始扇区号 结束扇区号 系统时钟

void prepare_sector(unsigned start_sector,unsigned end_sector,unsigned cclk)

{

    param_table[0] = PREPARE_SECTOR_FOR_WRITE;

    param_table[1] = start_sector;

    param_table[2] = end_sector;

    param_table[3] = cclk;

    iap_entry(param_table,result_table);

}

  该指令在写flash和擦除flash之前必须调用

具体的完整flash代码请查看工程文件,会在文章末尾上传

然后依旧是五个指令

"iap_down"

"iap_jump_app"

"iap_over"

"iap_set_flag"

"iap_clear_flag"

  功能和之前的stm32差不多,但是下载算法变化了,因为stm32支持的写入是每次写入一个十六位数据,而lpc1768每次写入8位数据,而且每次写入数据的量为128/256/512/1024/4096,正好没有我们之前所用的2048,所以算法修改成如下的样子


  1. u8 iapbuf[1024] = {0}; //用于缓存数据的数组

  2. u16 receiveDataCur = 0;  //当前iapbuffer中已经填充的数据长度,一次填充满了之后写入flash并清零

  3. u32 addrCur = FLASH_APP1_ADDR;         //当前系统写入地址,每次写入之后地址增加2048


  4. #define vu32 volatile unsigned int


  5. //开始下载

  6. void iap_down_s(void)

  7. {

  8.     u16 i = 0;

  9.     u16 receiveCount;

  10.     if(erase_user_flash())

  11.     {

  12.        printf("errorrn");

推荐阅读

史海拾趣

聚辰(Giantec)公司的发展小趣事

自1994年(部分资料显示为1993年,但此处采用最新信息)成立以来,港源公司始终将技术创新视为企业发展的核心驱动力。公司专注于轻触开关、微动开关、AC/DC插座、变压器等开关零组件产品的研发,通过引进国内外先进技术,并自主成功研发了自动化生产设备和检测设备,实现了生产自动化,大幅提升了产品质量和生产效率。港源公司还积极参与国际技术交流与合作,与众多行业标杆客户长期紧密合作,能够尽早了解市场需求,快速响应并推出符合行业标准的新产品,从而引领了电子开关行业的发展方向。

Hifn Inc公司的发展小趣事

面对电子行业的快速变革和市场需求的不断变化,港源公司始终保持敏锐的市场洞察力和持续的创新精神。公司不断加大研发投入,推动产业升级和产品结构优化。通过技术创新和高效智造系统构建,港源公司实现了产品自动化制造的高覆盖率,并在精密小型化的塑胶五金零部件领域取得了突破性技术优势。这些努力不仅使港源公司在市场竞争中保持领先地位,还为公司未来的发展奠定了坚实的基础。

固得沃克(GOODWORK)公司的发展小趣事

在追求经济效益的同时,固得沃克也高度重视环境保护和社会责任。公司所有产品均通过了美国UL、SGS欧盟ROHS及REACH环保认证,确保产品符合国际环保标准。这一举措不仅提升了公司的品牌形象,也为公司拓展国际市场提供了有力支持。近年来,固得沃克的产品已广泛应用于汽车电子、新能源、绿色照明等多个领域,并远销海外多个国家和地区。

Anytek Technology Corporation Ltd公司的发展小趣事

Anytek Technology Corporation Ltd自创立之初,便敏锐地捕捉到了车载电子产品的市场潜力。2003年,公司果断进军车载及行车记录仪领域,凭借前瞻性的市场洞察力和技术积累,迅速在行业内崭露头角。当时,随着汽车保有量的不断增加,行车记录仪作为保障行车安全、记录行车过程的重要设备,市场需求日益旺盛。Anytek凭借高品质的产品和专业的服务,赢得了广大消费者的信任和好评。

ECLIPTEK公司的发展小趣事

ECLIPTEK公司自创立之初就专注于高精度电子元件的研发与生产。面对激烈的市场竞争,公司不断投入研发资源,推出了一系列具有创新性的产品,如高精度时间同步模块和低功耗传感器。这些产品凭借其卓越的性能和可靠性,迅速在市场上赢得了良好的口碑,使ECLIPTEK成为电子元件行业的佼佼者。

台湾丰宾(CapXon)公司的发展小趣事

随着全球环保意识的不断提高,CapXon公司积极响应绿色生产的号召,致力于实现可持续发展。公司采用环保材料和制造工艺,减少生产过程中的污染物排放,降低对环境的影响。同时,CapXon还积极参与各种环保活动和公益事业,为推动电子行业的绿色发展贡献自己的力量。

以上五个故事分别从初创与起步、市场拓展与品牌塑造、技术创新与产业升级、品质管理与生产优化以及绿色生产与可持续发展五个方面,展示了台湾丰宾(CapXon)公司在电子行业发展的历程和成就。这些故事不仅体现了公司的实力和魅力,也展现了公司在推动电子行业进步和可持续发展方面所做的努力和贡献。

问答坊 | AI 解惑

数字电视地面标准推迟出台

本帖最后由 jameswangsynnex 于 2015-3-3 19:59 编辑 数字电视地面标准推迟出台 不含手机电视部分 2006-7-5     虽然已进入7月,原来“铁定”在6月底前出台的数字电视标准(即数字电视地面传输标准)却仍然迟迟不见踪影。   负 ...…

查看全部问答>

4位温度计,不能正确显示!

(有程序和Proteus仿真图)…

查看全部问答>

AVR(MEGA16)入门教程,详细的图解教程

AVR(MEGA16)入门教程,详细的图解教程…

查看全部问答>

如何用红外对射开关控制继电器

我想用一个红外对射开关控制欧姆龙MY2NJ继电器工作,对射开关的型号见图片 我用黄颜色的线接到继电器,继电器不能工作,继电器都是好的,我用12V电压直接控制继电器,是可以工作的,但用感应的不知道怎么接法。 红外对射开关工作电压是5V,继电器 ...…

查看全部问答>

在动车组两个车厢中的无线传输用什么样的方式更好

想在动车组两个车厢中实现数据的无线传输。 也考虑到一些实现方法,但是由于动车组有屏蔽大,速度快特点,造成无线数据包传输难度很大。 请问各位高手,用什么方式能达到这个目的呢?前提是不对车厢作出改造,比如车体外安装天线等 …

查看全部问答>

软键盘,模拟发送小数点的奇怪问题

现在软键盘基本上可以用了,但还有一个字符:小数点\'.\'不能用,发送字符小数点消息,可在我的应用程序里收到的消息却是:     第一个消息是:pMsg->hwnd为编辑框的句柄,但pMsg->message为15,也就是WM_PAINT,wParam和lParam为0, & ...…

查看全部问答>

又是一个石沉大海的问题!!??

如何在驱动代码中,获得U盘的插入?并获得其盘符(注:此U盘无文件系统) 谢谢,有钱的捧个钱场,无钱的捧个情场…

查看全部问答>

请高手详细介绍一下键盘IO口扩展IC:74164

我是个菜鸟,在学校学习的单片机都是很多过时的芯片,所以有很多不懂。请大家指教一下,这个芯片我还没有接触过。…

查看全部问答>

Fluke 27-II防水防尘数字多用表精确的使用方法

Fluke 27-II 工业多用表 新型 Fluke 27 II数字多用表树立了在困难情况下进行测量的新标准,它具有优异的功能和准确度,可以轻松解决大多数电气故障。 这款多用表均符合 IP 67(防水和防尘)规格,正在接受 MSHA 的认证审批,并且拥有更广的工作温 ...…

查看全部问答>