PICC编译指针详解

2020-02-14来源: eefocus关键字:PICC  编译指针  指针寻址

指向 RAM 的指针


如果是汇编语言编程,实现指针寻址的方法肯定就是用 FSR 寄存器,PICC 也不例外。为了生成高效的代码,PICC 在编译C原程序时将指向 RAM 的指针操作最终用 FSR 来实现间接寻址。这样就势必产生一个问题:FSR 能够直接连续寻址的范围是 256 字节(bank0/1或 bank2/3),要覆盖最大 512 字节的内部数据存储空间,又该如何让定义指针?PICC 还是将这一问题留给编程员自己解决:在定义指针时必须明确指定该指针所适用的寻址区域,例如:

unsigned char *ptr0; //①定义覆盖bank0/1的指针

bank2 unsigned char *ptr1; //②定义覆盖bank2/3的指针

bank3 unsigned char *ptr2; //③定义覆盖bank2/3的指针

上面定义了三个指针变量,其中①指针没有任何 bank 限定,缺省就是指向 bank0和 bank1;②和③一个指明了 bank2,另一个指明了 bank3,但实际上两者是一样的,因为一个指针可以同时覆盖两个 bank 的存储区域。另外,上面三个指针变量自身都存放在 bank0 中。我们将在稍后介绍如何在其它 bank 中存放指针变量。


指向函数的指针

单片机编程时函数指针的应用相对较少,但作为标准 C 语法的一部分,PICC 同样支持函数指针调用。如果你对编译原理有一定的了解,就应该明白在 PIC 单片机这一特定的架构上实现函数指针调用的效率是不高的:PICC 将在 RAM 中建立一个调用返回表,真正的调用和返回过程是靠直接修改 PC 指针来实现的。因此,除非特殊算法的需要,建议大家尽量不要使用函数指针。


bank 修饰词的位置含义

前面介绍的一些指针有的作用于 bank0/1,有的作用于 bank2/3,但它们本身的存放位置全部在 bank0。显然,在一个程序设计中指针变量将有可能被定位在任何可用的地址空间,这时,bank修饰词出现的位置就是一个关键,看下面的例子:

//定义指向bank0/1的指针,指针变量为于bank0 中

unsigned char *ptr0;

//定义指向bank2/3的指针,指针变量为于bank0 中

bank2 unsigned char *ptr0;

//定义指向bank2/3的指针,指针变量为于bank1 中

bank2 unsigned char * bank1 ptr0;

从中可以看出规律:前面的 bank 修饰词指明了此指针的作用域;后面的 bank 修饰词定义了此指针变量自身的存放位置。只要掌握了这一法则,你就可以定义任何作用域的指针且可以将指针变量放于任何 bank中。


volatile、persistent 和 const 修饰词的位置含义 如果能理解上面介绍的 bank 修饰词的位置含义,实际上 volatile、persistent 和 const 这些关键词出现在前后不同位置上的含义规律是和 bank 一词相一致的。例如:

//定义指向bank0/1易变型字符变量的指针,指针变量位于bank0中且自身为非易变型

volatile unsigned char *ptr0;

//定义指向bank2/3非易变型字符变量的指针,指针变量位于bank1 中且自身为易变型

bank2 unsigned char * volatile bank1 ptr0;

//定义指向ROM 区的指针,指针变量本身也是存放于ROM区的常数

const unsigned char * const ptr0;

亦即出现在前面的修饰词其作用对象是指针所指处的变量;出现在后面的修饰词其作用对象就是指针变量自己。


既然定义的指针有明确的 bank 适用区域,在对指针变量赋值时就必须实现类型匹配,下面的指针赋值将产生一个致命错误:

unsigned char *ptr0; //定义指向bank0/1的指针

bank2 unsigned char buff[8]; //定义bank2中的一个缓冲区

程序语句:

ptr0 = buff; //错误!试图将bank2内的变量地址赋给指向bank0/1的指针

若出现此类错误的指针操作,PICC 在最后连接时会告知类似于下面的信息:

Fixup oveRFlow in expression (...)


同样的道理,若函数调用时用了指针作为传递参数,也必须注意 bank 作用域的匹配,而这点往往容易被忽视。假定有下面的函数实现发送一个字符串的功能:

void SendMessage(unsigned char *);

那么被发送的字符串必须位于 bank0 或bank1 中。如果你还要发送位于 bank2或 bank3内的

字符串,必须再另外单独写一个函数:

void SendMessage_2(bank2 unsigned char *);

这两个函数从内部代码的实现来看可以一模一样,但传递的参数类型不同。


按笔者的应用经验体会,如果你看到了“Fixup overflow”的错误指示,几乎可以肯定是指针类型不匹配的赋值所至。请重点检查程序中有关指针的操作

关键字:PICC  编译指针  指针寻址 编辑:什么鱼 引用地址:http://news.eeworld.com.cn/mcu/ic488245.html 本网站转载的所有的文章、图片、音频视频文件等资料的版权归版权所有人所有,本站采用的非本站原创文章及图片等内容无法一一联系确认版权者。如果本网所选内容的文章作者及编辑认为其作品不宜公开自由传播,或不应无偿使用,请及时通过电子邮件或电话通知我们,以迅速采取适当措施,避免给双方造成不必要的经济损失。

上一篇:PICC ---- 函数
下一篇:PICC——基本知识(变量)

关注eeworld公众号 快捷获取更多信息
关注eeworld公众号
快捷获取更多信息
关注eeworld服务号 享受更多官方福利
关注eeworld服务号
享受更多官方福利

推荐阅读

PICC ---- 函数
简介:一个良好的程序设计应该有一个清晰的组织结构,把不同的功能用不同的函数实现是最好的方法,因此一个函数 2K字长的限制一般不会对程序代码的编写产生太多影响。函数的代码长度限制PICC决定了C原程序中的一个函数经编译后生成的机器码一定会放在同一个程序页面内。中档系列的 PIC 单片机其一个程序页面的长度是 2K字,换句话说,用 C 语言编写的任何一个函数最后生成的代码不能超过 2K字。一个良好的程序设计应该有一个清晰的组织结构,把不同的功能用不同的函数实现是最好的方法,因此一个函数 2K字长的限制一般不会对程序代码的编写产生太多影响。如果为实现特定的功能确实要连续编写很长的程序,这时就必须把这些连续的代码拆分成若干函数,以保证每个
发表于 2020-02-13
PICC ---- 各种变量修饰
volatile — 易变型变量声明PICC 中还有一个变量修饰词在普通的 C 语言介绍中一般是看不到的,这就是关键词“volatile”。顾名思义,它说明了一个变量的值是会随机变化的,即使程序没有刻意对它进行任何赋值操作。在单片机中,作为输入的 IO端口其内容将是随意变化的;在中断内被修改的变量相对主程序流程来讲也是随意变化的;很多特殊功能寄存器的值也将随着指令的运行而动态改变。所有这种类型的变量必须将它们明确定义成“volatile”类型,例如:volatile unsigned char STATUS @ 0x03;volatile bit commFlag;“volatile”类型定义在单片机的 C 语言编程中是如此的重要,是因为
发表于 2020-02-13
PICC中主程序和中断调用同一个子程序的问题
#pragma interrupt_level 1void function (void){}然后在中断函数那写句#pragma interrupt_level 1void interrupt(void){function();}void main (void){function();}程序中出现重入现象是错误的。PICC具有的重入保护可以防止这种现象的出现。换言之,在PIC架构的单片机中,楼主的做法是错误的。主程序和中断程序是不允许调用同一子程序的。比如子程序A,在主程序中被调用,这时发生中断,该子程序又在中断程序中被调用,这时就发生程序重入。在别的构造的单片机中,如果堆栈可以扩展,则重入问题可以解决,但PIC的堆栈的层数固定
发表于 2020-02-13
PIC8位在PICC中的数据类型
简介:PIC8位MCU的内存都是8位字节结构的,所以PICC中对于数据的划分都是以8位为基础的。在汇编中,我们对一个地址为0X20的内存附值:movlw 255;movwf 0x20;但一个内存是8位结构,能表示最大的数是255。要是超过了会怎么样呢?movlw 256;movwf 0x20;通过DEBUG后,可以看出0X20中的值不是256,而是0了。这里可以看出PIC处理器计算过程是当计算结果超过内存能容纳的最大数(也就是所谓溢出),则自动抛弃最高位。如下:255 - 25611111111-100000000256的2进制有9位,于是PIC处理器就自动抛弃最高位1,剩下的8个0放入内存,于是就成了0了。这过程是由硬件自动
发表于 2020-02-13
PIC单片机如何从汇编转向PICC
一、如何从汇编转向PICC首先要求你要有C语言的基础。C代码的头文件一定要有#include,它是很多头文件的集合,C编译器在pic.h 中根据你的芯片自动载入相应的其它头文件。这点比汇编好用。载入的头文件中其实是声明芯片的寄存器和一些函数。static volaTIle unsigned char TMR0 @ 0x01;staTIc volaTIle unsigned char PCL @ 0x02;staTIc volatile unsigned char STATUS @ 0x03;可以看出和汇编的头文件中定义寄存器是差不多的。如下:TMR0 EQU 0X01;PCL EQU 0X02;STATUS EQU 0X03;都是
发表于 2020-01-06
PIC单片机如何从汇编转向PICC
通过PICC编译环境下,对PIC单片机程序进行操作研究
PICC基本上符合ANSI标准,但是不支持函数的递归调用,其主要原因是PIC单片机特殊的堆栈结构。PIC单片机中的堆栈是硬件实现的,其深度已随芯片固定,无法实现需要大量堆栈操作的递归算法;另外在PIC单片机中实现软件堆栈的效率也不是很高。为此,PICC编译器采用一种“静态覆盖”技术,以实现对C语言函数中的局部变量分配固定的地址空间。经这样处理后产生出的机器代码效率很高。当代码量超过4KB后,C语言编译出的代码长度与全部用汇编代码实现的差别已经不是很大(<10%),当然前提是在整个C代码编写过程中需时时注意所编写语句的效率。PICC中的变量类型和标准C语言一样,这里不再重复。为了使编译器产生最高效的机器码,PICC把单片机中
发表于 2019-12-11
通过PICC编译环境下,对PIC单片机程序进行操作研究
小广播
何立民专栏 单片机及嵌入式宝典

北京航空航天大学教授,20余年来致力于单片机与嵌入式系统推广工作。

电子工程世界版权所有 京ICP证060456号 京ICP备10001474号 电信业务审批[2006]字第258号函 京公海网安备110108001534 Copyright © 2005-2020 EEWORLD.com.cn, Inc. All rights reserved