Loading

嵌入式作业2.1 汇编练习

原始参考代码(main.s)

汇编代码:

//=====================================================================
//文件名称:main.s
//功能概要:汇编编程调用GPIO构件控制小灯闪烁(利用printf输出提示信息)
//版权所有:SD-ARM(sumcu.suda.edu.cn)
//版本更新:20180810-20191018
//=====================================================================
.include "include.inc"    //头文件中主要定义了程序中需要使用到的一些常量
//(0)数据段与代码段的定义
//(0.1)定义数据存储data段开始,实际数据存储在RAM中
.section .data
//(0.1.1)定义需要输出的字符串,标号即为字符串首地址,\0为字符串结束标志
hello_information:           //字符串标号
    .ascii "-------------------------------------------------------\n"
    .ascii "金葫芦提示:                                             \n"
    .ascii "1、本程序用来示范如何输出指令所在flash单元的地址以及指令  \n"
    .ascii "所对应的机器码。                                        \n"
    .ascii "2、Debug文件夹中的.lst文件可搜索汇编指令找到对应的机器码。\n"
    .ascii "3、printf函数可根据输出格式输出参数的值。                \n"
    .ascii "------------------------------------------------------\n\0"
data_format:
    .ascii "%d\n\0"                 //printf使用的数据格式控制符

data_format1:
    .ascii "%08x:%02x\n\0"                 //printf使用的数据格式控制符,其中8表示输出位数,
                                         //0表示将输出的前面补上0,直到占满指定列宽为止
 
light_show1:
	.ascii "LIGHT_BLUE:ON--\n\0"    //灯亮状态提示   
light_show2:
	.ascii "LIGHT_BLUE:OFF--\n\0"   //灯暗状态提示
light_show3:
	.ascii "闪烁次数mLightCount=\0"  //闪烁次数提示
//(0.1.2)定义变量
.align 4               //.word格式四字节对齐
mMainLoopCount:		   //定义主循环次数变量
	.word 0
mFlag:				   //定义灯的状态标志,1为亮,0为暗
	.byte 'A'	
.align 4
mLightCount:
    .word 0

//(0.2)定义代码存储text段开始,实际代码存储在Flash中
.section   .text
.syntax unified        //指示下方指令为ARM和thumb通用格式
.thumb                 //Thumb指令集
.type main function    //声明main为函数类型                     
.global main           //将main定义成全局函数,便于芯片初始化之后调用
.align 2               //指令和数据采用2字节对齐,兼容Thumb指令集

//--------------------------------------------------------------------                        
//main.c使用的内部函数声明处

//--------------------------------------------------------------------
//主函数,一般情况下可以认为程序从此开始运行(实际上有启动过程,参见书稿)
main:
//(1)======启动部分(开头)主循环前的初始化工作======================
//(1.1)声明main函数使用的局部变量

//(1.2)【不变】关总中断
	cpsid i   
//(1.3)给主函数使用的局部变量赋初值
	
//(1.4)给全局变量赋初值
	
//(1.5)用户外设模块初始化
//  初始化蓝灯, r0、r1、r2是gpio_init的入口参数
	ldr r0,=LIGHT_BLUE     //r0指明端口和引脚(用=,因常量>=256,需用ldr)
	mov r1,#GPIO_OUTPUT    //r1指明引脚方向为输出
	mov r2,#LIGHT_OFF       //r2指明引脚的初始状态为亮
	bl  gpio_init          //调用gpio初始化函数
//  初始化串口UART_User1
	mov r0,#UART_User       //串口号
	ldr r1,=UART_BAUD       //波特率
	bl uart_init            //调用uart初始化函数
//(1.6)使能模块中断
    mov r0,#UART_User       //串口号
    bl  uart_enable_re_int  //调用uart中断使能函数

//(1.7)【不变】开总中断
	cpsie  i  
//显示hello_information定义的字符串
	ldr r0,=hello_information   //待显示字符串首地址
	bl  printf		            //调用printf显示字符串
	
	//bl .   //在此打桩(.表示当前地址),理解发光二极管为何亮起来了?

	
//(1)======启动部分(结尾)=======================================

//(2)======主循环部分(开头)=====================================
main_loop:                      //主循环标签(开头)
//(2.1)主循环次数变量mMainLoopCount+1
		ldr r2,=mMainLoopCount     //r2←mMainLoopCount的地址
		ldr r1, [r2]
		add r1,#1
		str r1,[r2]	
//(2.2)未达到主循环次数设定值,继续循环
        ldr r2,=MainLoopNUM
		cmp r1,r2
		blO  main_loop     //未达到,继续循环
//(2.3)达到主循环次数设定值,执行下列语句,进行灯的亮暗处理

//测试代码部分[理解机器码存储]
Label:	
	MOV  R0,#0xDE               //立即数范围为0x00~0xFF
	
	ldr r0,=data_format1        //输出格式送r0 
	ldr r1,=Label               //r1中是Label地址
	ldrb r2,[r1]                //r2中是Label地址中的数据
	bl  printf	
	
	ldr r0,=data_format1         //输出格式送r0 
	ldr r1,=Label+1              //r1中是Label+1地址
	ldrb r2,[r1]                 //r2中是Label+1地址中的数据
	bl  printf	
	
	ldr r0,=data_format1         //输出格式送r0 
	ldr r1,=Label+2              //r1中是Label+2地址
	ldrb r2,[r1]                 //r2中是Label+2地址中的数据
	bl  printf	
	
	ldr r0,=data_format1         //输出格式送r0 
	ldr r1,=Label+3              //r1中是Label+3地址
	ldrb r2,[r1]                 //r2中是Label+3地址中的数据
	bl  printf	

//(2.3.1)清除循环次数变量
		ldr r2,=mMainLoopCount     //r2←mMainLoopCount的地址
		mov r1,#0
		str r1,[r2]	
//(2.3.2)如灯状态标志mFlag为'L',灯的闪烁次数+1并显示,改变灯状态及标志	
		//判断灯的状态标志
		ldr r2,=mFlag		   
		ldr r6,[r2]
		cmp r6,#'L'			
		bne main_light_off	   //mFlag不等于'L'转
		//mFlag等于'L'情况
		ldr r3,=mLightCount	   //灯的闪烁次数mLightCount+1
		ldr r1,[r3]
		add r1,#1				
		str r1,[r3]
		ldr r0,=light_show3   //显示“灯的闪烁次数mLightCount=”
		bl  printf				
		ldr r0,=data_format    //显示灯的闪烁次数值
		ldr r2,=mLightCount
		ldr r1,[r2]
		bl  printf	
		ldr r2,=mFlag           //灯的状态标志改为'A'
		mov r7,#'A'
		str r7,[r2]             
		ldr r0,=LIGHT_BLUE      //亮灯
		ldr r1,=LIGHT_ON
		bl  gpio_set          
		ldr r0, =light_show1    //显示灯亮提示
		bl  printf	
		//mFlag等于'L'情况处理完毕,转
		b main_exit  
//(2.3.3)如灯状态标志mFlag为'A',改变灯状态及标志
main_light_off:
        ldr r2,=mFlag		   //灯的状态标志改为'L'        
		mov r7,#'L'
		str r7,[r2]   
        ldr r0,=LIGHT_BLUE      //暗灯
		ldr r1,=LIGHT_OFF
		bl  gpio_set  
        ldr r0, =light_show2    //显示灯暗提示
		bl  printf	
main_exit:
	b main_loop                 //继续循环
//(2)======主循环部分(结尾)=====================================
.end     //整个程序结束标志(结尾)

运行结果:

image-20240327200801792

蓝灯持续闪烁

作业

一、翻译汇编成C语言

将参考代码中 94~101行语句用C语言描述。

  • 汇编语句
main_loop:
		ldr r2,=mMainLoopCount
		ldr r1, [r2]
		add r1,#1
		str r1,[r2]
        ldr r2,=MainLoopNUM
		cmp r1,r2
		blO  main_loop
  • C 语言描述
const uint32_t MainLoopNUM = 6122338;
uint32_t mMainLoopCount = 0;
do
{
    mMainLoopCount += 1;
}while(mMainLoopCount < MainLoopNUM);

二、修改参考代码

  1. 在第一行显示 “广州大学” 字样。

增加代码:

.section .data
...
ToolTips:
	.ascii "广州大学 32106100066\n\0"
data_format2:
	.ascii "%s\n\0"
...
main:
...
tip:							//打印提示信息:广州大学
	ldr r0,=data_format2
	ldr r1,=ToolTips
	bl printf
bl .
...
main_loop:

运行结果

  1. 编写一个 1+2+...+10 的程序,将求和结果存入名为 “sumresult” 的内存单元中,并将求和结果用 printf 显示出来

增加代码:

.section .data
...
data_format3:
	.ascii "%s%d\n\0"
sum_show:
	.ascii "1+2+3+4+5+6+7+8+9+10=\0"
...
sumresult:
	.word 0
...
main:
...
sum:							//求和计算程序
	mov r0,#0
	mov r1,#1
	mov r2,#10
sum_loop:						//for循环计算
	cmp r1,r2
	bhi sum_outcome
	add r0,r1
	add r1,#1
	b sum_loop
sum_outcome:					//保存并打印结果
	ldr r1,=sumresult
	str r0,[r1]					//存储到sumresult
	ldr r0,=data_format3
	ldr r1,=sum_show
	ldr r3,=sumresult
	ldr r2,[r3]
	bl  printf
bl .
...
main_loop:

运行结果:

  1. 编写示例程序:datax、datay、dataz 三个数中,找出最大值并显示。

增加代码:

.section .data
...
data_format4:
	.ascii "0x%x、0x%x、0x%x\0"
data_format5:
	.ascii "%s0x%x\n\0"
max_show:
	.ascii " 进行有符号比较,其中最大值为:\0"
...
datax:
	.word 0x87654321
datay:
	.word 0x12345678
dataz:
	.word 0x06100066
datamax:
	.word 0
...
main:
...
compare1:						//对三个数进行有符号比较得出最大值datamax
	ldr r2,=datax
	ldr r0,[r2]
	ldr r2,=datay
	ldr r1,[r2]
	cmp r0,r1
	blt save2
save1:
	ldr r2,=datamax
	str r0,[r2]
	b compare2
save2:
	ldr r2,=datamax
	str r1,[r2]
	b compare2
compare2:		
	ldr r2,=datamax
	ldr r0,[r2]
	ldr r2,=dataz
	ldr r1,[r2]
	cmp r0,r1
	blt save4
save3:
	ldr r2,=datamax
	str r0,[r2]
	b max_outcome
save4:
	ldr r2,=datamax
	str r1,[r2]
	b max_outcome
max_outcome:	
	ldr r0,=data_format4
	ldr r6,=datax
	ldr r1,[r6]
	ldr r6,=datay
	ldr r2,[r6]
	ldr r6,=dataz
	ldr r3,[r6]
	bl printf	
	ldr r0,=data_format5
	ldr r1,=max_show
	ldr r3,=datamax
	ldr r2,[r3]
	bl printf
bl .
...
main_loop:

运行结果:

posted @ 2024-03-27 23:56  一只心耳  阅读(40)  评论(0编辑  收藏  举报