C18是MCHP老早针对PIC18高端片子自己出的编译器环境,可能是用户覆盖面的原因,个人感觉比PIC16上的Hi-tech PICC要难用很多。
针对不同的单片机要安装不同升级包,因为官方的头文件支持一直在更新;使用较新的单片机时,建议安装最新的C18 upgrade installation升级包。
下面说说不同之处和比较难配置的关键的几个点:
-------------------------------------------------------------------------------------
#pragma指令:
这个C/C++语言常见的预处理指令,是用来定位代码区域的,定位到RAM区和ROM区,以及类似Config关键配置字的作用。这个跟Freescale的HCS08/12系列单片机的Codewarrior环境风格有点像。这玩意儿是编译器相关的,也就是说有的编译环境支持,有的压根不支持,所以得仔细去读C18文档。。。头大。我就做个简单学习加翻译了!
# pragma udata [ 属性列表] [section-name [=address]]
# pragma idata [ 属性列表] [section-name [=address]]
# pragma romdata [overlay] [section-name [=address]]
# pragma code [overlay] [section-name [=address]]
但是每个PIC18器件的设定值并不相同,不能闭着眼睛猜,官方的C18用户手册是这么说的:
2.9.5.1
语法
pragma-config伪指令:
# pragma config setting-listsetting-list: setting
| setting-list, settingsetting:
setting-name = value-name
setting-name和value-name是特定于器件的,可通过使用 --help-config命令行选项来确定。另外,PIC18 Configuration Settings Addendum(DS51537)中给出了每个器件的有效设置和相关值。
然后在MCHP官网上,已经停止更新这个文档了:
PIC18
CONFIGURATION SETTINGS ADDENDUM Page 4. PIC18 Configuration Settings Addendum DS51537E-page iv 296
Page6. PIC18 Configuration Settings Addendum DS51537E-page vi http://ww1.microchip.com/downloads/en/DeviceDoc/C18_Config_Settings_51537e.pdf
The PIC18 Configuration Settings Addendum is no longer published as a .PDF file. It is included with MPLAB IDE and MPLAB C18 C Compiler as on-line help.
网上可以找到的是陈旧的2006年版本的,已经不需要看了,直接在打开MPLAB IDE--Help---Topic,里面找PIC18 Config Setting
里面很方便!!
---------------------------------------------------------------------
The ANSI C standard provides each C implementation a method for defining unique
constructs, as required by the architecture of the target processor. This is done using
the #pragma directive. The most common #pragma directive in the MPLAB C18
compiler identifies the section of memory to be used in the PIC18XXXX. For instance,
#pragma code
tells MPLAB 18 to compile the C language code following this directive into the “code”
section of program memory. The code section is defined in the associated linker script
for each PIC18XXXX device, specifying the program memory areas where instructions
can be executed. This directive can be inserted as shown, or it can also be followed by
an address in the code areas of the target processor, allowing full control over the
location of code in memory. Usually, it doesn’t matter, but in some applications, such
as bootloader, it is very important to have strict control over where certain blocks of
code will be executed in the application.
MPLAB® C18 #pragma DIRECTIVES
指令 |
用途 |
code
程序空间指令:将其后所有指令编译到目标PIC18单片机的程序空间。
romdata
存储在程序空间的数据:将其后所有静态数据存入目标PIC18单片机的程序空间。
udata
未初始化的数据:将后续需要的未初始化的静态变量,分配给数据data存储器空间。
idata
初始化过的数据:将后续需要的静态变量,分配给数据data存储器空间,且这些变量是在源代码中设过初始值的。
config
定义PIC18单片机的配置字,这些将会在链接输出的hex文件中生成并包含在固件内写入单片机。
interrupt
将已定义命名的C函数编译为高优先级的中断服务ISR程序;
interruptlow
将已定义命名的C函数编译为较低优先级的中断服务ISR程序;
varlocate
定义变量将要存储的位置,以便于编译器避免设定bank地址翻页。
详细内容要参见C18 User's Guide用户参考手册!
2.9.1.5 定位代码
在 #pragma code 伪指令后生成的所有代码将被分配到指定的代码段,直到遇到下一个 #pragma code 伪指令。绝对代码段允许将代码分配到一个特定的地址。例如:
#pragma code my_code=0x2000
将把代码段 my_code 分配到程序存储器地址0x2000。链接器会强制将代码段放入程序存储区;然而,代码段也可以位于指定的存储区。可以用链接器描述文件中的SECTION 伪指令把一个段分配到特定的存储区。下面链接器描述文件中的伪指令把代码段my_code1 分配到存储区page1:
SECTION NAME=my_code1 ROM=page1
2.9.1.6 定位数据
对于MPLAB C18 编译器,数据可以放入数据存储器或者程序存储器。如果没有用户提供的附加代码,片内程序存储器中的数据只能读不能写。如果没有用户提供的附加代码,片外程序存储器中的数据一般是只能读或者只能写。
例如,下面的语句为静态分配的未初始化数据(udata)声明了一个位于绝对地址0x120 的段:
#pragma udata my_new_data_section=0x120
rom 关键字告知编译器应该将变量放入程序存储器。编译器会把这个变量分配到当前
的romdata 型段。例如:
#pragma romdata const_table
const rom char my_const_array[10] = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9};
/* Resume allocation of romdata into the default section */
#pragma romdata
链接器强制将romdata 段放入程序存储区,将udata 和 idata 段放入数据存储区;
然而,数据段也可以位于指定的存储区。可以使用链接器描述文件中的SECTION 伪
指令把一个段分配到一个特定的存储区。下面的语句将把udata 段my_data 分配到
存储区gpr1:
SECTION NAME=my_data RAM=gpr1
-----------------------------------------------------------------------
我摸索了一阵子,还发现C18的另外几个特点:
1. 新来的rom指令(注意必须小写,否则C18编译器不认识),作用类似于#pragma romdata xxxxx
//The direction that the mouse will move in
rom signed char dir_table[]={-4,-4,-4, 0, 4, 4, 4, 0};
2. PORTBbits.RB3和LATBbits.LATB0的区别,
RB1=0;
RB2=1;
上面这种端口引脚定义在C18里是没法直接用的,所有bits位必须带寄存器名的前缀,比如PORTBbits.RB1;这跟PICC编译器的风格有很大不同,所以我刚开始感觉很不习惯。当然这样统一标准其实也有好处,就是增加程序代码的可读性和可辨识性,一眼就能看出bits操作。
操作PortX作为digital IO输出端口时,尽量用latch寄存器来操作,避免用PORTBbits.RB3,因为后者只是用来读取端口状态的;
#define LED0 LATBbits.LATB0
#define LED1 LATBbits.LATB1
#define LED2 LATBbits.LATB2
LED0=!LED0;