嵌入式课程作业记录(1)
本学期的第一次嵌入式(小)作业,出现了许多问题和解决办法,特开一文用以记录,以防忘记。
关于ARM开发工具ADS的一些注意点
(1)code32表示后面全部用 ARM 指令集!
(2)点击 debug,若出现如下错误:error starting external process process error code 87(0x57) can't read symbolics for this tar,请以管理员身份重新运行 ADS。
(3)编译时,若AREA出现unknown opcode,解决办法:AREA前面要加空格,不要顶格写,否则编译不通过!另外程序文件最开始最好空一行出来。
(4)在写 C 语言内嵌 ARM 汇编的程序时,主函数的名字不是main而要写成xmain或_main,否则编译不通过!
(5)编译时出现Warning: L6305W: Image does not have an entry point.(Not specified or not set due to multiple choices.)的警告,我不太了解这个是怎样解决的。
汇编作业
之前也自学过 x86 汇编,但从未写过一个完整的汇编程序。这次作业使用 ARM 汇编写程序,虽然与 x86 语法有较大的区别,但还是很容易理解的。
1、先赋值一段字符,然后统计出其中数字字符出现的频次
注意,如果使用LDR指令来读取数据段的字符串内容,会将整个字符串都读到寄存器中,不便于分离单个字符进行计数。因为LDR指令会加载整个字放入寄存器中。
而现在我们需要将一字节内容放入到寄存器中,通过查阅指令集,可以发现LDRB和LDRSB可以达到这个目的,有所区别的是后者为带符号字节读入。
按理说应该两个指令都可以,但我试了一下,只有LDRSB可以,用LDRB还是会整个字读入,不知道是什么原因,希望有知情者可以解释一下。
AREA COPY, CODE, READONLY
ENTRY
CODE32
START
LDR R5, =RESULT
LDR R0, =DATA
MOV R1, #0 ;统计数字次数
MOV R2, #20 ;循环次数
MOV R3, #0 ;测试是否为数字,若是则为负数
B LOOP
NUMBER
ADD R1, R1, #1 ;数字字符,加一
B NEXT
LOOP
LDRSB R4, [R0] ;从源地址获取数据
;数字字符ASCII:48-57
CMP R4, #47
BLE NEXT
CMP R4, #58
BLE NUMBER
NEXT
ADD R0, R0, #1 ;地址
SUB R2, R2, #1 ;循环减一
CMP R2, #0
BNE LOOP
STR R1, [R5]
B EXIT
EXIT
B EXIT
AREA COPYDATA, DATA, READONLY
DATA DCB "012abc34def56dd78j90"
RESULT DCD 0
END
调试过程中:

2. 约瑟夫问题(ARM汇编)
n 个人围成一圈,编号从 1 到 n ,从编号为 1 的人开始报数,报到 m 的人离队,下面的人接着从1开始报数,依次下去,写程序求最后剩下一个人编号是几?
有点惭愧,因为当时时间紧迫,这个题目我是直接拿网上的用 x86 汇编写的程序改的(前往:用80x86汇编 求约瑟夫环问题)。数据段分为两个部分,FLAG段是标记出列,RESULT记录出列标号。
这里给出的是 10 个人围成一圈,报到 4 时出列的约瑟夫问题求解程序。
AREA COPY, CODE, READONLY
ENTRY
START
LDR R8, =RESULT
LDR R6, =FLAG
MOV R0, #10 ;总共10个人
MOV R1, #4 ;出列号码4
MOV R2, #0 ;起始号码
MOV R3, #0 ;报数
MOV R4, #0 ;出列人数
MOV R5, #0 ;用于保存出列号码
L1
LDR R7, [R6, R2, LSL #2] ;R7=地址(R6+R2*4)的值
CMP R7, #0 ;检测是否为出列
BNE NEXT ;若不是,则转到下一个人处理
ADD R3, R3, #1 ;若是,则报数,加一
CMP R3, R1 ;检测是否已经报到出列号码
BNE NEXT ;若不是,则转到下一个人处理
ADD R7, R7, #1 ;若是,则标记出列
STR R7, [R6, R2, LSL #2] ;记录回memory
MOV R3, #0 ;报数重新置零
MOV R5, R2 ;保存出列号码
STR R5, [R8, R4, LSL #2]
ADD R4, R4, #1 ;出列人数加一
CMP R4, R0 ;检测出列人数是否等于总人数
BEQ EXIT ;若是,则结束程序
NEXT
ADD R2, R2, #1 ;转到下一个人
CMP R2, R0 ;检测是否数到了最后一个人
BNE L1 ;若不是,则继续数
MOV R2, #0 ;若是,起始号码从0开始数
B L1
EXIT
B EXIT
AREA COPYDATA, DATA, READWRITE
FLAG DCD 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
RESULT DCD 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
END
3. 约瑟夫问题(C和ARM混合)
将上面汇编程序改成 C 语言和 ARM 汇编混合。注意,LDR R8, [result]若写为LDR R8, =result编译时就会报错,不知道为什么。
我调试过,一直出现找不到函数入口,PC 指针一直指向初始位置,因此也无法得知该程序是否正确与否。在Edit->DebugRel Settings里设置Image entry point也没用,希望能有朝一日能解决这个问题。

#include <stdio.h>
#include <stdlib.h>
int _main()
{
int num[100];
int n=10, m=4, i;
int count, locate, sum;
int result[100];
for(i = 0; i < n; i++)
num[i] = 0;
__asm
{
LDR R8, [result]
LDR R6, [num]
LDR R0, [n]
LDR R1, [m]
LDR R2, [locate]
LDR R3, [count]
LDR R4, [sum]
LOOP:
LDR R7, [R6, R2]
CMP R7, #0
BNE NEXT
ADD R3, R3, #1
CMP R3, R1
BNE NEXT
ADD R7, R7, #1
MOV R3, #0
ADD R4, R4, #1
ADD R8, R8, R4
STR R2, [R8]
CMP R4, R0
NEXT:
ADD R2, R2, #1
CMP R2, R0
BNE LOOP
MOV R2, #0
B LOOP
}
for(i = 0; i < n; i++)
printf("%d ", result[i]);
return 0;
}

浙公网安备 33010602011771号