




已阅读5页,还剩110页未读, 继续免费阅读
版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领
文档简介
基于ARM的 嵌入式系统接口技术,广东省岭南职业技术学院 电子信息工程学院 主讲:陈卫东,第三章 嵌入式程序设计语言,基于ARM的嵌入式系统接口技术,回顾,1. 处理器内核和处理器核的概念。 2. ARM9微处理器的体系结构特点。 3. ARM9的存储组织结构。 4. ARM9存储相关的概念。 5. ARM9微处理器的寻址方式。 6. 系统启动程序的汇编代码。,基于ARM的嵌入式系统接口技术,学习目标与要求,1.了解ARM汇编器支持的伪操作和GNU ARM支持的伪操作。 2.了解ARM汇编程序的编程规则。 3.掌握嵌入式C语言的基本知识。 4.了解嵌入式C语言程序和汇编程序混合编程的方法。,3.1 工作场景导入,基于ARM的嵌入式系统接口技术,3.1.1 工作场景一,分析初始化程序 若要用程序控制ARM实验箱上的硬件工作,需要对实验箱进行初始化,初始化程序对实验箱都做了哪些设置?分析一种ARM实验箱的汇编启动代码。,基于ARM的嵌入式系统接口技术,引导问题,(1)ARM汇编和GNU ARM支持的伪操作如何使用? (2)嵌入式C语言编程与普通的C语言相比,有哪些特点? (3)如何在程序中实现汇编和C语言混合编程? (4)ARM汇编如何调用C语言代码?,基于ARM的嵌入式系统接口技术,3.1.2 工作场景二,ARM C语言程序 编写C语言程序,用扫描显示的方法,在六只数码管上显示出0,1,2,3,4,5。编写C语言程序,用扫描显示的方法,在六只数码管上显示出0,1,2,3,4,5。,基于ARM的嵌入式系统接口技术,引导问题,(1)嵌入式C语言编程与普通的C语言相比,有哪些特点? (2)如何在程序中实现汇编和C语言混合编程?,3.2 ARM汇编中的伪操作,基于ARM的嵌入式系统接口技术,3.2 ARM汇编中的伪操作,在ARM汇编语言程序中,有一些特殊的指令助记符,与指令系统的助记符不同,它们没有相对应的操作码,它们在源程序中的作用是为了完成汇编程序做各种准备工作的,通常称这些特殊的指令助记符为伪操作标识符(directive),它们所完成的操作称为伪操作。,基于ARM的嵌入式系统接口技术,3.2 ARM汇编中的伪操作,目前常见的ARM编译开发环境有两种。 一种是第一章介绍的ADS/SDT IDE集成开发环境(ARMASM),它由ARM公司开发,使用了CodeWarrior公司的编译器,绝大多数windows下的开发者都在使用这一环境,它完全按照ARM的规定开发。 另一种是集成了GNU开发工具的IDE集成开发环境(GNU ARM ASM),它由GNU的汇编器as、交叉编译器gcc、和链接器ld等组成,与ARMASM略有不同。 注:无论是哪一种开发环境,无论用的哪一种汇编器,其中的ARM指令是没有区别的,不同之处仅在于伪操作,类似于高级语言中的语法格式的不同规定。,基于ARM的嵌入式系统接口技术,AREA TEST1,CODE,READONLY ENTRY CODE32 START MOV R0,#1 MOV R1,#1 REPEAT ADD R2,R1,#1 MUL R3,R2,R1 ADD R0,R0,R3 ADD R1,R1,#1 CMP R1,#10 BLE REPEAT STOP B STOP END ,例:代码一,基于ARM的嵌入式系统接口技术,例:代码二,.section .text, “x“ .global _start _start: MOV R0,#1 MOV R1,#2 repeat: ADD R2,R1,#1 MUL R3,R2,R1 ADD R0,R0,R3 ADD R1,R1,#1 CMP R1,#10 BLE repeat stop: B stop .end ,基于ARM的嵌入式系统接口技术,比较上面完成同样功能的两段代码可以看到,其中ARM汇编的指令是相同的,另外还有一些不同的语句,而且这些语句一般对程序所完成的功能没有影响,这些语句的作用是为了完成汇编程序做各种准备工作的,即伪操作。之所以完成同样功能的程序代码的伪操作不同,是因为他们用的编译开发环境不同。第一段代码是ARM汇编集成开发环境所支持的伪操作,第二段代码是GNUARM汇编集成开发环境所支持的伪操作。 可见,不同的编译开发环境所使用的伪操作可能有所不同。,基于ARM的嵌入式系统接口技术,3.2.1 常用伪操作的分类,1. 符号定义伪操作 符号定义伪操作用于定义ARM汇编程序中的变量、对变量赋值及定义寄存器的别名等操作。常用的符号定义伪操作有如下4种。 (1)用于定义全局变量的GBLA、GBLL和GBLS。 (2)用于定义局部变量的LCLA、LCLL和LCLS。 (3)用于对变量赋值的SETA、SETL和SETS。 (4)为通用寄存器列表定义名称的RLIST。,基于ARM的嵌入式系统接口技术,3.2.1 常用伪操作的分类,2. 数据定义伪操作 数据定义伪操作用于为特定的数据分配存储单元,同时可完成已分配存储单元的初始化。常用的数据定义伪操作有如下9种。 (1)DCB用于分配一片连续的字节存储单元并用指定的数据初始化。 (2)DCW(DCWU)用于分配一片连续的半字存储单元并用指定的数据初始化。 (3)DCD(DCDU)用于分配一片连续的字存储单元并用指定的数据初始化。 (4)DCFD(DCFDU)用于为双精度的浮点数分配一片连续的字存储单元并用指定的数据初始化。 (5)DCFS(DCFSU)用于为单精度的浮点数分配一片连续的字存储单元并用指定的数据初始化。 (6)DCQ(DCQU)用于分配一片以8字节为单位的连续的存储单元并用指定的数据初始化。 (7)SPACE用于分配一片连续的存储单元。 (8)MAP用于定义一个结构化的内存表首地址。 (9)FIELD用于定义一个结构化的内存表的数据域。,基于ARM的嵌入式系统接口技术,3.2.1 常用伪操作的分类,3. 汇编代码控制伪操作 汇编代码控制伪操作用于控制汇编程序的执行流程。常用的汇编控制伪操作包括如下4种。 (1)IF、ELSE、ENDIF这三个符号连用,进行条件汇编。 (2)WHILE、WEND这二个符号连用,进行重复汇编。 (3)MACRO、MEND这二个符号连用,定义一个宏定义。 (4)MEXIT用来在宏结束前退出宏定义。,基于ARM的嵌入式系统接口技术,3.2.1 常用伪操作的分类,4. 信息报告伪操作 信息报告伪操作用于程序汇编指示,主要是在程序调试阶段使用。常用的信息报告伪操作包括如下4种。 (1)错误信息报告伪操作ASSERT。 (2)诊断信息报告伪操作INFO。 (3)列表选项设置伪操作OPT。 (4)插入文件标题伪操作TTL与SUBT。,基于ARM的嵌入式系统接口技术,3.2.1 常用伪操作的分类,5. 指令集类型标识伪操作 指令集类型标识伪操作用来告诉编译器所处理的是32位的ARM指令还是16位的Thumb指令,常用的指令集类型标识伪操作包括有两种。 (1)ARM或CODE32指示编译器将要处理的是32位的ARM指令。 (2)THUMB或CODE16指示编译器将要处理的是16位的Thumb指令。,基于ARM的嵌入式系统接口技术,3.2.1 常用伪操作的分类,6. 其他伪操作 ARM汇编中还有一些其他的伪操作,在汇编程序中经常会被使用,包括以下几种。 (1)AREA用于定义一个代码段或数据段。 (2)ALIGN用于使程序当前位置满足一定的对齐方式。 (3)ENTRY用于指定程序入口点。 (4)END用于指示源程序结束。 (5)EQU用于定义字符名称。 (6)EXPORT(或GLOBAL)用于声明符号可以被其他文件引用。 (7)EXPORTAS用于向目标文件引入符号。 (8)IMPORT用于通知编译器当前符号不在本文件中。 (9)EXTERN用于通知编译器要使用的标号在其他的源文件中定义,但要在当前源文件中引用。 (10)GET(或INCLUDE)用于将一个文件包含到当前源文件。 (11)INCBIN用于将一个文件包含到当前源文件。,基于ARM的嵌入式系统接口技术,3.2.2 常用伪操作的用法,1. 定义常量或标号名称的伪操作 定义常量或标号名称的伪操作,类似C语言中的宏定义#define。例如在第二章2.5.4节例题二中的语句,用到了EQU伪操作。 ARM:EQU、SETA 语法格式:标号名称 EQU/SETA expr(,type) expr可以是32位整形常量、基于寄存器的地址值、程序相对的地址、绝对地址。 例:USERMODE EQU 0x10 GNU:.equ 或 .set 语法格式:.equ/.set 标号名称, value同expr,表示数字常量或程序中的标号。 例:.equ USERMODE,0x10将常量0x10定义成符号USERMODE,NumCount EQU 0x40003000 ;定义变量NumCount ,基于ARM的嵌入式系统接口技术,3.2.2 常用伪操作的用法,2. 段属性定义的伪操作 段属性定义,用于定义一个代码段或数据段,或开始一个新的代码段或数据段。例如在3.2节的两段代码中的语句。 段是不可分的已命名独立代码或数据块,由链接器处理,在汇编程序中常常都要用到段属性定义。 ARM:AREA 语法格式:AREA 段名(,属性) (,属性) 例如:AREA M1TOM2,DATA,READWRITE ;定义数据段,AREA TEST1,CODE,READONLY ;第一段代码中,ARM汇编定义段属性,.section .text, “x“ 第二段代码中,GNU汇编定义段属性,基于ARM的嵌入式系统接口技术,3.2.2 常用伪操作的用法,GNU:.section 语法格式:.section .段名 ,”标志” 标志:各段有缺省标志,ELF格式允许的段标志如表3-1所示: 表3-1 ELF格式允许的段标志 GNU汇编中,有些段名是汇编系统预定义的,如:.text, 代码段;.data, 初始化数据段;.bss, 未初始化数据段等,每个段以段名开始,以下一个段名或者文件结尾为结束。 也可以不使用系统预定义的段名,而通过上面的伪操作自定义一个段,例如: .section .mysection 自定义数据段,段名为”.mysection”,基于ARM的嵌入式系统接口技术,3.2.2 常用伪操作的用法,3. 声明程序的入口点伪操作 声明程序的入口点伪操作,用于指定程序的入口点,例如在3.2节的两段代码中的语句。 ARM:ENTRY 语法格式:ENTRY GNU:_start 语法格式:_start,ENTRY ;第一段代码中,ARM汇编入口点声明,_start: 第二段代码中,GNU汇编入口点声明,基于ARM的嵌入式系统接口技术,3.2.2 常用伪操作的用法,4. 源程序结尾标识伪操作 源程序结尾标识,用于通知汇编程序它已到达源文件的末尾,例如在3.2节的两段代码中的语句。 ARM:END 语法格式:END GNU:.end 语法格式:.end 常常省略不用,END ;第一段代码中,ARM汇编结尾标识,.end 第二段代码中,GNU汇编结尾标识,基于ARM的嵌入式系统接口技术,3.2.2 常用伪操作的用法,5. 指令集类型标识伪操作 指令集类型标识伪操作,用来告诉编译器所处理的是32位的ARM指令还是16位的Thumb指令,例如在3.2节的第一段代码中的语句。CODE32 ARM:ARM、CODE32、THUMB、CODE16 语法格式:ARM(CODE32/THUMB/CODE16) 表示将要处理的是32位的ARM指令,其他三个伪操作用法相同。 GNU:.arm、.thumb、.code 语法格式:.arm(.thumb) 或者使用.code:.code16/.code32 设定指令宽度,16表示Thumb指令,32表示ARM指令。,基于ARM的嵌入式系统接口技术,3.2.2 常用伪操作的用法,6. 对齐方式设置伪操作 对齐方式设置,通过添加填充字节的方式,使当前位置满足一定的对齐方式。 ARM:ALIGN 语法格式:ALIGN 对齐表达式,偏移量,填充的字节 GNU:.align 或 .balign 语法格式:.align/.balign 对齐表达式,填充的数据,aa DCB 0x58 ;定义一个字节存储空间,字对齐方式被破坏 ALIGN ;声明字对齐,基于ARM的嵌入式系统接口技术,3.2.2 常用伪操作的用法,7. 声明全局标号伪操作 在ARM和C语言混合编程时,经常要用到全局标号声明,例如下面的代码段。 声明全局标号,用于在程序中声明一个全局的标号,该标号可在其他的文件中引用,标号在程序中区分大小写。类似C语言中的全局变量。 ARM:EXPORT或GLOBAL GNU:.global 或 .globl 例如:声明全局变量_start,EXPORT FUNCNAME FUNCNAME ,.global _start,基于ARM的嵌入式系统接口技术,3.2.2 常用伪操作的用法,8. 声明外部标号伪操作 声明外部标号伪操作,用于通知编译器要使用的标号在其他的源文件中定义,但要在当前源文件中引用,标号在程序中区分大小写。 ARM:IMPORT或EXTERN 语法格式:IMPORT/EXTERN 符号 WEAK,attr GNU:.extern 语法格式:.extern 符号 符号为要声明的外部变量名称,基于ARM的嵌入式系统接口技术,3.2.2 常用伪操作的用法,9. 声明数据缓冲池伪操作 ARM:LTORG 语法格式:LTORG GNU:.ltorg 语法格式:.ltorg, LTORG src DCD 1,2,3,4,5,6,7,8,1,2,3,4,5,6,7,8,1,2,3,4 ;字数据 dst DCD 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,LDR R0,=src .ltorg 定义数据缓冲池,存放在src开始的地址处 src: .LONG 1,2,3,4,5,6,7,8,1,2,3,4,5,6,7,8,1,2,3,4 dst: .LONG 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,基于ARM的嵌入式系统接口技术,3.2.2 常用伪操作的用法,10. 数据定义伪操作 数据定义伪操作,用于特定的数据分配存储单元,也可以完成已分配存储单元的初始化。 ARM:DCB(分配字节存储单元)、DCW(DCWU分配半字存储单元)、DCD(DCDU分配字存储单元)、DCFS(单精度浮点数)、DCFD(双精度浮点数)、DCQ(双字) 语法格式:标号 DCB(DCW/DCWU/DCD/DCDU) expr,expr GNU:.byte,.hword,.word,.long,.quad,.float,.string/.asciz/.ascii 语法格式:.byte(.hword/.word/.quad/) , ,基于ARM的嵌入式系统接口技术,3.2.2 常用伪操作的用法,11. 固定填充字节内存单元伪操作 固定填充字节内存单元伪操作,用于分配一片连续的存储单元。 ARM:SPACE,用于分配一片连续的存储区域并初始化为0。 语法格式:标号 SPACE 分配字节数 ;标号可选 例如:DataS SPACE 100 ;分配100字节的连续存储单元并初始化为0 GNU:.space 或 .skip 语法格式:.space/.skip 字节数 ,填充字节分配number_of_bytes字节的数据空间,并填充其值为fill_byte,若未指定该值,缺省填充0。 例如:.space 100,0x55 分配一段长度为100个字节的内存单元,并用0x55初始化,基于ARM的嵌入式系统接口技术,3.2.2 常用伪操作的用法,12. IF条件编译伪操作 用于条件编译的汇编代码控制伪操作使用方法类似于C语言中的if语句。 ARM:IF ELSE ENDIF 语法格式:IF 逻辑表达式 ELSE ENDIF GNU: .if .else .endif 语法格式:.if .else .endif,基于ARM的嵌入式系统接口技术,3.2.2 常用伪操作的用法,GNU:.macro、.endm(宏结束标志)、.exitm(宏跳出) 语法格式:.macro 宏名 , , .endm 参数可以使用“字符”直接使用,如:MOV R0,arg ;arg为宏参数,基于ARM的嵌入式系统接口技术,3.2.2 常用伪操作的用法,14. 文件包含伪操作 文件包含伪操作,将一个源文件包含到当前源文件中,并将被包含的文件在其当前位置进行汇编处理;也有一类文件包含伪操作,被包含文件不进行汇编处理。文件包含类似C中的#include。 ARM:INCLUDE 语法格式:INCLUDE 文件名;文件名不用双引号等符号 GNU:.include 语法格式:.include 文件名,3.3 汇编语言程序设计,基于ARM的嵌入式系统接口技术,ARM汇编程序设计,嵌入式系统开发的编程语言有汇编语言、C/C+语言及C与汇编混合编程、JAVA语言。ARM源程序文件(简称为源文件)可以由任意一种文本编辑器来编写程序代码,它一般为文本格式。,基于ARM的嵌入式系统接口技术,完整的ARM汇编语言源文件一般由一个或几个段组成,每个段均由AREA(或者GNU ARM下的.section)伪操作声明,并且以END(或者GNUARM下的.end)做为汇编源文件的结束。段可以分为多种,如代码段、数据段等,每个段又有不同的属性,如代码段的属性一般设为READONLY,数据段的属性一般设为READWRITE。 如: ARM汇编环境: AREA TEST,CODE,READONLY END GNU ARM环境: .section .text .end,3.3.1 汇编语言程序的编程规则,基于ARM的嵌入式系统接口技术,段的内部 ,ARM汇编程序中每一行的通用格式为: 标号 指令|指示符|伪指令 ;注解。 在ARM汇编语言源程序中,除了标号和注释外,指令、伪指令和指示符都必须有前导空格,而不能顶格书写。如果每一行的代码太长,可以使用字符“”将其分行书写,并允许有空行。指令助记符、指示符和寄存器名既可以用大写字母,也可以用小写字母,但不能混用。,3.3.1 汇编语言程序的编程规则,基于ARM的嵌入式系统接口技术,标签是一个符号,可以代表指令的地址、变量、数据的地址和常量。一般以字母开头,由字母、数字、下划线组成。 标号代表一个地址,段内标号的地址值在汇编时确定,段外标号的地址值在链接时确定。在程序段中,标号代表其所在位置与段首地址的偏移量。 在ARM汇编编译器中,所有的标签必须在一行的开头顶格写,前面不能留空格,后面不能加“:”; 在GNU ARM汇编编译器中,标签的后面需要加上“:”,对前面是否留空格也没有严格的规定。 注释从“;”or“”开始,到该行结束为止。在ARM汇编编译器中,注释从“;”开始;而在GNU ARM汇编编译器中,注释从“”开始。,3.3.1 汇编语言程序的编程规则,基于ARM的嵌入式系统接口技术,1. 预定义变量 ARM汇编器对ARM的寄存器进行了预定义,所有的寄存器和协处理器名都是大小写敏感的。预定义的寄存器如下: R0R15和r0r15; a1a4(参数、结果或临时寄存器,与r0r3同义); v1v8(变量寄存器,与r4r11同义); sb和SB(静态基址寄存器,与r9同义); sl和SL(堆栈限制寄存器,与r10同义); fp和FP(帧指针,与r11同义); ip和IP(过程调用中间临时寄存器,与r12同义);,3.3.2 汇编语言程序的变量,基于ARM的嵌入式系统接口技术,1. 预定义变量 sp和SP(堆栈指针,与r13同义); lr和LR(链接寄存器,与r14同义); pc和PC(程序计数器,与r15同义); cpsr和CPSR(程序状态寄存器); spsr和SPSR(程序状态寄存器); f0f7和F0F7(FPA寄存器); s0s31和S0S31(VFP单精度寄存器); d0d15和D0D15(VFP双精度寄存器); p0p15(协处理器015); c0c15(协处理器寄存器015)。,3.3.2 汇编语言程序的变量,基于ARM的嵌入式系统接口技术,2. 内置变量 ARM汇编器所定义的内置变量如表4-1所示。值得注意的是内置变量的设置不能用SETA、SETL或SETS等指示符来设置,只能用于表达式或条件语句。例如: IF ARCHITECTURE = “4T”,3.3.2 汇编语言程序的变量,基于ARM的嵌入式系统接口技术,3.3.2 汇编语言程序的变量,内置变量,基于ARM的嵌入式系统接口技术,3.3.2 汇编语言程序的变量,内置变量(续),基于ARM的嵌入式系统接口技术,3. 常量 十进制,如:123,1,0 十六进制,如:0x123,0xab,0x7b n_XXX,n表示n进制,从29:XXX是具体的数 字符常量:由单引号及中间的字符组成,包括C语言中的转义字符,如a,n 字符串:由一对双引号及双引号之间字符串组成,并包含C中的转义字符。如“abcdef0xarn” 逻辑常量为TRUE和FALSE。,3.3.2 汇编语言程序的变量,基于ARM的嵌入式系统接口技术,4. 汇编程序的变量代换 这里所说的变量,是相对于汇编程序的“变量”,是用于汇编程序进行处理的,但一旦编译到程序中,则不会改变,成为常量。 字符串变量的前面有一个“$”字符,在汇编时编译器将用该字符串变量的内容代替该串变量,类似于取变量的值。 数字变量前面有一个代换操作符“$”,编译器会将该数字变量的值转换为十六进制的字符串,并用该十六进制的字符串代换“$”后的数字变量。 “$”看作一个“$”,类似于转义字符的用法,3.3.2 汇编语言程序的变量,基于ARM的嵌入式系统接口技术,3.3.3 子程序的实现及调用,1. 汇编语言中子程序的定义 上面的代码相当于C语言中的代码: int asse_add(int x, int y) return (x+y); 在汇编程序中定义子程序比较简单,不需要考虑类型和参数,只要用一个标签表示程序名称,在子程序最后用一条语句(MOV pc, lr)返回,把保存在lr寄存器中的PC指针值恢复,返回调用的程序就可以了。,asse_add ;ARM汇编中不加“:”,GNU ARM汇编中用“:” ADD r0, r0, r1 ;r0 = r0 + r1 MOV pc, lr ;函数返回,基于ARM的嵌入式系统接口技术,3.3.3 子程序的实现及调用,2. 汇编语言中子程序的调用 使用BL跳转指令实现子程序的调用。调用时不需要考虑参数的问题,只要用带返回的跳转指令直接跳转即可。,BL asse_add ;用BL指令调用子程序,基于ARM的嵌入式系统接口技术,3.3.3 子程序的实现及调用,3. 子程序调用的实现过程 程序执行到BL语句时,PC指向下一个要执行的语句,此时PC(R15)中的值为下一条语句(ADD R1,R2,#2)指令所在的地址。由于BL是一个分支指令,这个指令将改变PC的值使之指向子程序所在的地址,同时还自动将断点地址(PC中的值,此例中即ADD R1,R2,#2指令所在的地址)保存在LR(R14)寄存器中,即保存现场,从而调用子程序,保存现场的工作是自动完成的;, BL func ;跳转到子程序 ADD R1,R2,#2 ;子程序调用完返回后执行的语句,返回地址 func ;子程序定义,ARM汇编中不加“:”,GNU汇编中用“:” ;子程序代码 MOV R15,R14 ;复制返回地址到PC,实现子程序的返回 (MOV pc,lr),基于ARM的嵌入式系统接口技术,3.3.3 子程序的实现及调用,3. 子程序调用的实现过程 子程序的功能完成后,需要用一个MOV指令将LR(14)中的值复制到PC(R15)中,即恢复现场,从而实现了子程序调用的返回功能,恢复现场即恢复PC的值不是自动完成的,必须使用MOV pc,lr这条语句。, BL func ;跳转到子程序 ADD R1,R2,#2 ;子程序调用完返回后执行的语句,返回地址 func ;子程序定义,ARM汇编中不加“:”,GNU汇编中用“:” ;子程序代码 MOV R15,R14 ;复制返回地址到PC,实现子程序的返回 (MOV pc,lr),3.4 嵌入式C语言程序设计,基于ARM的嵌入式系统接口技术,3.4.1 嵌入式C语言基础,例题: 已知存储器地址单元0x10000000可以存储8位二进制数(bit7bit0)即一个字节,假设其中高4位(bit7bit4)分别可以控制四个发光二极管的一个(发光二极管即LED显示器,原理参见11.2.2“单个LED显示器件”,此处可以不考虑其原理,只是简单假设某位为0时,LED发光,为1时,LED熄灭),下面这段代码实现了使四个发光二极管同时由亮到灭再由灭到亮的循环。,基于ARM的嵌入式系统接口技术,上面的例子是一段简单的C语言程序,和我们通常写的C语言程序相比,虽然基本的语法都是一样的,但在嵌入式C语言程序设计中,经常会使用到如例子中的预处理指令、对地址进行操作的指针等等。,#include “def.h“ #define rled_display (*(U8 *)0x10000000) void main(void) int i; for(;) rled_display = 0xFF; /*(unsigned char *)0x10000000)=0xFF for(i=100000;i!=0;i-); /利用循环延时,延时可使LED反映出亮灭 rled_display = 0x0F; /LED亮 for(i=100000;i!=0;i-); ,基于ARM的嵌入式系统接口技术,3.4.1.1 预处理指令,1. 文件包含 文件包含的作用是将另一源文件的全部内容包含到本文件中,C语言中头文件的后缀是.h,如例题中的语句。 格式: #include /用于包含标准头文件 #include “头文件名.h” /用于自定义头文件,先在当前目录查找再查找其他目录 包含文件包括两种:标准头文件和自定义头文件;使用形式有上面的两种,两者的区别是搜索路径不一样。,基于ARM的嵌入式系统接口技术,3.4.1.1 预处理指令,文件名外用尖括号括起来时为标准头文件。标准头文件就是按dos系统的环境变量所指定的目录顺序搜索头文件,也就是我们通常说的到系统指定的目录去搜索头文件,即按标准方式检索。例如:#include 。 文件名外用双引号括起来时为用户自定义头文件。搜索自定义头文件时,首先在当前目录(通常为源文件所在目录)中查找,如果没找到,再按环境变量所指定的目录顺序搜索(即后按标准方式检索)。例如:#include “2410addr.h“。,基于ARM的嵌入式系统接口技术,3.4.1.1 预处理指令,2. 宏定义 用一个指定的标识符来代表一个字符串,如例题中的语句。 格式: #define 标识符 字符串 嵌入式系统开发中常常使用宏定义把存储单元定义为变量。 如: / INTERRUPT #define rSRCPND (*(volatile unsigned *)0x4a000000) /源未决寄存器 #define rINTMOD (*(volatile unsigned *)0x4a000004) /中断模式寄存器 #define rINTMSK (*(volatile unsigned *)0x4a000008) /中断屏蔽寄存器,基于ARM的嵌入式系统接口技术,3.4.1.1 预处理指令,1) 在中断处理时需要用到这些寄存器,如果编程的时候直接使用地址进行赋值等操作,即不好记忆又容易出错,如果换一种硬件还不容易修改,利用宏定义,如第一个中断源末决寄存器地址是0x4a000000,取一个相关的名字rSRCPND(r表示是寄存器),则以后在程序中就可以使用这个名字进行赋值等操作,如同使用一个普通的变量一样。如本节例题中的语句。,#define rled_display (*(U8 *)0x10000000) rled_display = 0xFF; rled_display = 0x0F; ,基于ARM的嵌入式系统接口技术,3.4.1.1 预处理指令,2) unsigned意思是无符号整数,即32位的寄存器(CPU以字节为单位编址,而C语言指针以指向的数据类型长度作自增和自减)。也有些寄存器是存放8位的字节数据的,则定义的时候使用unsigned char;如实时时钟RTC的存放时间的寄存器: #define rBCDMIN (*(volatile unsigned char *)0x57000074) /分钟寄存器 例题中的语句定义的存储器地址,因为只用于存储一个字节,因此定义的时候也使用U8 (unsigned char)。,基于ARM的嵌入式系统接口技术,3.4.1.1 预处理指令,3) unsigned *或unsigned char *表示后面的十六进制数(如:0x4a000000或0x10000000)的数据类型是一个指针,指针即地址,所存放的内容是32位的字数据或8位的字节数据。 4) (*(volatile unsigned *)0x4a000000)或(*(U8 *)0x10000000)前面的*表示这个地址里的内容,可以取这个地址里的内容或给这个地址里赋值。 5) 修饰符volatile将在后面介绍。 6) 还有一些常量的定义,如def.h中用到的#define TRUE 1,把1用TRUE表示,使程序读起来更加直观。,基于ARM的嵌入式系统接口技术,3.4.1.1 预处理指令,3. 条件编译 条件编译是先测试条件是否成立,如测试是否定义过某标识符,然后根据测试结果决定如何处理。 例如,在上面的def.h文件中用到了下面这样的结构。,#ifndef _DEF_H_ #define _DEF_H_ #endif /*_DEF_H_*/,基于ARM的嵌入式系统接口技术,3.4.1.1 预处理指令,3. 条件编译 条件编译的格式如下所示。 #ifndef 标识符 程序段1 #else 程序段2 #endif 在嵌入式系统软件开发中,经常会包含多个头文件,而这些头文件中可能又还有包含的头文件,这样可能会造成重复定义。使用条件编译,可以避免这种错误的发生。,基于ARM的嵌入式系统接口技术,3.4.1.2 关键字const和关键字volatile,1. 关键字const const意味着“只读”, 可以称其为“不能改变的变量”。const常量是以变量的形式来定义的一个量,并且通过使用关键字const,来表明这个变量的值不能被改变。如:const int x = 1。 2. 关键字volatile volatile的作用是避免编译器优化。当编译器察觉到在代码中没有修改变量的值,就有可能在访问该变量时提供上次访问的缓存值。这样做可能会产生问题,如硬件寄存器中内容的改变,可能不是程序中改变的,因而每次访问其中的值都可能不一致。,基于ARM的嵌入式系统接口技术,3.4.1.3 数据指针,在嵌入式系统的实际调试中,多借助C语言指针所具有的对绝对地址单元内容的读写能力,用指针直接操作内存。例如: unsigned char *p = (unsigned char *)0xF000FF00; *p = “11“; 以上程序的意义为在绝对地址0xF0000FF00中写入8位字节数据11。这是在C语言中常用的指针的形式,把这两条语句合并成一条语句就是: *(unsigned char *)0xF000FF00) = “11“;,基于ARM的嵌入式系统接口技术,3.4.1.3 数据指针,上面这种形式的赋值语句在嵌入式系统程序设计中经常使用。也可以使用前面介绍的宏定义的方法,把物理地址定义为一个名字。 #define rSOURCE (*(volatile unsigned char *)0xF000FF00) 可以象C语言的变量一样使用rSOURCE,更加方便,它代表一个物理地址里面的内容。,基于ARM的嵌入式系统接口技术,3.4.1.4 位运算,在嵌入式系统开发中,经常会需要直接对底层硬件进行操作,因此需要用到位操作运算符。 & :与操作 | :或操作 :异或操作 :取反操作 :右移操作 :左移操作 例如:,a |= 0x4 / 0x4即二进制0100,把a的第2位设置为1(最后位为0位) b &= 0x4 /0x4即1011,把b的第2位设置为0 c &= (1 = 2 /右移一位相当于除以2,左移一位相当于乘2。此句把 e 除以4,基于ARM的嵌入式系统接口技术,3.4.1.4 位运算,如果要对一个字数据(或者半字、字节数据)中的某些位进行操作,常常使用掩码(Mask)来表示这些位在数据中的位置。掩码可以简单的认为就是把要操作的相应的位置1,其他位置0,如掩码0x0000ff00表示对一个32位字数据的815位(bit8到bit15是1)进行操作,例如: (1) 取出815位 或者用如下的语句也可以达到同样的效果。,unsigned int a, b, mask = 0x0000ff00; a = 0x12345678; b = (a / 0x00000056,b = (a 8) ,基于ARM的嵌入式系统接口技术,3.4.1.4 位运算,(2) 将815位清 (3) 将815位置 (4) 查询某位的状态(是否为1或为0),unsigned int a, b, mask = 0x0000ff00; a = 0x12345678; b = a / 0x12340078,unsigned int a, b, mask = 0x0000ff00; a = 0x12345678; b = a | mask; / 0x1234ff78,while(!(rUTRSTAT0 /若rUTRSTAT0位0为0则!(rUTRSTAT0 & 0x1)为真,基于ARM的嵌入式系统接口技术,3.4.1.4 位运算,掩码的方法是一种具有极高可移植性的方法,可以使用#define 和位掩码(bit masks)提高程序的移植性,例如:,#define BIT2 (0x1 2) static int a; void Set_bit2(void) /声明函数,功能是设置位2 a |= BIT2; void Clear_bit2(void) /声明函数,功能是清除位2 a ,基于ARM的嵌入式系统接口技术,3.4.2 嵌入式C语言编程,用存储器地址0x10000000的高四位控制跑马灯 ,在下面的控制程序中,假设跑马灯1(最左边一个发光二极管)由位4控制,跑马灯2(左边第二个发光二极管)由位5控制,依次类推。 例题一:使跑马灯从左开始,依次亮,灭(全灭1亮全灭2亮全灭3亮),void main(void) int i,j; while(1) for(j=4;j8;j+) *(unsigned char *)0x10000000)=0xFF;/放在循环内,每次亮过后全灭 for(i=100000;i!=0;i-); /延时程序,自己调节延时时间 *(unsigned char *)0x10000000)=(0x1j); /位j为0灯亮 for(i=100000;i!=0;i-); ,基于ARM的嵌入式系统接口技术,3.4.2 嵌入式C语言编程,例题二:使跑马灯从左开始,一个亮,两个亮,三个亮 最后全灭(1亮12亮123亮),void main(void) int i,j; while(1) *(unsigned char *)0x10000000)=0xFF; /全灭,在循环外 for(i=1000000;i!=0;i-); for(j=1;j5;j+) *(unsigned char *)0x10000000)=(0x0Fj); /43+j为0 for(i=1000000;i!=0;i-); ,基于ARM的嵌入式系统接口技术,3.4.2 嵌入式C语言编程,例题三:数码管显示程序,#define U8 unsigned char /没有包含头文件,因此直接使用宏定义 unsigned char seg7table16 = /* 0 1 2 3 4 5 6 7*/ 0xc0, 0xf9, 0xa4, 0xb0, 0x99, 0x92, 0x82, 0xf8, /* 8 9 A B C D E F*/ 0x80, 0x90, 0x88, 0x83, 0xc6, 0xa1, 0x86, 0x8e, ;/定义显示字形的数组,某位为0时点亮,下标对应要显示的字形,方便查表 void Delay(int time); /延时函数 void Test_Seg7(void) int i; *(U8*) 0x10000006) = 0x00; /位码置全0,两只数码管同时选中,同时亮 while(1) for(i=0;i=0x0;i-) /数码管从F到0依次将字符显示出来 *(U8*) 0x10000004) = seg7tablei; /查表并输出数据 Delay (100000); ,3.5 C语言和汇编语言混合编程,基于ARM的嵌入式系统接口技术,3.5 C语言和汇编语言混合编程,通过如下两段汇编程序代码,让我们认识一下C语言和汇编语言混合编程的方法。 汇编程序代码如下。,IMPORT main ;声明C程序main,是在外部定义的 EXPORT asse_add ;声明可被外部程序引用 AREA init, CODE, READONLY ; 定义段 ENTRY ; 程序入口地址 start MOV sp, #0x33000000 ;建立栈指针(r13) BL main ;调用C程序的函数,要用BL(不能用B)调用 stop B stop asse_add ;此函数可被外部程序引用 ADD r0, r0, r1 ;r0 = r0 + r1 MOV pc, lr ;函数返回 END,基于ARM的嵌入式系统接口技术,3.5 C语言和汇编语言混合编程,C语言程序代码如下。,extern int asse_add(int x, int y); /声明外部定义的函数 int embed_add(int x, int y); /函数声明 void main() int x, y; x = asse_add(10, 20); /调用汇编函数asse_add y = embed_add(10, 20); /调用函数embed_add int embed_add(int x, int y) int tmp; _asm /内嵌了汇编代码 add tmp, x, y ; return tmp; ,基于ARM的嵌入式系统接口技术,1. ARM编译器(如ADS IDE)中使用的格式 _asm /使用的是两个下划线 指令; 指令 /注释or /*注释*/,不能用分号注释 指令 ; 2. GNU ARM编译器中使用的格式 _asm_(“指令 指令”);,3.5.1 在C语言程序中内嵌汇编指令,基于ARM的嵌入式系统接口技术,3.5.1 在C语言程序中内嵌汇编指令,例如:在3.5节例题中用C语言内嵌汇编语言实现和3.3.3节中的asse_add 相同的功能:,int embed_add(int x, int y) int tmp; _asm add tmp, x, y ; return tmp; ,基于ARM的嵌入式系统接口技术,3.5.2 在C语言程序中调用汇编程序,1. C语言中函数声明 在C语言程序中,把被调用的汇编语言的函数声明为extern,如例题中的语句。 extern int asse_add(int x, int y); 当调用函数与被调用函数位于不同文件时,在C语言程序中把被调函数先声明为extern,表示此函数在其他源文件中定义,函数asse_add是在汇编语言程序中定义的。,基于ARM的嵌入式系统接口技术,3.5.2 在C语言程序中调用汇编程序,2. 汇编语言程序中函数声明 在汇编语言程序中,把被调用的函数声明为EXPORT,如例题中的语句。 EXPORT asse_add 如果被调用的函数是在ARM汇编中定义的,则需要在ARM汇编程序中使用伪操作如EXPORT声明此函数为全局符号,可被外部程序引用。 3. 调用函数 调用函数,如例题中的语句。 x = asse_add(10, 20); /在C程序中直接调用,参数遵循APCS,基于ARM的嵌入式系统接口技术,3.5.2 在C语言程序中调用汇编程序,为了满足ARM汇编、C与C+之间的互相调用,必须保证编写的代码遵循APCS(ARM过程调用标准)。 APCS规定了子程序调用的基本规则,这些规则包括子程序调用过程中寄存器、数据栈的使用规则以及参数的传递规则。 注意:如果函数有4个参数,则将分别用r0 、r1、r2和r3来传递,如果参数多于4个,则多余的参数将被压入堆栈。,基于ARM的嵌入式系统接口技术,3.5.2 在C语言程序中调用汇编程序,再看一个如何在C程序中调用汇编语言子程序的例子,该段代码实现了将一个字符串复制到另一个字符串。,#include extern void strcopy(char *d, const char *s); /声明引用的函数在其他源文件中定义 int main() const char *srcstr = “First string - source“; char dststr = “Second string - destination“; printf(“Before copying:n“); pri
温馨提示
- 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
- 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
- 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
- 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
- 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
- 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
- 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。
最新文档
- 2025年中国平面磨床行业发展潜力分析及投资方向研究报告
- 洗衣箩行业深度研究分析报告(2024-2030版)
- 中国航行数据记录仪市场竞争格局及投资战略规划报告
- 压缩空气系统风险评估报告
- 2025年中国木架太阳伞行业市场发展前景及发展趋势与投资战略研究报告
- 2025年中国化学建材行业市场发展前景及发展趋势与投资战略研究报告
- 铁路电子票教学课件
- 2025年中国打车软件移动应用市场运营趋势分析及投资潜力研究报告
- 中国扇型卡具项目投资可行性研究报告
- 中国火锅连锁行业发展趋势预测及投资战略咨询报告
- Unit 1 Animal Friends Reading Plus教学设计-2024-2025学年人教版英语七年级下册
- 腹膜透析患者随访的管理
- 职业技术学院《园艺产品及农资营销》课程标准
- 金氏五行升降中医方集
- 上海市黄浦区2024-2025学年八年级上学期期末物理试题(原卷版+解析版)
- 2、2024广西专业技术人员继续教育公需科目参考答案(97分)
- 结节性多动脉炎的早期诊断方法-深度研究
- 《水利工程建设项目法人工作手册2023版》知识培训
- 超星尔雅学习通《形势与政策》2025春章节测试附答案
- 广东省广州市越秀区2025年中考一模历史模拟试题(含答案)
- 有效咳嗽训练操作流程
评论
0/150
提交评论