资源描述
单击此处编辑母版标题样式,第五章,汇编语言程序设计及系统初始化,单击此处编辑母版标题样式,单击此处编辑母版文本样式,第二级,第三级,第四级,第五级,*,*,*,单击此处编辑母版标题样式,单击此处编辑母版文本样式,第二级,第三级,第四级,第五级,*,*,*,第五章汇编语言程序设计及 系统初分别化,5.1 ARM汇编语言程序框架,5.2 浮点数据处理,5.3 系统初始化,5.4 中断效劳程序,本章小结,5.1 ARM汇编语言程序框架,在MDK环境下,新建一个工程ex5_1,拷贝工程ex4_3中的文件和,然后,编写一个新的汇编语言程序,其代码如下:1 AREA LEDLIGHT, CODE, READONLY2 EXPORT _main ; LedFlash3 EXPORT _use_two_region_memory4 GPCDAT_ADDR EQU 0x560000245 LED_ON EQU 0x00006 LED_OFF EQU 0x00E0,7 ENTRY8 ; LedFlash9 _main10 LDR R0, =GPCDAT_ADDR11 MOV R1, #LED_ON 12 STR R1, R0 ; LED ON13 14 BL Delay15 16 MOV R1, #LED_OFF 17 STR R1, R0 ; LED OFF,18 19 BL Delay20 21 B _main22 Delay23 MOV R3, #0x0F000024 MOV R4, #0x0F000025 subcycle126 SUB R3, R3, #127 subcycle228 SUB R4, R4, #1,29 CMP R4, #030 BGE subcycle231 32 CMP R3, #033 BGE subcycle134 BX LR35 36 _use_two_region_memory ; no warning37 END 将添加到工程ex5_1中,当前工作主窗口如图5-1所示。先不要编译连接这个工程文件,在小节时才能正确地编译连接并执行该工程。,图5-1 工程ex5_1工作界面,5.1.1 通用输入输出C口配置在图5-1中,双击翻开它,保持其他设置不变(相对于工程ex4_3)的情况下,对I/O Configuration进行配置,如图5-2所示。图5-2中将PC5、PC6和PC7配置为输出特性(Output),对应于的第06060608行代码如下:PIOC_SETUP EQU 1PCONC_Val EQU 0xAAAA56AAPUPC_Val EQU 0x00000000,图5-2 通用I/O口配置,PIOC_SETUP为1表示图5-2中的Port C被勾选;当设置PC0PC15如图5-2时,端口C的控制存放器的值为0xAAAA56AA;端口C所有上拉电阻都是使能的,端口C上拉控制存放器的值为0x00000000。图5-2中的I/O Configuration勾选,对应于中的第0510行代码如下:PIO_SETUP EQU 1 如图5-2设置好之后,下面罗列出启动代码文件中与通用I/O口配置相关的代码,如表5-1所示。,表中与I/O口配置相关的代码,序号,行号,注 释 或 语 句,1,0488,; I/O Ports definitions,2,0489,PIO_BASE,EQU,0x56000000,; PIO Base Address,3,0490,PCONA_OFS,EQU,0x00,; PCONA Offset,4,0491,PCONB_OFS,EQU,0x10,; PCONB Offset,5,0492,PCONC_OFS,EQU,0x20,; PCONC Offset,6,0493,PCOND_OFS,EQU,0x30,; PCOND Offset,7,0494,PCONE_OFS,EQU,0x40,; PCONE Offset,8,0495,PCONF_OFS,EQU,0x50,; PCONF Offset,9,0496,PCONG_OFS,EQU,0x60,; PCONG Offset,10,0497,PCONH_OFS,EQU,0x70,; PCONH Offset,11,0498,PCONJ_OFS,EQU,0xD0,; PCONJ Offset,12,0499,PUPB_OFS,EQU,0x18,; PUPB Offset,13,0500,PUPC_OFS,EQU,0x28,; PUPC Offset,14,0501,PUPD_OFS,EQU,0x38,; PUPD Offset,15,0502,PUPE_OFS,EQU,0x48,; PUPE Offset,16,0503,PUPF_OFS,EQU,0x58,; PUPF Offset,17,0504,PUPG_OFS,EQU,0x68,; PUPG Offset,18,0505,PUPH_OFS,EQU,0x78,; PUPH Offset,19,0506,PUPJ_OFS,EQU,0xD8,; PUPJ Offset,20,0509,;/ I/O Configuration,21,0510,PIO_SETUP EQU,1,22,0512,0536,A口注释,23,0537,PIOA_SETUP,EQU,0,24,0538,PCONA_Val,EQU,0x000003FF,25,0540,0565,B口注释,26,0566,PIOB_SETUP,EQU,0,27,0567,PCONB_Val,EQU,0x000007FF,28,0568,PUPB_Val,EQU,0x00000000,29,0570,0605,C口注释,30,0606,PIOC_SETUP,EQU,1,31,0607,PCONC_Val,EQU,0xAAAA56AA,32,0608,PUPC_Val,EQU,0x00000000,33,0610,0645,D口注释,34,0646,PIOD_SETUP,EQU,0,35,0647,PCOND_Val,EQU,0x00000000,36,0648,PUPD_Val,EQU,0x00000000,37,0650,0685,E口注释,38,0686,PIOE_SETUP,EQU,0,39,0687,PCONE_Val,EQU,0x00000000,序号,行号,注 释 或 语 句,40,0688,PUPE_Val,EQU,0x00000000,41,0690,0709,F口注释,42,0710,PIOF_SETUP,EQU,0,43,0711,PCONF_Val,EQU,0x0000511A,44,0712,PUPF_Val,EQU,0x00000000,45,0714,0749,G口注释,46,0750,PIOG_SETUP,EQU,0,47,0751,PCONG_Val,EQU,0x00000000,48,0752,PUPG_Val,EQU,0x00000000,49,0754,0779,H口注释,50,0780,PIOH_SETUP,EQU,0,51,0781,PCONH_Val,EQU,0x000007FF,52,0782,PUPH_Val,EQU,0x00000000,53,0922,; I/O Configuration,54,0923,IF,PIO_SETUP 0,55,0924,PIOA_CFG,56,0925,DCD,PCONA_Val,57,0926,PIOB_CFG,DCD,PCONB_Val,58,0927,DCD,PUPB_Val,59,0928,PIOC_CFG,DCD,PCONC_Val,60,0929,DCD,PUPC_Val,61,0930,PIOD_CFG,DCD,PCOND_Val,62,0931,DCD,PUPD_Val,63,0932,PIOE_CFG,DCD,PCONE_Val,64,0933,DCD,PUPE_Val,65,0934,PIOF_CFG,DCD,PCONF_Val,66,0935,DCD,PUPF_Val,67,0936,PIOG_CFG,DCD,PCONG_Val,68,0937,DCD,PUPG_Val,69,0938,PIOH_CFG,DCD,PCONH_Val,70,0939,DCD,PUPH_Val,71,0940,ENDIF,72,0981,1038,S3C2410A.s有误,将在下面说明。,中的第09811038行原始代码如下:IF PIO_SETUP 0 LDR R14, =PIO_BASE IF PIOA_SETUP 0 ADR R0, PIOA_CFGSTR R0, R14, #PCONA_OFSENDIF IF PIOB_SETUP 0 ADR R0, PIOB_CFG,LDR R1, R0,#4 STR R0, R14, #PCONB_OFS STR R1, R14, #PUPB_OFS ENDIF IF PIOC_SETUP 0 ADR R0, PIOC_CFG LDR R1, R0,#4 STR R0, R14, #PCONC_OFS STR R1, R14, #PUPC_OFS ENDIF,IF PIOD_SETUP 0 ADR R0, PIOD_CFG LDR R1, R0,#4 STR R0, R14, #PCOND_OFS STR R1, R14, #PUPD_OFS ENDIF IF PIOE_SETUP 0 ADR R0, PIOE_CFG LDR R1, R0,#4 STR R0, R14, #PCONE_OFS STR R1, R14, #PUPE_OFS ENDIF,IF PIOF_SETUP 0 ADR R0, PIOF_CFG LDR R1, R0,#4 STR R0, R14, #PCONF_OFS STR R1, R14, #PUPF_OFS ENDIF IF PIOG_SETUP 0 ADR R0, PIOG_CFG LDR R1, R0,#4 STR R0, R14, #PCONG_OFS STR R1, R14, #PUPG_OFS ENDIF,IF PIOH_SETUP 0 ADR R0, PIOH_CFG LDR R1, R0,#4 STR R0, R14, #PCONH_OFS STR R1, R14, #PUPH_OFS ENDIF ENDIF 修正后的代码如下,其中,添加了注释的为补充和修正的代码行: IF PIO_SETUP 0 LDR R14, =PIO_BASE,IF PIOA_SETUP 0 ADR R0, PIOA_CFG LDR R2, R0; Added by ZY STR R2, R14, #PCONA_OFS; Changed by ZY ENDIF IF PIOB_SETUP 0 ADR R0, PIOB_CFG LDR R2, R0; Added by ZY LDR R1, R0,#4 STR R2, R14, #PCONB_OFS ; Changed by ZY STR R1, R14, #PUPB_OFS ENDIF,IF PIOC_SETUP 0 ADR R0, PIOC_CFG LDR R2, R0; Added by ZY LDR R1, R0,#4 STR R2, R14, #PCONC_OFS; R0,R14, #PCONC_OFS Changed by ZY STR R1, R14, #PUPC_OFS ENDIF,IF PIOD_SETUP 0 ADR R0, PIOD_CFG LDR R2, R0; Added by ZY LDR R1, R0,#4 STR R2, R14, #PCOND_OFS; Changed by ZY STR R1, R14, #PUPD_OFS ENDIF,IF PIOE_SETUP 0 ADR R0, PIOE_CFG LDR R2, R0; Added by ZY LDR R1, R0,#4 STR R2, R14, #PCONE_OFS ; Changed by ZY STR R1, R14, #PUPE_OFS ENDIF,IF PIOF_SETUP 0 ADR R0, PIOF_CFG LDR R2, R0 ; Added by ZY LDR R1, R0,#4 STR R2, R14, #PCONF_OFS; Changed by ZY STR R1, R14, #PUPF_OFS ENDIF,IF PIOG_SETUP 0ADR R0, PIOG_CFG LDR R2, R0 ; Added by ZYLDR R1, R0,#4 STR R2, R14, #PCONG_OFS ; Changed by ZY STR R1, R14, #PUPG_OFS ENDIF,IF PIOH_SETUP 0 ADR R0, PIOH_CFG LDR R2, R0 ; Added by ZY LDR R1, R0,#4 STR R2, R14, #PCONH_OFS ; Changed by ZY STR R1, R14, #PUPH_OFS ENDIF ENDIF,MDK软件虽然是个极其优秀的软件包,但是,此处的错误是很明显的,由于具有8个IO口,相同的错误连续出现了8次以上。例如对于C口,代码如下:IF PIOC_SETUP 0 ADR R0, PIOC_CFG LDR R1, R0,#4 STR R0, R14, #PCONC_OFS STR R1, R14, #PUPC_OFSENDIF,结合第二章,可知条件满足,执行完ADR指令后,R0装入的是PIOC_CFG的标号,即一个地址,这个地址内的值为配置字,但是这个地址本身不能作为配置字,所以,后面的“STR R0, R14, #PCONC_OFS语句就是完全错误的了。改正的方法很简单,代码如下:IF PIOC_SETUP 0 ADR R0, PIOC_CFGLDR R2, R0 ; Added by ZY LDR R1, R0,#4 STR R2, R14, #PCONC_OFS; R0,R14, #PCONC_OFS Changed by ZY STR R1, R14, #PUPC_OFSENDIF,像上述代码一样,将R0值指向的地址处的值赋给R2,然后,再使用“STR R2, R14, #PCONC_OFS就可以了。对于一个商业软件,其评估版的S3C2410芯片启动代码出现问题,一方面说明了这局部代码没有经过严格测试,另一方面也警告我们,汇编语言编程相对于C语言来说,确有一些劣势。 下面解释一下表和启动代码中关于IO口配置的方法。序号219:定义了IO口存储器映射存放器的基地址0x56000000,然后定义了AH口的偏移地址,这些IO口存放器的地址可参考附表1-1。例如,C口的控制存放器地址为0x56000020,相当于基址0x56000000 + 偏移地址PCONC_OFS(0x20)。这里没有J口,可以删除。,序号21:当勾选了图5-2中I/O Configuration后,此处,PIO_SETUP为1;否那么,不勾选时,PIO_SETUP为0,将不初始化IO口。序号2324:由于图5-2中没有勾选Port A,那么PIOA_SETUP为0,A口只有控制存放器,没有上拉存放器,这里只有PCONA_Val,当然,这个值由于PIOA_SETUP为0而不会被用到。序号2628:由于图5-2中没有勾选Port B,那么PIOB_SETUP为0;符号PCONB_Val和PUPB_Val的值表示B口的控制存放器和上拉存放器的配置字,这些值随着图形配置向导而自动变化。,序号3032:由于图5-2中勾选了Port C,那么PIOC_SETUP为1;同时,根据图形配置向导自动设置了控制存放器和上拉存放器的值PCONC_Val和PUPC_Val,这两个值代表的含义请参考图5-2和“S3C2410A Users Manual第九章第10页,把GPC7:5设为输出口。序号3452:介绍端口DH,与上述含义相近,不再重述。序号5471:如果PIO_SETUP不为0,那么开辟存储空间存放端口AH的配置字,其中,A口只有一个配置字,BH口均有两个配置字。,5.1.2 工程ex5_1的注解及运行情况在前面小节对进行修正之后,可以编译连接并下载这个工程了,在编译时会报告一条警告信息,即“ex5_1.sct(8): warning: L6314W: No section matches pattern *(InRoot$Sections),这里的是根据工程选项(像图4-15那样)的设置编译工程时自动产生的存储器配置文件,也称Scatter文件,以.sct结尾;“InRoot$Section是指为连接库里的段分配的空间,用于C语言程序设计中。双击该警告信息,那么弹出文件内容,如图5-3所示,在“*(InRoot$Sections)前面加上“;号将其注释掉,并保存文件。,图文件,这时先不要编译工程,翻开工程选项,选中“Linker页签,设置如图5-4所示,即使用Scatter File:。说明:工程选项中的其他页签保持不变(相对于工程ex4_3)。点击图5-4的“OK按钮后,可以重新编译工程ex5_1,此时没有错误,也没有警告信息了,如图5-5所示。在图5-5上,点击“Flash | Download菜单(或单击工具栏上的快捷按钮)那么把下载到UP-NETARM2410实验箱Nand型Flash上。下载完毕后,程序将启动,可以看到三个LED灯在闪烁!也可以在线仿真调试(一般地,要把程序下载到Flash中后再仿真),或者把ULINK2仿真器从实验箱上取下来,重新给实验箱上电,那么程序会从Flash中启动执行。,图5-4 工程选项卡设置,图5-5 完整的工程ex5_1,本节还有两个问题没有解决,其一为Scatter文件如何编写,其二为汇编语言程序的解释。笔者认为Scatter文件的内容及如何编写该文件方面的知识,除了一些ARM官方的文档之外,最好的资料是MDK软件的帮助菜单。这个帮助菜单和它的内容做得相当出色!本书中,笔者几乎无一例外地使用工程选项卡配置存储器,因此,对Scatter文件内容的介绍也不会很多。 现在,解释一下节开头给出的程序段,即文件,该文件内容如图5-6所示,在图5-6中给出语句的行号,下面按行号解释。,图5-6 文件内容,行号01:定义名为LEDLIGHT的只读代码段。行号02:标号_main在外部可见。行号03:标号_use_two_region_memory在外部可见。这句和行号36处没有实际意义,仅是为了编译时不出现警告或错误,因为在的第1095行(修正后的文件行号)有一句“IMPORT _use_two_region_memory。行号04:定义C口数据存放器地址。行号05:定义LED灯亮的常量。行号06:定义LED灯灭的常量。,行号07:ENTRY指程序入口点,一般的汇编程序只需要有一个入口点,而且这个入口点常被用作上电复位后的执行入口点。需要说明的是,这里的ENTRY入口点,并不是上电复位的执行入口点,在本程序中,由于RESET段是存储在地址0x00000000处的,所以,RESET是上电复位入口点(RESET在文件中)。行号09:定义标号_main。行号10:R0 = 0x56000024。行号11:R1 = 0。行号12:向地址0x56000024处赋值0,即使GPC5、GPC6和GPC7为0(低电平), 由第二章图2-26可知, 将点亮三个LED灯。,行号14:跳转到延迟子程序,这个程序段不作介绍。行号16:R1 = 0xE0。行号17:向地址0x56000024处赋值1,即使GPC5、GPC6和GPC7为1(高电平),由第二章图2-26可知,将熄灭三个LED灯。行号19:跳转到延迟子程序。行号21:跳转到_main,循环执行。程序功能:点亮三个LED灯后,等待约(0xF0000*0xF0000*指令周期)后,熄灭LED灯,再等待一段时间后,重新点亮LED灯,循环执行,给人LED灯闪烁的感觉。,5.1.3 汇编语言语法,ARM汇编语言的语法内容丰容,本书的重点不在于汇编语言,汇编语言主要用于初始化系统。因此,这里简单地介绍一些常用的汇编语言语法。1) AREAAREA已出现在中,用于定义汇编语言代码段或数据段,例如:AREA LEDLIGHT,CODE,READONLYAREA LEDSHINE,DATA,READWRITE,上述代码段定义一个名为LEDLIGHT的只读代码段和一个名为LEDSHINE的读写代码段。DATA用得较少。在中有如下语句:AREA STACK, NOINIT, READWRITE, ALIGN=3该语句中,NOINIT伪关键字表示该段代码只分配空间,不初始化(用0填充),ALIGN=3表示按双字对齐方式(23=8 B)。2) SPACE在中有如下语句:Stack_Mem SPACE Stack_Size,这里Stack_Mem为标号,Stack_Size为常量,SPACE表示为Stack_Mem分配大小为Stack_Size的连续空间,单位为字节。3) DCDDCD已出现在中,表示分配字大小的连续空间,并用其他的值初始化该空间,例如:Mem_Val_Conf DCD 0x22111110, 0x700表示为标号Mem_Val_Conf分配两个字空间,并初始化这个字的值为0x22111110和 0x700。此外,还有DCDU表示不按字对齐方式存储,慎用! 除了DCD之外,还有DCB、DCW、DCQ、DCFS、DCFD等,分别表示为字节、半字、双字、单精度浮点数(即字)、双精度浮点数(即字)分配空间,并使用指定的数据初始化。,4) EQUEQU是汇编语言的相等伪指令,用得较多。例如在中有:Mem_Addr_Base EQU 0x48000000 5) PRESERVE8PRESERVE8指定当前文件的堆栈采用8字节对齐方式,出现在中第0789行,要求每个栈的长度的最低3位为0,且栈底地址的最低3位也应为0。6) ARMARM指示符出现在中第0796行,指示编译器生成32位指令的ARM代码;而THUMB指示符表示生成16位指令的Thumb代码。另外,THUMBX用于生成Thumb-2EE代码。,7) NOPNOP即No operation,表示空操作。8) IF语句IF语句格式为: IF 条件表达式 语句组1ELSE 语句组2ENDIF,当条件表达式为真时,执行语句组1;否那么,执行语句组2。出现在条件表达式中的“(例如中的第0923行)表示不等于。表示等于、大于、小于、大于等于、小于等于的关系操作符为=、=、=。9) IMPORTIMPORT后面跟标识符,说明该标识符是在该文件外部定义的,标识符后可以加可选项WEEK,那么引用的标识符没有定义时,编译时也不会出错。而该文件中定义的标识符需要被工程中的其他文件引用时,使用EXPORT关键字。同时,GLOBAL可以声明一个全局标识符。此外,EXTERN的功能与IMPORT相似,当该文件中没有实际引用这个标识符时,EXTERN下编译器不会添加该标识符到符号表中。,10) 逻辑操作的第1054行出现了“:OR:,表示按位取或,还有以下伪操作符::AND:表示按位取与;:EOR:表示按位取异或;:NOT:表示取反。同时,还有:MOD:表示取模,:SHL:、:SHR:、:ROL:和:ROR:分别表示左移、右移、循环左移、循环右移,还可以使用+、-、*、/算符,其中“+出现在的第1100行。表示逻辑操作的有:LNOT:、:LAND:、:LOR:和:LEOR:,依次为逻辑取反、逻辑与、逻辑或、逻辑异或。,11) END汇编语言每个程序段均以END结尾。汇编语言程序是由AREA定义的一个个代码段组成的,每个代码段由汇编指令语句组成,完成某项特定的功能,最后以END结尾。不同的代码段之间可以通过引用标号的方式相互调用。工程ex5_1包含了汇编语言程序的根本特征,可以视为汇编语言程序的学习框架程序。在节中还将添加中断处理进一步完善该程序。,5.2 浮点数据处理浮点数即小数,使用ARM汇编语言表示和处理小数,需要借助于IEEE-754标准或者DSP定标的方法。DSP定标方法在定点DSP芯片进行浮点数据处理时经常使用,相关内容可参考?TMS320C5000系列DSP汇编语言程序设计?第六章,在这一章中,作者指出,“汇编语言是公认的硬件操作最好的语言,并且用它来编写算法对编程者的思维也是一个很好的启迪过程。事实上,由于汇编语言语法简单明了,用来实现算法时,没有现成的算法库来调用,因此,编程者必须亲自编写算法的每个函数和每个细节,从而要求编程者对算法非常熟悉才行。本节内容将介绍ARM920T下的数值定标和正余弦函数的计算。,5.2.1 计算根底 计算正弦和余弦函数的值,需要借助于泰勒级数展开式,如下:,例如,取x,那么,(1),(2),上两式为本节程序采用的算法。,5.2.2 数值定标汇编语言中的32位操作数只能为0或1组成的码字。所谓“码字,是指CPU只能把存储器的内容视为二进制数码符号(实际上是电平信号),而不是数字。人们习惯把二进制码字之间的运算关系称为二进制数(二进制补码)之间的运算,所以常常给人一种存储器存储的是数的假象。但是,在码和数之间确实有一种一一映射的关系,并且,在这个映射关系上可以将数的运算映射为码间的运算。同时,由于十六进制表示的整数和码字之间这种映射关系非常直观,以至于人们会忽略这种映射的存在。,例如,给定一个十六进制码字0x00000055,人们会不加思考地认为它等于十进制数85。这种相等是有条件的,即0x00000055码字的小数定标点位于第0位以后(或认为没有小数定标点),这个定标点是思想中添加的、用于码和数之间映射的一种关系。对于整数的处理,人们可以很直观地认为这个定标点不存在。对于小数处理,就不能无视这个定标点了。,定标的方法就是通过加定标的方法将小数转化为十六进制数(码)的方法,ARM是32位定点处理器,定标点可设为032。定标点确定后,32位的存储字存储的数据大小也就确定了。一个小数a的n定标值为取整(a2n),0n32。根据这种方法,小数的31定标值为0.45231=966367641.6d966367641d=0x39999999,即设置定标点为31后,十六进制值0x39999999不再是整数966367641,而是小数。定标有一种记号法,即Q(32n).n,定标点为31时,记作,有时简记为Q31,是最常用的一种定标方法。但是,Q31定标只能表示1, 1)区间的小数,如果表示更大范围内的小数,例如区间2, 2),那么需要采用定标。,小数定标后的值往往是小数的近似值,这说明计算机采用定标方法只能不精确地表示小数,例如,小数就不能精确定标。小数的定标值可参与加、减和乘等运算,由于定标值表示的数据范围有限,所以定标值间的运算不能有溢出,否那么计算结果错误。特别是乘法运算,乘法结果为64位,定标点位置移动到62位,必须取高32位(同时向左移一位)进行定标点的复原(为31位);加法和减法运算不改变定标点。,常用的做法为:在十进制数条件下进行小数的算法处理,找到所有参与运算的小数、中间结果和最终结果的绝对值最大值,按照这个最大值确定定标点位置。然后,将小数转换为定标值,编写汇编语言程序对定标值进行处理,得到定标值表示的最终结果。最后,用去定标的方法,即最终结果除去2n后得到真实的小数形式结果。在这个过程中,只有上一行的阴影局部是ARM汇编语言程序完成的。,计算的正弦和余弦值汇编语言程序,由于输入数据、中间结果和最终结果都不可能超过1,可以采用Q31定标方法。需要指出的是,上述介绍的是有符号的定标,即定标值的最高位31位为符号位,这种定标方法用得较多。关于无符号定标方法,由于与有符号定标方法相似,故本书不作介绍。下面把公式(1)和(2)中出现的常数按Q31定标方法计算的定标值列于表5-2中。,表5-2 公式(1)和(2)中常数的Q31定标值,小数,0.45,1/3!,1/5!,1/7!,定标值,0x3999 9999,0x1555 5555,0x111 1111,0x6 8068,小数,1,1/2!,1/4!,1/6!,定标值,0x7FFF FFFF,0x4000 0000,0x555 5555,0x2D 82D8,这里的定标点和小数点是完全不同的概念,请注意区分。,5.2.3 程序代码及结果分析 本小节的内容不是本书的重点,因此对本小节中的汇编程序不作深入分析,但是我们还是给出了完整的程序例如和源代码(注释清晰),供感兴趣的读者参考。 在工程ex5_1的根底上,新建工程ex5_2,修改文件,其代码如下所示:1 AREA LEDLIGHT, CODE, READONLY2 EXPORT _main ; LedFlash3 EXPORT _use_two_region_memory4,5 IMPORT Sin0p45 ; for Sincos0.456 GPCDAT_ADDR EQU 0x560000247 LED_ON EQU 0x00008 LED_OFF EQU 0x00E09 ENTRY10 ; LedFlash11 _main12 BL Sin0p45 ; for Sincos0.4513 ledflash14 LDR R0, =GPCDAT_ADDR15 MOV R1, #LED_ON,16 STR R1, R0 ; LED ON17 18 BL Delay19 20 MOV R1, #LED_OFF 21 STR R1, R0 ; LED OFF22 23 BL Delay24 25 B ledflash,26 Delay27 MOV R3, #0x0F000028 MOV R4, #0x0F000029 subcycle130 SUB R3, R3, #131 subcycle232 SUB R4, R4, #133 CMP R4, #034 BGE subcycle235 36 CMP R3, #037 BGE subcycle1,38 BX LR39 40 _use_two_region_memory ; no warning41 END 上述代码中后跟注释“; for Sincos0.45的语句为新添加的语句,即先进行求正余弦值的运算,然后再作使LED灯闪烁的处理。 新建汇编语言文件,并添加到工程ex5_2中,工程ex5_2的主界面如图5-7所示。,图5-7 工程ex5_2的工作界面,文件的完整代码如下:1 AREA SINCOS, CODE, READONLY2 EXPORT Sin0p453 Sin0p454 STMFD SP!, R0-R9,R145 6 ; calculate sin0.457 ; R0-R1 load address 8 ; R3-R8 load value9 ADR R0, x_q ; R0 is addr of x,10 LDR R4, R0 ; R4 = x11 12 SMULL R5, R6, R4, R413 MOV R7, R6, LSL #114 ADD R7, R7, R5, LSR #31; R7= x*x15 16 SMULL R5, R6, R4, R717 MOV R8, R6, LSL #118 ADD R8, R8, R5, LSR #31; R8= x*x*x 19 20 ADR R1, cof_3,21 LDR R3, R1 ; R3= cof322 23 SMULLR5, R6, R3, R824 MOV R2, R6, LSL #125 ADD R2, R2, R5, LSR #31; R2=x3/3!26 27 MOV R9, R428 SUB R9, R9, R2 ; R9= xx3/3!29 30 SMULL R5, R6, R7, R831 MOV R8, R6, LSL #1,32 ADD R8, R8, R5, LSR #31; R8=x533 34 ADR R1, cof_535 LDR R3, R1; R3= cof536 37 SMULL R5, R6, R3, R838 MOV R2, R6, LSL #139 ADD R2, R2, R5, LSR #31; R2=x5/5!40 41 ADD R9, R9, R2; R9= xx3/3!+x5/5!,42 43 SMULL R5, R6, R7, R844 MOV R2, R6, LSL #145 ADD R2, R2, R5, LSR #31; R2=x746 47 ADR R1, cof_748 LDR R3, R1 ; R3= cof749 50 SMULL R5, R6, R3, R251 MOV R2, R6, LSL #1,52ADD R2, R2, R5, LSR #31; R2=x7/7!53 54SUB R9, R9, R2 ; R9= xx3/3!+x5/5!x7/7! 55 56 LDR R1, = sin_x57 STR R9, R158 59 ; calculate cos0.4560 ADR R0, x_q; R0 is addr of x61 LDR R4, R0; R4 = x62,63 SMULL R5, R6, R4, R464 MOV R7, R6, LSL #165 ADD R7, R7, R5, LSR #31; R7= x*x66 67 SMULL R5, R6, R7, R768 MOV R8, R6, LSL #169 ADD R8, R8, R5, LSR #31; R8= x4 70 71 ADR R1, cof_272 LDR R3, R1; R3= cof273,74 SMULL R5, R6, R3, R775 MOV R2, R6, LSL #176 ADD R2, R2, R5, LSR #31; R2=x2/2!77 78 ADR R0, cof_179 LDR R9, R080 SUB R9, R9, R2; R9= 1x2/2!81 82 ADR R1, cof_483 LDR R3, R1; R3= cof484,85 SMULL R5, R6, R3, R886 MOV R2, R6, LSL #187 ADD R2, R2, R5, LSR #31; R2=x4/4!88 89 ADD R9, R9, R2; R9=1x2/2!+x4/4!90 91 SMULL R5, R6, R7, R892 MOV R2, R6, LSL #193 ADD R2, R2, R5, LSR #31; R2=x694,95 ADR R1, cof_696 LDR R3, R1; R3= cof697 98 SMULL R5, R6, R3, R299 MOV R2, R6, LSL #1100 ADD R2, R2, R5, LSR #31; R2=x6/6!101 102 SUB R9, R9, R2; R9= 1x2/2!+x4/4!-x6/6! 103 104 LDR R1, = cos_x105 STR R9, R1,106 107 ;BX LR; return 108 LDMFD SP!, R0-R9,PC; return109 110 x_q DCD 0x39999999; 0.45111 cof_1 DCD 0x7FFFFFFF ; 1112 cof_2 DCD 0x40000000 ; 1/2!113 cof_3 DCD 0x15555555 ; 1/3!114 cof_4 DCD 0x05555555 ; 1/4!115 cof_5 DCD 0x01111111 ; 1/5!116 cof_6 DCD 0x002D82D8 ; 1/6!,117 cof_7 DCD 0x00068068 ; 1/7!118 119 AREA SINCOSRES, DATA, READWRITE120 sin_xDCD 0; sin0.45121 cos_x DCD 0 ; cos0.45122 END编译连接下载工程ex5_2,然后调试工程,如图5-8所示。,图5-8 工程ex5_2的调试窗口,工程ex5_2的计算结果和保存在标号sin_x和cos_x处,即图5-8右侧Memory的0x30000000和0x30000004处,计算结果数值为0x37ACF357和0x7341D96B,去定标后的值(即转化为十进制数,再除以231后的值)为:计算值计算值,而真实值为:真实值真实值计算值和真实值的误差在10,7,数量级上,可见,计算结果是正确的。(数学角度上,还要考虑级数的截断误差!),5.3 系 统 初 始 化系统初始化是指上电复位后ARM芯片级程序首先要进行的处理,即配置工作时钟、看门狗电路、存储器空间、通用IO口、中断向量表及堆栈等,这些工作都可以借助MDK软件的启动
展开阅读全文