STM32的BootLoader升级

发布者:qiuxubiao最新更新时间:2018-08-22 来源: eefocus关键字:STM32  BootLoader  升级 手机看文章 扫描二维码
随时随地手机看文章

从串口升级固件


①Jump_To_Application  = (pFunction)(*(vu32*) (IAPSTART + 4));

__MSR_MSP(*(vu32*) IAPSTART);

Jump_To_Application();


跟踪__MSR_MSP(一般这个函数都在库文件里有,跟踪不到就用搜索找)找到汇编函数为


__MSR_MSP  

    MSR MSP, r0 ; set Main Stack value

    BX r14




②//跳转到应用程序段

//appxaddr:用户代码起始地址.

void iap_load_app(u32 appxaddr)

{

if(((*(vu32*)appxaddr)&0x2FFE0000)==0x20000000)//检查栈顶地址是否合法.

jump2app=(iapfun)*(vu32*)(appxaddr+4);//用户代码区第二个字为程序开始地址(复位地址)

MSR_MSP(*(vu32*)appxaddr);//初始化APP堆栈指针(用户代码区的第一个字用于存放栈顶地址)

jump2app(); //跳转到APP.

}

}


跟踪MSR_MSP找到函数为


//设置栈顶地址

//addr:栈顶地址

__asm void MSR_MSP(u32 addr) 

{

    MSR MSP, r0 //set Main Stack value

    BX r14

}




③  //判断用户是否已经下载程序,因为正常情况下此地址是栈地址。

   //若没有这一句的话,即使没有下载程序也会进入而导致跑飞。

   if (((*(__IO uint32_t*)ApplicationAddress) & 0x2FFE0000 ) == 0x20000000)

   {

       SerialPutString("Execute user Program\r\n\n");

       //跳转至用户代码

       JumpAddress = *(__IO uint32_t*) (ApplicationAddress + 4);

       Jump_To_Application = (pFunction) JumpAddress;


       //初始化用户程序的堆栈指针

       __set_MSP(*(__IO uint32_t*) ApplicationAddress);

       Jump_To_Application();

    }


跟踪__set_MSP找到函数为


__ASM void __set_MSP(uint32_t mainStackPointer)

{

  msr msp, r0

  bx lr

}


总结以上发现都是操作ARM的R0跟R14(LR)寄存器。


还有一种不太一样的,就是stm32F4的库函数中的跳转,如下所示


④ //测试用户app地址是不是在APPLICATION_ADDRESS位置。检测栈顶的地址,来检验app是否下载成功

 if (((*(__IO uint32_t*)APPLICATION_ADDRESS) & 0x2FFE0000 ) == 0x20000000)

 { 

    //APPLICATION_ADDRESS + 4对应的是app中断向量表的第二项,复位地址

    JumpAddress = *(__IO uint32_t*) (APPLICATION_ADDRESS + 4);

//把地址强转为函数指针

    Jump_To_Application = (pFunction) JumpAddress;

    //设置主函数栈指针

    __set_MSP(*(__IO uint32_t*) APPLICATION_ADDRESS);

//调用函数,实际失去app复位地址去执行复位操作

    Jump_To_Application();

 }


跟踪__set_MSP找到函数为


static __INLINE void __set_MSP(uint32_t topOfMainStack)

{

  register uint32_t __regMainStackPointer     __ASM("msp");

  __regMainStackPointer = topOfMainStack;

}


对于M4的这个库函数我也不太懂,感觉最终的操作应该跟其他的一样吧


二,关于跳转部分的代码的理解(转)


这里重点说一下几句经典且非常重要的代码:


第一句: if (((*(__IO uint32_t*)ApplicationAddress) & 0x2FFE0000 ) == 0x20000000)   //判断栈定地址值是否在0x2000 0000 - 0x 2000 2000之间


怎么理解呢? (1),在程序里#define ApplicationAddress    0x8003000 ,*(__IO uint32_t*)ApplicationAddress)  即取0x8003000开始到0x8003003 的4个字节的值, 因为我们的应用程序APP中设置把 中断向量表 放置在0x08003000 开始的位置;而中断向量表里第一个放的就是栈顶地址的值


也就是说,这句话即通过判断栈顶地址值是否正确(是否在0x2000 0000 - 0x 2000 2000之间) 来判断是否应用程序已经下载了,因为应用程序的启动文件刚开始就去初始化化栈空间,如果栈顶值对了,说应用程已经下载了启动文件的初始化也执行了;


第二句:    JumpAddress = *(__IO uint32_t*) (ApplicationAddress + 4);   [  common.c文件第18行定义了:  pFunction   Jump_To_Application;]


ApplicationAddress + 4  即为0x0800 3004 ,里面放的是中断向量表的第二项“复位地址”  JumpAddress = *(__IO uint32_t*) (ApplicationAddress + 4); 之后此时JumpAddress


第三句:    Jump_To_Application = (pFunction) JumpAddress;

 startup_stm32f10x_md_lv. 文件中别名  typedef  void (*pFunction)(void);     这个看上去有点奇怪;正常第一个整型变量   typedef  int  a;  就是给整型定义一个别名 a


 void (*pFunction)(void);   是声明一个函数指针,加上一个typedef 之后  pFunction只不过是类型 void (*)(void) 的一个别名;例如:


[cpp] view plaincopy


pFunction   a1,a2,a3;  

  

void  fun(void)  

{  

    ......  

}  

  

a1 = fun;  

所以,Jump_To_Application = (pFunction) JumpAddress;  此时Jump_To_Application指向了复位函数所在的地址;


第四 、五句: __set_MSP(*(__IO uint32_t*) ApplicationAddress);      \\设置主函数栈指针

               Jump_To_Application();                         \\执行复位函数


Jump_To_Application()是把用户代码的复位地址付给PC指针,我看到Jump_To_Application()这句代码debug的时候对应的汇编代码是

从SD卡升级固件

2. 初识BootLoader

2.1     百度百科的BootLoader
2.2     BootLoader的简单理解
2.3     BootLoader的作用
3. BootLoader预备知识
3.1     复位序列
3.1.1      栈指针
3.1.2      复位向量
3.2     重定位中断向量表
3.2.1      STM32的中断向量表
3.2.2      设置中断向量表偏移
3.3     分散加载文件相关
3.3.1      C语言的函数地址
3.3.2      BootLoader占用的ROM
3.3.3      修改ROM起始地址
3.4     hex文件和bin文件
3.4.1      hex文件
3.4.2      bin文件
3.5     Bin文件生成
4. 分几步实现BootLoader
4.1     跑FAT文件系统
4.2     读写Flash程序
4.2.1      Flash写入步骤
4.2.2      读写Flash调用的库函数
4.2.3      实现Flash读写
4.3     跳转到新程序运行
4.3.1      跳转到复位向量
4.3.2      App开始运行
5. Bootloader具体流程
5.1     主函数流程
5.2     BootLoader流程
5.3     跳转到新程序流程

2. 初识BootLoader可能有的同学听说过BootLoader,有的同学没有听说过,这个都很正常。关于BootLoader的概念大家可以上网查一下,有比较详细的说明,我在这里说说我自己比较片面的理解,并且是针对CortexM3说明的,实现平台为STM32F103VET6。

2.1       百度百科的BootLoader这里借用一下百度百科对BootLoader的解释。在嵌入式操作系统中,BootLoader是在操作系统内核运行之前运行。可以初始化硬件设备、建立内存空间映射图,从而将系统的软硬件环境带到一个合适状态,以便为最终调用操作系统内核准备好正确的环境。在嵌入式系统中,通常并没有像BIOS那样的固件程序(注,有的嵌入式CPU也会内嵌一段短小的启动程序),因此整个系统的加载启动任务就完全由BootLoader来完成。在一个基于ARM7TDMIcore的嵌入式系统中,系统在上电或复位时通常都从地址0x00000000处开始执行,而在这个地址处安排的通常就是系统的BootLoader程序。

2.2       BootLoader的简单理解BootLoader就是单片机启动时候运行的一段小程序,这段程序负责单片机固件更新,也就是单片机选择性的自己给自己下程序。可以更新也可以不更新,更新的话,BootLoader更新完程序后,跳转到新程序运行;不更新的话,BootLoader直接跳转到原来的程序去运行。

  需要注意的是:BootLoader下载新程序后并不擦除自己(BootLoader程序还在),下次启动依然先运行BootLoader程序,又可以选择性的更新或者不更新程序,所以BootLoader就是用来管理单片机程序的更新。

  这是本人的大概理解,大家有不明白请网上搜索一下更详细介绍吧。

2.3       BootLoader的作用BootLoader使单片机能自己给自己下载程序,所以在程序升级方面非常有作用。比如我们的BootLoader是通过GSM更新程序的,我们在升级单片机程序的时候,只要把新程序通过GSM发送给单片机,单片机自己实现程序更新,然后跳转到新程序执行,这样就省去我们很多升级的功夫啦。
可以想象一下如果把单片机安装在非常高的地方,或者危险的工业现场,或者封装得很难拆下来,我们很难直接给单片机下载程序,那么BootLoader的作用就体现出来了。简单的说,有了BootLoader,我们更新程序的话是省心又省力。
想想是不是很高级,还带点小兴奋哈哈。不用急,下面我们会继续介绍,让大家都能自己实现BootLoader。至于是通过什么方式升级,这个大家自由发挥,相信会设计出丰富多彩的BootLoader升级方式呢。


3.BootLoader预备知识我们这里是为ARM的Cortex-M3单片机写的BootLoader,需要了解一下M3内核的架构,并且要了解M3单片机是怎么启动的等等。这个方面的知识,可以参考《Cortex-M3权威指南》,这里的话我只是为了实现BootLoader简单介绍一下,大家有什么不清楚的请参考权威指南。并且这里是以STM32为例说明问题的,使用的开发环境是RVMDK(Keil)。

3.1       复位序列这里参考的是《Cortex-M3权威指南》的3.8节,复位序列。

M3单片机复位后,从0x00000000取栈指针(SP),从0x00000004取复位向量(PC),有了栈指针和复位向量后,单片机就按照正常流程运行了,在BootLoader里面,我们更新完程序后需要做的步骤之一就是设置栈指针,跳转到复位向量。

3.1.1   栈指针栈是一种数据结构,后进先出LIFO。借用百度百科的解释:栈由编译器自动分配释放,存放函数的参数值,局部变量的值等。其操作方式类似于数据结构中的栈。它使用的是一级缓存,他们通常都是被调用时处于存储空间中,调用完毕立即释放。

3.1.2   复位向量复位向量是一个函数地址,在CortexM3单片机里是复位函数的地址。也就是单片机启动后第一个执行的函数。

3.2       重定位中断向量表这里参考《Cortex-M3权威指南》的7.3节,向量表。

BootLoader是一个完整的程序,下载的新程序(以下称为App)也是一个完整的程序。都包含中断向量表,所以的话,我们是有两个中断向量表,相信因为有两个向量表,大家都知道我们应该需要对这两个向量表做点什么吧。

3.2.1   STM32的中断向量表我们只看前16个向量,因为其余的向量属于外设使用,与CortexM3内核无关。
__Vectors      DCD    __initial_spTop          ;Top of Stack
               DCD    Reset_Handler            ; Reset Handler
               DCD    NMI_Handler              ; NMI Handler
               DCD    HardFault_Handler        ; Hard Fault Handler
               DCD    MemManage_Handler        ; MPU Fault Handler
               DCD    BusFault_Handler         ; Bus Fault Handler
               DCD    UsageFault_Handler       ; Usage Fault Handler
               DCD    0                        ; Reserved
               DCD    0                        ; Reserved
               DCD    0                        ; Reserved
               DCD    0                        ; Reserved
               DCD    SVC_Handler              ; SVCall Handler
               DCD    DebugMon_Handler         ; Debug Monitor Handler
               DCD    0                        ; Reserved
               DCD    PendSV_Handler           ; PendSV Handler
               DCD    SysTick_Handler          ; SysTick Handler

__initial_spTop就是栈指针,Reset_Handler是复位向量。这里只显示了16个向量,CortexM3单片机的话总共有256个向量,也就是从栈指针的地址开始有1KB的区域属于中断向量表。

单片机启动默认先运行BootLoader,所以默认的中断向量表位置是BootLoader的中断向量表。为了App可以正常运行,下载完App后,我们还需要把中断向量表重新定位到App程序那里。根据《CortexM3权威指南》,介绍一下怎样重定位中断向量表。

3.2.2   设置中断向量表偏移Cortex-M3单片机有一个管理中断向量表的寄存器,叫做向量表偏移量寄存器(VTOR)(地址:0xE000_ED08)。具体可以看看截图:

STM332程序的起始地址一般在0x08000000。所以BootLoader程序是在0x08000000,不是在0x00000000是因为STM32的重映射技术(不符合Cortex-M3的设计,有点搞另类的感觉)。所以BootLoader的中断向量表在0x08000000那里。如果我们的App程序起始地址在0x08070000,并且App的中断向量表在起始地址,那么BootLoader程序下载App后,为了App程序能正确运行,开始App程序的运行后第一步,就要把中断向量表重定位到0x08070000那里。

具体实现下面会再介绍,接下来介绍分散加载文件相关内容。

3.3       分散加载文件相关这一节涉及的内容主要属于分散加载文件,大家具体上网了解,这里只是介绍了能够实现BootLoader的一小部分。

3.3.1   C语言的函数地址我们知道C语言的函数名就是函数的地址,并且STM32单片机ROM的起始地址是在0x08000000,那么使用编译器编译程序的话(这里使用的是RVMDK),函数的地址默认都在以0x08000000为首的一段ROM里面了。比如我们一个函数Delay(),它的地址可以是0x08000167(CortexM3中函数的地址0bit位一般是1),也就是Delay函数的代码在0x08000167,C语言函数调用Delay时,就是执行0x08000167的代码。

3.3.2   BootLoader占用的ROM我们需要注意的问题是,如果不修改程序默认的起始地址的话,那么BootLoader和新App程序的起始地址都是0x08000000,也就是他们重叠了(代码重叠),这样的话肯定相互之间有影响,程序是不能正常工作的。
这里的解决方法是,BootLoader程序依然占用0x08000000为首的那段ROM,因为STM32的默认就是从0x08000000运行程序的。保持BootLoader程序先能正确运行。然后App使用除BootLoader占用ROM以外的空间。这里需要知道BootLoader到底占用了多少ROM,很简单,查看MAP文件就行了。这里以我的BootLoader的MAP文件为例说明一下,看截图:
Memory Map of the image
  Image Entry point :0x08000131
  Load Region LR_IROM1 (Base: 0x08000000,Size: 0x00006da4, Max: 0x00080000, ABSOLUTE)
   Execution Region ER_IROM1 (Base: 0x08000000, Size: 0x00006d54, Max:0x00080000, ABSOLUTE)

主要是这句话“Base:0x08000000, Size: 0x00006da4, Max: 0x00080000”,这句话说明了我的BootLoader程序是从0x08000000开始,占用了0x00006DA4大小。只要我们的App不要和BootLoader程序占用的空间冲突就可以了。我的App程序的起始地址选择为0x08070000,不与BootLoader程序冲突。具体怎么修改ROM起始地址,下面介绍。

3.3.3   修改ROM起始地址编译新程序的时候,我们要修改程序的起始地址,我的修改方法如下(开发环境是RVMDK):打开TargetOption...,切换到Target选项卡,如下

修改IROM1的起始地址和长度:
比如,为了不产生地址冲突,我将起始地址0x08000000修改成0x0807000,将ROM长度0x80000修改成0x10000。如下图所示(左图为修改前、右图为修改后):

  

注意:BootLoader程序是不需要修改的,只是App需要修改(App就是使用BootLoader下载的程序)。

3.4       hex文件和bin文件3.4.1   hex文件平时我们用j-Link或者串口下载程序的话,都是打开hex文件下载的,因为hex文件包含地址信息,下载程序的时候知道程序下载到ROM的哪个区域。从另一个角度上说,也就是hex文件是不能直接写进ROM的,一边写需要一边转换(解码出地址信息,将对应内容写入ROM)。

3.4.2   bin文件bin文件的话,很好理解,是直接的可执行代码。也就是bin文件的内容跟下载ROM里面的内容是一样的。bin文件是没有包含地址信息的,所以在下载之前要知道bin文件是要下载到ROM的那个区域。

我们的BootLoader下载的是bin文件,直接写进STM32的Flash里面,地址信息的话就是上一节的IROM,0x08070000,从0x08070000开始连续写入,中间不间断。

3.5       Bin文件生成默认情况下编译后生成的是hex文件,不过很轻松可以生成bin文件。介绍具体怎么生成bin文件,工具的话是使用fromelf.exe(目录一般是在Keil安装目录里面,本人的fromelf.exe目录是在C:\Keil\ARM\ARMCC\bin),我们是使用fromelf工具将axf文件转换为bin文件。
熟悉命令行的同学可能会选择直接敲命令,不过这里介绍使用RVMDK提供的用户命令(编译时可以自动生成bin,省去每次生成bin文件都要敲命令的过程)。
打开TargetOption...,切换到User选项卡,如下

主要是在运行用户命令,Run#1

具体命令是(记得在Run#1前打勾,才会在编译后执行用户命令生成bin文件):

C:\Keil\ARM\ARMCC\bin\fromelf.exe

--bin

-o

.\Output\MY_STM32.bin

.\Output\MY_STM32.axf

命令可以分为五部分,简化后是fromelf --bin  -o xxx.bin  xxx.axf,需要注意的是命令的五个部分之间要有空格。还需要说明的是路径问题,这里的路径都是相对.uvproj文件的,下面是我的目录(注意MY_STM32.uvproj文件和Output文件夹)。

我的bin文件和axf文件都在Output文件夹里面,并且路径是相对MY_STM32.uvproj的,Output文件夹里的bin文件(MY_STM32.bin)相对于MY_STM32.uvproj应该写成“.\Output\MY_STM32.bin”。
l      第一部分
这部分是fromelf.exe文件的路径,根据自己的安装目录而变。我这里因为Keil是安装在C盘的,所以我的路径如下所示。
参考命令:C:\Keil\ARM\ARMCC\bin\fromelf.exe
l      第二部分
这部分是固定的,--bin表示生成bin文件。
参考命令:--bin
l      第三部分
这部分也是固定的,-o表示输出。
参考命令:-o
l      第四部分
这部分是生成文件的目录和文件名,我是输出在Output文件夹的,也就是bin文件在Output文件夹里面。
参考命令:.\Output\MY_STM32.bin
l      第五部分
这部分是axf文件的目录和文件名,我们的bin文件是根据axf文件生成的,也就是说axf文件相当于输入,bin文件相当于输出。我的axf文件也在Output文件夹的。
参考命令:.\Output\MY_STM32.axf
介绍了这些基本知识后,我们可以来实现BootLoader了。


4. 分几步实现BootLoader有了前面的基础知识后,应该是比较容易理解BootLoader需要怎么实现了。这一章,我们分几个步骤,一步一步实现BootLoader。

4.1       跑FAT文件系统我们的BootLoader是从SD卡更新程序的,把在电脑上编译后的App程序,也就是bin文件,复制到SD卡中,然后让单片机读取相应的bin文件,就可以实现程序的更新。需要注意的是,App程序需要修改ROM的起始地址,再编译,并且要生成bin文件才支持正常下载。
我跑的文件系统是FATFS_R0.07c,很经典的一个版本。如果大家对文件系统方面不了解的话,请自己网上查找教程,或者说很多同学对这一步应该已经很熟悉啦。

只要单片机上实现读取bin文件,结合Flash写入程序,就可以实现程序更新。下面介绍读写Flash。

4.2       读写Flash程序要实现BootLoader,还有一个前提是可以写入Flash了。如果是STM32单片机的话是很容易实现的,因为我们有官方库。本人使用的是3.0.0版本,参考官方例程,很容易实现Flash的读写,这里同样是为了实现BootLoader简单介绍一下。

4.2.1   Flash写入步骤l      解锁Flash
l      擦除Flash
l      写入Flash

l      验证读写是否正确

4.2.2   读写Flash调用的库函数l      voidFLASH_Unlock(void)                                     Flash解锁
l      FLASH_Status FLASH_ErasePage(uint32_tPage_Address)           Flash擦除

l      FLASH_Status FLASH_ProgramWord(uint32_t Address, uint32_tData)  Flash写入

4.2.3   实现Flash读写稍微封装一下STM32的官方库函数,就能实现Flash的读写,并验证读写是否正确,具体我实现的接口函数为以下截图,大家可以参考一下:

来到这里,我们可以实现在bin文件写入Flash了,写入完后,就要跳转到App程序执行了,接下来继续介绍。

4.3       跳转到新程序运行

  这一节要结合上面提到过的,Cortex-M3启动做了什么事情,然后我们的BootLoader下载App程序后,App程序就需要做同样的事情。主要有三个步骤,其中BootLoader程序需要做的是:

l      跳转到复位向量

App需要做的是:

l      重定位中断向量表

l      设置栈指针

4.3.1   跳转到复位向量BootLoader程序需要做的是跳转到复位向量,具体实现可以参考以下代码。
( (void (*)()) (Reset))();   //跳转到复位向量

注意( (void (*)()) (Reset) )();是一去就不返回的,执行完这条语句,单片机就直接跳转到App程序运行的,所以BootLoader程序下载完App后,做一些简单的处理(根据自己的应用,也可以不做任何处理),就用这条语句跳转到App执行。

4.3.2   App开始运行BootLoader跳转到App后,App需要做的是先设置栈指针,然后重定位中断向量表地址,具体可以参考以下代码。
__set_MSP( Msp);                 //设置栈指针
NVIC_SetVectorTable( base, offset);   //重定位中断向量表
其中Msp是栈指针,也就是中断向量表第一个字的内容,我们这里的内容是*((uint32_t)(0x08070000) )。
base是中断向量表的基地址,一般情况下就是ROM的起始地址,这里是0x08070000。
至此,BootLoader实现步骤完了,相信熟悉了这几个步骤后,大家可以自己给自己的单片机写个BootLoader。顺便说一下,Cortex-M4的BootLoader跟Cortex-M3几乎是一样的。我在STM32上的实现完全是参考自己上次在飞思卡尔Cortex-M4上的实现。下面说一下我的主函数吧,我们再看看具体的BootLoader流程,再熟悉一下BootLoader。


5.Bootloader具体流程

  先看看我的主函数,再啰嗦一下具体流程,可能有的同学已经有点厌烦啦,其实感觉有点多余。

5.1       主函数流程先看截图。

主函数的流程如下所示:
l      时钟初始化
l      LED初始化(无关紧要)
l      调试接口初始化(无关紧要)
l      Flash初始化(解锁Flash)
l      FAT初始化(挂载文件系统)
l      我们的BootLoader(重点,下面展开继续介绍)
l      主循环(实际不会运行到这里)

然后在具体讲解BootLoader_FromSDCard函数,这就是我们的重点,传说中STM32的BootLoader从SD卡更新固件。

5.2       BootLoader流程

老样子,先上截图:

具体流程如下所示:
l      打开bin文件,检查文件打开是否正确
l      设置Flash下载起始地址(App程序起始地址)
l      读取bin文件,检查读取是否正确
l      获取栈指针SP和复位向量PC
l      进入循环(这里是第5步),条件为如果读取bin文件字节数不为零
l      将读取到的bin写入Flash,并判写入状态
l      调整Flash地址,根据写入字节调整
l      继续读取bin文件,检查读取是否正确,回到5继续循环

来到这里已经是退出循环了,也就是说我们已经将bin写入Flash完成了,准备跳转到新程序运行

5.3       跳转到新程序流程其实上面已经讲过了,这里继续啰嗦,截图:

l      重定位中断向量
l      设置栈指针
l      跳转到复位向量(开始运行App程序)
说明一下,在这里重定位中断向量其实是多余的,App程序执行初始化后,又回到STM32初始状态,所以在App程序中需要执行重定位中断向量表操作,具体同以上操作相同。


关键字:STM32  BootLoader  升级 引用地址:STM32的BootLoader升级

上一篇:STM32 IAP/BOOT,三步速成
下一篇: stm32 printf 死机

推荐阅读最新更新时间:2024-03-16 16:11

STM32 内存分布探究
本人在运行ucos时遇到一个非常奇怪的问题,运行一段时间后就会莫名进入hardfault函数,导致系统死机。后来根据对堆栈调试,发现每次调用的函数都不一样,甚是费解。通过map文件最后得出结论,原来在系统初始化的时候在flash里面读出了系统配置参数,在系统运行过程中会写flash,而flash定义的地址与程序代码存储的位置发生了重叠,一写数据就擦掉了一些函数,当调用到这些函数的时候就会发生未知指令的错误。把这个参数存储地址定义的分开些就会解决这个问题。可是,开始这个地址写好了,随着程序代码不断增多,消耗的片上flash也会增大,是个动态增长的过程,不注意很有可能发生冲突。所以在项目开发过程中定期检查定义的参数存储地址,或者干脆把
[单片机]
STM32学习笔记一一时钟系统
一、系统架构: 二、时钟树: STM32 有5个时钟源:HSI、HSE、LSI、LSE、PLL。 ①、HSI是高速内部时钟,RC振荡器,频率为8MHz,精度不高。 ②、HSE是高速外部时钟,可接石英/陶瓷谐振器,或者接外部时钟源,频率范围为4MHz~16MHz。   ③、LSI是低速内部时钟,RC振荡器,频率为40kHz,提供低功耗时钟。 ④、LSE是低速外部时钟,接频率为32.768kHz的石英晶体。 ⑤、PLL为锁相环倍频输出,其时钟输入源可选择为HSI/2、HSE或者HSE/2。 倍频可选择为2~16倍,但是其输出频率最大不得超过72MHz。 2. 系统时钟SYSCLK可来源于
[单片机]
<font color='red'>STM32</font>学习笔记一一时钟系统
(纯干货)使用STM32测量频率和占空比的几种方法
使用平台:官方STM32F429DISCOVERY开发板,180MHz的主频,定时器频率90MHz。 相关题目: (1)测量脉冲信号频率f_O,频率范围为10Hz~2MHz,测量误差的绝对值不大于0.1%。(15分) (2)测量脉冲信号占空比D,测量范围为10%~90%,测量误差的绝对值不大于2%。(15分) 思路一:外部中断 思路:这种方法是很容易想到的,而且对几乎所有MCU都适用(连51都可以)。方法也很简单,声明一个计数变量TIM_cnt,每次一个上升沿/下降沿就进入一次中断,对TIM_cnt++,然后定时统计即可。如果需要占空比,那么就另外用一个定时器统计上升沿、下降沿之间的时间即可。 缺点:缺陷显而易见,当频率提高,
[单片机]
(纯干货)使用<font color='red'>STM32</font>测量频率和占空比的几种方法
关于STM32 的 硬件IIC和 模拟IIC理解学习
1. 硬件 IIC 用法比较复杂,模拟IIC的流程更清楚一些。 2. 硬件IIC速度比模拟快,并且可以用DMA 3. 模拟IIC可以在任何管脚上,而硬件只能在固定管脚上。 软件i2c是 程序员 使用程序控制SCL,SDA线输出高低电平,模拟i2c协议的时序。一般较硬件i2c稳定,但是程序较为繁琐,但不难。 硬件i2c程序员只要调用i2c的控制 函数 即可,不用直接的去控制SCL,SDA高低电平的输出。但是有些单片机的硬件i2c不太稳定,调试问题较多。
[单片机]
技术升级 美国机场安全防范体系构建分析
    航空运输业在世界经济活动中发挥着重要的作用,同时也是世界经济中增长最快的部门之一。据国际航空运输协会(LATA)2011年3月发布的数据,航空运输业2010年实现160亿美元的盈利,全球航空运输业总收入增至5520亿美元。2010年世界航空运输旅客数为24.39亿人次,客运量增加7.3%。按照这样的发展趋势来看,未来世界各国对机场和机场设施将有更大的需求,面对机场的高安全管理要求,如何利用技术手段有效保证航空运输安全倍受各国关注,本文以美国为例,从多个方面来了解美国如何构建机场的安全体系,希望对国内的机场安全建设有所借鉴。     全球航空安全战略的演变     1997年,国际民航组织通过将空中航行委员会与业界之间一
[安防电子]
STM32学习笔记--GPIO寄存器的定义
1、GPIO的寄存器按照功能可以分为以下几类: A、配置寄存器 B、数据寄存器 C、位寄存器 D、 锁定寄存器 2、对于GPIO端口,每个端口有16个引脚,每个引脚的模式由寄存器的四个位控制,每四位又分为两位控制引脚配置(CNFy ),两位控制引脚的模式及最高速度(MODEy ),其中y表示第y个引脚。配置GPIO引脚模式的一共有两个寄存器,CRH是高寄存器,用来配置高8位引脚,还有CRL配置低八位引脚。 3、端口位设置\清除寄存器(GPIOx_BSRR) 一个引脚 y 的输出数据由 GPIOx_BSRR 寄存器位的2 个位来控制分别为 BRy (Bit Reset y)和BSy (Bit Set y),BRy 位用于写 1清零
[单片机]
stm32的KEY控制LED
stm32的学习就是弄懂是怎么进行软件配置,先明白硬件连接,再结合起来; #include stm32f4xx.h #include led.h #define KEY0 GPIO_ReadInputDataBit(GPIOE,GPIO_Pin_4) // 这里读取IO的状态,将stm32的IO口作为输入使用 #define KEY1 GPIO_ReadInputDataBit(GPIOE,GPIO_Pin_3) #define KEY2 GPIO_ReadInputDataBit(GPIOE,GPIO_Pin_2) #define LED0 PFout(9) //D
[单片机]
stm32单片机待机模式的设计
一 待机模式简介 在stm32的低功耗模式中,待机模式可以实现系统的最低功耗,在这种模式下,只需要2uA左右的电流。 三 待机唤醒程序分析 实验现象: 将程序下载到开发板上后,LED灯会不断地亮灭,当按下KEY2键超过3s时,LED灯灭,标志着单片机进入待机模式,再按下KEY1键,这时唤醒单片机,LED又开始不断地亮灭亮灭。 程序中用到的一些宏定义 #definemacEXTI_GPIO_CLK(RCC_APB2Periph_GPIOC|RCC_APB2Periph_AFIO) #definemacEXTI_GPIO_PORTGPIOC #definemacEXTI_GPIO_PINGPIO_Pin_13 #definem
[单片机]
小广播
添点儿料...
无论热点新闻、行业分析、技术干货……
热门活动
换一批
更多
设计资源 培训 开发板 精华推荐

最新单片机文章
何立民专栏 单片机及嵌入式宝典

北京航空航天大学教授,20余年来致力于单片机与嵌入式系统推广工作。

更多精选电路图
换一换 更多 相关热搜器件
更多每日新闻
随便看看
电子工程世界版权所有 京B2-20211791 京ICP备10001474号-1 电信业务审批[2006]字第258号函 京公网安备 11010802033920号 Copyright © 2005-2024 EEWORLD.com.cn, Inc. All rights reserved