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

news/2024/6/3 18:33:03 标签: stm32, c语言, 反汇编

文章目录

  • 一. C语言调用汇编函数
      • 1. 项目创建
      • 2. 编写代码
      • 3. 配置环境及代码运行
        • (1)仿真器设置以及编译
        • (2)程序调试
  • 二. 修改函数功能
        • (1)修改代码
        • (2)设置断点
        • (3)编译并调试
  • 三. 汇编函数调用C语言函数
        • (1)新建func_.s、main_.c
        • (2)编写代码
        • (3)编译并调试
  • 四. 总结
  • 五. 参考文献

在基于Keil5创建STM32汇编语言工程的基础上,继续学习Keil5下的STM32的C与汇编语言混合编程.

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

一. C语言调用汇编函数

1. 项目创建

  • 创建工程test2,添加文件func.smain.c,我选择的芯片是STM32F103C8,具体步骤参考基于Keil5创建STM32汇编语言工程

2. 编写代码

  • 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段
	
LOOP_END   ;写在最左边的是程序段的段名,执行跳转程序时要用到
	NOP
	
	END    ;必须空格后再写END,不然会被认为是段名,表示程序结束。

  • main.c
#include<stdio.h>
extern void Init_1(void);
int main()
{
	Init_1();
	return 0;
}

3. 配置环境及代码运行

(1)仿真器设置以及编译

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

(2)程序调试

  • Ctrl+F5,开始调试
    在这里插入图片描述
  • 设置断点
    在这里插入图片描述
  • 点击Step进行单步调试
    在这里插入图片描述
    在这里插入图片描述
    观察R1、R2的寄存器值的变化,发现其由0逐步加到10
    说明C语言成功调用汇编程序!

二. 修改函数功能

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

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

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

(2)设置断点

在这里插入图片描述
在这里插入图片描述

(3)编译并调试

点击Run to Cursor Line
在这里插入图片描述

在这里插入图片描述
在这里插入图片描述
在main函数调用Init_1函数,给的参数10,函数执行完时,10+100的16进制数为6E,寄存器R0的值也是6E,调用成功!

三. 汇编函数调用C语言函数

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

(1)新建func_.s、main_.c

(2)编写代码

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

(3)编译并调试

  • 点击Rebuild进行编译
  • 设置断点
    在这里插入图片描述
    在这里插入图片描述
    执行get5后,寄存值R0变为5,调用成功!

四. 总结

本文通过具体实例讲解C与汇编语言混合编程的过程,让我们更加深刻的体会到C调用汇编语言以及汇编调用C的原理,也对调用函数参数的传递方式以及ARM寄存器使用方法有了一定的理解。C语言调用汇编程序要在C程序中用EXTERN声明,在汇编文件里用EXPORT将C函数与汇编函数联系起来;汇编程序调用C语言文件时要在汇编文件里用IMPORT。
文章仅供参考,若有纰漏,欢迎大家一起讨论~

五. 参考文献

https://blog.csdn.net/qq_45659777/article/details/120651310
https://blog.csdn.net/longintchar/article/details/79511747


http://www.niftyadmin.cn/n/1314736.html

相关文章

【git】之分支管理

git是鼓励开发者使用分支&#xff0c;尤其是在大型开发项目中&#xff0c;分支是非常重要的&#xff01;这里简单介绍一下分支的操作&#xff01; 1、创建分支 git branch 没有参数&#xff0c;显示本地版本库中所有的本地分支名称。 当前检出分支的前面会有星号。git branch n…

STM32F103寄存器方式点亮LED

文章目录一. STM32F103系列芯片的映射原理什么是寄存器&#xff1f;&#xff08;1&#xff09;地址映射&#xff08;2&#xff09;寄存器映射二. GPIO端口的初始化设置步骤&#xff08;1&#xff09;GPIO介绍&#xff08;2&#xff09;时钟配置&#xff08;3&#xff09;输入输…

文言文的理解 —— 字词篇

梼杌&#xff1a;to w&#xff0c;中国神话中上古时期的四凶之一&#xff1b; 《史记.五帝本纪》中的记述是&#xff1a;帝鸿氏之不才子“浑敦”、少皞氏之不才子“穷奇”、颛顼&#xff08;zhuān Xū&#xff0c;季氏将伐颛&#xff08;zhuān&#xff09;臾&#xff08;y&am…

STM32CubeMX+Keil使用HAL库点灯

文章目录一. CubeMX的安装二. 用CubeMX新建工程点亮LED灯1. STM32CubeMX生成工程文件2. 配置引脚3. 配置时钟4. 配置调试模式5. 工程管理6. 添加代码7. 硬件的烧录三. keil观察GPIO端口的输出波形1. 设置仿真模式2. 使用逻辑分析仪四. 总结五. 参考文献一. CubeMX的安装 STM32C…

STM32串口通信以及USB/TTL转232工作原理

文章目录一. 串口通信协议1. 简介2. RS-232 标准3. RS232电平与TTL电平的区别二. USB转串口工作原理USB转串口CH340接线三. 实例——STM32的USART串口通信1. CH340驱动安装2. 编写代码3. 烧录程序4.串口调试四. 总结五. 参考文献一. 串口通信协议 1. 简介 串口通信&#xff1…

基于STM32的中断及DMA通信

文章目录一. STM32之中断1. 何为中断2. 实例&#xff08;1&#xff09;——CubeMX中断点灯&#xff08;1&#xff09;配置调试模式&#xff08;2&#xff09;外设配置&#xff08;3&#xff09;时钟配置&#xff08;4&#xff09;工程管理&#xff08;5&#xff09;添加代码并编…

cURL(wget)—— 测试 RESTful 接口及模拟 GET/POST/PUT/DELETE/OPTIONS 请求

cURL 是一个简单的 http 命令行工具。与最优秀的 Unix 工具一样&#xff0c;在设计之时&#xff0c;cURL 是个小型程序&#xff0c;功能十分专一&#xff0c;而且是故意为之&#xff0c;仅用于访问 http 服务器。&#xff08;在 Linux 中&#xff0c;可以使用包管理器轻易安装&…

两台电脑串口通信实现文件传输

文章目录一. 实验过程1. 准备工作2. 传输文件3. 对比实际传输时间与预算传输时间4. 探究波特率和传输时间之间的关系5. 探究文件大小和传输时间之间的关系二. 总结本文将两台笔记本电脑&#xff0c;借助usb转rs232模块和杜邦线&#xff0c;建立起串口连接。然后用串口助手工具软…