STM32的C和汇编语言混合编程
实验要求:
-
参考附件资料,完成C语言调用汇编函数;
-
修改参考代码,要求将原汇编语言 Init_1函数的类型改为 int Init_1(init) ,此函数功能修改为 传入一个整型数x,函数运行后返回整型数 x+100。 请编程实现,并仿真跟踪调试;
-
如果要求在汇编函数中调用一个 C语言写的函数,应该如何修改汇编代码?
一、 搭建所需要的实验环境
1、 首先点击 Project ——> Open Project,打开之前实验“STM32汇编语言编程与仿真调试”创建的工程。
配置环境如下:
工程的目标环境设置为STM32F103C8;
CMSIS下选择CORE,Device下选择Startup;
Output 中勾选 Create HEX File 生成 hex 文件;
Debug中选择“Use Simulator”,设置Dialog DLL项为“DARMSTM.DLL”,parameter项为“-pSTM32F103C8”。
其次添加文件:
2、右击 Source Group 1 ,点击 Add New Item to Group;点击 Asm Files (.s)创建汇编文件Func.s 和C Flie(.c)创建C语言文件main.c,输入文件名。
二、C语言调用汇编语言
1、代码:
main.c:
#include<stdio.h>
extern void Init_1(void);
int main()
{
Init_1();
return 0;
}
Func.s:
AREA My_Function,CODE,READONLY ;这一行必要的除了My_Function可以自己取名以外,其他的都是模板
EXPORT Init_1 ; 与在c文件中定义的Init_1函数关联起来
; 高级语言中的声明和使用变量其实是对板子寄存器的使用,所以我们只需要直接使用寄存器即可
Init_1
MOV R1,#0 ; 设R1寄存器为i
MOV R2,#0 ; 设R2寄存器为j
LOOP ; 写在最左边的是程序段的段名,执行跳转程序时用到
CMP R1,#10 ; 比较R1和10的大小
BHS LOOP_END ; 如果R1大于等于10,则跳转到LOOP_END程序段,反之忽略该语句,直接执行下面的语句
ADD R2,#1 ; j++
ADD R1,#1 ; i++
B LOOP ; 循环
LOOP_END
NOP
END ; 必须空格后再写END,不然会被认为是段名,表示程序结束
2、编译和调试程序:
程序进入循环,R1和R2一次+1
最终 R1和R2会加到10:
三、修改程序并调试:
1、代码:
main.c:
# include<stdio.h>
extern int Init_1(int x);
int main(){
int xx=Init_1(10);
printf("%d",xx);
return 0;
}
Func.s:
AREA My_Function,CODE,READONLY
EXPORT Init_1 ; 与在c文件中定义的Init_1函数关联起来
; 高级语言中的声明和使用变量其实是对板子寄存器的使用,所以我们只需要直接使用寄存器即可
Init_1
ADD R0,#100 ; 将传入的值+100
MOV PC,LR ; LR(R14)保存返回地址,PC(R15)是当前地址,把LR给PC就是从子程序返回,返回R0
LOOP ; 写在最左边的是程序段的段名,执行跳转程序时用到
CMP R1,#10 ; 比较R1和10的大小
BHS LOOP_END ; 如果R1大于等于10,则跳转到LOOP_END程序段,反之忽略该语句,直接执行下面的语句
ADD R2,#1 ; j++
ADD R1,#1 ; i++
B LOOP ; 循环
LOOP_END
NOP
END ; 必须空格后再写END,不然会被认为是段名,表示程序结束
在ARM编程里,函数调用过程中,子函数的参数值传递按顺序存放在R0,R1,R2,R3里,超过4个参数值传递放栈帧里。 MOV PC,LR的作用:LR(R14)保存返回地址,PC(R15)是当前地址,把LR给PC就是从子程序返回。因此:Init_1(10)传入的10放到R0中,由MOV PC,LR返回110。
2、编译调试:
此时此时,Init_1(10)
的10
被自动传入R0。
此时,xx
的值为0x6E
,即110
,调用成功。
四、 汇编语言调用c程序
1、代码:
Func.s:
AREA My_Function,CODE,READONLY
EXPORT Init_1 ; 与在c文件中定义的Init_1函数关联起来
IMPORT get8 ; 声明get8为外部引用
; 高级语言中的声明和使用变量其实是对板子寄存器的使用,所以我们只需要直接使用寄存器即可
Init_1
MOV R1,#0 ; 设R1寄存器为i
MOV R2,#0 ; 设R2寄存器为j
LOOP ; 写在最左边的是程序段的段名,执行跳转程序时用到
CMP R1,#10 ; 比较R1和10的大小
BHS LOOP_END ; 如果R1大于等于10,则跳转到LOOP_END程序段,反之忽略该语句,直接执行下面的语句
ADD R2,#1 ; j++
ADD R1,#1 ; i++
BL get8 ; 调用get8,返回的值传入R0
B LOOP ; 循环
LOOP_END
NOP
END ; 必须空格后再写END,不然会被认为是段名,表示程序结束
main.c:
# include<stdio.h>
extern void Init_1(void);
int get5(void)
{
return 8;
}
int main()
{
Init_1();
return 0;
}
2、编译和调制:
此时,执行get8
后,R0
变为了8
,即成功调用。
五、总结
在本次实验中,我对于c语言和汇编语言的混合编程又了更加深入的了解 ,在整个实验的过程中我遇到了很多的问题,在互联网和同学的帮助之下,顺利完成了这次的实验,使我收获颇丰,学到了挺多的东西。