求助,用IAR扩展iar 关键字字

IAR-AVRC编译器简要;第一章;数据类型(编译器支持ISO/ANSIC基本数据类;1.1.整型数据:;数据类型boolcharsignedcharun;大小;范围0to1;对齐;;8bits8bits8bits8bits16bi;0to255-128to;-3to65535;-32768t
IAR-AVR C编译器简要
数据类型(编译器支持 ISO/ANSI C 基本数据类型和一些附加数据类型。)
1.1. 整型数据:
数据类型 bool char
signed char
unsigned char
signed short unsigned short
signed int
unsigned int signed long unsigned long
signed long long
1 1 1 1 1 1 1 1 1 1 1 1
-128 to 127 0 to 255
-32768 to 32767 0 to 65535
-32768 to 32767 0 to 65535
-231 to 231-1
0 to 232-1
-263 to 263-1
0 to 264-1
unsigned long long 64 bits
bool 数据类型在C++语言里是默认支持的。如果你在C代码的头文件里包含stdbool.h, bool数据类型也可以使用在C语言里。也可以使用布尔值 false和 true。
1.2.浮点数据类型:
long double *
32 bits long double *
±1.18E-38 to ±3.39E+38 ±2.23E-308 to ±1.79E+308
Range (+/-)
32 bits ±1.18E-38 to ±3.39E+38
23 bits 23 bits 52 bits
32 bits (default)
±1.18E-38 to ±3.39E+38
±2.23E-308 to ±1.79E+308
1.3.指针类型:指针有数据指针和函数指针。
1.3.1 数据指针:数据指针的大小为8位,16位,24位。定义为:在整型数据类型
后加”*”符号。如: char *p;
整型数据没有24位,具体定义指针见后面扩展关键字章节。 1.3.2 函数指针:函数指针的大小为16位,24位。
指针定义:在函数类型后加”*”符号。具体定义指针见后面章节。
扩展关键字
可以用来解决数据,函数的存放等。有了它我们就可以定义变量存放在EEPROM,FLASH中。定义中断函数,指针等等。
2.1.数据扩展关键字:用于控制数据的存放类型和对象属性。
用于数据存储空间,控制指针和变量的类型和存放:
__tiny, __near, __far, __huge, and __regvar
用于EEPROM 存储空间, 控制指针和变量的类型和存放:
用于flash 代码存储空间, 控制指针和变量的类型和存放:
__tinyflash, __flash, __farflash, and __hugeflash
用于I/O存储空间,控制指针和变量的类型和存放:
__ext_io, __io
特别指示能够访问所有的数据和代码空间:
其它的对象特性:
__root __no_init.
2.2.函数扩展关键字:用于控制数据的存放类型和对象属性。
● 关键字控制函数的存放和类型。这组关键字必须在函数声明和定义的时候指定:__nearfunc and
__farfunc.
关键字控制函数的类型。这组关键字必须在函数声明和定义的时候指定:
__interrupt, __task, __version_1.
关键字仅仅控制有定义的函数:
__root, __monitor, __noreturn.
2.3.其它特别的关键字:
@ ,用于变量的绝对地址定位。也可以用#pragma location命令 #pragma vector,提供中断函数的入口地址。
#pragma预编译里有很多命令,用在数据操作上都有直接的简单关键字代替,如上面提到的用#pragma location 命令和用 @ 来对变量绝对地址定位效果一样。
常用类型的具体操作方法
根据第一和第二章节的内容,我们可以对IAR的数据进行具体的定义
3.1.EEPROM区域数据存储。(用关键字 __eeprom控制来存放, __eeprom关键字写在数据类型前后效果一样)
__eep//定义一个变量存放在EEPROM空间
unsigned char __//效果同上
__eeprom unsigned char
p[];//定义一个数组存放在EEPROM空间
对于EEPROM空间的变量操作同SRAM数据空间的操作方法一样,编译器会自动调用
__EEPUT(ADR,VAL),
__EEGET(VAR,
ADR)宏函数来对EEPROM变量的操作。
#include&iom8.h&
__eeprom unsigned char
__ee void main(void)
{p[1]++;// EEPROM变量的操作 a++;// EEPROM数组的操作 }
定义常数在EEPROM空间,只要给变量赋与初值就可以了。由于常数在EEPROM空间的地址是随机分配的,读取变量才可以读取到常数值。
__eeprom unsigned char
a=9;//定义一个常数存放在EEPROM空间
__eeprom unsigned char
p[]={1,2,3,4,5,6,7,8};//定义一个组常数存放在EEPROM空间
#include&iom8.h&
__eeprom unsigned char
p[]={1,2,3,4,5,6,7,8}; __eeprom unsigned char a=9;
void main(void)
{PORTB=a;//读取EEPROM空间值9 PORTC=p[0]; //读取EEPROM空间值 }
EEPROM空间绝对地址定位:
__eeprom unsigned char
a @ 0x8;//定义一个变量存放在EEPROM空间0X08单元
__eeprom unsigned char
p[] @ 0x22//定义一个数组存放在EEPROM空间,开始地址为0X22单元
__eeprom unsigned char
a @ 0x08=9;//定义一个常数存放在EEPROM空间0X08单元
__eeprom unsigned char
p[] @0x22={1,2,3,4,5,6,7,8};
//定义一个组常数存放在EEPROM空间开始地址为0X22单元
由于常数在EEPROM空间的地址是已经分配的,读取EEPROM空间值可以用变量和地址。 3.2.与 __eeprom有关的指针操作。
__eeprom关键字控制指针的存放和属性 3.2.1指向eeprom空间的指针EEPROM指针(控制属性)
unsigned char
__eeprom *p;//定义一个指向EEPROM空间地址的指针,8位指针本身存放在SARM中。 unsigned int
__eeprom *p;//定义一个指向EEPROM空间地址的指针,16位指针本身存放在SARM中。 unsigned char
__eeprom *p;//定义一个指向EEPROM空间地址的指针,指针本身存放在SARM中。P的值代表EEPROM的空间的某一地址。*p表示EEPROM空间某一地址单元存放的内容。例:假定p=10,表示EEPROM空间地址10单元,而EEPROM空间10单元的内容就用*p来读取。
#include&iom8.h&
__eeprom t @ 0x10 ; char
* void main(void)
{PORTB=*p;//读取EEPROM空间10单元的值 PORTB=*(p+3);//读取EEPROM空间13单元的值 }
3.2.2.存储于eeprom空间的指针数据指针(就象存储与EEPROM空间的数据一样)控制存储
__eeprom unsigned char *p; //定义一个指向SARMM空间地址的指针,指针本身存放在EEPROM中。
3.3.控制数据和指针存放的__eeprom定义必须是全局变量,控制属性(好像只有指针)可以是局部变量。 #include&iom8.h&
__ee//控制存放
void main(void)
{unsigned char
__eeprom *t;//控制属性 PORTB=p; PORTB=*t; }
__root关键字:告诉编译器未使用的代码也要编译。
定义存放在eeprom空间的数据在程序编译时会自动生成.eep文件以供烧录。对于程序没有使用也要求编译的数据必须加关键字
__root限制。 例:
#include&iom8.h&
__eeprom unsigned char p @ 0x10 =0x56;
void main(void) {}
程序没有使用P变量,编译也会生成.eep文件的。 :FC : :000001FF
3.5.EEPROM操作宏取函数:在comp_a90.h
intrinsics.h头文件里有详细说明。
__EEPUT(ADR,VAL);//向指定EEPROM空间地址(ADR)中写入数据(VAL)。
__EEGET(VAR,ADR);//从指定EEPROM空间地址(ADR)中读取数据(VAL)。
实际上两种函数的原形如下:
__EEPUT(ADR,VAL)
{while (EECR & 0x02); \
EEAR = (ADR); EEDR = (VAL); EECR = 0x04; EECR = 0x02;}
__EEGET(VAR, ADR) {while (EECR & 0x02); \
EEAR = (ADR); EECR = 0x01; (VAR) = EEDR;}
对于定义为EEPROM空间的变量操作同SRAM数据空间的操作方法一样,编译器会自动调用
__EEPUT(ADR,VAL),
__EEGET(VAR, ADR)宏函数来对EEPROM变量的操作。 例:
#include&iom8.h&
__ee void main(void)
{a++;// EEPROM数组的操作,自动调用
__EEPUT(ADR,VAL),
__EEGET(VAR, ADR)函数。 }
对于直接在程序中使用
__EEPUT(ADR,VAL),
__EEGET(VAR, ADR)函数必须要包含头文件ina90.h。 例:
#include&iom8.h&
#include&ina90.h&
void main(void) {
__EEPUT(0x10,0x23);//向EEPROM空间0X10单元写入值0X23
__EEGET(c, 0x10); //读取EEPROM空间0X10单元值 PORTB=c; }
3.6.自动生成.eep文件置: 操作步骤:
1、 在Project-&Options-&linker-&config&的linker command line中观察该Project使用了哪个XCL
文件 。本文使用M8编译,使用文件
是”$TOOLKIT_DIR$\src\template\
cfgm8.xcl”
包含各类专业文献、外语学习资料、高等教育、幼儿教育、小学教育、文学作品欣赏、各类资格考试、生活休闲娱乐、应用写作文书、行业资料、32IAR-AVR C编译器简要指南等内容。 
 AVR 编译器的选择_信息与通信_工程科技_专业资料。目前AVR编译软件众多,本文详细...IAR-AVR CC 编译器简要... 10页 免费
AVR的选择 38页 1下载券 在...  主要是 5.40 以上才包括了 aTtiny87,至于安装文件和和谐文件,大家自己找吧,...在 AVR_IAR C/C++编译器中,通过选择某种存储模式(memory model),可设置一些...  IAR for AVR的中断函数名_信息与通信_工程科技_专业资料。IAR for AVR的中断函数...IAR_AVR_C语言中断编程 5页 1下载券 IAR for AVR 15页 1下载券 ...  ?高度优化的 IAR AVR C/C++编译器; ? ?AVR IAR...后者在调试 C++源代码时特别有效,主要针对大量的外部...IAR使用指南 22页 2下载券 IAR及开发工具使用方法 ...  有软件模 www.hpinfotech.ro IAR AVR C 编译器 为昂贵,所以,中国大陆内,...与 JTAG 相比其主要区别在于仅使用一根信号线(R ESET),即可完成调试信息的交互...  IAR AVR C/C++编译器; AVR IAR 汇编器; 通用 IAR XLINK L IAR XAR ...后者在调试 C++源代码时特别有效,主要针对大量的外部函数调用,比如对象构造器。 ...  为了减少这些不利,AVR体系结构优化了由C编译 器生成的标准指令的有效解码和执行。在AVR体系结构和指令集规范完成以前,C编译器的开发是 由IAR系统(公司)来做的。...  3.2 IAR C 安装与使用 IAR C 语言开发软件由 IAR 公司开发的第三方 MSP430...COSMIC+IAR介绍 21页 免费
IAR-AVR CC 编译器简要... 10页 免费
C...  第四个, ICC AVR 大部分AVR 教材所用的示例软件, AVR, 也是十分简单易用, ...IAR AVR 3.20A 版 C 编译器,有 软件模块,Demo 版 为限 2KB 版。 如果...SAM8系列S3C825A型单片机及其软件设计-IC技术文档
&&&&&|&&|&&|&&|&&|&&|&&|&&|&&|&
作者: 发布时间: 09:15:26 来源: 
摘要:以S3C825A为例介绍三星公司SAM8系列单片机的内部结构及其软件开发环境,详细描述采用混合编辑法来对SAM8系列单片机进行软件设计的一般方案,最后给出用混合编程法对S3C825A进行软件设计的具体应用实例。
摘要:以S3C825A为例介绍三星公司SAM8系列单片机的内部结构及其软件开发环境,详细描述采用混合编辑法来对SAM8系列单片机进行软件设计的一般方案,最后给出用混合编程法对S3C825A进行软件设计的具体应用实例。 &&& 关键词:SAM8系列单片机;OPENice i500;IAR C编译器;混合编程引言三星SAM8系列单片机是8位CMOS型微控制器,该系列单片机具有功耗超低、多样型号、资源丰富、CPU时钟可调及软件对硬件控制灵活等优点,其中,S3C825A型是目前应用较为广泛的单片机。S3C825A与三星SAM8系列其他单片机一样,其常用的开发环境是IAR公司的IAR Embedded Workbench集成开发资源,该环境支持混合编程,可以编辑、汇编和编译汇编语言和C语言的源文件,并且汇编程序与C程序可以共同相同格式的头文件,使得开发过程灵活方便,是一种高效的软件设计方法,具有广泛的应用前景。1 S3C825A型单片机的内部结构S3C825A的内部结构框图如图1所示。从图1可以该单片机具有以下特点:●使用SAM88RC作为中央处理单元;●具有48KB片内ROM和2096byte的寄存器空间;●带有多达67个可编程I/O接口;●具有2个8位的定时/计数器和2个16位定时/计数器;●带有LCD驱动控制器;●带有一个4输入的10bit A/D转换器;●带有主从两个晶振接口。1.1 存储空间分配S3C825A型微控制器有2类存储空间,48KB内部掩膜可编程存储空间(ROM)和2096byte的内部寄存器空间。其中可编程存储空间主要用来存储程序代码和列表数据,它的起始256Byte(00H0FFH)用来存储中断矢量列表,未使用的空间也可用作代码存储空间,但中断矢量必须放在这段空间中。对S3C825A而言,当程序执行RESET后,ROM的起始地址是0100H。&&& S3C825A共有2137个8位可编址寄存器,其中13byte用作CPU和系统控制寄存器,60byte用作接口控制和数据寄存器,16byte用作共享的工作寄存器,其余的2048byte用作通用寄存器(其中包括32byte的LCD显示寄存器),S3C825A的内部寄存器图2所示,它的内部寄存器空间实行页式管理,每一个页的上端64byte作为Set2空间,下端192byte作为主数据寄存器空间,共7页(第7页的00H-1FH为LCD显示数据寄存器空间)。另外扩展出的96byte可作为Set1的Bank0(64byte)和Bank1(32byte)空间,该空间可作为系统控制寄存器空间和工作寄存器空间。1.2 A/D转换器S3C825A内部集成了有一个4路输入10bit模/数转换器(A/D)。该A/D转换器可将每一路的模拟电平用连续的近似逻辑值表示,从而得到与之相等的10bit数字电平,其转换过程需要50个时钟周期。模拟信号输入端口是I/O Port3的P3.0~P3.2复用的,Port3的控制寄存器(P3CONH,P3CONL)可确定Port3是否用于A/D转换器的模拟信号输入,A/D转换器的控制寄存器(ADCON)控制P3.0~P3.2中哪一路作为A/D输入端口。输入信号模拟电平值要求在AVREF和AVSS之间。转换后的值放在ADDATAH/ADDATAL寄存器中,每次转换前必须将这2个寄存器清空。1.3 LCD控制器S3C825A内部集成了一个LCD控制器,可以直接驱动224点(28segX8com)的LCD面板。实际应用中只需要将要显示的数据存储在LCD显示寄存器(700H-71FH)中,然后通过配置LCD控制寄存器(LCON)和LCD模式控制寄存器(LMOD)来选择合适的帧刷新频率,LCD控制器就会自动地将要显示的内容从显示寄存器送到seg脚以进行显示输出,而不需要再进行其他的编程控制。2 S3C825A的软件开发环境2.1 在线仿真器OPENic i500AIJIsysterm公司为三星SAM8系列单片机提供了一套有效的在线仿真器——OPENice i500,该仿真器可以运行在windows 95/98/2000/NT等操作系统下,具有可选的CPU时钟资源(最高可达80MHz)和高达64kbyte的仿真代码存储器,同时内嵌功能强大的代码编辑器,可支持基于RS232的高速代码下载(最高下载速度可达115200b/s),同时支持C语言编译/调试(IAREW,CSPY),因此,应用此仿真器可以大大提高程序调试开发的效率。2.2 SAM8的开发环境SAM8系列单片机常用的开发软件是IAR公司提供的基于IAR Embedded Wordbench的集成开发环境,该开发系统集IAR C编译器、汇编器、连接器、代码编辑器、工程管理器及C-SPY调试器于一体,可以编辑、汇编和编译汇编语言和C语言的源文件,而且汇编程序和C程序可共用相同格式的头文件,是一个功能强大的开发环境。该集成开发平台(IDE)可在Windows 98/ME/NT4/2000/XP下进行工程管理、运行属性设置、代码编辑和调试等。其中内部IAR C语言编码器的功能强大,能支持ISO/ANSI标准C语言编译,且具有多样的代码大小和编译速度模式以及可选的堆栈模式。此外,还支持SAM8扩展关键字,同时支持C语言和汇编语言的混合程序编译。&&& 该开始环境集成有基于通用指令集的重定位宏汇编器,且内嵌C语言预处理程序,可接受所有的C语言宏定义。而集成的IAR XLINK连接器支持灵活的代码段和数据段重定位,并可根据重定位模块提供的信息将若干个应用程序所需要的可重定位代码模块文件组装成一个程序,从而产生可执行的目标代码。此外,环境中的C-SPY调试器具有多种测试分析功能,支持单步调试,控制程序运行到指定位置(Go to Cursor/Go to Label/Go to Address),调试返回(Go to Return)、实时跟踪变量、寄存器(Register Groups)、存储器(Memory)等,这些都在很大程序上提高了开发效率。3 混合编程的软件设计在对SAM8系列单片机进行软件开发过程中,用C语言编程具有开发周期短、可读性强、可移植性好和修改方便等优点,但是C程序反汇编生成的汇编代码往往较长。若直接用汇编语言编程,虽然编制的程序较短,但开发周期长,修改也不方便,所以,较好的解决方法是把程序的框架或主体部分用C语言编写,而将执行效率要求较高的部分用汇编语言来编写。下面主要介绍针对SAM8系列单片机进行混合编程的软件设计方法。3.1 IAR C语言编译器的函数参数传送规则IAR C语言编译器规定函数参数传递有2种方式,即寄存器传递和堆栈传递。传递顺序是从左至右,具体采用哪种方式传递取决于函数参数的类型。IAR C语言编译器把单片机的寄存器分成2组,其中高速暂存器组(R10-R15)中的函数参数由左至右依次传入R15至R10,直至这些寄存器点满,而其余函数参加由堆栈来传递。由迂些寄存器是暂存器,用完就释放掉,所以应用过程中不用保护。第二组为普通寄存器(R1、R4-R9),这组寄存器主要用作寄存器变量和保存中间变量,应用过程不必须对其进行保护,但在C语言函数编写中可以不体现,而由编译器自动完成。当函数参数为以下2种类型时,应当选用堆栈方式传递:第一种是传递参数为struct或union大于4字节的参数类型。第二种是长度可变函数的未命名参数类型。函数参数通常放在由堆栈指针指定的位置为起始的主存储器中,被调用函数的参数则由左至右依次存放在被指定的堆栈中,当被调用函数返回调用函数时,堆栈自动清零,主存储器空间被释放,以供下次供传递函数使用。函数返回值可根据其类型放在R15或R15:R14寄存器对中。若返回值是struct或union类型,则返回R15中的值是存放返回结果的堆栈指针起始位置。C语言编译器也是编译中断函数时会自动保护所用到的寄存器(包括R10-R15),状态寄存器FLAGS的保护也是在中断处理过程中自动完成的。中断过程中用到的寄存器都使用PUSH Rn的指令进行保护,而采用POP Rn指令恢复。当用IRET指令自动恢复状态寄存器FLAGS时,可以从中断中返回。3.2 对汇编语言函数的约定对于一个可以被C语言函数调用的汇编程序来说,使用时必须满足以下3点:(1)符合C语言参数传递规则;(2)有PUBLIC函数入口标志;(3)在C语言函数中用extern声音为外部函数。参加传递规则和C语言函数一样,所不同的是,要在汇编语言函数编写过程中具体体现出来。4 应用实例明确了以上调用规则,混合编程就比较容易了,归纳起来有以下几点:(1)在C语言源文件中用“extern”关键字导入被汇编语言源文件导出的标号;(2)在汇编语言源文件用“PUBLIC”关键字把标号导出到C语言源文件;(3)在汇编语言中用“EXTERN”关键字导入被C语言函数源文件导出的关键字;(4)用C语言把标号导出给汇编语言,这一步不需要关键字;(5)把编辑好的C语言和汇编语言源文件导入设计系统,并用各自调用函数的指令调用。下面以笔者在校音器设计中用到的2个例子来具体说明。4.1 C语言和汇编语言相互调用在该例中,用C语言函数main()调用汇编语言函数get_rand()以得到一个随机数,接着,用汇编语言函数get_rand()调用C语言库函数rand()再得到一个整型机随机数,然后用调用C语言函数mult()的方法把这个随机值的高位乘以main()函数传递给自己的实参,同时把乘积值返回给main()参数。/****C语言源程序****/#include&ios3c825a.h&/*头文件*/extern unsigned char get_rand (unsigned char seed);/* 汇编语言原型声明*/void main(void)/*主函数*/{/*定义变量*/WTCON=0xa0; /*关闭watch dog*/Seed=0x05;Value=get_rand(seed); /*调用汇编语言函数,得到一个随机数*/While(1); /*程序结束*/}/**加法子程序,供汇编语言调用**/unsigned char add(unsigned char x,unsigned chary){return (x+y);}/****C语言源程序结束 ****//****汇编语言源程序 ****/#include &ios3c825a.h& ;头文件EXTERN rand ;C语言库函数EXTERN add ;用户自定义C函数PUBLIC get_rand ;导出函数名给C函数调用Get_rand:PUSH R9 ;普通C函数入栈保护LD R9,R15;C函数传递参数给R15,暂时存储在R9CALL rand ;调用C库函数得到一个随机数,作为add的第一实参,存储在R15LD R14,R9;C函数传递的参数,作为add的第二实参,存储在R14CALL add ;add返回的值存储在R15中POP R9 ;add出栈恢复寄存器内定RETEND/**** 汇编语言源程序结束 ****/4.2 汇编语言写中断服务程序为了提高系统响应速度,设计时往往要求中断服务程序的执行时间较短,执行速度较快。因此,最好的方法就是用汇编语言编写中断服务程序。但要注意以下2点:(1)中断函数不传递参数和返回结果;(2)中断过程中用到的寄存器都要进行保护。本例中用汇编语言编写看门狗定时器的中断服务程序,而用C语言编写主程序。/****C语言主程序****/#include&ios3c825a.h& /*头文件*/extern void in0(void); /*中断函数声明*/void main(void){CLKCON=0X98; /*开中断*/IMR=0X10; /*IRQ4使能*/WTCON=0X84;/*看门狗定时器设为0.25秒*/P2CONL=0X03; /*P2.0为输出*/IPH=0X00;IPL=0XD6; /*中断函数所对矢量位置*/CLKCON=0X18; /*关中断*/while(1);}/****C语言主程序结束****//****汇编语言编写的中断程序****/#include &ios3c825a.h& ;头文件public ‘int0‘ ;中断函数声音RSEG WATCHT:CODE:RROT (1),0X00D6 ;中断矢量在代码段中的绝对位置Int0:PUSH R1 ;寄存器保护LD R1,#01H ;给PORT2寄存器赋值,使连接P2.1的LED定时发头POP R1;寄存器恢复IRET;中断返回END/****汇编语言编写的中断程序逻辑****/5 结束语以上方法已经应用于笔者参与设计的校音器设计中并取得良好的效果。但也要注意调试过程中编译器选项的设置对程序运行结果有一定的影响,因此,对SAM8系统中不同的核,一定要选用不同的内核版本号,否则,寄存器传递的参数可能会错位,从而导致参数传递错误,给调试带来不便。(
【】【】【
※ 相关信息
无相关信息
※ 其他信息
访问数:&|&
数据加载中..--数据类型
数据类型(编译器支持 ISO/ANSI C 基本数据类型和一些附加数据类型)
1.1. 整型数据
bool 数据类型在C++语言里是默认支持的。如果你在C代码的头文件里包含stdbool.h, bool数据类型也可以使用在C语言里。也可以使用布尔值 false和 true。
1.2.浮点数据类型:
1.3.指针类型:指针有数据指针和函数指针。
1、数据指针:
数据指针的大小为8位,16位,24位。定义为:在整型数据类型后加”*”符号。
例如:char *
整型数据没有24位,具体定义指针见后面扩展关键字章节。
2、函数指针:函数指针的大小为16位,24位。
指针定义:在函数类型后加”*”符号
--扩展关键字
&可以用来解决数据,函数的存放等。有了它我们就可以定义变量存放在EEPROM,FLASH空间。定义中断函数,指针等等。IAR关键字很多,这里只列举常用的。
2.1.扩展关键字:用于控制数据和指针。
__eeprom 用于EEPROM 存储空间, 控制数据存放,控制指针类型和存放
__tinyflash, __flash, __farflash, __hugeflash 用于flash 存储空间, 控制数据存放,控制指针类型和存放:
__ext_io, __io 用于I/O存储空间, 控制数据存放,控制指针类型和存放
__regvar 放置一个变量在工作寄存器中
2.2.函数扩展关键字:。
__nearfunc __farfunc 用于控制数据存放,这组关键字必须在函数声明和定义的时候指定:
__interrupt. 关键字控制函数的类型。这组关键字必须在函数声明和定义的时候指定
__root. 关键字仅仅控制有定义的函数:
2.3.其它特别的关键字:
@ 用于变量的绝对地址定位。也可以用#pragma location 命令
#pragma vector 提供中断函数的入口地址。
__root 保证没有使用的函数或者变量也能够包含在目标代码中
__no_init 禁止系统启动的时候初始化变量.
asm, __asm 插入汇编代码
3.1.在c语言里对位的操作如一般如下:
PORTB|=(1&&2);//置PORTB的第2位=1
PORTB&=~(1&&2);//置PORTB的第2位=0
PORTB^|=(1&&2);//取反PORTB的第2位
While(PORTB&(1&&2));//判断1
While(!(PORTB&(1&&2)));//判断为0
3.2.IAR编译器对位的支持更强大,除了上面的方法外还有以下更简单的操作方法:
PORTB_ Bit2=1; //置PORTB的第2位=1
PORTB_ Bit2=0; //置PORTB的第2位=0
PORTB_ Bit2=~ PORTB_ Bit2;//取反PORTB的第2位
While(PORTB_ Bit2);或者while(PORTB_Bit2==1);//判断1
while(PORTB_ Bit2==0);//判断0
PORTC_Bit4=PORTB_Bit2;//把PORTB的第2位传送到PORTC的第4位
3.3.位变量定义:
由于iar使用了扩展语言,它对位域的支持变为最小为char类型,我们可以很方便地用来定义位变量。
采用结构体来定义位变量:
unsigned char bit0:1;
unsigned char bit1:1;
unsigned char bit2:1;
unsigned char bit3:1;
unsigned char bit4:1;
unsigned char bit5:1;
unsigned char bit6:1;
unsigned char bit7:1;
然后就可以用以下位变量了。
t.bit0=~t.bit0;
但是采用以上结构体做出来的位变量只可以访问t的位,不能够直接访问变量t,和标准的IAR位操作也不一样。采用联合体来定义效果更佳。
#i nclude&iom8.h&
{unsigned char t_bit0:1,
void main(void)
t_bit0=1;//访问变量t的位
t_bit0=~t_bit0;
PORTB=t;//直接访问变量t
位变量也可以直接定义在工作寄存器里。
3.4 bool 数据类型在C++语言里是默认支持的。
&&&&如果你在C代码的头文件里包含stdbool.h, bool数据类型也可以使用在C语言里。也可以使用布尔值 false和 true。不过是占用8位1个字节。
#i nclude&iom8.h&
#i nclude&stdbool.h&
bool y=0;//定义位变量
void main(void)
y=!y;//取反位变量
PORTB_Bit3=y;//传递位变量
--Flash操作
FLASH常用类型的具体操作方法
4.1.FLASH 区域数据存储。
用关键字 __flash 控制来存放, __ flash 关键字写在数据类型前后效果一样
__f//定义一个变量存放在flash空间
unsigned char __//效果同上
__flash unsigned char p[];//定义一个数组存放在flash空间
对于flash空间的变量的读操作同SRAM数据空间的操作方法一样,编译器会自动用
LPM,ELPM 指令来操作。
#i nclude&iom8.h&
__flash unsigned char p[];
void main(void)
{PORTB=p[1];// 读flash 数组变量的操作
PORTB=a;// 读flash 变量的操作
由于在正常的程序中,flash 空间是只读的,所以没有赋值的变量是没有意义的。定义常数在flash 空间,只要给变量赋与初值就可以了。由于常数在flash空间的地址是随机分配的,读取变量才可以读取到常数值。
IAR-AVR –C 编译器简要指南
__flash unsigned char a=9;//定义一个常数存放在EEPROM空间。
__flash unsigned char p[]={1,2,3,4,5,6,7,8};
//定义一个组常数存放在flash 空间。
#i nclude&iom8.h&
__flash unsigned char p[]={1,2,3,4,5,6,7,8};
__flash unsigned char a=9;
void main(void)
&&&PORTB=a;//读取flash 空间值9
&&&PORTC=p[0]; //读取flash 空间值
4.1.2flash 空间绝对地址定位:
__flash unsigned char a @ 0x8;//定义变量存放在flash 空间0X08单元__flash unsigned char p[] @ 0x22//定义数组存放在flash 空间,开始地址为0X22单元
__flash unsigned char a @ 0x08=9;//定义常数存放在flash 空间0X08单元
__flash unsigned char p[] @ 0x22={1,2,3,4,5,6,7,8};
//定义一个组常数存放在EEPROM空间开始地址为0X22单元
由于常数在flash 空间的地址是已经分配的,读取flash 空间值可以用变量和地址。
4.2.与 __flash 有关的指针操作。 __flash 关键字控制指针的存放和类型。
4.2.1指向flash 空间的指针flash 指针(控制类型属性)
unsigned char __flash *//定义指向flash 空间地址的指针,8位。
unsigned int __flash *//定义个指向flash 空间地址的指针,16位。
unsigned int __farflash *//定义指向flash 空间地址的指针,24位。
unsigned int __hugeflash *//定义指向flash 空间地址的指针,24位。
unsigned char __flash *//定义一个指向flash 空间地址的指针,指针本身存放在SARM中。P的值代表flash 空间的某一地址。*p表示flash 空间该地址单元存放的内容。例:假定p=10,表示flash空间地址10单元,而flash M空间10单元的内容就用*p来读取。
#i nclude&iom8.h&
char __flash t @ 0x10 ;
char __flash *
void main(void)
PORTB=*p;//读取flash 空间10单元的值
PORTB=*(p+3);//读取flash 空间0x13单元的值
4.2.2.存储于flash 空间的指针数据指针
就象存储与flash 空间的数据一样控制存储属性
__flash unsigned char * //定义指向SARMM空间地址的指针,指针本身存放在flash 中。
4.3.控制数据和指针存放的__flash 定义必须是全局变量,控制类型属性(好像只有指针)可以是局部变量。
#i nclude&iom8.h&
__f//控制存放
void main(void)
unsigned char __flash*//控制属性
4.4. __root 关键字保证没有使用的函数或者变量也能够包含在目标代码中.
定义存放在__flash 空间的数据在程序编译时会自动生成代码嵌入到flash代码中,对于程序没有使用也要求编译的数据(比如可以在代码中嵌入你的版本号,时间等)必须加关键字__root 限制。
#i nclude&iom8.h&
__root __flash unsigned char p @ 0x10 =0x56;
void main(void)
程序没有使用P变量,编译也会生成该代码。
:FECF0FE94A
:DBF00E00EBFC0E8D0E003D0F4DFF4DF76
:CF01E008957A
4.5.flash 操作宏函数:在comp_a90.h intrinsics.h头文件里有详细说明。flash 空间具正常情况下有只读性能,对于读flash 数据编译器会自动编译对应的LPM,ELPM指令,但对于flash 空间的自编程写命令SPM就没有对应的C指令了,这里不讲解详细的自编程方法,只是讲解一下对flash 的读写函数。
直接在程序中读取flash 空间地址数据:要包含intrinsics.h头文件
__load_program_memory(const unsigned char __flash *);//64K空间
//从指定flash 空间地址读数据。该函数在intrinsics.h头文件里有详细说明。
在comp_a90.h文件有它的简化书写_LPM(ADDR)。注意汇编指令LPM Rd ,Z中的Z是一个指针。所以用(const unsigned char __flash *)来强制转换为指向flash空间地址指针。故该条宏函数的正确写法应该如下:
__load_program_memory((const unsigned char __flash *)ADDR);
#i nclude&iom8.h&
#i nclude &intrinsics.h&
void main(void)
{PORTB=__load_program_memory((const unsigned char __flash *)0x12);
该条函数书写不方便,在comp_a90.h文件有简化:
#define _LPM(ADDR) __load_program_memory (ADDR)稍微方便一点。改为
#define _LPM(ADDR) __load_program_memory ((const unsigned char
__flash *)ADDR)就更方便了,直接使用数据就可以了。
#i nclude&iom8.h&
#i nclude&comp_a90.h&
#i nclude&intrinsics.h&
void main(void)
PORTB=__LPM(0x12);// 从指定flash 空间地址单元0x12中读数据
__extended_load_program_memory(const unsigned char __farflash *);
//128K空间_ELPM(ADDR); //128K空间
参照上面的理解修改可以书写更简单。
4.6.自编程函数:
_SPM_GET_LOCKBITS();//读取缩定位
_SPM_GET_FUSEBITS();//读取熔丝位
_SPM_ERASE(Addr);//16位页擦除
_SPM_FILLTEMP(Addr,Word);//16位页缓冲
_SPM_PAGEWRITE(Addr;)//16位页写入
_SPM_24_ERASE(Addr); //24位页擦除
_SPM_24_FILLTEMP(Addr,Data); //24位页缓冲
_SPM_24_PAGEWRITE(Addr) //24位页写入
--SRAM操作
SARM数据类型的具体操作方法
&&&&SARM空间是AVR单片机最重要的部分,所有的操作必须依赖该部分来完成。变量在SARM空间的存储模式有tiny ,small large 三种,也就是对应于__tiny, __near __far三中存储属性。一旦选择为哪种存储模式,对应的数据默认属性也就确定了,但可以采用__tiny, __near __far关键字来更改。
对于程序中的局部变量,编译器会自动处理的,我们也不可能加什么储存属性,但IAR提供了强大的外部变量定义。
5.1.定义变量在工作寄存器
IAR编译器内部使用了部分工作寄存器,留给用户的只有R4-R15供12个寄存器供用户使用,要使用工作寄存器必须在工程选项里打开锁定选项。
定义两个变量使用工作寄存器R14,R15。
#i nclude&iom8.h&
__regvar __no_init char g @ 15;
__regvar __no_init char P @ 14;
void main(void)
g++;
P++;
在工程选项里c/c++ complier&code里打开要使用的寄存器R14-R15。
编译结果就如下,看看是不是直接使用了寄存器做为数据应用
// 4 void main(void)
CFI Block cfiBlock0 Using cfiCommon0
CFI Function main
// 5 { g++;
REQUIRE ?Register_R14_is_global_regvar
REQUIRE ?Register_R15_is_global_regvar
// 6 P++; }
注意:定义在寄存器里变量不能带有初始值。最好不要使用超过9个寄存器变量,不然可能引起潜在的危险,因为建立库的时候没有锁定任何寄存器。
5.2.定义变量的绝对地址.没有特性的变量是随机分配的,要给变量分配地址必须加以特性修饰注意在定义地址的时候千万不要和片内寄存器地址重合了。
5.2.1定义没有存储特性的绝对地址变量必须加__no_init 或者const对象特性
__no_init char t @ 0x65;//定义在I/O地址以外
const char t @ 0x65;//定义只读变量的地址
#i nclude&iom8.h&
__no_init char u @ 0x65 ;
void main(void)
{u++;}
对应汇编:
void main(void)
{u++;}
\ E5 LDI R30, 101
\ F0 LDI R31, 0
\ 0 LD R16, Z
\ 3 INC R16
\ 0 ST Z, R16
5.2.2带存储特性的关键字定义变量的绝对地址__io,__ext_io定义变量在i/o空间
#i nclude&iom8.h&
__io char u @ 0x65 ;
void main(void)
{u++;}
对应汇编:
void main(void)
{u++;}
\ 00065 LDS R16, 101
\ 3 INC R16
\ 00065 STS 101, R16
从5.2.1和5.2.2对比,发现用5.2.2方法定义代码小多了。
5.3.关键字volatile保证从最原始的位置读取变量。在IAR编译器里,除了__no_init和__root定义的变量外,其他的类型的变量都包含有volatile和__no_init特性
--中断及相关函数操作
6.1.中断函数:
&&&&在IAR编译器里用关键字来__interrupt来定义一个中断函数。用#pragma vector来提供中断函数的入口地址
#pragma vector=0x12//定时器0溢出中断入口地址
__interrupt void time0(void)
&&&&上面的入口地址写成#pragma vector=TIMER0_OVF_vect更直观,每种中断的入口地址在头文件里有描述。函数名称time0可以为任意名称。中断函数会自动保护局部变量,但不会保护全局变量。
6.2.内在函数也可以称为本征函数
&&&&编译器自己编写的能够直接访问处理器底层特征的函数。在intrinsics.h中有描述完整类型在comp_a90.h里有进一步的简化书写方式
6.2.1延时函数,以周期为标准
__delay_cycles(unsigned long );
如果处理器频率为1M,延时100us,如下:
__delay_cycles(100 );
当然你也可以对该函数进行修改:
#define CPU_F 1000000
#define delay_us (unsigned long) __delay_cycles((unsigned long )*CPU_F)
#define delay_ms (unsigned long) __delay_cycles((unsigned long )*CPU_F/1000)
6.2.2中断指令
&&&__disable_interrupt( );//插入CLI指令, 也可以用_CLI();也可以SREG_Bit7=0;
&&&&__enable_interrupt( );// 插入SEI指令,也可以用_SEI();也可以SREG_Bit7=1;
&&&&其实对于状态字的置位和清零只有BSET S 和BCLR S两条指令。像SEI不过是BSET 7;的另一个名字而已。AVR指令中还有很多类似的现象,如:ORI 和 SBR 指令完全一样,号称130多条指令的AVR其实没有那么多指令的。
6.2.3从FLASH空间指定地址读取数据
__extended_load_program_memory(unsigned char __farflash *);
__load_program_memory(unsigned char __flash *);
该条指令以及正确的使用方法在4.5.flash 操作宏函数里详细讲解,这里不再重复
6.2.4乘法函数
__fracdtional_multiply_signed(signed char, signed char);
__fractional_multiply_signed_with_unsigned(signed char, unsigned char);
__fractional_multiply_unsigned(unsigned char, unsigned char);
//以上为定点小数乘法
__multiply_signed(signed char, signed char);//有符号数乘法
__multiply_signed_with_unsigned(signed char, unsigned char);
//有符号数和无符号数乘法
__multiply_unsigned(unsigned char, unsigned char);//无符号数乘法
6.2.4 半字节交换指令
__swap_nibbles(unsigned char);
6.2.5 MCU控制指令
__no_operation();&&& //空操作指令
__sleep();&&&& //休眠指令
_SLEEP();
__watchdog_reset();&&&& //看门狗清零
--头文件含义
avr_macros.h里面包含了读写16位寄存器的简化书写,和几个位操作函数
comp_a90.h对大量的内在函数做了简要书写
ina90.h包含&inavr.h& &comp_A90.h&文件
intrinsics.h内在函数提供最简单的操作处理器底层特征。休眠,看门狗,FLASH函数。
iomacro.H I/O寄存器定义文件样本。
iom8.h 包含I/O等寄存器定义
--汇编嵌入方式
嵌入汇编语言
在线汇编:使用asm或者__asm,推荐使用__asm。
#i nclude&iom8.h&
void main()
&&&asm(&NOP \n&
&&&&&&&&CLH \n&
&&&&&&&&OR R16,R17 \n&);
不过IAR提供了完全可以访问底层的函数,建议不要频繁使用汇编
参考知识库
* 以上用户言论只代表其个人观点,不代表CSDN网站的观点或立场
访问:5008次
排名:千里之外
原创:24篇
(2)(1)(1)(4)(4)(1)(13)(4)

我要回帖

更多关于 文献求助 的文章

 

随机推荐