如何在Cc语言中嵌入汇编编语言,解决方案

最近几天工程师的朋友圈们都已经被STM32峰会相关消息刷……
一场Pokemon
Go,让全世界的小精灵师都暴露了。因此,在……
2016年初,一场人机大战点燃了人工智能芯片的争夺战,而……
随着物联网、5G等不断演进深入,数据量将呈指数式增长。……
一款智能电源模组需要在封装中集成控制、保护、栅极驱动……
演讲人:谢亦峰时间: 10:00:00
演讲人:李唐山时间: 10:00:00
演讲人:杜建中时间: 10:00:00
预算:¥50,000-¥100,000预算:小于¥10,000
在KEIL中实现C语言嵌套汇编语言
[导读]一、讲解背景在单片机学习的过程中,掌握一点汇编语言是非常有必有的,作为低级语言汇编语言在单片机开发中有它不可取代的作用,比如每条指令可以精确的确定延时时间,便于理解非常适合硬件工程师学习。但是要提高单
一、讲解背景
在单片机学习的过程中,掌握一点汇编语言是非常有必有的,作为低级语言汇编语言在单片机开发中有它不可取代的作用,比如每条指令可以精确的确定延时时间,便于理解非常适合硬件工程师学习。但是要提高单片机技能,必须掌握C 语言编程,因为C 语言有强大的模块化管理思想。我想在很多人学习的过程中即学了汇编语言,又学习了C& 语言,那么一个问题便随之而产生,如果将C& 语言与汇编语言相互结合,达到更好的编程效果,本次讲解就是基于这个问题而生成的。
二、操作步骤
在KEIL 中新建工程及文件并复制以下程序并保存为C 文件:
功能:C 语言里嵌套汇编语言,起到抛砖引玉的作用
#include&reg51.h&
for(i=0;i&1000;i++)
for(j=0;j&120;j++); //12M 晶振下延时1MS
P2=0x00; //控制8 个LED 亮
delay(); //延时1S
#pragma ASM//汇编嵌套开始
MOV P2,#0FFH&& //汇编嵌套结束
#pragma ENDASM//汇编嵌套开始
while(1); //C 程序结束
选中 Project&& 窗口中的C& 文件,比如CX1.C,并右键,选择&Options&& for&& ...&,点击右边的&Generate Assembler SRC File&和&Assemble SRC File&,使复选框的打钩由灰色变成黑色状态(双击即可);
将相应的库文件(如 Small&&&&&&& 模式时,是 KeilC51LibC51S.Lib)加入工程中,&&&&&& 该文件必须作为工程的最后文件 (将该文件像头文件一样加载到工程中);
在KEIL 中编译生成HEX 文件,并按如下图设计仿真图,在仿真中查看效果。
三、演示效果
如下图,如果你在你自己的仿真软件PROTEUS 上看到单片机P2& 口控制的8 个LED 先亮延时1S 左右自动熄灭的效果。那说明你已经完全掌握C 语言里嵌套汇编语言的方法了。
  Windows 服务被设计用于需要在后台运行的应用程序以及实现没有用户交互的任务。为了学习这种控制台应用程序的基础知识,C(不是C++)是最佳选择。本文将建立并实现一个简单的服务程序,其功能是查询系统中可用物理......关键字:
在今年的国际消费电子展(CES)上,索尼的OLED电视是一大亮点。索尼新款Bravia系列OLED电视通过来回振动屏幕发出声音,把屏幕转化成了扬声器。不过,这项打着索尼品牌的热门新技术其实来自韩国LG Display公司。
......关键字:
Linux已经在官网发布最新的内核修复这一问题,预计Ryzen 7处理器又能纵横在Linux系统上。......关键字:
自动驾驶汽车到底需不需“监护人”,这是个争论了很久的问题。......关键字:
喝完啤酒就去厕所,厕所里的水回收又可以酿啤酒,又是“毅”种循环啊。......关键字:
12月29日消息,今日下午,针对宽带、4G等问题,工信部信息通信发展司司长闻库在线回答了网友提问。......关键字:
我 要 评 论
热门关键词2705人阅读
Linux(9)
大家知道,用C或者C++等高级语言编写的程序,会被编译器编译成最终的机器指令。这中间,编译器会对代码自动进行优化。但是,这种优化往往不一定非常高效。
所以,出于性能优化的目的,对非常关键的代码,任然需要直接用汇编指令编写。
并且在C和C++中,是无法直接对寄存器进行操作的,如果要实现的功能需要频繁与底层硬件打交道,也需要用汇编指令编写。
GCC编译器支持直接在C或者C++代码中,嵌入ARM汇编代码。其基本格式非常简单,大致如下:
__asm__ [__volatile__] ( assembler template
: [output operand list]
/* optional */
: [input operand list]
/* optional */
: [clobbered register list]
/* optional */
);首先是关键字“__asm__”,其实也可以写成“asm”。但是“asm”并不是所有版本的GCC编译器都支持的,而且有可能和程序中别的地方定义的变量或函数名冲突,所以用“__asm__”的话,兼容性会好一点。
下面是“__volatile__”关键字,这个是可选的,其作用是禁止编译器对后面编写的汇编指令再进行优化。一般情况下,自己写的汇编代码肯定是自己进行设计优化过了的,如果编译器再进行优化的话,很有可能效果还不如不优化,而且也有可能会出现奇怪的错误,所以通常都会带上这个关键字。同样,“__volatile__”也可以写成“volatile”,但可能兼容性会没那么好。
下面,在括号里面的,就是真正的汇编代码了,其主要有四部分组成。第一个是具体的汇编代码,这是必需的。而后面三个是一些辅助参数,这些参数是可选的。
各个部分间使用冒号“:”进行分割。如果前面的部分没有使用,而后面的部分使用了,则前面的部分也需要用冒号留空。例如:
__asm__ __volatile__ (&msr cpsr, %0& : : &r& (status));可以看出,本例中没有第二部分(输出参数列表),只有第三部分(输入参数列表),但它们中间任然要留出冒号进行分割。同时,也没有第四部分,但并不需要在第三部分后面加上冒号。
下面一一解释各个部分的作用:
1)汇编代码模板
所有的汇编代码必须用双引号括起来。如果有多行汇编代码的话,每一条语句都要用双引号括起来,并且在代码后面要加上换行符(“\n”或者“\n\t”)。这样做是因为GCC会将汇编代码部分作为字符串形式直接传给汇编器,加上换行符后,汇编器就能准确知道哪些字符串表示的是一条汇编语句。同时,为了增加可读性,每条汇编语句都可以换行。
其具体形式如下:
__asm__ __volatile__ ( &instruction 1\n\t&
&instruction 2\n\t&
&last instruction&
因为汇编代码部分是必需的,所以即使一行汇编代码也没有,也需要传入空字符串(&&),否则会报错。
2)输出操作数列表和输入操作数列表
前面介绍了,第二部分和第三部分分别表示输出操作数列表和输入操作数列表。
输入操作数表示要作为汇编代码输入的C表达式,而输出操作数刚好相反,表示汇编代码处理完后要输出结果的C表达式。如果有多个输出或输入表达式,需要用逗号(“,”)将它们分隔开来。
可以再前面的汇编代码模板中直接应用定义的输出操作数和输入操作数,其用法是使用百分号(“%”)后面接一个数字,0表示定义的第一个操作数,1表示定义的第二个操作数,依次类推。下面举个例子:
__asm__(&mov %0, %1, ror #1&
: &=r& (result)
: &r& (value)
这里%0代表后面定义的第一个操作数,即输出操作数,代表C语言中的result变量。%1代表定义的第二个操作数,即输入操作数,代表C语言中的value变量。其作用是将value的值右移一位,然后保存到result中。
每一个操作数由三部分组成,分别是修改符(Modifier),限定符(Constraint)和C表达式,其中修改符是可选的。具体形式如下:
&[modifier]constraint& (C expression)修改符和限定符要用双引号括起来,而C表达式要用括号括起来。那么这些修改符和限定符又是什么呢?有什么作用呢?
我们接下来先来说说所谓的限定符。可以看出,操作数在这里的作用是将C语言定义的变量与汇编语言中要使用到的变量进行一一对应。但并不是所有的汇编指令都可以接受任何类型的变量作为输入或输出变量的,因此汇编器需要知道这些变量到底用在什么地方,从而帮助在传递之前做一些转换。常用的限定符主要有以下一些,而且汇编语句到底是ARM的还是Thumb的,对限定符的定义也会不同:
在ARM指令集下
在Thumb指令集下
浮点寄存器f0...f7
寄存器r8...r15
浮点常量立即数
和G作用相同
数据处理指令中用到的立即数
范围为0...255的常量
范围为-4095...4095的索引常量
范围为-255...-1的常量
和I作用相同
和I作用相同
和I作用相同
范围为-7...7的常量
和r作用相同
寄存器r0...r7
范围为0...32或者是2的幂次方的常量
范围为0...1020的4的倍数的常量
范围为0...31的常量
范围为-508...508的4的倍数的常量
通用寄存器r0...r15
向量浮点寄存器s0...s31
任何类型的操作数
任何类型的操作数
看起来很复杂,但是常用的也就是r,f和m等几个。
好,说完了限定符,下面来看看修改符。修改符是加在限定符之前的,并且是可选的,如果没有修改符的话,则表明这个操作数是只读的。这个对输入操作数没有问题,但是对输出操作数来说,肯定是需要被修改的,那怎么办呢?答案就是使用修改符,修改这个操作数的属性。目前,GCC中定义了三个修改符,分别是:
只写操作数,通常用于输出操作数中
可读且可写操作数,必须要列在输出操作数中
寄存器只能用于输出
所以,作为输出操作数,只需要在限定符前加上“=”就可以了。
在汇编代码中,请绝对不要修改输入操作数的值。
如果想让一个C变量既作为输入操作数,也作为输出操作数的话,可以使用“+”限定符,并且这个操作数只需要在输出操作数列表中列出就行了。例如:
__asm__(&mov %0, %0, ror #1&
: &+r& (y)
上面的例子是将变量y中的值又移1位。因为输入和输出操作数是一个,所以该操作数要既可读也可写,因此添加了“+”修改符。
但是GCC的老版本不一定支持“+”修改符,如果也想达到前面的这种输入和输出操作数是一个的目的,可以用一种变通的做法,并且这种变通的做法GCC的新版本也是支持的。其实,在限定符中,也可以使用数字,其作用是指代前面定义的操作数,0代表第一个,1代表第二个,以此类推。例如:
__asm__(&mov %0, %0, ror #1&
: &=r& (y)
);如果GCC编译器支持的话,这个例子的效果和前面的例子是相同的。本例不同的是,先定义了一个可写的输出变量,同时在输入变量列表中,明确用数字0指出了前面定义的第一个操作数同时也要用来作为输入操作数。
好了,已经介绍了两个修改符的用处了,还剩下最后一个“&”。前面的例子是明确要求输出操作数和输入操作数使用同一个寄存器,但有时候刚好相反,输出操作数使用的寄存器一定不能和输入操作数使用的寄存器一样。但是,由于编译器的优化,是完全有可能出现同一个寄存器既用作输入操作数也用作输出操作数的情况的。这时,可以在输出操作数中使用“&”修改符,明确告诉编译器,代表输出操作数的寄存器一定不能使用输入操作数已经使用过的寄存器。下面举个例子:
__asm__ __volatile__(&ldr %0, [%1]\n\t&
&str %2, [%1, #4]&
: &=&r& (rdv)
: &r& (&table), &r& (wdv)
: &memory&);本例中,将操作一个table数组,读出它的第一个数存放到rdv中,然后修改第二个数为wdv中存放的值。乍看一下没什么问题,但是如果编译器用同一个寄存器来表示输入操作数&table(%1)和输出操作数rdv(%0)怎么办呢?执行完第一条语句之后,table数组的地址就被修改掉了。所以,可以在输出操作数中加上一个“&”修改符,强制保证输出操作数不能和输入操作数复用同一个寄存器,这个问题就解决了。如果汇编代码中有输入寄存器还没有使用完毕,就对输出操作数进行修改的情况,则特别需要用“&”修改符,保证不复用。
3)修改寄存器列表
在汇编指令中,有可能会用到一些指定的寄存器,但是在执行你定义的汇编程序时,那个指定的寄存器有可能另有别的用途,存放了非常重要的数据。等你的程序执行完成后,那个寄存器的值已经被你修改过了,肯定会造成执行错误。因此,在执行你的程序之前必须要做必要的备份和恢复的动作。但是,编译器并不会分析你的汇编代码,找出这种被你修改过,需要恢复的寄存器,因此你必须显式的告诉编译器,被你修改过的寄存器有哪些。这就是修改寄存器列表所起到的作用。
对于嵌入内联ARM汇编来说,此列表中的值有下面三种类型:
告诉编译器汇编代码中修改了通用寄存器r0...r15
告诉编译器汇编代码会导致CPU状态位的改变
告诉编译器汇编代码会读取或修改内存中某个地址存放的值
对于“memory”来说,它并不是表示寄存器被读取或修改了,而是表示内存中的值被修改了。出于优化的目的,在执行你的汇编代码之前,编译器将某些变量的值还保存在寄存器中,并没有被写到实际的内存中。但是,如果你的汇编代码会读取内存中的值,则很有可能新的值还在寄存器中,而内存中存放的还是老的值,这样就会造成错误。添加了“memory”之后,编译器会在执行你的代码之前,保证将保存在寄存器中,没有更新到内存中的值全部都写入到内存中。
此列表中的每一项都要用双引号(&&)括起来,每项之间要用逗号(“,”)分割。
&&相关文章推荐
* 以上用户言论只代表其个人观点,不代表CSDN网站的观点或立场
访问:282253次
积分:3310
积分:3310
排名:第10068名
原创:65篇
评论:160条
(1)(2)(1)(2)(2)(2)(4)(4)(4)(2)(4)(4)(4)(4)(4)(2)(1)(1)(3)(8)(6)单片机编程中在C语言中嵌入汇编语言
单片机&嵌入式
单片机应用
嵌入式操作系统
学习工具&教程
学习和开发单片机的必备工具
(有问必答)
(带你轻松入门)
电子元件&电路模块
当前位置: >>
>> 浏览文章
单片机编程中在C语言中嵌入汇编语言
在C语言中可以嵌入汇编语言,以发挥汇编语言在编程中的优点
方法是,在项目建好以后,加入建立的C文件,其他设置不变,先把
汇编语言写在 & & & & & &&&#pragma &asm
& & & & & & & & & & & & & & & & & & ...... &;汇编语言编写区
& & & & & & & & & & & & & & & & & &#pragma &endasm
之间,同时还要对进行编译器相应汇编语言混编设置。
第三步编译运行&
如果取消了C语言中的汇编程序,则前面的设置也应相应的去掉,否则会出错。&
#include&reg51.h&
void main(void)
for(i=0;i&8;i++)
& & & & &&{
& & & & & &P2=1&&i;
#pragma asm
& & & & & & & & &&mov r7,#00h
& & & & & & &dd:mov r6,#00h
& & & & & &ddd:nop
& & & & & & & & & nop
& & & & & & & & &&nop
& & & & & & & & &&nop
& & & & & & & & &djnz r6,ddd
& & & & & & & & &djnz r7,dd
& & & & & &#pragma endasm
【】【】【】【】
上一篇:下一篇:
CopyRight @
单片机教程网
, All Rights Reserved

我要回帖

更多关于 gcc c语言嵌入arm汇编 的文章

 

随机推荐