您的位置 首页 嵌入式

PIC 单片机 C 言语编程简介(4)

119C和汇编混合编程有两个原因决定了用C语言进行单片机应用程序开发时使用汇编语句的必要性:单片机的一些特殊指令操作在标准的C

11.9

C 和汇编混合编程

有两个原因决议了用 C 言语进行单片机运用程序开发时运用汇编句子的必要性:单片

机的一些特别指令操作在规范的 C 言语语法中没有直接对应的描绘,例如 PIC 单片机的清

看门狗指令“clrwdt”和休眠指令“sleep”;单片机体系着重的是操控的实时性,为了完成这

一要求,有时有必要用汇编指令完成部分代码以进步程序运转的功率。这样,一个项目中就会

呈现 C 和汇编混合编程的景象,咱们在此评论一些混合编程的根本办法和技巧。

11.9.1 嵌入行内汇编的办法

C 原程序中直接嵌入汇编指令是最直接最简略的办法。假如只需求嵌入少数几条的

汇编指令,PICC 供给了一个类似于函数的句子:

asm(“clrwdt”);

双引号中能够编写任何一条 PIC 的规范汇编指令。例如:

for (;;) {

asm(“clrwdt”); //清看门狗

Task();

ClockRun();

asm(“sleep”);

asm(“nop”);

}

//休眠

//空操作延时

例 11-8 逐行嵌入汇编的办法

假如需求编写一段接连的汇编指令,PICC 支撑别的一种语法描绘:用“#asm”开端汇

编指令段,用“#endasm”完毕。例如下面的一段嵌入汇编指令完成了将 0x20~0x7F 间的

RAM 悉数清零:

#asm

movlw 0x20

movwf _FSR

clrf _INDF

incf _FSR,f

btfss _FSR,7

goto $-3

#endasm

例 11-9 整段嵌入汇编的办法

11.9.2 汇编指令寻址 C 言语界说的大局变量

C 言语中界说的大局或静态变量寻址是最简略的,由于这些变量的地址已知且固定。按

C 言语的语法规范,全部 C 中界说的符号在编译后将主动在前面添加一下划线符“_”,因

此,若要在汇编指令中寻址 C 言语界说的各类变量,必定要在变量前加上一“_”符号,我

们在上面例 11-9 中现已表现了这一变量引证的规则,由于 FSR 和 INDF 等全部特别寄存器

是以 C 言语语法界说的,因而汇编中需求对其寻址时前面有必要添加下划线。

关于 C 言语顶用户自界说的大局变量,用行内汇编指令寻址时也相同有必要加上“_”

下面的例 11-10 阐明晰详细的引证办法:

volatile unsigned char tmp; //界说坐落 bank0 的字符型大局变量

void Test(void)

{

#asm

clrf _STATUS

movlw 0x10

movwf _tmp

#endasm

if (tmp==0x10) {

;

}

}

//测验程序

//开端行内汇编

//挑选 bank0

//设定初值

//tmp=0x10

//完毕行内汇编

//开端 C 言语程序

例 11-10 行内汇编寻址 C 大局变量(坐落 bank0)

上面的比如阐明晰汇编指令中寻址 C 言语所界说变量的根本办法。PICC 在编译处理嵌

入的行内汇编指令时将会原封不动地把这些指令复制成最终的机器码。全部对 C 编译器所

作的优化设定对这些行内汇编指令而言将不起任何效果。编程员有必要自己担任编写最高效的

汇编代码,一同处理变量地点的 bank 设定。关于界说在其它 bank 中的变量,还有必要在汇编

指令中加以清晰指示,见例 11-11 的代码典范。

volatile bank1 unsigned char tmpBank1; //界说坐落 bank1 的字符型大局变量

volatile bank2 unsigned char tmpBank2; //界说坐落 bank2 的字符型大局变量

volatile bank3 unsigned char tmpBank3; //界说坐落 bank3 的字符型大局变量

void Test(void)

{

#asm

bcf _STATUS,6

bsf _STATUS,5

movlw 0x10

movwf _tmpBank1^0x80

bsf _STATUS,6

bcf _STATUS,5

movlw 0x20

//测验程序

//开端行内汇编

//挑选 bank1

//设定初值

//tmpBank1=0x10

//挑选 bank2

//设定初值

movwf _tmpBank1^0x100 //tmpBank2=0x20

bsf _STATUS,6

bsf _STATUS,5

movlw 0x30

//挑选 bank3

//设定初值

movwf _tmpBank1^0x180 //tmpBank1=0x30

}

#endasm

//完毕行内汇编

例 11-11 行内汇编寻址 C 大局变量(非 bank0 变量)

经过上面的代码实例,咱们能够把握这样一个规则:在行内汇编指令中寻址 C 言语定

义的大局变量时,除了在寻址前设定正确的 bank 外,在指令描绘时还有必要在变量上异或

地点 bank 的开端地址,实践上坐落 bank0 的变量在汇编指令中寻址时也能够这样了解,只

是异或的是 0x00,能够省掉。假如你了解 PIC 单片机的汇编指令编码格局,上面异或的 bank

开端地址是无法在真实的汇编指令中表现的,其意图朴实是为了告知 PICC 衔接器变量地点

的 bank,以便衔接器进行 bank 类别检查。

11.9.3 汇编指令寻址 C 函数的局部变量

前面现已说到,PICC 对主动型局部变量(包含函数调用时的进口参数)选用一种“静

态掩盖”技能对每一个变量确认一个固定地址(坐落 bank0),因而嵌入的汇编指令对其寻

址时只需选用数据寄存器的直接寻址办法即可,唯一要考虑的是怎么才干在编写程序时知道

这些局部变量的寻址符号(详细地址在最终衔接后才干决议,编程时无需关怀)。一个最实

用也是最牢靠的办法是先编写一小段 C 代码,其中有最简略的局部变量操作指令,然后参

考图 11-5(B)对话框挑选“Compile to assembly only”,把此 C 原代码编译成对应的 PICC 汇

编指令;检查 C 编译器生成的汇编指令是怎么寻址这些局部变量的,你自己编写的行内汇

编指令就选用相同的寻址办法。例如,例 11-12 的一小段 C 原代码编译出的汇编指令

//C 原程序代码

void Test(unsigned char inVar1, inVar2)

{

unsigned char tmp1, tmp2;

inVar1++;

inVar2–;

tmp1 = 1;

tmp2 = 2;

}

//编译器生成的汇编指令

_Test

; _tmp1 assigned to ?a_Test+0 //tmp1 的寻址符为 ?a_Test+0

_Test$tmp1 set

?a_Test

; _tmp2 assigned to ?a_Test+1 //tmp2 的寻址符为 ?a_Test+1

_Test$tmp2 set

?a_Test+1

; _inVar1 assigned to ?a_Test+2 //inVar1 的寻址符为 ?a_Test+2

_Test$inVar1 set ?a_Test+2

44line

;_inVar1 stored from w

bcf

bcf

movwf ?a_Test+2

//榜首个字符型行参由 W 寄存器传递

;ht16.c: 43: unsigned char tmp1, tmp2;

incf

45line

;ht16.c: 45: inVar2–;

decf

46line

;ht16.c: 46: tmp1 = 1;

clrf

incf

47line

;ht16.c: 47: tmp2 = 2;

movlw 2

movwf ?a_Test+1

48line

;ht16.c: 48: }

return

//行参 inVar2 的寻址符为 ?_Test

例 11-12 PICC 完成局部变量操作的寻址办法

根据上面得到的 PICC 编译后局部变量的寻址办法,咱们在 C 言语程序顶用嵌入汇编指

令时有必要采样相同的寻址符以完成对应变量的存取操作,见下面的例 11-13。

//C 原程序代码

void Test(unsigned char inVar1, inVar2)

{

unsigned char tmp1, tmp2;

#asm

//开端嵌入汇编

incf

decf

movlw

addwf

rrf

0x10

?a_Test+0,f

?a_Test+1,f

?a_Test+2,f

?_Test,w

//tmp1++;

//tmp2–;

//inVar1 +=

//inVar2 循环右移一位

}

rrf

#endasm

?_Test,f

//完毕嵌入汇编

例 11-13 嵌入汇编指令完成局部变量寻址操作

假如局部变量为多字节方式组成,例如整型数、长整型等,有必要依照 PICC 约好的存储

格局进行存取。前面现已阐明晰 PICC 选用“Little endian”格局,低字节放在低地址,高字

节放在高地址。下面的例 11-14 完成了一个整型数的循环移位,在 C 言语中没有直接针对循

环移位的语法操作,用规范 C 指令完成的功率较低。

//16 位整型数循环右移若干位

unsigned int RR_Shift16(unsigned int var, unsigned char count)

{

}

while(count–)

{

#asm

rrf ?_RR_Shift16+0,w

rrf ?_RR_Shift16+1,f

rrf ?_RR_Shift16+0,f

#endasm

}

return(var);

//移位次数操控

//开端嵌入汇编

//最低位送入 C

//var 高字节右移 1 位,C 移入最高位

//var 低字节右移 1 位

//完毕嵌入汇编

//回来成果

例 11-14 嵌入汇编指令对多字节变量的操作

11.9.4 混合编程的一些经历

C 和汇编言语混合编程能够使单片机运用程序的开发功率和程序自身的运转功率到达

最佳的合作。笔者从实践运用中得到一些经历供读者一同共享。

慎用汇编指令

比较于汇编言语,用 C 言语编程的优势是毋庸置疑的:开发功率大大进步、人性化的

句子指令加上模块化的程序易于日常办理和保护、程序在不同渠道间的移植便利。所以已然

用了 C 言语编程,就尽量防止运用嵌入汇编指令或整个地编写汇编指令模块文件。PICC 已

具有高效的优化功用,假如在写 C 原程序时就十分注意程序的编译和运转功率问题,加上

PICC 的后道编译优化,最终得到的代码功率不会比悉数用汇编编写的代码差多少,尤其是

程序量较大时。别的,PICC 对数据存储空间的利用率必定比用户人工定位变量时的利用率

要高,一同还供给完好的库函数支撑。C 言语的语法功用强大,能够高功率地完成绝大部分

操控和运算功用。因而,除了一些十分着重单片机运转时刻的代码或 C 言语没有直接对应

的操作能够考虑用汇编指令完成外,其它部分都应该用 C 言语编写。

以上面的例 11-14 进一步阐明,变量的循环右移操效果 C 言语完成十分不便利,PIC

片机已有对应的移位操作汇编指令,因而用嵌入汇编的方式完成功率最高。一同对移位次数

的操控,实质上说变量 count 的递减判零也能够直接用汇编指令完成,但这样做节省不了多

少代码,用规范的 C 言语描绘更直观,更易于保护。

一句话:用了 C 言语后,就不要再老想着用汇编。

尽量运用嵌入汇编

这和上面的慎用汇编指令的说法并不矛盾。假如的确需求用汇编指令完成部分代码以提

高运转功率,应尽量运用行内汇编,防止编写纯汇编文件(*.as 文件)。

尽管 PICC 支撑 C 和汇编原程序模块存在于同一个项目中,但要编写纯汇编文件有必要首

先了解 PICC 特有的汇编语法结构。Hitech 公司供给了完好的文档介绍其汇编器的运用办法,

有爱好者能够从其网站上下载 PICC 的用户运用手册检查。

笔者以为,类似于纯汇编文件的代码也能够在 C 言语结构下完成,办法是根据 C 规范

语法界说全部的变量和函数名,包含需求传递的方式参数、回来参数和局部变量,但函数内

部的指令根本用嵌入汇编指令编写,只要最终的回来参数用 C 句子完成。这样做后函数的

运转功率和纯汇编编写时简直如出一辙,但各参数的传递统一用 C 规范完成,这样办理和

保护就比较便利。例如下面的例 11-15 完成一个字节变量的偶校验位核算。

bit EvenParity(unsigned char data)

{

#asm

swapf ?a_EvenParity+0,w

xorwf ?a_EvenParity+0,f

rrf ?a_EvenParity+0,w

xorwf ?a_EvenParity+0,f

btfsc ?a_EvenParity+0,2

incf ?a_EvenParity+0,f

#endasm

//至此,data 的最低位即为偶校验位

if (data&0x01) return(1);

else return(0);

}

//进口参数 data 的寻址符为 ?a_EvenParity+0

例 11-15 C 函数结构中运用嵌入汇编指令

尽量运用大局变量进行参数传递

运用大局变量最大的优点是寻址直观,只需在 C 言语界说的变量名前添加一个下划线

符即可在汇编句子中寻址;运用大局变量进行参数传递的功率也比形参高。编写单片机的 C

程序时不能死硬强求教科书上的模块化编程而很多选用行参和局部变量的做法,在开发编程

时应视实践情况灵敏变通,全部以最高的代码功率为方针。

声明:本文内容来自网络转载或用户投稿,文章版权归原作者和原出处所有。文中观点,不代表本站立场。若有侵权请联系本站删除(kf@86ic.com)https://www.86ic.net/qianrushi/261697.html

为您推荐

联系我们

联系我们

在线咨询: QQ交谈

邮箱: kf@86ic.com

关注微信
微信扫一扫关注我们

微信扫一扫关注我们

返回顶部