Keil下STM32的C语言和汇编语言混合编程

一、简介

C语言直观,易上手,且适用普及范围广,汇编语言效率高,内存占用少。两者结合,取长补短,是最佳的选择

二、实例题目要求

  • 参考附件资料,完成C语言调用汇编函数
  • 修改参考代码,要求将原汇编语言 Init_1函数的类型改为 int Init_1(init) ,此函数功能修改为传入一个整型数x,函数运行后返回整型数 x+100。 请编程实现,并仿真跟踪调试;
  • 如果要求在汇编函数中调用一个 C语言写的函数,应该如何修改汇编代码?

参考代码如下:
C语言部分:

#include<stdio.h>

extern void Init_1(void);

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

汇编语言部分:

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

三、实例第一部分

1.准备工作

  • 首先应该在keil中新建工程并创建两个文件用于存放代码

如果有不熟悉如何在keil中新建工程的小萌新可以参考我之前的博客:基于Keil5创建STM32汇编语言工程以及hex文件分析

  • 注:在创建两个文件时,一个应该选择C File(.c)文件,一个应该选择Asm File(.s)文件,如下图:
    在这里插入图片描述

2.代码部分

  • 将参考代码中的两部分代码分别存放在各自的文件中,如图,我将汇编语言存放在Funs.s文件下,C语言存放在main.c文件下
    在这里插入图片描述
    在这里插入图片描述

3.环境配置和调试

(1)环境配置

  • 点击打开魔法棒,在Debug下选择Use Simulator,并将左下的Dialog DLL中的内容改为DARMSTM.DLL,将Parameter的内容改为-pSTM32F103C8
    在这里插入图片描述

  • 点击Rebuild,进行编译,显示0 error,表示代码无误
    在这里插入图片描述
    在这里插入图片描述

(2) 调试

  • 编译无误后,点击Start Debug Session开始调试
    在这里插入图片描述

  • 在main.c中增加断点
    在这里插入图片描述
    在这里插入图片描述

  • 点击Step进行单步调试
    在这里插入图片描述

  • 如图,寄存器R1、R2变为0,表明程序已经从C语言出调用到汇编语言中
    在这里插入图片描述

  • 如图,寄存器R1、R2逐步增加1,表明函数能执行其功能,说明C语言调用汇编程序成功!
    在这里插入图片描述

四、实例第二部分(修改函数功能)

将原汇编语言 Init_1函数的类型改为 int Init_1(init),此函数功能修改为传入一个整型数x,函数运行后返回整型数x+100

1.代码部分

在Keil中,子函数的参数值传递按顺序存放到了R0、R1、R2、R3中,超过四个参数值传递放栈帧里。所以Init_1(10)传入的10放到了R0中,由MOV PC,LR返回110.

main.c代码:

#include<stdio.h>

extern int Init_1(int x);

int main(){
	
	int y = Init_1(10);
	printf("%d", y);
	
	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,不然会被认为是段名,表示程序结束

2.调试

  • 设置断点,如图
    在这里插入图片描述
    在这里插入图片描述
  • 点击ctrl+F5进入调试,并根据实例一调试步骤进行调试
    在这里插入图片描述
    在这里插入图片描述
    如图显示:R0的寄存器的值为6E,将16进制转化为10进制,寄存器R0的值也就是110。在main函数调用Init_1函数,给的参数10,函数执行完时,值变为10+100,也是110,与寄存器R0的值相同,调用成功!

五、实例第三部分(汇编调用C语言函数)

在汇编中调用C语言函数XXX,则加上IMPORT XXX,注意Keil工具不允许汇编语句顶格写,否则会报错

1.代码部分

Funs.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 get8(void)
{
     return 8;
}
int main()
{
	Init_1();
	
	return 0;
}

2.调试

  • 设置断点,如图:
    在这里插入图片描述
    在这里插入图片描述
  • 编译后,ctrl+F5进入调试
    在这里插入图片描述
  • 按实例一部分进行调试后,结果如图:
    在这里插入图片描述
    寄存器R0的值变为了8,表明C语言函数调用成功!

六、总结

通过本篇博客的学习,读者可以通过三个具体的实例了解到C语言和汇编语言的混合使用。采用C语言和汇编语言的混合使用在节约存储空间的同时,又能直观的读出程序的内容。读者可以多多使用这种混合的方法,通过多次的实际操作,真正掌握C语言和汇编的混合使用方法。文章仅供参考,若有纰漏,欢迎大家一起讨论纠正。

七、参考资料

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值