STM32下C语言与汇编语言混合编程

目录

一、新建一个工程

1.新建工程 

2.代码 

 二、C语言中调用汇编函数

 1.无参数的调用

 2.带有参数的调用

 三、汇编语言中调用C语言函数

 四、寄存器的使用规则

 五、参考文献


 

一、新建一个工程

1.新建工程 

打开下载好的MDK5,点击project,创建一个新的工程,命名文件并且保存,选择芯片,我选择的是STM32F103C8,然后点击CMSIS,勾选CORE选项,点击Device,勾选Starup选项,点击OK完成设置。

 然后添加源main.c和func.s文件至Source Group 1

2.代码 

func.s

	AREA	MY_FUNCTION,CODE,READONLY
	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,不然会被认为是段名,表示程序结束

main.c

# include<stdio.h>

extern void	Init_1(void);

int main(){
	
	Init_1();
	
	return 0;
}

 二、C语言中调用汇编函数

 1.无参数的调用

上述代码进行编译运行,没有错误

 然后设置断点,并进行调试,如图:

 

 程序进入循环,R1与R2不断加一,最终加到10

 如上图,均变成0x00……00A即10。

 2.带有参数的调用

修改后的代码:

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		; 返回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,不然会被认为是段名,表示程序结束

 编译调试

此时,Init_1(10)10被自动传入R0。 

 

如上图,xx的值为0x6E,即110,调用成功。

ARM中,子函数的参数值传递按顺序存放在r0,r1,r2,r3里,超过4个参数值传递放栈帧里。
因此Init_1(10)传入的10放到了R0,由MOV PC,LR返回110。

 三、汇编语言中调用C语言函数

修改后的代码:

main.c 

# include<stdio.h>

extern void	Init_1(void);

int get5(void);

int main(){
	
	printf("Begin...\n");
	Init_1();

	return 0;
}

int get5(){
	return 5;
}

 func.s

	AREA	MY_Function,CODE,READONLY
	EXPORT 	Init_1  ; 与在c文件中定义的Init_1函数关联起来
	IMPORT  get5    ; 声明get5 为外部引用


; 高级语言中的声明和使用变量其实是对板子寄存器的使用,所以我们只需要直接使用寄存器即可

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 get5  	  ; 调用get5,返回的值传入R0
	B LOOP		  ; 循环
	
LOOP_END
	NOP	

	END  ; 必须空格后再写END,不然会被认为是段名,表示程序结束

 设置断点之后调试,如图

 

 执行get5后,R0变为了5,成功调用。

 四、寄存器的使用规则

在ARM编程里,函数调用过程中,子函数的参数值传递按顺序存放在r0,r1,r2,r3里,超过4个参数值传递放栈帧

r0-r3 用作传入函数参数,传出函数返回值。在子程序调用之间,可以将 r0-r3 用于任何用途。被调用函数在返回之前不必恢复 r0-r3。—如果调用函数需要再次使用 r0-r3 的内容,则它必须保留这些内容。
r4-r11 被用来存放函数的局部变量。如果被调用函数使用了这些寄存器,它在返回之前必须恢复这些寄存器的值。r11 是栈帧指针 fp。
r12 是内部调用暂时寄存器 ip。它在过程链接胶合代码(例如,交互操作胶合代码)中用于此角色。在过程调用之间,可以将它用于任何用途。被调用函数在返回之前不必恢复 r12。
寄存器 r13 是栈指针 sp。它不能用于任何其它用途。sp 中存放的值在退出被调用函数时必须与进入时的值相同。
寄存器 r14 是链接寄存器 lr。如果您保存了返回地址,则可以在调用之间将 r14 用于其它用途,程序返回时要恢复
寄存器 r15 是程序计数器 pc。它不能用于任何其它用途。

 五、参考文献

STM32的C与汇编语言混合编程_鹤引的博客-CSDN博客STM32的C与汇编语言混合编程混合编程C语言嵌套汇编调用函数操作无参数有参数汇编语言嵌入C语言总结参考混合编程C语言还是有其局限性。有些硬件地址是没有地址一说的。比如处理器的寄存器,协处理器和协处理器的寄存器,系统控制器等。这些硬件资源是不可能使用C语言指针来访问的,这时就只好应用汇编指令了。汇编程序中调用C语言函数汇编程序使用C语言中定义的全局变量、、C语言中使用汇编程序中定义的全局变量C语言中使用汇编程序中定义的全局变量C语言中内嵌汇编指令C语言嵌套汇编调用函数操作无参数C语https://blog.csdn.net/weixin_47554309/article/details/120688906 

寄存器的使用规则_xd1103121507的专栏-CSDN博客1.       子程序之间通过寄存器R0-R3来传递参数,当参数个数多于4个时,使用堆栈来传递参数。此时R0-R3可记作A1-A4.2.       在子程序中,使用寄存器R4-R11保存局部变量。因此当进行子程序调用时要注意对这些寄存器的保存和恢复。此时R4-R11可记作V1-V8.3.       寄存器R12用于保存堆栈指针SP,当子程序返回时使用该寄存器出栈,记作IP.4.https://blog.csdn.net/xd1103121507/article/details/6941169 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值