嵌入式程序复习.docx
《嵌入式程序复习.docx》由会员分享,可在线阅读,更多相关《嵌入式程序复习.docx(21页珍藏版)》请在冰豆网上搜索。
嵌入式程序复习
一、写出下列各条指令的执行含义。
1.ADDR0,R0,#1;指令实现的功能是将R0+1的结果送R0是保存。
2.ADDR0,R1,[R2];指令实现的功能是将以R2中的内容为地址的单元中的值和R1相加,结果送R0保存。
3.LDRR0,[R1+4];指令实现的功能是将R1的内容加4后送R0。
4.LDRR0,[R1+4]!
;指令实现的功能是将R1的内容加4后送R0,然后R1的内容自增4个字节。
5.BLable;程序无条件跳转到标号Lable处执行。
MOVR1,R0;指令实现的功能是将寄存器R0的值传送到寄存器R1。
7.CMPR1,R0;指令实现的功能是寄存器R1的值和寄存器R0的值相减,根据结果设置CPSR的标志位。
8.CMNR1,R0;指令实现的功能是将寄存器R1的值和寄存器R0的值相加,根据结果设置CPSR的标志位。
9.ORRR0,R0,#3;该指令设置R0的0、1位,其余位保持不变。
10.MRSR0,SPSR;传送SPSR的内容到R0。
11.CMPR1,R2;指令实现的功能是寄存器R1的值和寄存器R2的值相减,根据结果设置CPSR的标志位。
12.MRSR0,CPSR;传送CPSR的内容到R0
13.MOVR2,R0;指令实现的功能是将寄存器R0的值传送到寄存器R2。
14.ADDR1,R1,#3;指令实现的功能是将R1+3的结果送R1是保存。
15.ADDR2,R1,[R0];指令实现的功能是将以R0中的内容为地址的单元中的值和R1相加,结果送R2保存。
16.LDRR1,[R0+4];指令实现的功能是将R0的内容加4后送R1。
17.LDRR1,[R0+4]!
;指令实现的功能是将R0的内容加4后送R1,然后R0的内容自增4个字节。
18.ANDR0,R0,#3;该指令保持R0的0、1位,其余位清零。
19.B0x1200;跳转到绝对地址0x1200处执行。
20.CMNR1,R2;指令实现的功能是将寄存器R1的值和寄存器R2的值相加,根据结果设置CPSR的标志位。
1、写一条ARM指令,完成操作r1=r2*4
MOVR1,R2,LSL#2
2.写一条ARM指令,完成操作r1=r2*3
ADDR1,R2,R2,LSL#1
3.初始值R1=23H,R2=0FH执行指令BICR0,R1,R2,LSL#1后,寄存器R0,R1的值分别是多少?
R0=21H,R1=23H
4.初始值R2=5,R3=9,R4=3,执行指令SUBSR2,R3,R4,LSR#2后,寄存器R2,R3的值分别是多少?
R2=9,R3=9
5.ADDR0,R0,R0,LSL#2;执行结果R0=5*R0
ADDR5,R3,R1,LSL#2;R5←R3+R1*4
SUBR1,R1,R2,LSR#2;R1=R1-R2÷4,因为R2右移2位相当于R2除以4。
LSL#n;逻辑左移n位(1≤n≤31),低端空位补0。
LSR#n;逻辑右移n位(1≤n≤32),高端空位补0
6.LDRR2,[R3,#0x0C];前变址,传数前计算地址
;读取R3+0x0C地址上的存储单元的内容,放入R2。
STRR1,[R0,#-4]!
;[R0-4]←[R1],R0=R0-4,符号“!
”表明指令在完成数据传送后应该更新基址寄存器,否则不更新;属于回写前变址。
LDRR0,[R1],#4 ;后变址:
先进行R1->R0操作然后R1+4->R1,操作完毕后,R1=R1+4。
不需要"!
"号。
7.多寄存器寻址即是一次可传送几个寄存器值,允许一条指令传送16个寄存器的任何子集或所有寄存器。
多寄存器寻址指令举例如下:
LDMIAR1!
,{R2-R7,R12}
;将R1指向的单元中的数据读出到R2~R7、R12中
;(R1自动增加)
LDMIA R0!
{R1, R2, R3, R4}
; R1←[R0]
; R2←[R0+4]
; R3←[R0+8]
; R4←[R0+12]
STMIAR0!
,{R2-R7,R12}
;将寄存器R2~R7、R12的值保存到R0指向的存储单元中,
;(R0自动增加)
STMIAR0!
,{R1—R7}
;将R1~R7的数据保存到存储器中。
存储指针在保存第一
;个值之后增加,增长方向为向上增长
;R0←R1
;[R0+4]←R2
;[R0+8]←R3
;[R0+12]←R4
;[R0+16]←R5
;[R0+20]←R6
;[R0+24]←R7
;R0保持自动增值
8.LDRR2,[R3,#0x0C]
读取R3+0x0C地址上的一个字数据内容,放入R2。
属前变址。
参看教材第125页。
STRR1,[R0,#-4]!
[R0-4]←[R1],R0=R0-4,符号“!
”表明指令在完成数据传送后应该更新基址寄存器,否则不更新;属回写前变址。
LDRR1,[R0,R3,LSL#1]
将R0+R3×2地址上的存储单元的内容读出,存入R1。
属前变址。
9写一段ARM汇编程序:
循环累加队列myarray中的所有元素,直到碰上零值元素,结果放在r4中。
程序框架如下,补充代码完成上述功能。
AREAtotal,CODEREADONLY
ENTRY
start
MOVr4,#0
ADRr0,myarray
;在此补充代码
loop
LDRr1,[r0],#4
ADDr4,r4,r1
CMPr1,#0
BNEloop
stop
Bstop
myarray
DCD0x11
DCD0x22
……
DCD0x0
END
10并编写了如下的汇编程序:
问:
现执行上述程序,请列出R0,R1,R2的最终值,并告知整个程序的功能。
R0=1
R1=2
R2=1
功能:
对R0和R1分别赋值0,1,在R1为5的条件下循环给R0赋值R0和R1之和,给R1加1,
取得RESULT的地址赋值于R2,将R0的值保存在RESULT中
11读如下程序
test.s:
test.c:
请列出上述程序执行后R0,R1的值,并说明上述程序的作用。
R0=31
R1=23
功能:
test.c调用s_program函数,将54赋值R0,23赋值R1,两者相减后,赋值给R0,R0作为返回值赋值给num,然后输出num。
12有如下C语言定义的函数mypro
intmypro(inta,intb)
{
a=a*b;
return(a);
}
请补充完成调用上述函数的汇编程序,实现11和22相乘,并要求将结果保存在地址为0x40001000处:
areatest3,code,readonly
importmypro
entry
code32
start
movr0,#11
(1)
movr1,#22
(2)
BLmypro(3)
Ldrr3,=0x40001000(4)
Strr0,[r3](5)
END
13程序段如下,实现下面流程图,试补充编写ARM汇编代码。
\
程序段:
MOVr2,#15
MOVr3,#9
start
;补充代码
stop
Bstop
END
程序:
Start:
CMPr2,r3
SUBLTr3,r3,r2
SUBGTr2,r2,r3
BNEstart
14明指令STMIAr8!
{r0-r7}的操作功能。
将R0-R7八个寄存器中的32位数据,存储到R8地址指针为起始地址的内存中,地址的操作方式是先操作、后增加,并更新地址。
15汇编程序调用C程序的方法为:
首先在汇编程序中使用IMPORT伪指令事先声明将要调用的C语言函数;然后通过BL指令来调用C函数。
(写出注释能把程序写出来,给出程序能将注释写出来)
例如在一个C源文件中定义了如下求和函数:
intprom(intx,inty){
return(x&y);
}
调用prom()函数的汇编程序结构如下:
IMPORTprom;声明要调用的C函数
…
MOVr0,1
MOVr1,2
BLprom;调用C函数prom
16C程序调用汇编子程序的方法为:
首先在汇编程序中使用EXPORT伪指令声明被调用的子程序,表示该子程序将在其他文件中被调用;然后在C程序中使用extern关键字声明要调用的汇编子程序为外部函数。
(写出注释能把程序写出来,给出程序能将注释写出来)
例如在一个汇编源文件中定义了如下求和函数:
EXPORTprom;声明prom子程序将被外部函数调用
…
prom;求和子程序prom
ANDr0,r0,r1
MOVpc,lr
…
在一个C程序的main()函数中对prom汇编子程序进行了调用:
externintprom(intx,inty);//声明prom为外部函数
voidmain(){
inta=1,b=2,c;
c=prom(a,b);//调用prom子程序
…
}
综合编程
1、教材第六章关于GPIO的应用,列举了一个I/O管脚控制4个LED发光二极管的例子,但我们实验箱所提供的LED发光二极管位于不同的引脚,它们分别使用了S3C2410的GPC5,GPC6,GPC7,如下图,请修改原程序段以实现三个灯的交替闪烁(注:
未用引脚设置为input状态)。
(写出注释能把程序写出来,给出程序能将注释写出来)
博创经典版LED接线原理图
相关寄存器定义:
#definerGPCCON(*(volatileunsigned*)0x56000020)
#definerGPCDAT(*(volatileunsigned*)0x56000024)
#definerGPCUP(*(volatileunsigned*)0x56000028)
端口初始化:
voidport_init(void)
{
rGPCCON=0x56aa;
rGPCUP=0xff;//GPF所有端口都不加上拉电阻
}
所有LED交替亮灭:
voidled_on_off(void)
{
inti;
rGPCDAT=0;//所有LED全亮
for(i=0;i<100000;i++);
rGPCDAT=0xE0;//所有LED全灭
for(i=0;i<100000;i++);
}
2.例程:
4个led灯循环亮(会配置端口)
#definerGPEDAT(*(volatileunsigned*)0x56000044)//PortEdata
#definerGPEUP(*(volatileunsigned*)0x56000048)//Pull-upcontrolE
#definerGPHCON(*(volatileunsigned*)0x56000070)//PortHcontrol
#definerGPHDAT(*(volatileunsigned*)0x56000074)//PortHdata
#definerGPHUP(*(volatileunsigned*)0x56000078)//Pull-upcontrolH
/*主程序*/
externvoiddelay(inttimes);
voidxmain(void)
{
rGPECON&=~(3<<22);
rGPECON|=(1<<22);//GPE11设置为output
rGPECON&=~(3<<24);
rGPECON|=(1<<24);//GPE12设置为output
rGPHCON&=~(3<<8);
rGPHCON|=(1<<8);//GPH4设置为output
rGPHCON&=~(3<<12);
rGPHCON|=(1<<12);//GPH6设置为output
while
(1)
{
rGPEDAT&=~(1<<11);//GPE11output0
rGPEDAT|=(1<<12);//GPE12output1
rGPHDAT|=(1<<4);//GPH4output1
rGPHDAT|=(1<<6);//GPH6output1
delay(200000);//delay
rGPEDAT|=(1<<11);//GPE11output1
rGPEDAT&=~(1<<12);//GPE12output0
rGPHDAT|=(1<<4);//GPH4output1
rGPHDAT|=(1<<6);//GPH6output1
delay(200000);//delay
rGPEDAT|=(1<<11);//GPE11output1
rGPEDAT|=(1<<12);//GPE12output1
rGPHDAT&=~(1<<4);//GPH4output0
rGPHDAT|=(1<<6);//GPH6output1
delay(200000);//delay
rGPEDAT|=~(1<<11);//GPE11output1
rGPEDAT|=(1<<12);//GPE12output1
rGPHDAT|=(1<<4);//GPH4output1
rGPHDAT&=~(1<<6);//GPH6output0
delay(200000);//delay
}
}
3.通过对G口的操作控制CPU板左下角的LED1和LED2实现轮流闪烁。
(写出注释能把程序写出来,给出程序能将注释写出来)
voidMain(void){
intflag,i;
Target_Init();//进行硬件初始化操作,包括对I/O口的初始化操作
for(;;){
if(flag==0){
for(i=0;i<1000000;i++);//延时
rGPGCON=rGPGCON&0xffff00ff|0x00002800;//配置第6、第7位为输出引脚
rGPGDAT=rGPGDAT&0x8f|0x8f;//第6位输出为低电平第7位输出高电平
for(i=0;i<10000000;i++);//延时
flag=1;
}
else{
for(i=0;i<1000000;i++);//延时
rGPGCON=rGPGCON&0xffff00ff|0x00002800;//配置第6、第7位为输出引脚
rGPGDAT=rGPGDAT&0x4f|0x4f;//第6位输出为高电平第7位输出低电平
for(i=0;i<1000000;i++);//延时
flag=0;
}
}
}
4、列举了一个通过按钮产生中断请求的实验例子,但我们实验箱所提供的按钮位于不同的引脚,如下图,按键接到INT5中断。
博创经典版中断实验电路图
请修改原程序段以实现实例中要求的功能(即当按钮按下,向CPU发出中断请求,当CPU受理中断后,进入相应的中断服务程序,通过超级终端的主窗口显示当前进入的中断号)(有关EXTINTn参数配置请参考附件“EXTINTn参数.doc”(注:
直接在原来的程序上修改,并删除同此实验要求无关的原有代码部分)。
相关寄存器定义:
#definerGPFCON(*(volatileunsigned*)0x56000050)//端口F的控制寄存器
#definerEXTINT0(*(volatileunsigned*)0x56000088)//外部中断控制寄存器0
#definerEINTMASK(*(volatileunsigned*)0x560000a4)//外部中断屏蔽寄存器
#definerEINTPEND(*(volatileunsigned*)0x560000a8)//外部中断挂起寄存器
#definerINTMSK(*(volatileunsigned*)0x4a000008)//中断屏蔽寄存器
#definerSRCPND(*(volatileunsigned*)0x4a000000)//源挂起寄存器
#definerINTPND(*(volatileunsigned*)0x4a000010)//中断挂起寄存器
中断初始化:
(下面程序写出注释能把程序写出来,给出程序能将注释写出来)
voidint_init(void)
{
rGPFCON=(rGPFCON&~(3<<0))|(0x2<<0);//将GPF0配置为EINT5
pISR_EINT5=(UINT32T)int0_int;//注册中断处理函数
rEINTPEND=0xffffff;//清除所有外部中断挂起状态
rSRCPND=BIT_EINT5;//清除源的挂起状态
rINTPND=BIT_EINT5;//清除挂起状态
rEXTINT0=(rEXTINT0&~(7<<0))|(0x2<<0);//EINT5下降沿触发
rINTMSK&=~(BIT_EINT0);//打开INTMSK中的中断0
}
中断处理函数:
void__irqint0_int(void)//外部中断0处理函数
{
uart_printf("EINT0interruptoccurred.\n");
ClearPending(BIT_EINT0);//清除中断源
}
#defineClearPending(bit)
{rSRCPND=bit;
rINTPND=rINTPND;}//precentwritewrongdata
}//清除中断源,注意清除的顺序,要从源头开始清除
5.阅读下列和看门狗有关的寄存器描述,解释每一行代码的功能。
看门狗定时器控制寄存器(WTCON)
寄存器
地址
读/写
描述
初始值
WTCON
0x53000000
读/写
看门狗定控制寄存器
0x8021
WTCON的标识位
WTCON
Bit
描述
初始值
PrescalerValue
[15:
8]
预装比例值,有效范围值为0~255
0x80
Reserved
[7:
6]
保留
00
WatchdogTimer
[5]
使能和禁止看门狗定时器
0=禁止看门狗定时器
1=使能看门狗定时器
0
ClockSelect
[4:
3]
这两位决定时钟分频因素
00:
1/1601:
1/32
10:
1/6411:
1/128
00
InterruptGeneration
[2]
中断的禁止和使能
0=禁止中断产生
1=使能中断产生
0
Reserved
[1]
保留
0
Reset
Enable/Disable
[0]
禁止很使能看门狗复位信号的输出
1=看门狗复位信号使能
0=看门狗复位信号禁止
1
看门狗定时器数据寄存器(WTDAT)
寄存器
地址
读/写
描述
初始值
WTDAT
0x53000004
读/写
看门狗数据寄存器
0x8000
看门狗计数寄存器(WTCNT)
寄存器
地址
读/写
描述
初始值
WTCNT
0x53000008
读/写
看门狗计数器当前值
0x8000
#definerWTCON(*(volatileunsigned*)0x53000000)//第1行
#definerWTDAT(*(volatileunsigned*)0x53000004)//第2行
#definerWTCNT(*(volatileunsigned*)0x53000008)//第3行
voidwatchdog_test(void)
{
rWTCON=((PCLK/1000000-1)<<8)|(3<<3)|(1<<2);//第4行
rWTDAT=7812;//第5行
rWTCNT=7812;//第6行
rWTCON|=(1<<5);//第7行
}
第1-3行:
定义看门狗控制寄存器、数据寄存器和计数寄存器为rWTCON、rWTDAT和rWTCNT。
第4行:
设置看门狗的预装比例值为,分频因素为1/128,并使能中断。
第5-6行:
对数据寄存器和计数寄存器赋值为7812。
第7行:
启动看门狗。
6.阅读下列和定时器有关的寄存器描述,解释每一行代码的功能。
(1)定时器预分频器配置寄存器(TCFG0)的含义
(2)定时器控制寄存器(TCON)
TCON
位
表述
初始状态
保留
[7:
5]
保留
死区
[4]
0:
死区使无效;1:
死区使能
0
定时器0自动加载
[3]
0不自动加载,1自动加载
0
定时器0输出反转
[2]
0不反转,1反转
0
定时器0手动更新位
[1]
0:
无用,
1:
将TCNTBn/TCMPBn寄存器的值装入内部寄存器TCNTn\TCMPn中
0
定时器0开启停止位
[0]
0:
停止定时器,1:
开始定时器
0
(3):
DMA模式和分频选择寄存器(TCFG1)
(4)定时器计数缓冲寄存器(TCNTBn)
程序:
#definerTCFG0(*(volatileunsigned*)0x51000000)//第1行
#definerTCFG1(*(volatileunsigned*)0x51000004)//第2行
#definerTCON(*(volatileunsigned*)0x51000008)//第3行
#definerTCNTB4(*(volatileunsigned*)0x5100003c)//第4行
⏹voidinit_Time0()
{
//定时器输入时钟频率=PCLK/{预分频值+1}/分频值
rTCFG0=49;//预分频值=49;
rTCFG1&=~(0xf<<0);
rTCFG1|=(1<<0); /