IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> 嵌入式 -> ARM 编程 -> 正文阅读

[嵌入式]ARM 编程

分支

X - Y

int x = 0x1234;
int y = 0x5678;
if (x > y) {
    z = x - y;
    z = 7 * z;
} else {
    z = y - x;
    z = 9 * z;
}
.text
.globl _start
_start:
	LDR R0, =0x1234
	LDR R1, =0x5678
	h
	CMP R0,R1
	BHI XY
	BLS YX

XY:
	SUB R2,R0,R1
	RSB R2,R2,R2,LSL #3  @ 逆向减
	
YX:	
	SUB R2,R1,R1
	ADD R2,R2,R2,LSL #3
	
	b .			@ B .表示一直在当前指令处原地跳转,也就是死循环
.end

大于小于

<	:	CC			>=	:	CS
>	:	HI			<=	:	LS
=	:	EQ

完成如下动作

.text
.globl _start
_start:
	# 给R0赋值为3 	0x00000003
	MOV R0,#3   
	# 给R1赋值为4	0x00000004 
	MOV R1,#4	
	# 将R0逻辑左移R1当前值位			0x00000006
	MOV R0,R0,LSL #1   
	# 将R0减5						  0x00000001
	SUB R0,R0,#5
	# 将R0第2位取反				   0x00000041
	EOR R0,R0,#0x40
	# 将R0第3位置0   				0x00000041
	AND R0,R0,#0xDF   
	# 将R0第4为置1					0x00000051
	ORR R0,R0,#0x10
	B .						
.end

函数的应用

如何在汇编中实现函数调用

通过 BL func进行函数调用

函数中如何返回

两种方法:

  1. BX LR 更通用一些,可以在Thumb和ARM间互相调用
  2. MOV PC,LR

PC R15 里面存放将要执行的指令的地址
LR R14 里面存放要返回到的指令的地址

一般在实际编程中:R13写成SP,R14写成LR,R15写成PC

函数调用过程中如何传参

参数依次用r0,r1,r2,r3来进行传递
函数的返回值首选r0来进行传递,如果有两个结果则首先R0,R1,。。。。。。

函数定义和调用的模板

/*函数调用*/

@通过给R0、R1、R2、R3设置值,来向func函数传递参数,用几个寄存器,根据函数的参数个数决定,绝大多数函数的参数个数不会超过4个
BL func  @调用名为 func 的函数

/*函数定义*/
func:
	@ 功能实现
	@ 通过给R0设置值,来向函数调用处返回实现结果,如果结果有多个则继续使用R1、R2....,绝大多数函数的实现结果是一个
	BX LR @函数返回

add 函数

.text
.globl _start
_start:
	MOV R0,#3
	MOV R1,#5
	BL foo
	B .
foo:
	ADD R0,R0,R1
	MOV PC,LR @BX LR
		
.end

求三角形周长

.text
.global _start
_start:
	MOV R0,#3   @a  
	MOV R1,#4   @b
	MOV R2,#5	@c
	BL TRI_C
	B .
	
TRI_C:
	ADD R0,R0,R1
    ADD R0,R0,R2
	BX LR
	
.end

大小端

内存序:整数在内存的存放次序

12345678

小端 78 56 23 12 X86

大端 12 34 56 78 Power PC、ARM(默认,但可改)

LDR/STR

LDR:取地址里的数,如LDR R1, [R0] @ 将 R0 地址的 内容放入 R1 中 (先看后面的)

STR:将数存入地址,如STR R1, [R0] @ 将 R1 的内容放入 R0 所对应的地址里 (先看前面的)

.text		
.globl _start
_start:
	LDR R0,=0x11223344  	
	MOV R1,#0x40000000
	STR R0,[R1]		@ 将 R0 的内容放入 R1 的内容的地址
	LDRB R2,[R1]	@ 读取 R1 地址的前两个 2 进制
	B .
.end

字数据和8位无符号字节数据Load和Store的寻址方式

基址变址寻址:在基础地址上做一些改变形成新地址

基址:基础地址,用寄存器来存放,因此这样的寄存器被称为基址寄存器

LDR|STR{cond}{B}{T} <Rd>,<address_mode>
<address_mode>有九种方式:访问内存用的地址是[]里计算出来的地址
不索引三种:先计算新地址但不更新基址寄存器,然后用新地址访问内存
[<Rn>,#+/-<offset_12>]

[<Rn>,+/-<Rm>]

[<Rn>,+/-<Rm>,<shift> #<shift_imm>]

前索引三种:先计算新地址并更新基址寄存器,然后用新地址访问内存

[<Rn>,#+/-<offset_12>]!

[<Rn>,+/-<Rm>]!

[<Rn>,+/-<Rm>,<shift> #<shift_imm>]!

后索引三种:先用基址寄存器的地址访问内存,然后计算新地址并更新基址寄存器

[<Rn>],#+/-<offset_12>

[<Rn>],+/-<Rm>

[<Rn>],+/-<Rm>,<shift> #<shift_imm>

两数相加

将内存中的两个数相加并保存到内存

.text		
.globl _start
_start:
	LDR R0, =Value1 		@ 将 Value1 的地址放入 R0 中
	LDR R1, [R0] 			@ 将 R0 地址的 内容放入 R1 中
	LDR R0, =Value2 
	LDR R2, [R0] 
	# 两数x
	ADD R1, R1, R2 
	LDR R0, =Result 
	STR R1, [R0] 			@ 将 R1 的内容放入 R0 所对应的地址里
	B .
.data
Value1: .word 0x11111111
Value2: .word 0x22222222
Result: .word 0x0
.end

两数比较

LDR 取后地址的内容 后面有立即数,地址加上立即数

STR 存前到地址的内容

@找内存中两个32位数的最大数,并将最大数保存到新的内存块
.text		
.globl _start
_start:
	LDR R0, =Value1 
	LDR R1, [R0],#4 		@ 将 R0 地址的内容放入 R1 ,并且 R0 地址 + 4
	LDR R2, [R0]			@ 将 R0 地址的内容放入 R2
    
	CMP R1,R2
    MOVHI R3,R1				@ > 
    MOVLS R3,R2				@ <=
	
	LDR R0, =Result 		@ 将 Result 地址的内容放入 R0
	STR R3, [R0] 			@ R3(大的值)放入 R0 (result) 中
	B .
.data
Value1: .word 0x11111111
Value2: .word 0x22222222
Result: .word 0x0
.end

数组

数组相加

ARM汇编编写程序,程序功能为:定义一个数组,数组中包含4个32位无符号整数,找出最大值,并将结果保存到内存

@定义一个数组,数组中含4个32位数,求数组中元素的总和,并将结果保存到内存
.text		
.globl _start
_start:
	LDR R0,=Length
	LDR R2, [R0] 			@ R2  数组的长度

	LDR R0, =Table 
	EOR R1, R1, R1 			@ 清零
Loop:
	LDR R3, [R0],#4
	ADD R1, R1, R3
	SUBS R2, R2, #0x1
	BNE Loop
	
	LDR R0, =Result
	STR R1, [R0]
	B .

.data
Table: .word 0x1000,0x2000,0x3000,0x4000
TablEnd: .word 0
Length: .word (TablEnd-Table)/4 		
Result: .word 0 

.end

数组最小数

.text		
.globl _start
_start:
	LDR R0,=Length
	LDR R2, [R0] 			@ R2  数组的长度

	LDR R0, =Table 			@ Table 起始地址

	LDR R1, [R0]			@ R1 为数组中的第一个元素
	
	SUBS R2, R2, #0x1
Loop:

	LDR R3, [R0,#4]!			
	
	CMP R1,R3
	MOVHI R1,R3
	SUBS R2, R2, #0x1
	
	BNE Loop
	
	LDR R0, =Result
	STR R1, [R0]
	B .

.data
Table: .word 0x2000,0x1234,0x3000,0x4000
TablEnd: .word 0
Length: .word (TablEnd-Table)/4 		@ d
Result: .word 0 

.end

数组最大数

ARM汇编编写程序,程序功能为:定义一个数组,数组中包含4个32位无符号整数,找出最大值,并将结果保存到内存

.text		
.globl _start
_start:
	LDR R0,=Length
	LDR R2, [R0] 			@ R2  数组的长度

	LDR R0, =Table 			@ Table 起始地址

	LDR R1, [R0]			@ R1 为数组中的第一个元素
	
	SUBS R2, R2, #0x1
Loop:

	LDR R3, [R0,#4]!		
	
	CMP R1,R3
	MOVCC R1,R3
	
	SUBS R2, R2, #0x1
	
	BNE Loop
	
	LDR R0, =Result
	STR R1, [R0]
	B .

.data
Table: .word 0x2000,0x1234,0x5555,0x3000
TablEnd: .word 0
Length: .word (TablEnd-Table)/4 		
Result: .word 0 

.end

数组复制

.equ num,20
.text
.global _start
_start:
	LDR R0,=src
	LDR R1,=dst
	MOV R2,#num

blockcopy: @以8个字为单位复制
	MOVS R3,R2,LSR #3   @除以2的3次方,得到以8个字为单位复制的次数
	BEQ copywords
octcopy:
	LDMIA R0!,{R4-R11}
	STMIA R1!,{R4-R11}
	SUBS R3,R3,#1
	BNE octcopy

copywords:@以单个字为单位复制
	ANDS R2,R2,#7 @总字数对8取余,得到剩余要复制的字数
	BEQ stop
wordcopy:
	LDR R3,[R0],#4
	STR R3,[R1],#4
	SUBS R2,R2,#1
	BNE wordcopy

stop:
	B stop
.data
src:
	.word 1,2,3,4,5,6,7,8,1,2,3,4,5,6,7,8,1,2,3,4
dst:
	.word 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0

.end

实验

@ 亮第个灯
.text
.global _start
_start:
	 LDR R0,=0x114001E0 @GPF3CON
	 LDR R1,=0x114001E4 @GPF3DAT

	 /*Set CON 20~23 0001*/
	 LDR R2,[R0]			@ R2 0x00000000
	 BIC R2, #0xF00000		@ R2 0x00000000		清楚之前 R2 残余的数据
	 ORR R2,R2, #0x100000	@ R2 0x00100000
	 STR R2,[R0]			@ R0  0x114001E0	:	0x00100000
	 
	 /*LED5 ON*/
	 LDR R2,[R1]			@ R2 0x00000000
	 ORR R2, #0x20			@ R2 0x00200000
	 STR R2,[R1]			@ R1 0x114001E4		:	0x00200000

	 B .
.end

生成裸机可执行文件

# 编译各源文件得到对应的.o
"C:\Program Files (x86)\CodeSourcery\Sourcery G++ Lite\bin\arm-none-eabi-gcc.exe" -c myprogram.S
# 链接生成elf格式的可执行文件(注意次序,汇编源码的.o文件在前):
"C:\Program Files (x86)\CodeSourcery\Sourcery G++ Lite\bin\arm-none-eabi-ld.exe" -Ttext 0x40008000 myprogram.o -o led.elf
#  由elf格式的可执行文件生成裸机可执行文件(.bin文件)
"C:\Program Files (x86)\CodeSourcery\Sourcery G++ Lite\bin\arm-none-eabi-objcopy.exe" -O binary -S led.elf led.bin

下载并运行裸机程序

如何将文件从电脑发送到开发板的内存中?

loadb 0x40008000	

0x40008000代表开发板上内存的地fs址

点击 File -> Transfer -> Kermit -> Send 选择 led.bin 文件

C:\Users\admin\Documents\Tencent Files\xxxx\FileRecv led.bin

go 0x40008000

执行裸机程序led.bin

  嵌入式 最新文章
基于高精度单片机开发红外测温仪方案
89C51单片机与DAC0832
基于51单片机宠物自动投料喂食器控制系统仿
《痞子衡嵌入式半月刊》 第 68 期
多思计组实验实验七 简单模型机实验
CSC7720
启明智显分享| ESP32学习笔记参考--PWM(脉冲
STM32初探
STM32 总结
【STM32】CubeMX例程四---定时器中断(附工
上一篇文章      下一篇文章      查看所有文章
加:2021-09-12 13:19:13  更:2021-09-12 13:20:52 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年11日历 -2024/11/14 21:04:57-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码