微波EDA网,见证研发工程师的成长!
首页 > 硬件设计 > 嵌入式设计 > PIC 单片机 C 语言编程简介(4)

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

时间:11-22 来源:互联网 点击:
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),因此嵌入的汇编指令对其寻

址时只需采用数据寄存器的直接寻址方式即可,唯一要考虑的是

Copyright © 2017-2020 微波EDA网 版权所有

网站地图

Top