ARM编程实例
ARM汇编语言程序设计实例解析-阶乘操作

ARM汇编语言程程序设计精讲
阶乘操作实例解析
求一个数的阶乘(64位结果)
用ARM汇编语言设计程序实现求20!(即20的阶乘),并将其64位结果放在[R9:R8]中。
(R9中存放高32位)
解:程序设计思路:64位结果的乘法指令通过两个32位的寄存器相乘,可以得到64位的结果,在每次循环相乘中,我们可以将存放64位结果两个32位寄存器分别与递增量相乘,最后将得到的高32 位结果相加。
程序设计流程如图7-1所示:
程序设计流程图
程序代码如下:
在ARM集成开发环境下编程ADS:
;
声明代码段Fctrl
AREA
Fctrl,CODE,READONL Y
ENTRY ; 标识程序入口
CODE32 ; 声明32 位ARM 指令START
MOV R8 , #20 ;低位初始化
MOV R9 , #0 ;高位初始化
SUB R0,R8,#1 ;初始化计数器
Loop
MOV R1 , R9 ;暂存高位值
UMULL R8 , R9 , R0 , R8 ;[R9:R8]=R0*R8
MLA R9 , R1 , R0 , R9 ;R9=R1*R0+R9
#1 ;计数器递减
,
R0
,
SUBS R0
BNE Loop ;计数器不为0继续循环Stop
B Stop
END ; 文件结束
程序执行后输出结果如下:R8=0x82B40000
R9=0x21C3677C。
arm编程实例c语言

arm编程实例c语言ARM编程实例C语言是一种高效的编程语言,它可以用于开发各种类型的应用程序。
在本文中,我们将介绍一些ARM编程实例C语言的基本知识和技巧。
首先,我们需要了解ARM架构的基本知识。
ARM是一种基于RISC (精简指令集计算机)架构的处理器,它具有高效的指令集和低功耗的特点。
ARM处理器广泛应用于移动设备、嵌入式系统、智能家居等领域。
接下来,我们需要掌握C语言的基本语法和数据类型。
C语言是一种高级编程语言,它具有强大的数据类型和控制结构。
在ARM编程中,我们通常使用C语言来编写应用程序。
下面是一个简单的ARM编程实例C语言程序:```#include <stdio.h>int main(){printf("Hello, ARM!\n");return 0;}```这个程序的作用是输出“Hello, ARM!”这个字符串。
在这个程序中,我们使用了stdio.h头文件中的printf函数来输出字符串。
同时,我们还使用了int类型的main函数来定义程序的入口点。
除了基本的语法和数据类型,我们还需要掌握一些常用的ARM编程实例C语言库函数。
这些函数可以帮助我们更加高效地编写应用程序。
下面是一些常用的ARM编程实例C语言库函数:1. memcpy函数:用于将一个内存区域的数据复制到另一个内存区域。
2. memset函数:用于将一个内存区域的数据设置为指定的值。
3. strlen函数:用于计算一个字符串的长度。
4. strcmp函数:用于比较两个字符串是否相等。
5. sprintf函数:用于将格式化的数据写入字符串中。
最后,我们需要了解一些ARM编程实例C语言的调试技巧。
调试是编程过程中非常重要的一步,它可以帮助我们找到程序中的错误并进行修复。
在ARM编程中,我们通常使用调试器来进行调试。
常用的ARM调试器包括GDB和JTAG。
总之,ARM编程实例C语言是一种非常有用的编程语言,它可以帮助我们开发高效、低功耗的应用程序。
arm-gcc编译实例

arm-gcc编译实例以下是一个简单的arm-gcc编译实例:假设有一个名为test.c的源文件,内容如下:```c。
#include <stdio.h>。
int main() 。
printf("Hello World\n");。
return 0;。
}。
```。
接下来使用arm-gcc进行编译:1. 安装arm-gcc。
在Linux系统中,可以使用apt-get或yum安装arm-gcc,命令如下:```。
$ sudo apt-get install gcc-arm-none-eabi。
```。
2.编译源文件。
使用arm-gcc编译test.c,命令如下:```。
$ arm-none-eabi-gcc -Wall -mcpu=cortex-m0 -mthumb -otest.bin test.c。
```。
解释一下各个参数的含义:- Wall:开启所有警告提示。
- mcpu:指定目标处理器的类型,这里为cortex-m0。
- mthumb:生成Thumb指令集的代码。
- o:指定输出文件名,这里为test.bin。
- test.c:需要编译的源文件。
3.运行。
将编译生成的test.bin文件烧录到目标设备中,即可运行程序。
注意事项:- 在编译的过程中,需要根据目标设备的类型和指令集来选择相应的mcpu和mthumb参数。
- 在Windows系统中,需要将arm-none-eabi-gcc的路径添加到环境变量中。
-编译生成的文件一般为二进制文件,需要烧录到目标设备中才能运行。
实验三 基于ARM的汇编编程实验

实验三基于ARM的汇编编程实验1 实验目的1.熟悉ADS1.2软件开发环境;2.掌握ARM7TDMI汇编指令的用法,并能编写简单的汇编程序;3.掌握指令的条件执行和使用LDR/STR指令完成存储器的访问。
4.掌握ARM乘法指令的使用方法;5.了解子程序编写及调用。
2 实验内容实验内容一:1.使用LDR指令读取0x30003100上的数据,将数据加1,若结果小于10,则使用STR指令把结果写回原地址,若结果大于等于10,则把0写回原地址。
2.使用ADS1.2软件仿真,单步,全速运行程序,设置断点,打开寄存器窗口(Processor Registers)监视R0,R1的值,打开存储器观察窗口(Memory)监视0x30003100上的值。
实验内容二:1.使用STMFD/LDMFD,MUL指令编写一个整数乘方的子程序,然后使用BL指令调用子程序计算X n的值。
2.X n= X*X*X ……*X,其中相乘的X的个数为n个。
先将X的值装入R0和R1,使用寄存器R2进行计数,循环n-1次R0=R0*R1,运算结果就保存在R0中。
(不考虑溢出问题)3.注意:若n=0,则运算结果直接赋1;若n=1,则运算结果直接赋X。
3 预备知识1.ARM指令系统内容;2.ADS1.2工程编辑和AXD调试的内容。
4 实验设备硬件:PC机一台。
软件:Windows98/XP/2000系统,ADS1.2集成开发环境。
5 实验步骤实验内容一的步骤:1.启动ADS1.2,使用ARM Executable Image工程模板建立一个工程arm1.mcp。
如图5.1所示。
图5.1 新建工程对话框2.建立汇编源文件arm1.s,编写实验程序,然后添加到工程中。
如图5.2所示。
图5.2 新建汇编文件对话框3.设置工程连接地址RO Base为0x30000000,RW Base为0x30003000,设置调试口地址Image entry point为0x30000000。
ARM指令集详解(超详细带实例)

ARM指令集详解(超详细带实例)算术和逻辑指令ADC : 带进位的加法(Addition with Carry)ADC{条件}{S} dest, op 1, op 2dest = op_1 + op_2 + carryADC 将把两个操作数加起来,并把结果放置到目的寄存器中。
它使用一个进位标志位,这样就可以做比32 位大的加法。
下列例子将加两个128 位的数。
128 位结果: 寄存器0、1、2、和3第一个128 位数: 寄存器4、5、6、和7第二个128 位数: 寄存器8、9、10、和11。
ADDS R0, R4, R8 ; 加低端的字ADCS R1, R5, R9 ; 加下一个字,带进位ADCS R2, R6, R10 ; 加第三个字,带进位ADCS R3, R7, R11 ; 加高端的字,带进位如果如果要做这样的加法,不要忘记设置S 后缀来更改进位标志。
ADD : 加法(Addition)ADD{条件}{S} dest, op 1, op 2dest = op_1 + op_2ADD 将把两个操作数加起来,把结果放置到目的寄存器中。
操作数1 是一个寄存器,操作数2 可以是一个寄存器,被移位的寄存器,或一个立即值:ADD R0, R1, R2 ; R0 = R1 + R2ADD R0, R1, #256 ; R0 = R1 + 256ADD R0, R2, R3,LSL#1 ; R0 = R2 + (R3 1)加法可以在有符号和无符号数上进行。
AND : 逻辑与(logical AND)AND{条件}{S} dest, op 1, op 2dest = op_1 AND op_2AND 将在两个操作数上进行逻辑与,把结果放置到目的寄存器中;对屏蔽你要在上面工作的位很有用。
操作数 1 是一个寄存器,操作数2 可以是一个寄存器,被移位的寄存器,或一个立即值: AND R0, R0, #3 ; R0 = 保持R0 的位0和1,丢弃其余的位。
ARM嵌入式开发实例1-2

ARM嵌入式开发实例1-2
1. 引言
在嵌入式领域,ARM架构是最常用的处理器架构之一。
ARM嵌入式开发涉及到硬件设计、软件开发、驱动程序编写等多个方面。
本文将介绍一个ARM嵌入式开发的实例,以帮助读者更好地理解和应用ARM相关技术。
2. 实例介绍
本实例基于ARM Cortex-M系列处理器开发一个简单的LED控制程序。
通过这个实例,读者可以学习到如下内容:
•嵌入式系统的概念和根本原理
•ARM Cortex-M处理器的根本架构和特点
•使用Keil MDK开发环境进行ARM嵌入式开发
•硬件和驱动程序设计的根本技巧
该LED控制程序将使用一个ARM开发板和一只LED灯。
通过编程控制,可以实现LED的亮灭控制。
3. 环境搭建
在开始实例之前,需要搭建好开发环境。
以下是搭建环境的步骤:
1.安装Keil MDK开发环境
2.配置编译器和调试器
3.连接ARM开发板
4.安装驱动程序
完成以上步骤后,就可以开始进行ARM嵌入式开发了。
4. 程序设计
4.1 硬件设计
该实例使用一个ARM开发板和一只LED灯。
首先,需要将LED灯连接到开发板上的一个GPIO引脚上。
具体连线方式可以参考开发板的硬件手册。
在连接完成后,就可以进行软件开发了。
4.2 软件开发
首先,在Keil MDK中创立一个新的工程。
然后,在工程中添加相关的源文件和头文件。
在源文件中,我们需要编写代码来控制LED灯的亮灭。
以下是一个简单的LED控制函数的例如代码:
```c #include。
ARM程序示例

ARM程序示例EXAMPLE 1 (About LDR、LTORG)AREA Loadcon, CODE, READONLYENTRY ; Mark first instruction to executestart BL func1 ; Branch to first subroutineBL func2 ; Branch to second subroutinestop MOV r0, #0x18 ; angel_SWIreason_ReportExceptionLDR r1, =0x20026 ; ADP_Stopped_ApplicationExitSWI 0x123456 ; ARM semihosting SWIfunc1LDR r0, =42 ; => MOV R0, #42LDR r1, =0x55555555 ; => LDR R1, [PC, #offset to; Literal Pool 1]LDR r2, =0xFFFFFFFF ; =>MVN R2, #0MOV pc, lrLTORG ; Literal Pool 1 contains; literal Ox55555555func2LDR r3, =0x55555555 ; => LDR R3, [PC, #offset to; Literal Pool 1]; LDR r4, =0x66666666 ; If this is uncommented it; fails, because Literal Pool 2; is out of reachMOV pc, lrLargeTableSPACE 4200 ; Starting at the current location,;clears a 4200 byte area of memory; to zeroEND ; Literal Pool 2 is emptyThe LDR pseudo-instruction generates the most efficient code for a specific constant:if the constant can be constructed with a MOV or MVN instruction, the assembler generates the appropriate instruction.if the constant cannot be constructed with a MOV or MVN instruction, the assembler:●places the value in a literal pool (a portion ofmemory embedded in the code to hold constant values)●generates an LDR instruction with aprogram-relative address that reads the constant from the literal pool.For example:LDR rn, [pc, #offset to literal pool] ; load register n withone word; from the address [pc + offset]You must ensure that there is a literal pool within range of the LDR instruction generated by the assembler. Refer to Placing literal pools for more information.The offset from the pc to the constant must be: less than 4KB in ARM state, but can be in either directionforward and less than 1KB in Thumb state.When an LDR Rd,=const pseudo-instruction requires the constant to be placed in a literal pool, the assembler:●checks if the constant is available andaddressable in any previous literal pools. If so, it addresses the existing constant.●attempts to place the constant in the nextliteral pool if it is not already available. If the next literal pool is out of range, the assembler generates an error message. In this case you must use the LTORG directive to place anadditional literal pool in the code. Place the LTORG directive after the failed LDR pseudo-instruction, and within 4KB (ARM) or 1KB (Thumb). Refer to LTORG for a detailed description.EXAMPLE 2 (ADR ADRL)AREA adrlabel, CODE,READONLYENTRY ; Mark first instruction to executeStartBL func ; Branch to subroutinestop MOV r0, #0x18 ; angel_SWIreason_ReportExceptionLDR r1, =0x20026 ; ADP_Stopped_ApplicationExitSWI 0x123456 ; ARM semihosting SWILTORG ; Create a literal poolfunc ADR r0, Start ; => SUB r0, PC, #offset to StartADR r1, DataArea ; => ADD r1, PC, #offset to DataArea; ADR r2, DataArea+4300 ; This would fail because the offset; cannot be expressed by operand2; of an ADDADRL r2, DataArea+4300 ; => ADD r2, PC, #offset1; ADD r2, r2, #offset2MOV pc, lr ; ReturnDataArea SPACE 8000 ; Starting at the current location,; clears a 8000 byte area of memory; to zeroENDThe assembler converts an ADR rn,label pseudo-instruction by generating:●a single ADD or SUB instruction that loads theaddress, if it is in range●an error message if the address cannot be reachedin a single instruction.The offset range is ±255 bytes for an offset to a non word-aligned address, and ±1020 bytes (255 words) for an offset to a word-aligned address. (For Thumb, the address must be word aligned, and the offset must be positive.)The assembler converts an ADRL rn,label pseudo-instruction by generating:●two data-processing instructions that load theaddress, if it is in range●an error message if the address cannot beconstructed in two instructions.The range of an ADRL pseudo-instruction is ±64KB for a non word-aligned address and ±256KB for a word-aligned address. (There is no ADRL pseudo-instruction for Thumb.)ADRL assembles to two instructions, if successful.The assembler generates two instructions even if the address could be loaded in a single instruction.EXAMPLE 3 ARM code jump tableAREA Jump, CODE, READONLY ; Name this block of codeCODE32 ; Following code is ARM codenum EQU 2 ; Number of entries in jump tableENTRY ; Mark first instruction to executestart ; First instruction to callMOV r0, #0 ; Set up the three parametersMOV r1, #3MOV r2, #2BL arithfunc ; Call the functionstop MOV r0, #0x18 ;angel_SWIreason_ReportExceptionLDR r1, =0x20026 ; ADP_Stopped_ApplicationExitSWI 0x123456 ; ARM semihosting SWIarithfunc ; Label the functionCMP r0, #num ; Treat function code as unsigned integerMOVHS pc, lr ; If code is >= num then simply returnADR r3, JumpTable ; Load address of jump tableLDR pc, [r3,r0,LSL#2] ; Jump to the appropriate routineJumpTableDCD DoAddDCD DoSubDoAdd ADD r0, r1, r2 ; Operation 0MOV pc, lr ; ReturnDoSub SUB r0, r1, r2 ; Operation 1MOV pc, lr ; ReturnEND ; Mark the end of this fileExample 4 String copyAREA StrCopy, CODE, READONLYENTRY ; Mark first instruction to executestart LDR r1, =srcstr ; Pointer to first stringLDR r0, =dststr ; Pointer to second stringBL strcopy ; Call subroutine to do copystop MOV r0, #0x18 ; angel_SWIreason_ReportExceptionLDR r1, =0x20026 ;ADP_Stopped_ApplicationExitSWI 0x123456 ; ARM semihosting SWIstrcopyLDRB r2, [r1],#1 ; Load byte and update addressSTRB r2, [r0],#1 ; Store byte and update addressCMP r2, #0 ; Check for zero terminatorBNE strcopy ; Keep going if notMOV pc,lr ; ReturnAREA Strings, DATA, READWRITEsrcstr DCB "First string - source",0dststr DCB "Second string - destination",0 ENDExample 5 Block copyAREA Word, CODE, READONLY ;name this block of codenum EQU 20 ; set number of words to be copiedENTRY ; mark the first instruction to callstartLDR r0, =src ; r0 = pointer to source blockLDR r1, =dst ; r1 = pointer to destination blockMOV r2, #num ; r2 = number of words to copywordcopy LDR r3, [r0], #4 ; load a word from the source andSTR r3, [r1], #4 ; store it to the destinationSUBS r2, r2, #1 ; decrement the counterBNEwordcopy ; ... copy morestop MOV r0, #0x18 ; angel_SWIreason_ReportExceptionLDR r1, =0x20026 ; ADP_Stopped_ApplicationExitSWI 0x123456 ; ARM semihosting SWIAREA BlockData, DATA, READWRITEsrc DCD 1,2,3,4,5,6,7,8,1,2,3,4,5,6,7,8,1,2,3,4dst DCD 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0ENDAREA Block, CODE, READONLY ; name this block of codenum EQU 20 ;set number of words to be copiedENTRY ; mark the first instruction to callstartLDR r0, =src ;r0 = pointer to source blockLDR r1, =dst ;r1 = pointer to destination blockMOV r2, #num ; r2 = number of words to copyMOV sp, #0x400 ; Set up stack pointer (r13)blockcopy MOVS r3,r2, LSR #3 ; Number of eight word multiplesBEQ copywords ; Less than eight words to move?STMFD sp!, {r4-r11} ; Save some working registersoctcopy LDMIA r0!, {r4-r11} ; Load 8 words from the sourceSTMIA r1!, {r4-r11} ; and put them at the destinationSUBS r3, r3, #1 ; Decrement the counterBNEoctcopy ; ... copy moreLDMFD sp!, {r4-r11} ; Don't need these now - restore;originalscopywords ANDS r2, r2, #7 ; Number of odd words to copyBEQ stop ;No words left to copy?wordcopy LDR r3, [r0], #4 ; Load a word from the source andSTR r3, [r1], #4 ; store it to the destinationSUBS r2, r2, #1 ; Decrement the counterBNEwordcopy ; ... copy morestop MOV r0, #0x18 ; angel_SWIreason_ReportExceptionLDR r1, =0x20026 ; ADP_Stopped_ApplicationExitSWI 0x123456 ; ARM semihosting SWIAREA BlockData, DATA, READWRITEsrc DCD1,2,3,4,5,6,7,8,1,2,3,4,5,6,7,8,1,2,3,4dst DCD 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0ENDTest-and-branch macro exampleA test-and-branch operation requires two ARM instructions to implement.You can define a macro definition such as this:MACRO$label TestAndBranch $dest, $reg, $cc$label CMP $reg, #0B$cc $destMENDThe line after the MACRO directive is the macro prototype statement. The macro prototype statement defines the name (TestAndBranch) you use to invokethe macro. It also defines parameters ($label, $dest, $reg, and $cc). You must give values to the parameters when you invoke the macro. The assembler substitutes the values you give into the code.This macro can be invoked as follows:test TestAndBranch NonZero, r0, NE......NonZeroAfter substitution this becomes:test CMP r0, #0BNE NonZero......NonZeroEXAMPLE 6 MAP & FIELDtypedef struct Point{float x,y,z;} Point;Point origin,oldloc,newloc;The following assembly language code is equivalent to the typedef statement above:PointBase RN r11MAP 0,PointBasePoint_x FIELD 4Point_y FIELD 4Point_z FIELD 4The following assembly language code allocates space in memory. This is equivalent to the last line of C code:origin SPACE 12oldloc SPACE 12newloc SPACE 12You must load the base address of the data structure into the base register before you can use the labels defined in the map. For example:LDR PointBase,=originMOV r0,#0STR r0,Point_xMOV r0,#2STR r0,Point_yMOV r0,#3STR r0,Point_zis equivalent to the C code:origin.x = 0;origin.y = 2; origin.z = 3;Examples 7; straightforward substitutionGBLS add4ff;add4ff SETS "ADD r4,r4,#0xFF" ; set up add4ff$add4ff.00 ; invoke add4ff; this producesADD r4,r4,#0xFF00; elaborate substitutionGBLS s1GBLS s2GBLS fixupGBLA count;count SETA 14s1 SETS "a$$b$count" ; s1 now has value a$b0000000Es2 SETS "abc"fixup SETS "|xy$s2.z|" ; fixup now has value |xyabcz||C$$code| MOV r4,#16 ; but the label here is C$$codeC 与汇编的混合编程The ARM C++ compilers support the asm syntax proposed in the ANSI C++ Standard, with the restriction that the string literal must be a single string. For example:asm("instruction[;instruction]");The inline assembler is invoked with the assembler specifier. The specifier is followed by a list of assembler instructions inside braces. For example: __asm{instruction [; instruction]...[instruction]}ATPCS registers, r0-r3, r12, lr, and PSR, are corrupted.(不可靠)Example 4-1 String copy#include <stdio.h>void my_strcpy(const char *src, char *dst) {int ch;__asm{loop:#ifndef __thumb// ARM versionLDRB ch, [src], #1STRB ch, [dst], #1#else// Thumb versionLDRB ch, [src]ADD src, #1STRB ch, [dst]ADD dst, #1#endifCMP ch, #0BNE loop}}int main(void){const char *a = "Hello world!";char b[20];my_strcpy (a, b);printf("Original string: '%s'\n", a);printf("Copied string: '%s'\n", b);return 0;}LabelsC and C++ labels can be used in inline assembler statements. C and C++ labels can be branched to by branch instructions only in the form:B{cond} labelYou cannot branch to C or C++ labels using BL. Storage declarationsAll storage can be declared in C or C++ and passed to the inline assembler using variables. Therefore, the storage declarations that are supported byarmasm are not implemented.SWI and BL instructionsSWI and BL instructions must specify exactly the calling standard used. Three optional register lists follow the normal instruction fields. The register lists specify:●The registers that are the input parameters●The registers that are output parameters afterreturn●The registers that are corrupted by the calledfunction.For example:SWI{cond} swi_num, {input_regs}, {output_regs}, {corrupted_regs}BL{cond} function, {input_regs}, {output_regs}, {corrupted_regs}UsageThe following points apply to using inline assembly language:稢omma is used as a separator in assembly language, so C expressions with the comma operator must beenclosed in parentheses to distinguish them:__asm {ADD x, y, (f(), z)}稩 f you are using physical registers, you must ensure that the compiler does not corrupt them when evaluating expressions. For example:__asm{MOV r0, xADD y, r0, x / y // (x / y) overwrites r0 with the result.}Because the compiler uses a function call to evaluate x / y, it:●corrupts r2, r3, ip, and lr●updates the NZCV flags in the CPSR●alters r0 and r1 with the dividend and modulo. The value in r0 is lost. You can work around this by using a C variable instead of r0:mov var,xadd y, var, x / yThe compiler can detect the corruption in many cases, for example when it requires a temporaryregister and the register is already in use:__asm{MOV ip, #3ADDS x, x, #0x12345678 // this instruction is expandedORR x, x, ip}The compiler uses ip as a temporary register when it expands the ADD instruction, and corrupts the value 3 in ip. An error message is issued.稤o not use physical registers to address variables, even when it seems obvious that a specific variable is mapped onto a specific register. If the compiler detects this it either generates an error message or puts the variable into another register to avoid conflicts:int bad_f(int x) // x in r0{__asm{ADD r0, r0, #1 // wrongly asserts that xis still in r0}return x; // x in r0}This code returns x unaltered. The compiler assumes that x and r0 are two different variables, despite the fact that x is allocated to r0 on both function entry and function exit. As the assembly language code does not do anything useful, it is optimized away. The instruction should be written as:ADD x, x, #1Do not save and restore physical registers that are used by an inline assembler. The compiler will do this for you. If physical registers other than CPSR and SPSR are read without being written to, an error message is issued. For example:int f(int x){__asm{STMFD sp!, {r0} // save r0 - illegal: read before writeADD r0, x, 1EOR x, r0, xLDMFD sp!, {r0} // restore r0 - not needed.}return x;}4.2 Accessing C global variables from assembly codeGlobal variables can only be accessed indirectly, through their address. To access a global variable, use the IMPORT directive to import the global and then load the address into a register. You can access the variable with load and store instructions, depending on its type.For unsigned variables use:●LDRB/STRB for char●LDRH/STRH for short (Use two LDRB/STRBinstructions for Architecture 3)●LDR/STR for int.For signed variables, use the equivalent signed instruction, such as LDRSB and LDRSH.Small structures of less than eight words can be accessed as a whole using the LDM and STM instructions. Individual members of structures can be accessed by a load or store instruction of the appropriate type. You must know the offset of a member from the start of the structure in order to access it.Example 4-6 loads the address of the integer global globvar into r1, loads the value contained in that address into r0, adds 2 to it, then stores the new value back into globvar.Example 4-6 Address of globalAREA globals,CODE,READONLYEXPORT asmsubroutineIMPORT globvarasmsubroutineLDR r1, =globvar ; read address of globvar into; r1 from literal pool LDR r0, [r1]ADD r0, r0, #2STR r0, [r1]MOV pc, lrENDCalling assembly language from CExample 4-9 and Example 4-10 show a C program that uses a call to an assembly language subroutine to copy one string over the top of another string. Example 4-9 Calling assembly language from C#include <stdio.h>extern void strcopy(char *d, const char *s);int main(){ const char *srcstr = "First string - source "; char dststr[] = "Second string - destination ";/* dststr is an array since we're going to change it */printf("Before copying:\n");printf(" %s\n %s\n",srcstr,dststr);strcopy(dststr,srcstr);printf("After copying:\n");printf(" %s\n %s\n",srcstr,dststr);return (0);}Example 4-10 Assembly language string copy subroutineAREA SCopy, CODE, READONLYEXPORT strcopystrcopy ; r0 points to destination string.; r1 points to source string.LDRB r2, [r1],#1 ; Load byte and update address.STRB r2, [r0],#1 ; Store byte and update address.CMP r2, #0 ; Check for zero terminator. BNE strcopy ; Keep going if not.MOV pc,lr ; Return.ENDCalling C from assembly languageExample 4-11 and Example 4-12 show how to call C from assembly language.Example 4-11 Defining the function in Cint g(int a, int b, int c, int d, int e){return a + b + c + d + e;}Example 4-12 Assembly language call; int f(int i) { return g(i, 2*i, 3*i, 4*i, 5*i); }EXPORT fAREA f, CODE, READONLYIMPORT g ; i is in r0STR lr, [sp, #-4]! ; preserve lrADD r1, r0, r0 ; compute 2*i (2nd param) ADD r2, r1, r0 ; compute 3*i (3rd param) ADD r3, r1, r2 ; compute 5*iSTR r3, [sp, #-4]! ; 5th param on stackADD r3, r1, r1 ; compute 4*i (4th param) BL g ; branch to C functionADD sp, sp, #4 ; remove 5th paramLDR pc, [sp], #4 ; returnENDCalling C from C++Example 4-13 and Example 4-14 show how to call C from C++.Example 4-13 Calling a C function from C++ struct S { // has no base classes// or virtual functionsS(int s) : i(s) { }int i;};extern "C" void cfunc(S *);// declare the C function to be called from C++ int f(){S s(2); // initialize 's'cfunc(&s); // call 'cfunc' so it can change 's'return s.i * 3;}Example 4-14 Defining the function in Cstruct S {int i;};void cfunc(struct S *p) {/* the definition of the C function to be called from C++ */p->i += 5;}Calling assembly language from C++Example 4-15 and Example 4-16 show how to call assembly language from C++.Example 4-15 Calling assembly language from C++ struct S { // has no base classes// or virtual functionsS(int s) : i(s) { }int i;};extern "C" void asmfunc(S *); // declare the Asm function// to be called int f() {S s(2); // initialize 's'asmfunc(&s); // call 'asmfunc' so it// can change 's' return s.i * 3;}Example 4-16 Defining the assembly language functionAREA Asm, CODEEXPORT asmfuncasmfunc ; the definition of the Asm LDR r1, [r0] ; function to be called from C++ADD r1, r1, #5STR r1, [r0]MOV pc, lrENDCalling C++ from CExample 4-17 and Example 4-18 show how to call C++ from C.Example 4-17 Defining the function to be called in C++struct S { // has no base classes or virtualfunctionsS(int s) : i(s) { }int i;};extern "C" void cppfunc(S *p) {// Definition of the C++ function to be called from C.// The function is written in C++, only the linkage is Cp->i += 5; //}Example 4-18 Declaring and calling the function in Cstruct S {int i;};extern void cppfunc(struct S *p);/* Declaration of the C++ function to be called from C */int f(void) {struct S s;s.i = 2; /* initialize 's' */ cppfunc(&s); /* call 'cppfunc' so it *//* can change 's' */ return s.i * 3;}Calling C++ from assembly languageExample 4-19 and Example 4-20 show how to call C++ from assembly language.Example 4-19 Defining the function to be called in C++struct S { // has no base classes or virtual functionsS(int s) : i(s) { }int i;};extern "C" void cppfunc(S * p) {// Definition of the C++ function to be called from ASM.// The body is C++, only the linkage is Cp->i += 5;}In ARM assembly language, import the name of the C++ function and use a Branch with link instruction to call it:Example 4-20 Defining assembly language function AREA Asm, CODEIMPORT cppfunc ; import the name of the C++ ; function to be called from AsmEXPORT ffSTMFD sp!,{lr}MOV r0,#2STR r0,[sp,#-4]! ; initialize structMOV r0,sp ; argument is pointer to structBL cppfunc ; call 'cppfunc' so it can change; the structLDR r0, [sp], #4ADD r0, r0, r0,LSL #1LDMFD sp!,{pc}ENDPassing a reference between C and C++Example 4-21 and Example 4-22 show how to pass a reference between C and C++.Example 4-21 C++ functionextern "C" int cfunc(const int&);// Declaration of the C function to be called from C++extern "C" int cppfunc(const int& r) {// Definition of the C++ to be called from C.return 7 * r;}int f() {int i = 3;return cfunc(i); // passes a pointer to 'i'}Example 4-22 Defining the C functionextern int cppfunc(const int*);/* declaration of the C++ to be called from C */int cfunc(const int* p) {/* definition of the C function to be called from C++ */int k = *p + 4;return cppfunc(&k);}Calling C++ from C or assembly languageThe code in Example 4-23, Example 4-24 and Example 4-25 demonstrates how to call a non-static, non-virtual C++ member function from C or assembly language. Use the assembler output from the compiler to locate the mangled name of the function.Example 4-23 Calling a C++ member function struct T {T(int i) : t(i) { }int t;int f(int i);};int T::f(int i) { return i + t; }// Definition of the C++ function to be called from C.extern "C" int cfunc(T*);// declaration of the C function to be called from C++int f() {T t(5); // create an object of type Treturn cfunc(&t);}Example 4-24 Defining the C functionstruct T;extern int f__1TFi(struct T*, int);/* the mangled name of the C++ *//* function to be called */int cfunc(struct T* t) {/* Definition of the C function to be called from C++. */return 3 * f__1TFi(t, 2); /* like '3 * t->f(2)' */}Example 4-25 Implementing the function in assembly languageEXPORT cfuncAREA cfunc, CODEIMPORT f__1TFiSTMFD sp!,{lr} ; r0 already contains the object pointerMOV r1, #2BL f__1TFiADD r0, r0, r0, LSL #1 ; multiply by 3 LDMFD sp!,{pc}ENDARM-THUMB Procedure Call Standard(ATPCS)C 与汇编相互调用在C 程序和ARM 汇编程序之间相互调用必须遵守ATPCS.使用ADS 的C 语言编译器编译的C 语言子程序满足用户指定的ATPCS 类型.而对于汇编语言来说,完全要依赖用户来保证各个子程序满足选定的ATPCS 类型.具体来说,汇编语言子程序必须满足下面3 个条件:在子程序编写时必须遵守相应的ATPCS 规则堆栈的使用要遵守相应的ATPCS 规则.在汇编编译器中使用-apcs 选项基本ATPCS 规定了在子程序调用时的一些基本规则,包括:各寄存器的使用规则及其相应的名称,堆栈的使用规则,参数传送的规则.寄存器的使用规则子程序间通过寄存器R0~R3 来传递参数.这时,寄存器R0~R3 可记作A0~A3.被调用的子程序在返回前无须恢复寄存器R0~R3 的内容.在子程序中,使用寄存器R4~R11 来保存局部变量.这时,寄存器R4~R11 可以记作V1~V8.如果在子程序中使用了寄存器V1~V8 中的某些寄存器,子程序进入时必须保存这些寄存器的值,在返回前必须恢复这些寄存器的值.在Thumb 程序中,通常只能使用寄存器R4~R7 来保存局部变量.寄存器R12 用作过程调用中间临时寄存器,记作IP.在子程序间的连接代码段中常有这种使用规则.寄存器R13 用作堆栈指针,记作SP.在子程序中寄存器R13 不能作其他用途.寄存器SP 在进入子程序时的值和退出子程序时的值必须相等.寄存器R14 称为连接寄存器,记作LR.它用于保存子程序的返回地址.如果在子程序中保存了返回地址,寄存器R14 则可以用作其他用途.寄存器R15 是程序计数器,记作PC.它不能用作其它用途.堆栈使用规则ATPCS 规定堆栈为FD 类型,即满递减堆栈,并且对堆栈的操作是8 字节对齐.使用ADS 中的编译器产生的目标代码中包含了DRAFT2 格式的数据帧.在调试过程中, 调试器可以使用这些数据帧来查看堆栈中的相关信息.对于汇编语言来说,用户必须使用FRAME 伪指令来描述堆栈的数据帧.ARM 汇编器根据这些伪指令在目标文件中产生相应的DRAFT2 格式的数据帧.(堆栈中的数据帧---在堆栈中,为子程序分配的用来保存寄存器和局部变量的区域).对于汇编程序来说,如果目标文件中包含了外部调用,则必须满足下列条件:外部接口的堆栈必须是8 字节对齐的.在汇编程序中使用PRESERVE8 伪指令告诉连接器,本汇编程序数据是8 字节对齐的.参数传递规则根据参数个数是否固定可以将子程序分为参数个数固定的子程序和参数个数可变化的子程序.这两种子的参数传递规则是不一样的.参数个数可变的子程序参数传递规则对于参数个数可变的子程序,当参数不超过4 个时,可以使用寄存器R0~R3 来传递参数;当参数超过4 个时,还可以使用堆栈来传递参数.在参数传递时,将所有参数看作是存放在连续的内存字单元的字数据.然后,依次将各字数据传送到寄存器R0,R1,R2,R3 中,如果参数多于4 个,将剩余的字数据传送堆栈中, 入栈的顺序与参数顺序相反,即最后一个字数据先入栈.按照上面的规则,一个浮点数参数可以通过寄存器传递,也可以通过堆栈传递,也可能一半通过寄存器传递,另一半通过堆栈传递.参数个数固定的子程序参数传递规则对于参数个数固定的子程序,参数传递与参数个数可变的子程序参数传递规则不同.如果系统包含浮点运算的硬件部件,浮点参数将按下面的规则传递;各个浮点参数按顺序处理;为每个浮点参数分配FP 寄存器;分配的方法是,满足该浮点参数需要的且编号最小的一组连续的FP 寄存器第一个整数参数,通过寄存器R0~R3 来传递.其他参数通过堆栈传递.子程序结果返回规则子程序中结果返回的规则如下;结果为一个32 位的整数时,可以通过寄存器R0 返回;结果为一个64 位的整数时,可以通过寄存器R0 和R1 返回;结果为一个浮点数时,可以通过浮点运算部件的寄存器f0,d0 或s0 来返回;结果为复合型的浮点(如复数)时,可以通过寄存器f0~fnA 或d0~dn 来返回;对于位数更多的结果,需要通过内存来传递.。
arm汇编编程范例

一。
if语句实例1/**if(a > 50)* puts("a > 50"); r0 r1 r2 r3*else if(b < a)* puts("b < a");*else if(b < 20)* puts("b < 20");**/.section .rodata.align 2.LC0:.string "a > 50".LC1:.string "b < a".LC2:.string "b < 20".text.align 2.global mainmain:push {lr} @上一个函数的返回地址压到栈中;@ mov r0, #60mov r0, #10mov r1, #30cmp r0, #50bgt do1cmp r1, r0blt do2cmp r1, #20blt do3b outdo1:ldr r0, .L0bl putsb outdo2:ldr r0, .L0+4bl putsb outdo3:ldr r0, .L0+8bl putsout:pop {pc} @从栈中取出lr存到pc中;.L0:.word .LC0.word .LC1.word .LC2if语句实例2, &运算/**if (a > 10 &&<20)* puts("a > 10 && a < 20");*/.section .rodata.align 2.LC0:.string "a > 10 && a < 20".text.align 2.global mainmain:push {lr} @上一个函数的返回地址压到栈中;mov r0, #15@if( (a>10) && (a<20) )@ puts("a > 10 && a < 20");cmp r0, #10ble outcmp r0, #20ldrlt r0, .L0bllt printfout:pop {pc} @从栈中取出lr存到pc中;.word .LC0if语句实例3, ||运算.section .rodata.align 2.LC0:.string "a < 10 || a > 20".text.align 2.global mainmain:push {lr} @上一个函数的返回地址压到栈中;mov r0, #15@if( (a<10) || (a>20) )@ puts("a < 10 || a > 20");cmp r0, #10blt docmp r0, #20ble outdo:ldr r0, .L0bl putsout:pop {pc} @从栈中取出lr存到pc中;.L0:.word .LC0二,switch语句的实现1/**char ch = 'A';**switch (ch)*{* case x:* break;* ...*}*/.section .rodata.align 2.LC0:.ascii "val = %d \012\000".text.align 2.global mainmain:stmfd sp!, {fp, lr}add fp, sp, #4sub sp, sp, #16mov r3, #65 @ch = 'A';strb r3, [fp, #-5]ldrb r3, [fp, #-5] @ zero_extendqisi2str r3, [fp, #-16] @int --> switchldr r3, [fp, #-16]cmp r3, #45 @二分查找;beq .L5ldr r3, [fp, #-16]cmp r3, #45bgt .L9ldr r3, [fp, #-16]cmp r3, #2beq .L3ldr r3, [fp, #-16]cmp r3, #9beq .L4b .L11.L9:ldr r3, [fp, #-16]cmp r3, #97beq .L7ldr r3, [fp, #-16]cmp r3, #99beq .L8ldr r3, [fp, #-16]cmp r3, #65beq .L6b .L11ldrb r3, [fp, #-5] @ zero_extendqisi2ldr r0, .L12mov r1, r3bl printfb .L11.L8:ldrb r3, [fp, #-5] @ zero_extendqisi2ldr r0, .L12mov r1, r3bl printfb .L11.L3:ldrb r3, [fp, #-5] @ zero_extendqisi2ldr r0, .L12mov r1, r3bl printfb .L11.L4:ldrb r3, [fp, #-5] @ zero_extendqisi2ldr r0, .L12mov r1, r3bl printfb .L11.L5:ldrb r3, [fp, #-5] @ zero_extendqisi2ldr r0, .L12mov r1, r3bl printfb .L11.L6:ldrb r3, [fp, #-5] @ zero_extendqisi2ldr r0, .L12mov r1, r3bl printf.L11:sub sp, fp, #4ldmfd sp!, {fp, pc}.L13:.align 2.L12:.word .LC0switch语句的实现2(哈希实现).section .rodata.align 2.LC0:.ascii "val = %d \012\000".text.align 2.global mainmain:stmfd sp!, {fp, lr}add fp, sp, #4sub sp, sp, #16mov r3, #65strb r3, [fp, #-5]ldrb r3, [fp, #-5] @ zero_extendqisi2sub r3, r3, #59cmp r3, #8ldrls pc, [pc, r3, asl #2]b .L11.L9:.word .L3.word .L4.word .L11.word .L5.word .L6.word .L11.word .L7.word .L11.word .L8.L3:ldrb r3, [fp, #-5] @ zero_extendqisi2ldr r0, .L12mov r1, r3bl printfb .L11.L4:ldrb r3, [fp, #-5] @ zero_extendqisi2ldr r0, .L12mov r1, r3bl printfb .L11.L6:ldrb r3, [fp, #-5] @ zero_extendqisi2ldr r0, .L12mov r1, r3bl printfb .L11.L5:ldrb r3, [fp, #-5] @ zero_extendqisi2ldr r0, .L12mov r1, r3bl printfb .L11.L8:ldrb r3, [fp, #-5] @ zero_extendqisi2ldr r0, .L12mov r1, r3bl printfb .L11.L7:ldrb r3, [fp, #-5] @ zero_extendqisi2ldr r0, .L12mov r1, r3bl printf.L11:sub sp, fp, #4ldmfd sp!, {fp, pc}.L13:.align 2.L12:.word .LC0.size main, .-main.ident "GCC: (Sourcery G++ Lite 2008q3-72) 4.3.2".section .note.GNU-stack,"",%progbits三,while语句实现1/**while(1)*{* if(i >= 10)* break;* printf("i = %d \n", i);* i++;*}*/.section .rodata.align 2.LC0:.string "i = %d \n".text.align 2.global mainmain:push {lr} @上一个函数的返回地址压到栈中;@for(i = 0; i < 10; i++)@{@ printf("i = %d \n", i);@}@i = 0;mov r4, #0loop:cmp r4, #10bge outldr r0, .L0mov r1, r4bl printfadd r4, #1b loopout:pop {pc} @从栈中取出lr存到pc中;.L0:.word .LC0四,for语句实现1/**for (;;)* ;*/.section .rodata.align 2.LC0:.string "a > b".text.align 2.global mainmain:push {lr} @上一个函数的返回地址压到栈中;loop:ldr r0, .L0bl printfb looppop {pc} @从栈中取出lr存到pc中;.L0:.word .LC0for语句实现2/**for (;;)*{* printf("a > b");* sleep(1);*}*/.section .rodata.align 2.LC0:.string "a > b".text.align 2.global mainmain:push {lr} @上一个函数的返回地址压到栈中;loop:ldr r0, .L0bl putsmov r0, #1bl sleepb looppop {pc} @从栈中取出lr存到pc中;.L0:.word .LC0for语句实现3/**for (i = 0; i < 10; i++)*{* printf("a > b");* sleep(1);*}**/.section .rodata.align 2.LC0:.string "a > b".text.align 2.global mainmain:push {lr} @上一个函数的返回地址压到栈中;mov r4, #10loop:cmp r4, #0beq outldr r0, .L0bl putsmov r0, #1bl sleepsub r4, r4, #1b loopout:pop {pc} @从栈中取出lr存到pc中;.L0:.word .LC0for语句实现4/**for (i = 10; i > 0; i--)*{* printf("a > b");* sleep(1);*}*/.section .rodata.align 2.LC0:.string "a > b".text.align 2.global mainmain:push {lr} @上一个函数的返回地址压到栈中;mov r1, #10loop:cmp r1, #0beq outldr r0, .L0bl puts @ --> write@ r0 r1 r2 r3@ puts r4 r5 r6@ atpcs : r4-r14mov r0, #1bl sleep @ sleep -> alarmsub r1, r1, #1b loopout:pop {pc} @从栈中取出lr存到pc中;.L0:.word .LC0for语句实现5/**for(i = 0; i < 10; i++)*{* printf("i = %d \n", i);*}*.section .rodata.align 2.LC0:.string "i = %d \n".text.align 2.global mainmain:push {lr} @上一个函数的返回地址压到栈中;mov r4, #0loop:cmp r4, #10bge outldr r0, .L0mov r1, r4bl printfadd r4, #1b loopout:pop {pc} @从栈中取出lr存到pc中;.L0:.word .LC0for语句实现6/**for(i = 0; i < 10; i++)*{* for(j = 0; j < 10; j++)* {* printf("i = %d j = %d \n", i, j);* }*}*/.section .rodata.align 2.LC0:.string "i = %d j = %d\n".text.align 2.global mainmain:push {lr} @上一个函数的返回地址压到栈中;mov r4, #0for:cmp r4, #10bge outmov r5, #0for1:cmp r5, #10bge out1ldr r0, .L0mov r1, r4mov r2, r5bl printfadd r5, #1b for1out1:add r4, #1b forout:pop {pc} @从栈中取出lr存到pc中;.L0:.word .LC0do_wihle 语句实现/**i = 0;*do{* printf("i = %d \n", i);* i++;*}while(i < 10);**/.section .rodata.align 2.LC0:.string "i = %d \n".text.align 2.global mainmain:push {lr} @上一个函数的返回地址压到栈中;mov r4, #0loop:ldr r0, .L0mov r1, r4bl printfadd r4, #1cmp r4, #10blt looppop {pc} @从栈中取出lr存到pc中;.L0:.word .LC0。
arm eeprom编程

EEPROM(Electrically Erasable Programmable Read-Only Memory)是一种可以通过电子方式擦除和编程的非易失性存储器。
在ARM微控制器上,通常使用内置的EEPROM模块或外部EEPROM芯片来存储数据。
下面是一个简单的示例,演示如何在ARM微控制器上编程EEPROM。
1.硬件连接首先,需要将EEPROM芯片连接到微控制器的I/O引脚上。
通常,EEPROM芯片会有一些特定的引脚用于数据输入/输出、地址选择和擦除/编程控制。
根据EEPROM芯片的数据手册,将相应的引脚连接到微控制器的相应I/O引脚上。
2.配置微控制器在编程EEPROM之前,需要配置微控制器的一些参数,例如I/O引脚的工作模式、时钟频率等。
根据EEPROM芯片的数据手册,设置微控制器的一些特定寄存器。
3.EEPROM编程函数下面是一个简单的示例EEPROM编程函数的代码:c复制代码#include<stdio.h>#include<stdint.h>#include"eeprom.h"// EEPROM库的头文件void eeprom_write(uint32_t address, uint8_t data) {// EEPROM编程函数,写入单个字节的数据// 具体实现取决于使用的EEPROM库和微控制器型号eeprom_write_byte(address, data); // 使用库函数将数据写入EEPROM }int main() {uint32_t address = 0x0000; // EEPROM地址uint8_t data = 0x12; // 要写入的数据eeprom_write(address, data); // 调用EEPROM编程函数return0;}在这个示例中,eeprom_write()函数是用来写入单个字节数据的函数,它的实现取决于所使用的EEPROM库和微控制器型号。
实验1-ARM基础编程仿真(Keil)

5、ARM汇编实现冒泡算法(选做) 冒泡排序参考流程-----较小的数值排放到后面
24
5、ARM汇编实现冒泡算法(选做)
冒泡排序法原理:
这种方法的基本思想:是将待排序的元素看作是竖着排列的 “气泡”,较大的元素比较重,从而要往下沉。在冒泡排序算法 中我们要对这个“气泡”序列处理若干遍。所谓一遍处理,就是 自上向下检查一遍这个序列,并时刻注意两个相邻的元素的顺序 是否正确。如果发现两个相邻元素的顺序不对,即“轻”的元素 在下面,就交换它们的位置。显然,处理一遍之后,“最重”的 元素就沉到了最低位置;处理二遍之后,“次重”的元素就沉到 了次低位置。在作第二遍处理时,由于最低位置上的元素已是 “最重”元素,所以不必检查。一般地,第i遍处理时,不必检 查第i低位置以下的元素,因为经过前面i-1遍的处理,它们已正 确地排好序。
25
5、ARM汇编实现冒泡算法(选做)
实验步骤: 1、建立新工程,加入实验1.5文件夹中的maopao.s。 2、补充完成源代码中缺失的部分,实现冒泡排序功能。 3、运行Debug进行调试
实验一 ARM基础编程实验
1
一、实验目的与实验环境
实验目的
1.熟悉并掌握常用ARM汇编指令 2.熟悉并掌握“C+汇编”混合编程技术 3.熟练使用ARM软件开发调试工具Keil
实验环境
1. 硬件:PC 机 2. 软件:Windows操作系统,Keil软件
2
二、实验内容
1. 学习使用Keil开发工具 2. 实现累加运算功能(汇编编程,必做) 3. 实现字符串拷贝功能(C+汇编,必做) 4. 实现求和运算功能(C+汇编,必做) 5. 实现冒泡排序算法(汇编编程,选做)
16
2、用汇编语言实现1+2+...+N的累加(必做)
arm7单片机编程实例,ARM7之输入-输出端口GPIO编程教程

arm7单片机编程实例,ARM7之输入/输出端口GPIO编程教程一、输入/输出端口GPIO编程一(01)、一位数码管静态显示(通过74HC595实现)1、管脚连接模块首先介绍一下LPC2106的相关的管脚~~特性:可以实现独立的管脚配置应用:管脚连接模块的用途是将管脚配置为需要的功能(这一章节主要就是介绍GPIO功能~~别的会在接下来的章节中分别予以介绍~~)描述:管脚连接模块可以使所选管脚具有一个以上的功能。
配置寄存器控制多路开关来连接管脚与片内外设。
外设在激活和任何相关只读使能之前必须连接到适当的管脚。
任何使能的外设功能如果没有映射到相应的管脚,则被认为是无效的。
寄存器的描述:管脚连接模块包括两个寄存器:管脚功能寄存器0:(PINSEL0)PINSEL0寄存器按照下表当中的设定来控制管脚的功能。
IODIR寄存器中的方向控制位只有在管脚选择为GPIO的功能时才有效(也就是本章要讲述的)。
对于其它功能,方向是自动控制的。
管脚功能寄存器1:(PINSEL1)PINSEL1寄存器按照下表来设定控制管脚的功能。
IODIR寄存器中的方向控制位只有在管脚选择GPIO功能时才有效。
对于其它功能,方向是自动控制的。
在复位时拉低DBGSEL时,只要管脚P0.17-P0.31的功能控制有效。
管脚功能寄存器值:PINSEL寄存器控制器件管脚的功能。
如下图。
每一对寄存器位对应一个特定的器件管脚。
只有当管脚选择为GPIO功能时,IODIR寄存器的方向控制位才有效。
其它功能的方向是自动控制的。
每个派生期间通常具有不同的管脚分布,因此每个管脚可能有不同的功能。
2、GPIO特性:1)单个位的方向控制2)单独控制输出的置位和清零3)所有I/0口在复位后默认为输入应用:1)通用I/0口2)驱动LED或者其他指示器3)驱动片外器件4)检测数字输入管脚描述:寄存器描述:GPIO包含4个寄存器,如下表:GPIO引脚值寄存器IOPIN:GPIO输出置位寄存器IOSET:GPIO输出清零寄存器:GPIO方向寄存器:然后就是今天要做的实验:一位数码管的静态显示用IAR for ARM就是调不好~~换用了Keil浪费我大把时间了早知道就早用Keil了回头还得再调试一下IAR然后就是程序了~~MDK1_1.c(先是主程序吗~~你懂得)//------------------------------------------------------------------------------//LED数码管显示//通过I/O模拟同步串行接口与74HC595进行连接,控制74HC595驱动LED数码管显示//------------------------------------------------------------------------------#includelpc210x.htypedef unsigned long uint32;typedef unsigned char uchar;#define SPI_IO 0x00000150 //SPI接口的I/O设置字uchar const seg[]={0xc0,0xf9,0xa4,0xb0,0x99,0x92,0.82,0xf8,0x80,0x90,0x88,0x83,0xc6,0xa1,0x86,0x8e};//------------------------------------------------------------------------------//延时函数void delay(uint32 z){uint32 i;for(;z》0;z--)for(i=0;i《50000;i++);}//------------------------------------------------------------------------------//mainint main(){uchar i;PINSEL0=0X00000000;PINSEL1=0X00000000; //设置左右引脚连接GPIOIODIR=SPI_IO; //设置SPI控制口为输出~~由于这是模拟的,所以需要自己设置方向位while(1){for(i=0;i《16;i++){HC595_send_data(seg[i]);delay(1);}}}74HC595.c//------------------------------------------------------------------------------//74HC595模拟SPI通信,便于调用#includelpc210x.htypedef unsigned long uint32;typedef unsigned char uchar;#define SPI_CS 0x00000100 //P0.8模拟片选#define SPI_DA 0x00000040 //P0.6模拟数据传输口#define SPI_CLK 0x00000010 //P0.4模拟CLK//------------------------------------------------------------------------------//向74HC595发送一个字节函数(发送数据时,高位在前)//还是大概介绍一下74HC595吧://74HC595是具有8位移位寄存器和一个存储器,三态输出功能。
ARM指令集详解(超详细!带实例!)

ARM指令集详解(超详细!带实例!)算术和逻辑指令ADC : 带进位的加法(Ad dition with C arry)ADC{条件}{S} <dest>, <op 1>, <op 2>dest = op_1 + op_2 + carryADC 将把两个操作数加起来,并把结果放置到⽬的寄存器中。
它使⽤⼀个进位标志位,这样就可以做⽐ 32 位⼤的加法。
下列例⼦将加两个 128 位的数。
128 位结果: 寄存器 0、1、2、和 3第⼀个 128 位数: 寄存器 4、5、6、和 7第⼆个 128 位数: 寄存器 8、9、10、和 11。
ADDS R0, R4, R8 ; 加低端的字ADCS R1, R5, R9 ; 加下⼀个字,带进位ADCS R2, R6, R10 ; 加第三个字,带进位ADCS R3, R7, R11 ; 加⾼端的字,带进位如果如果要做这样的加法,不要忘记设置 S 后缀来更改进位标志。
这两个指令与普通指令在对操作数的限制上有所不同:1. 给出的所有操作数、和⽬的寄存器必须为简单的寄存器。
2. 你不能对操作数 2 使⽤⽴即值或被移位的寄存器。
3. ⽬的寄存器和操作数 1 必须是不同的寄存器。
4. 最后,你不能指定 R15 为⽬的寄存器。
译注:CMP 和 CMP 是算术指令,TEQ 和 TST 是逻辑指令。
把它们归⼊⼀类的原因是它们的 S 位总是设置的,就是说,它们总是影响标志位。
CMN : ⽐较取负的值(C o m pare N egative)CMN{条件}{P} <op 1>, <op 2>status = op_1 - (- op_2)CMN 同于 CMP,但它允许你与⼩负值(操作数 2 的取负的值)进⾏⽐较,⽐如难于⽤其他⽅法实现的⽤于结束列表的 -1。
这样与 -1 ⽐较将使⽤:CMN R0, #1 ; 把 R0 与 -1 进⾏⽐较详情参照 CMP 指令。
ARM编程实例

一.ARM指令的特点以RISC为架构体系的ARM指令集的指令格式统一,种类比较少,寻址方式也比复杂指令集少。
当然处理速度就提高很多。
ARM处理器都是所谓的精简指令集处理机(RISC)。
其所有指令都是利用一些简单的指令组成的,简单的指令意味着相应硬件线路可以尽量做到最佳化,而提高执行速率,相对的使得一个指令所需的时间减到最短。
而因为指令集的精简,所以许多工作都必须组合简单的指令,而针对较复杂组合的工作便需要由编译器来执行,而CISC 体系的X86指令集因为硬体所提供的指令集较多,所以许多工作都能够以一个或是数个指令来代替,编译器的工作因而减少许多。
除了具备上述RISC的诸多特性之外,可以总结ARM指令集架构的其它一些特点如下:1.体积小,低功耗,低成本,高性能2.支持Thumb (16 位)/ARM (32 位)双指令集,能很好的兼容8 位/16 位器件;3.大量使用寄存器,指令执行速度更快;4.大多数数据操作都在寄存器中完成;5.寻址方式灵活简单,执行效率高;6.指令长度固定;7.流水线处理方式8.Load_store结构另外,ARM的一些非RISC思想的指令架构:1.允许一些特定指令的执行周期数字可变,以降低功耗,减小面积和代码尺寸。
2.增加了桶形移位器来扩展某些指令的功能。
3.使用了16位的Thumb指令集来提高代码密度。
4.使用条件执行指令来提高代码密度和性能。
5.使用增强指令来实现数据信号处理的功能。
二.ARM汇编语言程序设计实例2.1 问题描述链表是最基本的数据结构之一。
其实现思想是每一个链表节点包含数据域和指针域两个属性,指针域保存下一节点的地址值,各个节点由指针域链接起来。
链表的插入操作时间复杂度为常量级别,只需进行节点指针域的调整。
链表的正序排序可以使用常用的插入排序法,当发现一个不满足序列的节点A时,从链表头节点到当前节点进行遍历,直到找到第一个数据域大于该节点数据域的节点B,然后调整指针域将A节点插入在B节点之前。
arm半字编程操作方法

arm半字编程操作方法摘要:1.ARM半字编程基本概念2.ARM半字编程操作方法3.实例演示4.总结与展望正文:ARM半字编程是一种在ARM处理器上进行编程的方法,它允许程序员以半字(16位)为单位编写代码,从而提高代码的执行效率。
下面将详细介绍ARM半字编程的操作方法。
一、ARM半字编程基本概念在ARM半字编程中,数据操作指令、寄存器和寻址方式都与整数编程有所不同。
首先,数据操作指令分为两类:字节操作指令和半字操作指令。
字节操作指令以8位为单位进行操作,如LD1、ST1等;半字操作指令以16位为单位进行操作,如LDH、STH等。
其次,在半字编程中,寄存器使用R0-R15,其中R0-R13为通用寄存器,R14为程序计数器,R15为堆栈指针。
最后,半字寻址方式与整数寻址方式类似,可以使用直接寻址、寄存器间接寻址等。
二、ARM半字编程操作方法1.数据加载与存储在ARM半字编程中,可以使用LDH和STH指令进行数据加载和存储。
例如:```LDH R0, [R1] ; 加载半字数据到R0STH R0, [R1] ; 将R0的半字数据存储到内存中```2.数据传送可以使用BXH指令进行半字数据在不同寄存器之间的传送。
例如:```BXH R0, R1 ; 将R1的半字数据传送到R0```3.算术运算ARM半字编程支持加法、减法、乘法和除法等算术运算。
例如:```ADDH R0, R1, R2 ; R0 = R1 + R2SUBH R0, R1, R2 ; R0 = R1 - R2MULH R0, R1, R2 ; R0 = R1 * R2DIVH R0, R1, R2 ; R0 = R1 / R2```4.逻辑运算ARM半字编程支持逻辑与、逻辑或、逻辑异或和逻辑非等运算。
例如:```ANDH R0, R1, R2 ; R0 = R1 & R2ORH R0, R1, R2 ; R0 = R1 | R2XORH R0, R1, R2 ; R0 = R1 ^ R2NOTH R0, R1 ; R0 = ~R1```5.移位操作ARM半字编程支持左移、右移和无符号右移等操作。
ARM编程实例

ADS
• ARM ADS 的全称为ARM Developer Suite,它是ARM 公司推出的新一代ARM 集成开发环境,我们使用的 ADS 为1.2 版本。 • ADS由命令行开发工具、GUI(Graphics User Interface,图形用户界面)开发环境(Code Warrior 和AXD)、支持软件组成。
• 将ads.s文件拷贝到工程目录中,但并不代表已进入工程中,还需要
添加:ProjectAdd Files,将ads.s添加到工程中。 • 配置:Edit DebugRel Settings(参考Mini2440手册) • 编译:Project Make,在hello_Data\DebugRel目录中生成了hello.bin 可执行文件
S3C2440 GPIO
• S3C2440有130个GPIO口,分为A~J共9组:GPA、GPB 、GPC、……、GPJ。 • 通过设置相应寄存器,可以选择某个GPIO口是用于 输入、输出还是其他特殊功能。 • 例如:可以设置GPH6作为一般的输入、输出端口, 或者用于串口。
设置GPIO
• 每组GPIO(GPA~GPJ),都可以通过3个寄存器来控 制与访问,分别为: • GPxCON:GPIO配置寄存器 • GPxDAT:GPIO数据寄存器 • GPxUP:上拉电阻使能寄存器 (其中x表示A、B、C、D、E、F、G、H、I、J)
mini2440硬件布局led1先将相应的引脚设置为输出模式通过设置控制寄存器来实现2再向相应的引脚输出低电平即可点亮led灯通过向数据寄存器写入相应的值来实现ledled整个工程由四个文件组成2440initsmainc2440libc2440slibs2440inits是开发板上电后首先要运行的汇编程序功能是配置相应的寄存器包括对cpu内部的多个寄存器的配置以实现对内存中断堆栈的配置为c语言的运行建立环境
ARM IO口编程实例

通过一个对G口的操作实例控制LED1和LED2实现轮流闪烁对I/O口的操作是通过对相关寄存器的读/写实现的。
要对寄存器进行读/写操作,首先要对寄存器进行定义。
有关I/O相关寄存器的宏定义代码如下:1.GPxCON 寄存器用于配置引脚功能。
ConfigurePORT A 与PORT B~PORT H/J 在功能选择上有所不同,GPACON 中每一位对应一根引脚,共23 个引脚。
当某位被设为0 时候,相应引脚为输出引脚。
此时我们可以在GPADAT 中相应的写入1或者0 来让此引脚输出高电平或者低电平;当某位被设为1时,相应引脚为地址线或用于地址控制,此时GPADATA无用。
一般而言GPACON 通常被设为1 ,以便访问外部器件。
PORT B~PORT H/J在寄存器操作方面完全相同,GPxCON 中每两位控制一根引脚,00 输入01 输出10 特殊功能11 保留不用2. GPxDAT 寄存器GPxDAT用于读写引脚,当引脚被设为输入时候,读此寄存器可知道相应引脚的电平状态高还是低,当引脚被设为输出时候,写此寄存器的位,可令引脚输出高电平还是低电平。
3. GPxUP寄存器GPxUP寄存器某位为1的时候,相应管脚没有内部上拉电阻;为0 时候相应管脚有内部上拉电阻。
上拉电阻作用在于,当GPIO 引脚处于第三种状态时候,既不是输出高电平,也不是输出低电平。
而是呈现高阻态,相当于没有接芯片。
它的电平状态由上下拉电阻决定。
#define rGPACON (*(volatile unsigned*)0x56000000) //Port A控制寄存器#define rGPADAT (*(volatile unsigned*)0x56000004) //Port A数据寄存器#define rGPBCON (*(volatile unsigned*)0x56000010) //Port B控制寄存器#define rGPBDAT (*(volatile unsigned*)0x56000014) //Port B数据寄存器#define rGPBUP (*(volatile unsigned*)0x56000018) //Port B上拉电阻禁止寄存器#define rGPCCON (*(volatile unsigned*)0x56000020) //Port C控制寄存器#define rGPCDAT (*(volatile unsigned*)0x56000024) //Port C数据寄存器#define rGPCUP (*(volatile unsigned*)0x56000028) //Port C上拉电阻禁止寄存器#define rGPDCON (*(volatile unsigned*)0x56000030) //Port D控制寄存器#define rGPDDAT (*(volatile unsigned*)0x56000034) //Port D数据寄存器#define rGPDUP (*(volatile unsigned*)0x56000038) //Port D上拉电阻禁止寄存器#define rGPECON (*(volatile unsigned*)0x56000040) //Port E控制寄存器#define rGPEDAT (*(volatile unsigned*)0x56000044) //Port E数据寄存器#define rGPEUP (*(volatile unsigned*)0x56000048) //Port E上拉电阻禁止寄存器#define rGPFCON (*(volatile unsigned*)0x56000050) //Port F控制寄存器#define rGPFDAT (*(volatile unsigned*)0x56000054) //Port F数据寄存器#define rGPFUP (*(volatile unsigned*)0x56000058) //Port F上拉电阻禁止寄存器#define rGPGCON (*(volatile unsigned*)0x56000060) //Port G控制寄存器#define rGPGDAT (*(volatile unsigned*)0x56000064) //Port G数据寄存器#define rGPGUP (*(volatile unsigned*)0x56000068) //Port G上拉电阻禁止寄存器#define rGPHCON (*(volatile unsigned*)0x56000070) //Port H控制寄存器#define rGPHDAT (*(volatile unsigned*)0x56000074) //Port H数据寄存器#define rGPHUP (*(volatile unsigned*)0x56000078) //Port H上拉电阻禁止寄存器要想实现对G口的配置,只要在地址0x56000060中给32位的每一位赋值就可以了。
arm编程实例c语言

ARM编程实例C语言1. 引言随着科技的飞速发展和嵌入式系统的普及,ARM处理器在嵌入式领域得到了广泛应用。
ARM(Advanced RISC Machine)是一种精简指令集(RISC)架构的处理器,并且具有低功耗、高性能、易于开发等优点。
在实际的ARM编程中,C语言是最常用的编程语言之一。
本文将通过具体的编程实例,探讨如何使用C语言进行ARM编程。
2. ARM架构简介在开始具体的编程实例之前,我们先来简单了解一下ARM架构。
ARM处理器通常具有32位指令集,包括ARMv6、ARMv7和ARMv8等不同版本。
其中,ARMv8处理器还具有64位的指令集,可以更好地支持高性能计算。
ARM处理器的体系结构分为三个级别:用户级、特权级和系统级。
用户级是处理器的最高级别,用于运行普通应用程序。
特权级是处理器的中间级别,用于运行操作系统和驱动程序。
系统级是处理器的最低级别,对于外设、存储器等进行底层控制。
3. ARM编程实例3.1 实例1:LED闪烁3.1.1 实例描述在这个实例中,我们使用C语言编写程序,控制ARM处理器上的一个LED灯闪烁。
3.1.2 实例代码#include <stdio.h>#include "arm_control.h"int main(void) {// 初始化LED控制led_init();while(1) {// 点亮LEDled_on();// 延时一段时间delay(1000);// 熄灭LEDled_off();// 延时一段时间delay(1000);}return 0;}3.1.3 实例说明实例代码中,我们使用了一个自定义的”arm_control.h”头文件,其中包含了一些用于控制ARM处理器的函数。
在”main”函数中,我们先初始化LED控制,然后进入一个无限循环。
在循环中,我们先点亮LED,然后延时一段时间,再熄灭LED,最后再延时一段时间。
arm汇编编程(示例)

一、arm的认知及基本概念(一).arm的基本概念1.什么是armarm是一家英国电子公司的名字,全名是Advanced RISC Machine这家企业设计了大量高性能、廉价、耗能低的RISC(精简指令集)处理器,ARM公司只设计芯片而不生产,它将技术授权给世界上许多公司和厂商。
目前采用arm技术知识产权内核的微处理器,即通常所说的arm微处理器所以arm也是对一类微处理器的通称。
arm指令集体系版本号(软件)为V1 ~ V7目前V1 ~ V3已很少见。
从V4版不再与以前的版本兼容。
arm的CPU系列(硬件)主要有ARM7 ~ ARM112.典型的嵌入式处理器arm 占市场79.5%ARMmips 占市场13.9%MIPSmicroSPARC 占市场3.1%SUNPowerPc 占市场2.8%IBM其它占市场0.8%3. arm的应用范围:工业控制:如机床、自动控制等无线通信:如手机网络应用:如电子产品:如音视频播放噐、机顶盒、游戏机、数码相机、打印机其它各领域:如军事、医疗、机器人、xx等4.计算机体系结构见图:xx.xx计算机体系图xx.xx体系结构处理器使用同一个存储器,经由同一个总线传输完成一条指令需要3个步骤:即取指令->指令译码->执行指令指令和数据共享同一总线的结构哈佛体系结构将程序指令存储和数据存储分开中央处理器首先到程序指令存储器中读取程序指令。
解码后到数据地址,再到相应的数据存储器读取数据,然后执行指令程序指令存储与数据存储分开,可以使指令和数据有不同的数据宽度。
5.复杂指令集与精简指令集CISC 复杂指令集:采用冯.诺依曼体系结构。
数据线和指令线分时复用(只能通过一辆车)。
存储器操作指令多汇编程序相对简单指令结束后响应中断CPU电路丰富面积大功耗大RISC 精简指令集:采用哈佛体系结构。
数据线和指令线分离(同时能通过多辆车)。
对存储器操作有限汇编程序占空间大在适当地方响应中断CPU电路较少体积小功耗低ARM采用RISC精简指令集Thumb是ARM体系结构中一种16位的指令集。
ARM编程实例.

第四章ARM程序设计基础 1 汇编语言程序示例Example1/Example1.DOC; 例一:数据块拷贝,利用LDR/STR指令; 项目名:Example1.mcp,文件名:Example1.s ——————————————————————————————————AREA Block, CODE, READONLYnum EQU 10ENTRYstartLDR R0, =srcLDR R1, =dstMOV R2, #numblockcopyLDR R3, [R0], #4STR R3, [R1], #4SUBS R2, R2, #1BNE blockcopyB .AREA BlockData, DATA, READWRITEsrc DCD 0,1,2,3,4,5,6,7,8,9dst SPACE 10*4ENDExample2/Example2.DOC; 例二:数据块拷贝,利用LDM/STM指令; 项目名:Example2.mcp,文件名:Example2.s ——————————————————————————————————AREA Block, CODE, READONLYnum EQU 20ENTRYstartLDR R0, =src第四章ARM程序设计基础 2LDR R1, =dstMOV R2, #numMOV SP, #0x400blockcopyMOVS R3, R2, LSR #3BEQ copywordsSTMFD SP!, {R4-R11}octcopyLDMIA R0!, {R4-R11}STMIA R1!, {R4-R11}SUBS R3, R3, #1BNE octcopyLDMFD SP!, {R4-R11}copywordsANDS R2, R2, #7BEQ stopwordcopyLDR R3, [R0], #4STR R3, [R1], #4SUBS R2, R2, #1BNE wordcopystopB .AREA BlockData, DATA, READWRITEsrc DCD 0,1,2,3,4,5,6,7,8,9,0,1,2,3,4,5,6,7,8,9dst SPACE 20*4ENDExample3/Example3.DOC;例三:ADR伪指令;项目名:Example3.mcp,文件名:Example3.s ———————————————————————————————————————第四章ARM程序设计基础 3AREA adrlabel1, CODE, READONLYENTRYstartBL funcB .LTORGfuncADR R0, startADR R1, DataArea;ADR R2, DataArea+4300ADRL R3, DataArea+4300MOV PC, LRDataAreaSPACE 8000ENDExample4/Example4.DOC;例四:LDR伪指令;项目名:Example4.mcp,文件名:Example4.s ———————————————————————————————————————AREA LDRlabel1, CODE, READONLYENTRYstartBL func1BL func2B .func1LDR R0, =startLDR R1, =Darea+12LDR R2, =Darea+6000MOV PC, LRLTORG第四章ARM程序设计基础 4func2LDR R3, =Darea+6000LDR R4, =Darea+6004MOV PC, LRDareaSPACE 8000ENDExample5/Example5.DOC;例五:利用跳转表实现程序跳转;项目名:Example5.mcp,文件名:Example5.s ———————————————————————————————————————AREA Jump, CODE, READONLYnum EQU 2ENTRYstartMOV R0, #0MOV R1, #3MOV R2, #2BL arithfuncB .arithfuncCMP R0, #numMOVHS PC, LRADR R3, JumpTableLDR PC, [R3,R0,LSL #2]JumpTableDCD DoAddDCD DoSubDoAddADD R0, R1, R2第四章ARM程序设计基础 5 MOV PC, LRDoSubSUB R0, R1, R2MOV PC, LRENDExample6/Example6.DOC;例六:基于S3C4510B的串行通信程序;项目名:Example6.mcp,文件名:Example6.s ———————————————————————————————————————;Define Special Function RegisterIOPMOD EQU 0x3FF5000IOPDATA EQU 0x3FF5008UARTLCON0 EQU 0x3FFD000UARTCONT0 EQU 0x3FFD004UARTSTAT0 EQU 0x3FFD008UTXBUF0 EQU 0x3FFD00CUARTBRD0 EQU 0x3FFD014AREA Init, CODE, READONLYENTRY;LED DisplayLDR R1, =IOPMODLDR R0, =&ffSTR R0, [R1]LDR R1, =IOPDATALDR R0, =&ffSTR R0, [R1];UART0 line control registerLDR R1, =UARTLCON0LDR R0, =0x03第四章ARM程序设计基础 6 STR R0, [R1];UART0 control regiserLDR R1, =UARTCONT0LDR R0, =0x9STR R0, [R1];UART0 baud rate divisor regiser;Baudrate=19200,对应于50MHz的系统工作频率LDR R1, =UARTBRD0LDR R0, =0x500STR R0, [R1];Print the messages!LOOPLDR R0, =Line1BL PrintLineLDR R0, =Line2BL PrintLineLDR R0, =Line3BL PrintLineLDR R0, =Line4BL PrintLineLDR R1, =0x7FFFFFLOOP1SUBS R1, R1, #1BNE LOOP1B LOOP;Print linePrintLineMOV R4, LRMOV R5, R0第四章ARM程序设计基础7LineLDRB R1, [R5], #1AND R0, R1, #&FFTST R0, #&FFMOVEQ PC, R4BL PutByteB LinePutByteLDR R3, =UARTSTAT0LDR R2, [R3]TST R2, #&40BEQ PutByteLDR R3, =UTXBUF0STR R0, [R3]MOV PC, LRLine1 DCB &A, &D, "0123456789*", 0Line2 DCB &A, &D, "ABCDEFGHIJKLMNOPQRSTUVWXYZ", 0Line3 DCB &A, &D, "abcdefghijklmnopqrstuvwxyz.",0Line4 DCB &A, &D, 0END3、存储器从0x400000开始的100个单元中存放着ASCII码,编写程序,将其所有的小写字母转换成大写字母,对其它的ASCII码不做变换。
- 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
- 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
- 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。
ARM中断机制
2.中断方式
当事件发生时,硬件会设置某个寄存器; CPU再每执行完一个指令时,通过硬件查看 这个寄存器,如果所关注的事件发生了,则中 断当前程序流程,跳转到一个固定的地址处理 这个事件,最后返回被中断的程序。它的实现 相对复杂,但是效率较高,是常用的方法。
ARM七种工作模式
1、用户模式(Usr) 用于正常执行程序
如何设置宿主机软件——H-JTAG
• JTAG是一种国际标准测试协议,最初是用来对芯片 进行测试的,基本原理是在器件内部定义一个TAP
(Test Access Port测试访问口),通过专用的JTAG
测试工具对内部节点进行测试。现在,JTAG接口还
常用于实现ISP(In-system Programmable:在线编程
• 将ads.s文件拷贝到工程目录中,但并不代表已进入工程中,还需要
添加:ProjectAdd Files,将ads.s添加到工程中。 • 配置:Edit DebugRel Settings(参考Mini2440手册) • 编译:Project Make,在hello_Data\DebugRel目录中生成了hello.bin 可执行文件
Code Warrior
• Code Warrior IDE提供了一个简单通用的图形化用户 界面用于管理项目。可以以ARM处理器为对象,利 用Code warrior IDE 开发C、C++和ARM汇编代码。 • 可编辑编译源文件
实例演示
• Code Warrior创建工程、编译工程 • 打开一个简单的汇编程序:ads.s,基于该汇编程序创建和编译工程 ,并调试程序 • FileNew ARM Executable Image:
如何使用CodeWarrior和AXD调试程序?
• ProjectDebug:此时CodeWarrior自动将AXD启动起来,前提是前面 配置好
• 此时PC指针指到汇编入口处:Start • 下面开始调试:单步工作 点击 ,程序开始单步运行 • 查看寄存器: • 点击 ,查看寄存器值,Register Value,有Current、 User/System、FIQ、IRQ、SVC、Abort、Undef、CP15等多种 模式。查看当前模式: 随着程序运行,各个寄存器的值在改变,每运行一行代码 ,PC指针加4
ARM中断机制
CPU运行过程中,如何知道各类外设发生
了某些不预期的事件,比如串口收到数
据、按键按下等?
ARM中断机制
1. 查询方式
程序不断地查询各设备的状态,并做出相 应的反应。他实现比较简单,常用在比较 单一的系统中,比如一个温控系统中可以 实用查询方式不断检测温度的变化。缺点 是占用CPU资源过高,不适应多任务的系 统。
ARM编程实例
版权声明:本课件及其印刷物、视频的版权归成都国嵌信息技术有限公司所有,并保留所有权力:任何单 位或个人未经成都国嵌信息技术有限公司书面授权,不得使用该课件及其印刷物、视频从事商业、教学活 动。已经取得书面授权的,应在授权范围内使用,并注明“来源:国嵌”。违反上述声明者,我们将追究其 法律责任。
通过向数据寄存器写入相应的值来实现
实例分析与演示—LED全亮全灭控制程序
整个工程由四个文件组成 2440init.s、Main.c、2440lib.c、2440slib.s • 2440init.s
是开发板上电后首先要运行的汇编程序,功能是配置相应的寄 存器,包括对CPU内部的多个寄存器的配置,以实现对内存、中断 、堆栈的配置,为C语言的运行建立环境。 C语言运行是需要条件的,如首先要用到堆栈,如果不把堆栈设 置好,C语言将无法运行。
GPxCON寄存器
• 属于配置(Configure)寄存器,用于选择GPIO口的 功能。 • 其中PORTA与PORTB~PORTJ在功能选择方面有所不 同。 • GPACON中每一位对应一个I/O口(共23个)。当某 位为0时,相应的I/O口为输出;为1时,相应的I/O 引脚为地址线或用于地址控制。(S3C2440 芯片手 册,”I/O PORTS”)
GPxUP寄存器
• GPxUP:某位为1时,相应引脚无内部上拉电阻; 为0时相应的引脚使用内部上拉电阻。
• 上拉电阻:由于管脚悬空时容易受到外界的电磁干 扰,因此通过一个电阻来将此管脚与高电平相连, 让其固定在高电平,这样的电阻称之为上拉电阻。
每位对应一个引脚,0—相应引脚使用上拉;1—无上拉
LED程序设计
(2) 控制亮灭:通过设置GPBDAT寄存器 点亮:使GPB5~GPB8输出低电平
rGPBDAT =rGPBDAT&(LED1_ON)&(LED2_ON)&(LED3_ON)&(LED4_ON);
=X X X … X 0 0 0 0 X X X X X 熄灭:使GPB5~GPB8输出高电平 rGPBDAT = rGPBDAT|(LED1_OFF)|(LED2_OFF)|(LED3_OFF)|(LED4_OFF); =XXX…X1111XXXXX
Contents
ADS集成开发环境
S3c2440 GPIO
LED程序设计
必修实验
ADS集成开发环境
学习目的:
学习开发板的连接,开发板工具的使用,如ADS1.2集成开发环 境的使用,把裸机程序运行起来
宿主机
目标机
交叉开发模型
交叉开发模型
在嵌入式开发过程中有宿主机和目标机的角色 之分:宿主机是执行编译、链接嵌入式软件的计算 机;目标机是运行嵌入式软件的硬件平台。
ADS
• ARM ADS 的全称为ARM Developer Suite,它是ARM 公司推出的新一代ARM 集成开发环境,我们使用的 ADS 为1.2 版本。 • ADS由命令行开发工具、GUI(Graphics User Interface,图形用户界面)开发环境(Code Warrior 和AXD)、支持软件组成。
S3C2440 GPIO
• S3C2440有130个GPIO口,分为A~J共9组:GPA、GPB 、GPC、……、GPJ。 • 通过设置相应寄存器,可以选择某个GPIO口是用于 输入、输出还是其他特殊功能。 • 例如:可以设置GPH6作为一般的输入、输出端口, 或者用于串口。
设置GPIO
• 每组GPIO(GPA~GPJ),都可以通过3个寄存器来控 制与访问,分别为: • GPxCON:GPIO配置寄存器 • GPxDAT:GPIO数据寄存器 • GPxUP:上拉电阻使能寄存器 (其中x表示A、B、C、D、E、F、G、H、I、J)
每种工作模式下
• • • • 使用不同的寄存器(图) 不同的权限 触发条件 例1:同是MOV R8, #1指令,在不同的工作模式下对应不同 的寄存器,好处是模式切换时,先前模式的寄存器内容就 不用保存了。 • 例2:系统模式切换到快速中断模式时,首先要保护现场, 即上一个模式的寄存器,由于快速中断模式中R8~R14有自 己的寄存器,故只需保存R0~R7即可,体现了“快速”。
(3)设置初始化脚本: • 把 光 盘 “Windows 平台工具\H-JTAG ” 目录中的 FriendlyARM2440.his 和H-Flasher_mini2440.hfc 文件 复制到H-JTAG 的安装目录:c:\program files\H-JTAG • Init Init Script Load 打开 “FriendlyARM2440.his”装载脚本OK (注意不要 选中“Enable Auto Init”); • 再次检测硬件:Control Detect Target,显示成功 检测到ARM920T
),对FLASH等器件进行编程。
H-JTAG
• H-JTAG 是一款简单易用的的调试代理软件 ,包括三 个工具软件: • H-JTAG Server:实现调试代理的功能 • H-Flasher:实现FLASH烧写的功能 • H-JTAG emulator:仿真器
实例演示
• 安装、配置H-JTAG (1)安装H-JTAG (2)配置:SettingLPT JTAG Setting :
I/O PORTS
• 首先看GPBCON寄存器,GPBCON中每两位控制一条引脚:00—输入 ;01—输出;10—特殊功能;11—保留。GPCCON~GPJCON类似。
GPxDAT寄存器
• GPxDAT寄存器用于读/写引脚: • 当引脚被设置为输入时,通过读该寄存器可知相应 引脚电平状态是高还是低; • 当引脚被设置为输出时,写该寄存器相应的位可令 此引脚输出高电平或低电平。 • 以GPB为例
2、快速中断模式(FIQ)
用于高速数据传输 3、外部中断模式(IRQ) 用于通常的中断处理
ARM七种工作模式
4. 管理模式(svc) 操作系统使用的保护模式 5. 数据访问终止模式(abt) 当数据或指令预取终止时进入该模式,可用于虚拟存储及 存储保护。 6. 系统模式(sys) 运行具有特权的操作系统任务。 7. 未定义指令中止模式(und) 当未定义的指令执行时进入该模式,可用于支持硬件
不同的权限
• 管理模式下可以访问所有的东西,体现为不同的权限,需 要配合MMU来使用。
触发条件
• 上电后,2440CPU处于管理模式svc • 发生中断就进入IRQ模式
• 还可能出现其他情况,如数据访问终止、未定义指 令终止等
中断
• 中断 举例:一个人在家里,怎样知道有客人来? • 查询:每过5分钟开门查看 • 中断:客人来了按门铃 程序想知道按键是否被按下? 查询 中断 中断属于一种异常
• Main.c
(1) Led_port_init(); 对GPBCON进行设置, rGPBCON &= ~((3<<10)|(3<<12)|(3<<14)|(3<<16)); 11111111111111 00000000 1111111111 与rGPBCON 进行“与”运算后 赋值给rGPBCON寄存器,相当于将D17~D10清零。