在main()之前,IAR都做了啥
IAR_使用最全方法
软件介绍AVR?IAREmbeddedWorkbench?IDE用户手册的这部分包括以下章节:✍✍✍产品介绍✍✍✍已安装文件1.1产品介绍嵌入式IAREmbeddedWorkbench?是一个非常有效的集成开发环境(IDE),它使用户充分有效有效提一个可扩展的模块化的环境尽管嵌入式IAREmbeddedWorkbenchIDE可以提供完成一个成功工程所需的所有工具,但我们也认识到集成其他工具的必要性。
因此,IAREmbeddedWorkbenchIDE容易适应于用户喜欢的编辑器和源代码控制系统。
IARXLINKLinker可以输出多种格式,使用户可在第三方的软件上进行调试。
实时操作系统(RTOS)支持也可加载到产品中。
编译器,汇编器和连接器也可在命令行环境中运行,用户可以在一个已建好的工程环境中把它们作为外部工具使用。
特性嵌入式IAREmbeddedWorkbench是一个灵活的集成开发环境,使用户可以针对多种不同的目标处理器开发应用程序。
并为快速开发和调试提供便捷的Windows截面。
++源窗口管理为使用户充分而方便地控制窗口的位置,每个窗口都可停靠,用户就可以有选择地给窗口做上标记。
可停靠的窗口系统还通过一种节省空间方式使多个窗口可同时打开。
另外,重新分配窗口大小也很方便。
2文本编辑器集成化的文本编辑器可以并行编辑多个文件,并具有时兴编辑器所期望的所有编辑特性,包括无限次的撤销/重做和自动完成。
另外它还包含针对软件开发的特殊功能,比如关键字的着色(C/C++,汇编和用户定义等)、段缩进、以及对源文件的导航功能。
还可识别C语言元素(例如括号的匹配问题)。
下表指出另外的一些特性:✍✍✍上下文智能帮助系统可以显示DLIB库的参考信息;✍✍✍使用文本风格和色条指出C、C++和汇编程序的语法;✍✍✍强大的搜索和置换功能,包括多文件搜索;驱动C-SPY 驱动的概述,请参见第8页,IARC-SPY调试器系统。
Kinetis实战开发——IAR使用详解
Kinetis实战开发——IAR使用详解目前适合开发飞思卡尔Kinetis系列单片机的软件开发环境有IAR、Keil和CodeWarrior,三种软件的功能各有千秋。
本文档将介绍如何使用IAR开发Kinetis系列单片机,希望读者阅读本文档后能对IAR这款软件有所了解。
本文所使用的IAR开发环境的版本为IAR for ARM 6.30。
1.IAR功能介绍●IAR支持ARM汇编、C和C++三种语言的开发;●IAR软件本身集成了编译器,能将用户开发的工程编译成二进制文件,进而烧写到单片机的FLASH中;●IAR软件集成了当前主流仿真器的驱动,比如开发K60单片机时所使用的J-LINK和OSJTAG仿真器的驱动;2.IAR开发环境界面介绍打开IAR软件后,首先会进入IAR开发环境的主界面。
IAR主界面由菜单栏、工具栏、WorkSpace、编程界面和结果显示窗口(Message)组成,如图1.1所示。
下面我们将介绍每个部分的作用。
图1.1 IAR主界面2.1IAR菜单栏在IAR主界面中可以看到菜单栏中有7个选项,如图2.1所示。
图2.1 IAR菜单栏2.1.1F ile选项如图2.2所示,在File选项中包括如下子选项。
“New”可以新建空白文件和工作空间(WorkSpace);“Open”可以打开文件和工作空间(WorkSpace);“Save Workspace”和“Close Workspace”分别对应保存工作空间和关闭工作空间;“Recent Files”用于快速打开最近使用过的源文件;“Recent Files”用于快速打开最近使用过的工作空间。
图2.2 Files选项2.1.2E dit选项如图2.3所示,在Edit选项中,包括了最常用的复制、粘贴、重置和查找等通用的编辑类选项,同时也包括了一些IAR开发环境特殊的编辑功能。
图2.3 Edit选项接下来我们介绍一些比较常用的功能。
a)Find and Replace查找和替换功能查找和替换是我们在编程中使用最频繁的功能。
IAR主窗口与工具栏详细描述
IAR主窗口与工具栏详细描述
宁波三维电测设备有限公司张婷婷 2018.10.18 主窗口:
Menu Bar:菜单栏,包含IAR所有操作及内容,在编辑模式和调试模式下存在一些不同。
Tool Bar工具栏:该窗口是一些常见的快捷按钮。
Workspace Window:工作空间窗口,一个工作空间可以包含多个工程,该窗口主要显示工作空间下面工程项目的内容。
Edit Window:编辑空间,代码编辑区。
Message Window:信息窗口,该窗口包括编译信息、调试信息、查找信息等一些信息的窗口。
Status Bar:状态栏:该窗口包含错误警告、光标行列等一些状态信息。
工具栏:
IAR的Tool Bar工具栏共有两个:Main主工具栏和Debug调试工具栏。
在编辑(默认)状态下只显示Main工具栏只显示,在进入调试模式后会显示Debug工具栏。
工具栏可以在通过菜单打开:View -> Tool Bar
在编辑(默认)状态下,只有主工具栏,这个工具栏里面内容也是在编辑状态下常用的快捷按钮。
PS:Download and Debug是下载代码之后再进行调试,Debug without Downloading:只调试不下载。
也就是说你之前下载过了代码,只需要再点击该按钮即可,否则会出现错误。
这两个按钮图标在编辑和调试模式下略有点差异,在调试模式下可以再次下载/调试。
调试工具栏调试工具栏是在程序调试时候才有效的一下快捷按钮,在编辑状态下,这些按钮是无效的。
Reset:复位
Run to Cursor:运行到光标行。
MDK main函数运行前的详细分析
图 2-10 MAP 文件分析 0x0800 015D 地址是函数_scatterload_copy 的入口,该函数到底 copy 了什么 值呢?在此之前我们先要熟悉一下.map 文件 .map 文件是值包括了映像文件信息图和其它信息的一个映射文件, 该文件包 含了: (1) 从映像文件中删除的输入段中未使用段的统计信息,对应参数-remove; (2) 域符号映射和全局、局部符号及生成符号映射统计信息,对应参数 -symbol; (3) 映射文件的信息图,对应参数-map,该信息中包含映像文件中的每个加载 域、运行域和输入段的大小和地址,如 2-11 图、2-12 图所示:
图 2-19
经 过 该 函 数 处 理 得 : r0=0x2000 0098,r1=0x2000 0698,r2=0x2000 0298,r3=0x2000 0298。最后用户栈顶被设置成 0x2000 0698,完成了堆栈的初始 化工作,程序返回到 rt_entry_main
三、 总结
最终函数终于跳转到我们的 main 函数执行我们写的代码。 总结启动文件的整个过程,分为如下: (1) 系统初始化,包括对中断向量表的重新映射; (2) 加载 RW 段; (3) ZI 段清零; (4) 初始化用户堆栈; (5) 初始化微库(具体干什么我也不知道,屏蔽此处函数好像也能正常运行) ; (6) 调用 main 函数。
Main 函数运行前的分析(原创,转载请注明出处)
一、 启动文件的介绍
在 MDK 的启动文件 startup_stm32f10x_md_vl 中,该文件分别定义了栈段、 堆段、存放中断向量表的数据段、还有一个代码段 大小为 0x400 的栈段定义如图 1-1:
图 1-1 大小为 0x200 的堆段如图 1-2:
Keil程序运行main函数之前的汇编
Keil开发的ARM程序main函数之前的汇编分析——BIN文件中RW段的数据移动系统平台:STM32系列STM32F103ZE,512KB内部FLASH,64KB片内存储;FLASH地址范围0x0800 0000 ~ 0x0808 0000,用于存放代码;片内存储地址范围0x2000 0000 ~ 0x2001 0000,用于存放数据;Cortex-M3上电后来到复位中断(已将前4个字节的值存入MSP堆栈指针),转到__main 标号,完成RW段的移动、ZI段的初始化,建立堆栈,初始化库函数,然后跳转到main函数,开启C程序之旅,执行流程如图1所示。
图1 main函数之前的汇编程序执行流程图本文主要讨论RW段的移动,RW段就是程序中赋了初值的变量,它的搬移我看到过两种方式。
在BIN文件中,RO段和RW段之间有8个双字的Region$$Table,4个双字一组,分别用于完成RW段的搬移和ZI段的初始化。
(1)__scatterload_copy来完成此时RW段的内容保存到内存开始的地方,本文中是0x20000000,用这一方式完成后,内存中存放的不是RW数据的内容,而是一个地址。
这个地址是在FLASH中,即指向了其在RO段的地址,实际的内容是在RO段中。
(2)通过__uncompressed1实现RW是程序中初始化的变量,但是这些变量有可能初值是0,因此为了节省空间,实际在BIN文件中RW段是压缩过的。
调用__uncompressed1解压缩RW段的数据内容,并将其保存到内存开始的地方。
图2 BIN文件中压缩RW段内容图2是BIN文件中RW段的数据内容,影印部分显示,大小是164字节。
其中0x0001 C72C前面8个双字的内容是Region$$Table,将其列出如下。
0x0801 C72C BIN文件中RW段的开始地址0x2000 0000 RW段要存放到RAM中的地址0x0000 0334 要存放到RAM中的RW段数据大小0x0800 0184 执行函数__scatterload_copy或者__uncompressed1上面4个双字完成RW段的搬移。
IARFORAVR编译环境中启动代码和堆栈设置的分析
IARFORAVR编译环境中启动代码和堆栈设置的分析1.例子1程序中仅包含一个空的main()函数,代码如下:#include <ioavr.h>int main(void){}此时对应的map文件显示:表中CSTACK的区域由编译环境中DATA STACK的值确定,起始位置是0060H,而RSTACK区域的起始地址就是CSTACK的最大地址+1,即RSTACK紧接着CSTACK,其大小由编译环境则为Return address stack中的值*2。
从0000-0025都是中断向量表的区域,从0026-0049才是程序代码中断向量表的区域如下图所示:从表中可以看出,上电复位后的第一条指令就转移到启动代码?C_STARTUP中。
程序代码如下图所示:在启动代码中,首先设置堆栈指针SP位009FH,这个值就是MAP文件中给出的RSTACK区域的最大地址。
然后将(R29,R28)寄存器对设置成0080H,这个值就是MAP文件中给出的RSTACK区域的最小地址。
由于在AVR中,当压栈时,堆栈指针进行减法,出栈时进行加法,所以栈顶就是009FH,实际上堆栈可使用的区域为0080到009FH。
这部分区域主要用来保存返回地址,因此在编译环境中也被称为返回地址的堆栈,而CSTACK则称为数据堆栈。
这个部分区域应该是用于局部变量的操作,因此要小心设置改值,否则会导致空间溢出。
2.例子2程序包含有一个main()函数,其中定义了一个10个字节的数组,如下图所示:int main(void){unsigned char i;char s[10];for(i=0;i<10;i++){s[i] = 0x55;}}这个程序编译后,生成的MAP图如下:从这里可以发现,没有CSTACK和RSRTACK没有发生变化。
启动代码部分如下所示:可以看出,也没有什么变化。
那么再来看看main()函数的汇编代码,如下图所示:通过读代码,可以看出R16用于存储局部变量i,用于for循环的计数。
IAR用法点滴
IAR用法点滴程序固化后运行方式:程序开始运行后需要将RW 和ZI段搬移到RAM中去,程序下载进Flash中以后,上电后是怎样将RW ZI断搬移到RAM中去的?注意IAR和ADS在进行完.s文件的初始化以后都不是直接跳转到main函数去执行,IAR是跳转到?main中而ADS是跳转到__main函数中,在这些函数中根据icf文件的配置,将RW和ZI段搬移到icf文件规定的RAM区域中。
如果程序的运行时域是在片外RAM中,那程序是在什么时候对片外RAM控制器进行初始化呢?因为.s文件的开始部分是CODE RO的,不需要RAM空间,所以可以在.s文件中对片外RAM进行配置。
还有一个问题,这个问题是在硬件设计时必须注意的,如果需要程序固化在外部Flash中,必须注意外接的Flash必须是片子上电后默认片外总线就支持的片子。
程序在RAM中调试的运行方式为了调试的方便,程序有时候是不需要下载进flash进行调试,而是直接在RAM 中运行,将icf文件中的ROM 和RAM地址都设成硬件RAM的地址,将Flashloader 的使能关掉,那么程序就运行在RAM中了。
但是问题又产生了,因为有时我们想在外部RAM 中调试代码,所以片外RAM控制器需要在代码下载进RAM之前进行初始化,怎么能够实现呢?IAR是通过.mac文件实现的。
在程序下载之前先执行了。
mac文件中的程序,下面是一个例子execUserFlashInit(){__writeMemory32(0x1000ffef, 0xffe00000 , "Memory");__writeMemory32(0x0f000114, 0xE002C014, "Memory");}该例子是lpc初始化外部RAM的例子。
配置好了外部RAM就可以在里面跑代码了。
程序的IAR下载1.文件在片内Flash中下载运行这是最简单也是最常用的方式,一般的ARM芯片都会带有片内Flash,IAR会通过Flashloader将二进制的可执行文件下载到Flash中。
iar编译器使用指南
iar编译器使用指南(原创实用版)目录1.IAR 编译器的概述2.IAR 编译器的安装3.IAR 编译器的使用4.常见问题与解决方法正文【概述】IAR 编译器是一款功能强大的编译器,适用于多种处理器架构。
它能够将 C、C++语言源代码编译成高效的目标代码,广泛应用于嵌入式系统开发。
本文将为您介绍如何使用 IAR 编译器进行程序开发。
【安装】在使用 IAR 编译器之前,首先需要在电脑上安装它。
您可以从 IAR 官网下载对应版本的编译器,并按照安装向导的提示进行安装。
在安装过程中,请确保选择正确的处理器架构和相应的开发板支持包。
【使用】安装完成后,您可以使用 IAR 编译器编写、编译和调试程序。
以下是使用 IAR 编译器的基本步骤:1.创建一个新的项目:在 IAR Embedded Workbench 中,选择“新建项目”创建一个新的项目。
2.编写源代码:在新建的项目中,编写您的 C 或 C++代码。
3.编译程序:在 IAR Embedded Workbench 中,选择“编译”或按 F7 键,编译器将自动编译您的源代码。
4.调试程序:编译完成后,您可以使用 IAR Embedded Workbench 的调试功能对程序进行调试。
【常见问题与解决方法】在使用 IAR 编译器过程中,可能会遇到一些问题。
以下是一些常见问题的解决方法:1.编译器无法识别源代码文件:请确保您的源代码文件扩展名为.c 或.cpp,并检查文件路径是否正确。
2.编译器报错:遇到编译错误时,请仔细阅读错误信息,并检查您的代码。
常见的错误包括语法错误、拼写错误和库文件缺失等。
3.调试时程序无法运行:请确保您的目标系统已正确连接并启动。
同时,检查您的调试配置是否正确。
通过以上步骤,您应该能够熟练地使用 IAR 编译器进行嵌入式系统开发。
简介如何在IAR开发环境下建立ARM工程
简介如何在IAR开发环境下建立ARM工程一.首先准备好必要的初始化系统的文件1.内部存储器配制文件:(1)at91SAM7X256_RAM.xcl ;(2)(2) at91SAM7X256_FLASH.xcl ;(3) SAM7_RAM.mac ;(4) SAM7_FLASH.mac主要供编译器器调用,以便产生正确的影象文件和二进制代码.2.启动代码(在进入MAIN之前执行的代码---相当于BOOT)文件:(1) 汇编语言文件Cstartup.s79 ----配制中断,初始化ARM的各种模式,引导程序进入C语言程序.(2)C语言文件Cstartup_SAM7.c (此处以SAM7系列芯片为例) ----初始化目标板,主要有系统时钟,地址映射,内层管理,FLASH读写时间的设置,看门狗,中断管理等,以便在程序进入MAIN函数时能正常工作.3.必要的头文件:(1)AT91SAM7X256.h----定义了所有的寄存器及其相关数据结构(2)Lib_AT91SAM7X256.h----定义了各功能最底层的函数,,可供用户调用(3)AT91SAM7X256_inc.h----汇编语言头文件,供汇编语言文件调用()以上文件在会在光盘中提供(购买我的开发板后附带提供的),或到ATMEL公司网站下载。
用户可根据自己工程实际需要稍做修改。
建议将上述文件分为三个文件夹,放到待进工程的目录下:(1)resource 文件夹: at91SAM7X256_RAM.xcl ,at91SAM7X256_FLASH.xcl , SAM7_RAM.macSAM7_FLASH.mac(2)srclAR文件夹: Cstartup.s79 , Cstartup_SAM7.c(3)imclude 文件夹: A T91SAM7X256.h ,lib_AT91SAM7X256.h,AT91SAM7X256_inc.h其它头文件,另外用时再加.最好将所有的头文件放到一个文件夹下.(4)scr文件夹:包含项目中用到的所有原文件二.工程建立1.打开IAR 选择PROJECT/CREATE NEW PROJECT/---OK---起工程名: EG:BASE-GPIO2.在WORKSPACE的BASE-GPIO-DEBUG下建立子文件夹(1) srcL AR文件夹: 加入Cstartup.s79,Cstartup_SAM7.c 文件(2) scr文件夹: 加入, 或新进项目中用到的所有原文件3.设置调试模式,一般分三种: RAM_DEBUG, FLASH_DEBUG,BINARY(一)R AM_DEBUG 模式------在RAM中调试程序(1). 选择性PROJECT/EDIT CONFIGURTION/IEW 输入名字RAM_DEBUG, 选择DEBUD 模式(2)在WORKSPACE 的RAM_DEBUG 模式下点击右键选择OPTIONS 以下仅说明与默认设置不同的地方.Generak Option:Tager: Core , Device…set according to ApplyLibrary options : 1----Tiny 2----SmallC/C++ Compiler:Optinization :HighPreprocessor : sccition include directories----设置比较重要, 不能用/…/来表示头文件的位置$PROJ_DIR$\...\--表示在工程所在目录的上一级目录中,也可以指定文件夹如: $PROJ_DIR$\srclAR\ 表示部分头文件在—工程所在目录的srcIAR下Assembler:List: Output listPreprocessor: $PROJ_DIR$\..include\Linker:Output: Format—debug information for C-SPYW/ith I/O emulation modulModule-local: include allList: Genreate linker listingConfig: override default--/…./at91SAM7X256_RAM.xclOverride default program---Defined by applicat Debugger:Setup: Driver: J-Link Run to : do not use!Use macros file: $PROJ_DIR$\resource\SAM7_RAM.macDownload: Verify download(二) FLASH_DEBUG 模式---- 在FLASH中调试程序1.选择PROJECT/EDIT CONFIGURTION/NEW 输入名字FLASH_DEBUG, 选择DEBUD 模式2.在WORKSPACE的FLASH_DEBUG 模式下点击右键选择OPTIONS 以下仅说明与默认设置不同的地方.Generak Option :Tager : Core , Cevice ………set according to applyLibrary options: 1----Tiny 2----SnallC/C++Compiler:Optimization : High / NoneList : Output list file 全选Preprocessor: addition include directories: ----设置比较重要$PROJ_DIR$\..\--表示在工程所在目录的上一级目录中,也可以指定文件夹如:$PROJ_DIR$srcLAR\ 表示部分头文件在--工程所在目录srcLAR下Assembler:List: Output listPreprocessor: $PROJ_DIR$\..include\Linker:Output: Format—debug information for C-SPY----With I/O emulation modul----Allow C-SPY-specific extra output file Module-local:lnclude allExtera output: Generate extra output fileOutput format:simple-codeFormat variant: NoneList: Genreate linker listingConfig: override default--/…./at91SAM7X256_FLASH.xcl Override default program-----Defined applicat Debugger:Setup: Driver: J-Link Run to: do not use!Override default:$TOOLKIT_DIR$CONFIG\ioat91sam7x256.ddf Use macros file:$PROJ_DIR$\resource\SAM7_FLASH.macDownload: Use foash loader(,,,,(default),)单击EDIT/NEW/OK即可(三) BINARY模式------在中调试程序1.选择PROJECT/EDIT CONFIGURTION/NEW输入名字BINARY,选择Release模式2.在WORKSPACE的模式下点击右键选择OPTIONS以下仅说明与默认设置不同的地方.Generak Option:Tager : Core ,Device……….set according to applyLibrary options: 1----Tiny 2----SmallC/C++CompilerOptimization: HighPreprocessor: addition include directories----设置比较重要$PROJ_DIR$.\..\--表示在工程所在目录的上一级目录中,也可以指定文件夹如: $PROJ_DIR$\srcLAR\表示部分头文件在—工程所在目录的srcLAR下Assembler:List: Output listPreprocessor: $PROJ_DIR$\..\include\Linker:Output: Output file:***.binFormat—other----output---mpds-code(非常重要)----format variant: noneModule-local: Include allExtera output: Generate extra output fileOutput format: simple-codeFormat variant: NoneList: Genreate linker listingConfig: override default--/…./at91SAM7X256_FLASH.xclOverride default program------Definde by applicat Debugger:Setup: Driver: J_Link Run to: do nit use!Ues macros file: $PROJ_DIR$\resource\SAM7_FLASH.mac三.编译调试1.在RAM中调试.2.在FLASH中调试,同时将代码写进FALSH3.编译生成二进制代码,通过编程器或SAM-BA写入FLASH中.欢迎咨询:embed_tech@Shenzhen:embed_tech Mr zhang。
IAR基本使用解析
IAR基本使用解析
IAR的基本使用分为以下几个步骤:新建项目、配置项目、编写代码、编译代码和调试代码。
首先,可以通过选择“新建项目”来创建一个新的项目。
在创建项目时,可以选择目标设备和编程语言(C、C++等),并设置项目名称和存放
位置。
创建项目后,可以在项目目录中看到生成的项目文件。
第二步是配置项目。
在配置项目时,可以设置编译器的选项、目标设
备的选项以及其他与项目有关的选项。
这些选项包括编译器优化级别、编
译器警告级别、目标设备的存储器映射等。
根据项目的要求,可以对这些
选项进行适当的调整。
完成代码编写后,可以选择“编译”选项来编译代码。
在编译过程中,IAR会将代码转换为目标设备可以执行的二进制文件。
编译器会对代码进
行语法检查和代码优化,以提高代码的执行效率和功能。
最后,可以选择“调试”选项来调试代码。
IAR提供了一套强大的调
试工具,可以在目标设备上进行硬件调试和软件调试。
可以设置断点、监
视变量的值、查看寄存器的状态等。
调试过程中,可以单步执行代码,观
察代码的执行过程,以发现和解决问题。
除了以上的基本使用步骤外,IAR还提供了许多其他的功能和工具。
例如,它可以与版本控制系统集成,可以进行性能分析和代码覆盖率分析,还可以生成可执行文件和调试信息文件等。
总结起来,IAR是一种功能强大的嵌入式系统开发工具,能够帮助开
发人员高效地开发和调试嵌入式应用程序。
通过正确使用IAR的基本使用
步骤,可以提高开发效率,减少开发周期,并最终提供高质量的嵌入式系统。
iar 初始化流程
IAR 初始化流程IAR(IAR Embedded Workbench)是一个功能强大的集成开发环境(IDE),专为嵌入式系统开发而设计。
IAR 提供了从代码编辑、编译、调试到编程的一系列工具,可以帮助开发人员快速高效地开发嵌入式系统。
IAR 的初始化流程包括以下几个步骤:1. 安装IAR首先,需要从 IAR 官网下载并安装 IAR。
安装过程非常简单,只需按照提示操作即可。
2. 创建一个项目安装完成后,打开 IAR,创建一个新的项目。
在“新建项目”对话框中,选择要创建的项目类型,输入项目名称和路径,然后单击“确定”。
3. 添加源文件接下来,需要将源文件添加到项目中。
IAR 支持多种编程语言,包括 C、C++、汇编等。
您可以将源文件拖放到 IAR 的编辑器中,也可以使用“添加文件”菜单添加源文件。
4. 配置项目在添加完源文件后,需要对项目进行配置。
IAR 提供了多种配置选项,包括编译器选项、链接器选项和调试选项等。
您可以根据自己的需要进行配置。
5. 编译项目配置完成后,就可以编译项目了。
IAR 提供了多种编译模式,包括调试模式、发布模式等。
您可以根据自己的需要选择合适的编译模式。
6. 调试项目编译完成后,就可以对项目进行调试了。
IAR 提供了多种调试工具,包括断点、单步执行、变量监视等。
您可以使用这些工具来查找和修复程序中的错误。
7. 编程项目调试完成后,就可以将程序编程到目标设备中了。
IAR 提供了多种编程工具,包括 JTAG、SWD、UART 等。
您可以根据自己的需要选择合适的编程方式。
IAR 的初始化流程相对简单,但它可以帮助您快速高效地开发嵌入式系统。
如果您是嵌入式系统开发的新手,那么强烈建议您学习和使用 IAR。
IAR 初始化流程图(仅供参考):[开始]-> **安装IAR**-> **创建项目**-> **添加源文件**-> **配置项目**-> **编译项目**-> **调试项目**-> **编程项目** [结束]。
IAR基本使用及其构造
工程相关源文件的树型结构,可分为“工程配置文件”、“源程序文件”、“机器码文件”三个部分“工程配置文件”中包含的文件与芯片及工程初始化相关,包括链接文件与启动代码文件。
启动代码文件有“crt0.s”与“start.c”,而且前面都有一个,展开后会看到好多文件,这些都是与其相关联的文件。
“链接文件”定义了芯片存储器的分配和可执行代码地址空间的分配,包括Pflash.icf 与Ram.icf 两个文件,通过修改它们可以将可执行代码链接到芯片RAM 中或Flash 中。
“源程序文件夹“包括C 语言程序、头文件。
其中C 语言程序包括构件C 文件夹”Component_C “、框架C 文件夹”Frame_C “、中断服务例程源文件isr 与主程序源文件main,头文件包括构件头文件”Component_H “、框架头文件夹”Frame_H “与总头文件includes.h。
系统启动并初始化后,程序根据main.c 中定义的主循环顺序执行,当遇到中断请求时,转而执行isr.c 中定义的相应中断处理程序;中断处理结束,则返回中断处继续顺序执行。
由于main.c 和isr.c 文件反映了软件系统的整体执行流程,故而在工程文件组织时,将它与其余C 语言程序文件分开管理。
”Component_C“与”Component_H “包含构件代码,每个构件都对应一个.c 文件与.h 文件,例如GPIO.c 与GPIO.h 文件。
以后的章节还会出现“串行通信”、“键盘”、“LED”、“液晶”等构件。
与总体框架程序相关的头文件和源文件分别放在了Frame_H 和Frame_C 文件夹中,以归类管理。
Frame_H 里包含了common.h、MK60N512VMD100.h、sysinit.h 与vectors.h 四个头文件。
MK60N512VMD100.h 是芯片寄存器及相关位定义头文件,它被视为芯片的接口文件,没有这个文件,就不可能对该芯片进行任何操作。
1、在main执行之前和之后执行的代码可能是什么?
1、在main执⾏之前和之后执⾏的代码可能是什么?
1、在main执⾏之前和之后执⾏的代码可能是什么?
main函数执⾏之前,主要就是初始化系统相关资源:
设置栈指针
初始化静态 static 变量和 global 全局变量,即 .data 段的内容
将未初始化部分的全局变量赋初值:数值型 short , int , long 等为 0 , bool 为 FALSE ,指针为 NULL 等等,即 .bss 段的内容 全局对象初始化,在 main 之前调⽤构造函数,这是可能会执⾏前的⼀些代码
将main函数的参数 argc , argv 等传递给 main 函数,然后才真正运⾏ main 函数
__attribute__((constructor))
main函数执⾏之后:
全局对象的析构函数会在main函数之后执⾏;
可以⽤ atexit 注册⼀个函数,它会在main 之后执⾏;
__attribute__((destructor)。
在main函数之前调用函数,以及对设计的作用
在main函数之前调用函数,以及对设计的作用前几天为新员工写一个简单的测试框架,可让他们方便的写测试用例并且执行。
期间遇到一个问题就是如何让他们增加测试用例而用不影响测试框架的代码?c++的单件模式可以解决这个问题,但是其中一个难点是要在main之前注册单件。
c++可以通过构造函数来实现注册,c如何注册?最后查了下资料,原来可以定义在main之前调用的函数!有了这个特性可以改善c的模块化设计。
特性介绍:如果想定义在main函数之前调用的函数,可以在函数的声明之后加上一句“__attribute__((constructor))”,如下:int before()__attribute__((constructor));如果想定义在main函数之后调用的函数,可以在函数的声明之后加上一句“__attribute__((destructor))”,如下:int after()__attribute__((destructor));可以看得出来,应该类似于c++中的构造和析构。
一些细节问题:写测试代码测试了一下这个程序,发现几点:1、before在main之前调用,调用之前,各个全局变量已经完成初始化。
也就是说,这些函数是在全局变量初始化之后,main函数之前调用的。
这一点是非常重要的,否则可能会引起很多的问题。
2、after在main之后调用,但是有一点比较特殊,必须是在main中return的话才执行,否则,需要通过atexit执行某函数。
这个特性目前对我没有太大的用处。
3、在main函数之前调用的函数可以声明为static。
4、在main函数之前调用的函数可以调用多个。
这里就有一个问题,就是这些函数的调用顺序的问题。
这个问题首先是一个设计的问题,也就是,我们应该设计这些函数为顺序无关的函数。
另外,调用顺序和编译的顺序相关,我在linux下使用make进行编译,发现最后编译的源文件中的函数会最先调用。
c 主线程和子线程执行顺序
c 主线程和子线程执行顺序1.引言1.1 概述在编程中,线程是执行计算机指令的基本单位。
C语言作为一种通用的编程语言,提供了多线程的支持。
在C语言中,存在主线程和子线程两种类型的线程。
主线程是程序的入口点,也是程序的默认线程。
它负责执行程序的主要逻辑,并与用户进行交互。
主线程的执行顺序通常是按照程序代码的顺序进行执行。
与主线程相反,子线程是由主线程创建和操纵的额外线程。
子线程可以并行执行,从而提高程序的并发性和效率。
子线程的执行顺序不受主线程的控制,而是由操作系统的线程调度器决定。
在C语言中,主线程和子线程的执行顺序可能会有所不同。
当程序启动时,主线程会首先执行。
然后,主线程可以选择创建一个或多个子线程,并将它们分配给不同的任务。
子线程会在主线程的指导下执行特定的任务,直到任务完成或主线程终止。
需要注意的是,主线程和子线程之间的执行顺序是无法确定的,因为线程的调度是由操作系统决定的。
具体而言,主线程和子线程的执行顺序可能会受到多种因素的影响,例如操作系统的调度算法、线程的优先级等。
因此,在编写多线程程序时,我们需要充分考虑线程之间的执行顺序以及可能出现的并发问题。
合理地安排主线程和子线程的执行顺序,可以提高程序的性能和可靠性。
总之,主线程和子线程是C语言中常见的线程类型,它们的执行顺序是由操作系统的线程调度器决定的。
在编写多线程程序时,我们需要充分考虑线程之间的执行顺序以及可能出现的并发问题,以提高程序的性能和可靠性。
1.2文章结构1.2 文章结构本文将探讨主线程和子线程在执行过程中的顺序。
首先,我们会对整篇文章进行简要的概述,明确本文的目的。
随后,我们将详细讨论主线程和子线程分别在执行过程中的顺序。
接下来的2.1节中,我们将深入研究主线程的执行顺序。
我们会介绍主线程的概念,并详细讨论主线程中不同任务的执行顺序。
我们将提供相关的代码示例和执行流程图,以帮助读者更好地理解。
在2.2节中,我们将转向子线程的执行顺序。
C51–在main__之前到底做了什么
1C51–在main()之前到底做了什么??用C 写过东西的都知道,程序是从main()函数开始执行的,在main()之前会有一系列的初始化工作,那么这些初始化到底做了些什么了??大家也都知道在MCU 中,程序是在Flash 里面,而数据是在RAM 里面,掉电之后,Flash 里面的东西还在,RAM 里面的东西就没有了.那么你把程序下载到芯片里面之后,数据是在哪里了?你会想,它当然是在Flash 里面的.那数据又是在什么时候跑到RAM 里面了呢?结合C51生成的M51文件,大概的说一下main()函数之前,到底都做了哪些初始化的工作.程序编译(assembly,compile),连接(link)过后会生成HEX 文件.整个HEX 文件是由程序和数据(主要是global 和static 的数据)组成的.当然程序和数据会放在不同的地址,这些地址是绝对的地址.绝对的地址是在连接(link)过程中生成的.如果是C51的话,何以看一下他的M51文件.M51文件就是link 的MAP 文件. 例如:MCU 是C8051F340,IDE 是uVersion4,C51是v9.01,main()函数如下://main.cunsigned int a = 0;unsigned int b = 0xff;void main(void){unsigned int c;unsigned int d;d = c;while(1);} build output 的信息是:Build target ‘Target 1′assembling STARTUP.A51…compiling main.c…linking…Program Size: data=17.0 xdata=0 code=160“test” – 0 Error(s), 0 Warning(s).可以看到,data用里17Byte,code是160Byte,没有用到xdata.查看M51文件:BL51 BANKED LINKER/LOCATER V6.22 04/25/2010 11:27:23 PAGE 1BL51 BANKED LINKER/LOCATER V6.22, INVOKED BY:D:\PROGRAM FILES\KEIL\C51\BIN\BL51.EXE STARTUP.obj, main.obj TO test RAMSIZE (256)MEMORY MODEL: SMALLINPUT MODULES INCLUDED:STARTUP.obj (?C_STARTUP)main.obj (MAIN)D:\PROGRAM FILES\KEIL\C51\LIB\C51S.LIB (?C_INIT)LINK MAP OF MODULE: test (?C_STARTUP)TYPE BASE LENGTH RELOCATION SEGMENT NAME—————————————————–* * * * * * * D A T A M E M O R Y * * * * * * *REG 0000H 0008H ABSOLUTE “REG BANK 0″DATA 0008H 0004H UNIT ?DT?MAINDATA 000CH 0004H UNIT _DATA_GROUP_IDATA 0010H 0001H UNIT ?STACK* * * * * * * C O D E M E M O R Y * * * * * * *CODE 0000H 0003H ABSOLUTECODE 0003H 008CH UNIT ?C_C51STARTUPCODE 008FH 0009H UNIT ?C_INITSEGCODE 0098H 0008H UNIT ?PR?MAIN?MAIN说一下里面的意义,首先是DATA MEMORY,REG是特殊寄存器(SFR)R0-R7,SFR是映射到RAM上的.BASE是0000H,LENGTH是0008H.后面是DATA,从0008H开始,LENGTH是0004H,TYPE是UINT,这个是全局变量a,b在RAM中的位置.2后面是_DATA_GROUP_,是存放临时变量时用的,_DATA_GROUP_在C51中解释的原话是“The _DATA_GROUP_ is a segment that contains all the automatic variables and function arguments from your program that are stored in DATA memory.These segments are created so that the linker can perform overlay analysis and better optimize your use of DATA and BIT memory.”上面的意思是说_DATA_GROUP_好像是执行overlay analysis的.我现在还不清楚的是它的具体作用,还有他和SP指向的栈有什么区别?我记得好像是函数的局部变量是放在栈里面的,函数退出的时候,会执行POP命令.因为我在main()里面声明了两个局部变量,这两个变量是放在_DATA_GROUP_里面的吗??后面的IDATA是堆栈的位置.堆栈在RAM中的0×0010的地方,但是LENGTH只有0001H,不知道为什么是这样的?CODE MEMORY中开始是0000H,也是绝对地址0,一上电,PC指针指向的地方,这个地方肯定有一个LJMP,跳转到STARTIP1这个标号的位置,这个指令占三个字节.后面的是C_C51STARTUP段,这个段就是startup.a51中的内容,0003H也就是STARTUP1在Flash中的位置,程序上电后就跳到这个地方,主要的作用是初始化内存,把RAM中00H-7FH全部清零.后面的是C_INITSEG段,看一下?C_INITSEG原话解释:The initial values of global and static variables are stored in ROM in a segment called ?C_INITSEG. They are then copied to the relevent RAM locations after the code in STARTUP.A51 has been executed and before the main() function is called. The code that performs the variable initialization may be found in the file INIT.A51 inside the LIB folder.从中知道就是把global and static variables 在ROM中的段就是?C_INITSEG段.那么这个段中的数据时怎么到RAM中区的呢?把这个段中的数据copy到RAM中去,看?C_INITSEG解释的最后一句,使用的文件是INIT.A51,但是现在好像不是显式的添加这个文件,而是用的库文件,可以在M51的头部看到,INPUT MODULES INCLUDED:STARTUP.obj (?C_STARTUP)main.obj (MAIN)D:\PROGRAM FILES\KEIL\C51\LIB\C51S.LIB (?C_INIT)也就是说在STARTUP.A51之后,在main()之前,执行的是INIT.A51的程序,也就是把ROM中的数据copy到RAM中区.这个之后,main()函数之前的所有准备工作也就做完了.可以去执行main()函数了.小结:以前一直没有搞清楚这个程序到底是怎么运行的,隐约的觉得数据一开始是在Flash中的,但是什么时候跑到RAM中去了呢??现在基本搞清楚了.下面想仔细研究一下在main()函数之前执行的程序究竟是什么意思.主要也就是STARTUP.A51和INIT.A51.结合A51和C51的datasheet看.3。
Keil程序运行main函数之前的汇编
Keil开发的ARM程序main函数之前的汇编分析——BIN文件中RW段的数据移动系统平台:STM32系列STM32F103ZE,512KB内部FLASH,64KB片内存储;FLASH地址范围0x0800 0000 ~ 0x0808 0000,用于存放代码;片内存储地址范围0x2000 0000 ~ 0x2001 0000,用于存放数据;Cortex-M3上电后来到复位中断(已将前4个字节的值存入MSP堆栈指针),转到__main 标号,完成RW段的移动、ZI段的初始化,建立堆栈,初始化库函数,然后跳转到main函数,开启C程序之旅,执行流程如图1所示。
图1 main函数之前的汇编程序执行流程图本文主要讨论RW段的移动,RW段就是程序中赋了初值的变量,它的搬移我看到过两种方式。
在BIN文件中,RO段和RW段之间有8个双字的Region$$Table,4个双字一组,分别用于完成RW段的搬移和ZI段的初始化。
(1)__scatterload_copy来完成此时RW段的内容保存到内存开始的地方,本文中是0x20000000,用这一方式完成后,内存中存放的不是RW数据的内容,而是一个地址。
这个地址是在FLASH中,即指向了其在RO段的地址,实际的内容是在RO段中。
(2)通过__uncompressed1实现RW是程序中初始化的变量,但是这些变量有可能初值是0,因此为了节省空间,实际在BIN文件中RW段是压缩过的。
调用__uncompressed1解压缩RW段的数据内容,并将其保存到内存开始的地方。
图2 BIN文件中压缩RW段内容图2是BIN文件中RW段的数据内容,影印部分显示,大小是164字节。
其中0x0001 C72C前面8个双字的内容是Region$$Table,将其列出如下。
0x0801 C72C BIN文件中RW段的开始地址0x2000 0000 RW段要存放到RAM中的地址0x0000 0334 要存放到RAM中的RW段数据大小0x0800 0184 执行函数__scatterload_copy或者__uncompressed1上面4个双字完成RW段的搬移。
main方法的执行顺序
main方法的执行顺序
在Java程序中,main方法是程序的入口,它是执行程序的第一个方法。
main方法的执行顺序如下:
1. Java虚拟机(JVM)加载类文件,并定位到程序中的main方法。
2. JVM调用main方法,并将命令行参数传递给main方法。
3. main方法开始执行,并按照自己的代码逻辑执行程序。
4. 当main方法结束时,JVM将退出程序。
需要注意的是,main方法是程序的入口,但不是程序唯一的方法。
程序中的其他方法可以在main方法中被调用,也可以在其他方法中被调用。
但无论哪个方法被调用,当所有代码执行完毕后,JVM 都将退出程序。
- 1 -。
- 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
- 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
- 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。
[原创]在main()之前,IAR都做了啥?最近要在Cortex-M3上写一个简单的操作系统,打算使用IAR,为了写好启动代码,花了一些时间了解了IAR在main()以前做了些什么事。
首先系统复位时,Cortex-M3从代码区偏移0x0000'0000处获取栈顶地址,用来初始化MSP寄存器的值。
接下来从代码区偏移0x0000'0004获取第一个指令的跳转地址。
这些地址,是CM3要求放置中断向量表的地方。
这里是一个程序的启动区的反汇编:__vector_table:08004000 260008004002 200008004004 7E1D08004006 0800这个程序是由IAP程序来启动的,IAP程序获取0x0800'4000处的MSP值(0x20002600),并设置为MSP 的值,即主堆栈最大范围是0x2000'0000~0x2000'25FF。
接下来IAP程序获取0x0800'4004处的Reset_Handler的地址(0x0800'7E1D),并跳转到Reset_Handler()执行。
IAP在这里完全是模仿了Cortex-M3的复位序列,也就是说,在没有IAP的系统上,CM3只能从0x0800'0000获取MSP,从0x0800'0004获取第一条指令所处地址。
而IAP就存在在0x0800'0000这个地址上,IAP的启动,已经消耗掉了这个复位序列,所以IAP要启动UserApp程序的时候,也是完全模仿Cortex-M3的复位序列的。
接下来我们看看复位后第一句指令——Reset_Handler()函数里有什么。
若我们使用的是ST公司标准外设库,那么已经有了现成的Reset_Handler,不过他是弱定义——P U B W E A K,可以被我们重写的同名函数覆盖。
一般来说,我们使用的都是ST提供的Reset_Handler,在V3.4版本的库中,可以在startup_stm32f10x_xx.s中找到这个函数:PUBWEAK Reset_HandlerSECTION .text:CODE:REORDER(2)Reset_HandlerLDR R0, =SystemInitBLX R0LDR R0, =__iar_program_startBX R0看来ST没有做太多的事,他只调用了自家库提供的SystemInit函数进行系统时钟、Flash读取的初始化,并把大权交给了__iar_program_start这个IAR提供的“内部函数”了,我们就跟紧这个__iar_program_start跳转,看看IAR做了什么,上面一段代码的反汇编如下:Reset_Handler:__iar_section$$root:08007E1C 4801 LDR R0, [PC, #0x4]; LDR R0, =SystemInit08007E1E 4780 BLX R0;BLX R008007E20 4801 LDR R0, [PC, #0x4];LDR R0, =__iar_program_start08007E22 4700 BX R0;BX R008007E24 6C6908007E26 080008007E28 7D8D08007E2A 0800细心的观众会发现地址是0x0800'7E1C,比我们查到的0x0800'7E1D差了1,这是ARM家族的遗留问题,因为ARM处理器的指令至少是半字对齐的(16位THUMB指令集 or 32位ARM指令集),所以PC指针的LSB是常为0的,为了充分利用寄存器,ARM公司给PC的LSB了一个重要的使命,那就是在执行分支跳转时,PC的LSB=1,表示使用THUMB模式,LSB=0,表示使用ARM模式,但在最新的Cortex-M3内核上,只使用了THUMB-2指令集挑大梁,所以这一位要常保持1,所以我们查到的地址是0x0800'7E1D(C=1100,D=1101),放心,我们的CM3内核会忽略掉LSB(除非为0,那么会引起一个fault),从而正确跳转到0x0800'7E1C。
从0x0800'7E20处的加载指令,我们可以算出__iar_program_start所处的位置,就是当前PC指针(0x0800'7E24),再加上4,即0x0800'7E28处的所指向的地址——0x0800'7D8D(0x0800'7D8C),我们跟紧着跳转,__iar_program_start果然在这里:__iar_program_start:08007D8C F000F88C BL __low_level_init08007D90 2800 CMP R0, #0x008007D92 D001 BEQ __iar_init$$done08007D94 F7FFFFDE BL __iar_data_init208007D98 2000 MOVS R0, #0x008007D9A F7FDFC49 BL main我们看到IAR提供了__low_level_init这个函数进行了“底层”的初始化,进一步跟踪,我们可以查到__low_level_init这个函数做了些什么,不是不是我们想象中的不可告人。
__low_level_init:08007EA8 2001 MOVS R0, #0x108007EAA 4770 BX LR__low_level_init出乎想象的简单,只是往R0寄存器写入了1,就立即执行"BX LR"回到调用处了,接下来,__iar_program_start检查了R0是否为0,为0,则执行__iar_init$$done,若不是0,就执行__iar_data_init2。
__iar_init$$done这个函数很简单,只有2句话,第一句是把R0清零,第二句就直接"BL main",跳转到main()函数了。
不过既然__low_level_init已经往R0写入了1,那么我们还是得走下远路——看看__iar_data_init2做了些什么,虽然距离main只有一步之遥,不过这中间隐藏了编译器的思想,我们得耐心看下去。
__iar_data_init2:08007D54 B510 PUSH {R4,LR}08007D56 4804 LDR R0, [PC, #0x10]08007D58 4C04 LDR R4, [PC, #0x10]08007D5A E002 B 0x8007D6208007D5C F8501B04 LDR R1, [R0], #0x408007D60 4788 BLX R108007D62 42A0 CMP R0, R408007D64 D1FA BNE 0x8007D5C08007D66 BD10 POP {R4,PC}08007D68 7C7808007D6A 080008007D6C 7C9C08007D6E 0800看来IAR迟迟不执行main()函数,就是为了执行__iar_data_init2,我们来分析分析IAR都干了些什么坏事~首先压R4,LR入栈,然后加载0x0800'7C78至R0,0x0800'7C9C至R4,马上跳转到0x0800'7D62执行R0,R4的比较,结果若是相等,则弹出R4,PC,然后立即进入main()。
不过IAR请君入瓮是自不会那么快放我们出来的——结果不相等,跳转到0x0800'7D5C执行,在这里,把R0指向的地址——0x0800'7C78中的值——0x0800'7D71加载到R1,并且R0中的值自加4,更新为0x0800'7C7C,并跳转到R1指向的地址处执行,这里是另一个IAR函数:__iar_zero_init2:__iar_zero_init2:08007D70 2300 MOVS R3, #0x008007D72 E005 B 0x8007D8008007D74 F8501B04 LDR R1, [R0], #0x408007D78 F8413B04 STR R3, [R1], #0x408007D7C 1F12 SUBS R2, R2, #0x408007D7E D1FB BNE 0x8007D7808007D80 F8502B04 LDR R2, [R0], #0x408007D84 2A00 CMP R2, #0x008007D86 D1F5 BNE 0x8007D7408007D88 4770 BX LR08007D8A 0000 MOVS R0, R0__iar_data_init2还没执行完毕,就跳转到了这个__iar_zero_inti2,且看我们慢慢分析这个帮凶——__iar_zero_inti2做了什么。
__iar_zero_inti2将R3寄存器清零,立即跳转到0x0800'7D80执行'LDR R2, [R0], #0x4',这句指令与刚才在__iar_data_init2见到的'LDR R1, [R0], #0x4'很类似,都为“后索引”。
这回,将R0指向的地址——0x0800'7C7C中的值——0x0000'02F4加载到R2寄存器,然后R0中的值自加4,更新为0x0800'7C80。
接下来的指令检查了R2是否为0,显然这个函数没那么简单想放我我们,R2的值为2F4,我们又被带到了0x0800'7D74处,随后4条指令做了如下的事情:1、将R0指向的地址——0x0800'7C80中的值——0x2000'27D4加载到R1寄存器,然后R0中的值自加4,更新为0x0800'7C84。
2、将R1指向的地址——0x2000'27D4中的值——改写为R3寄存器的值——0,然后R1中的值自加4,更新为0x2000'27D8。
3、R2自减44、检查R2是否为0,不为0,跳转到第二条执行。
不为,则执行下一条。
这简直就是一个循环!——C语言的循环for(r2=0x2F4;r2-=4;r!=0){...},我们看看循环中做了什么。
第一条指令把一个地址加载到了R1——0x2000'27D4是一个RAM地址,以这个为起点,在循环中,对长度为2F4的RAM空间进行了清零的操作。
那为什么IAR要做这个事情呢?消除什么记录么?用Jlink查看这片内存区域,可以发现这片区域是我们定义的全局变量的所在地。