首页天道酬勤keil mdk和keil c51区别,keilc51和arm区别

keil mdk和keil c51区别,keilc51和arm区别

张世龙 06-23 20:51 40次浏览

摘自migratingfromkeilvision for 8051 toiarembeddedworkbenchfor 8051

基本代码差异以下几节介绍了IAR C51和Keil C51的代码格式之间的基本差异。

注:最大的区别是C可以使用了。 名字空间什么都有。

在IAR环境中,引导代码缺省位于cstartup.s51文件中。 此文件包含重置后执行的系统引导代码,并在main ()函数之前执行。 内存数据、堆栈指针和其他初始化操作在此完成。 启动代码是运行时库的一部分,但可以将其替换为项目中程序集代码文件的副本。 的缺省启动文件位于IAR安装位置的8051\src\lib路径中。

cstartup.s51调用内存初始化和主(int__low_level_init ) void (int _ _ low _ level _ init )函数,以在该函数之前执行所需的硬件初始化操作。 要在项目中使用此函数的自定义版本,请将8051\src\lib路径中low_level_init.c文件的副本添加到项目中,然后根据需要编辑函数代码。

对于IAR支持的每个设备,特殊功能寄存器(SFR )包含用于访问相应头文件中的SFR的变量定义。 头文件的命名规则是io设备名称. h,例如ioN76E003.h。 默认情况下,头文件位于8051\inc路径下。

某些SFR定义的名称可能与Keil C51不同。

SFR的位操作与Keil不同。 因为IAR不支持非标准的sbit关键字,所以位操作——结构的每个成员都使用c结构来表示一个位。 结构体的命名规则是寄存器名_bit,例如IE_bit。 SFR的几个位在Keil中被定义为几个独立的变量,在IAR中有时会集成到寄存器结构的位域成员中,所以必须重写用于操作这些寄存器位的Keil代码以适应。

注意:这些结构被定义为全局变量,但不初始化,因此不消耗内存。

IAR使用__SFR关键字声明和定义sfr变量。 例如:

_ _ sfr _ _ no _ initvolatileunsignedchartl0@0x8a; 定义双字节SFR时,不需要像Keil那样使用sfr16这样的特殊关键字。 如果将变量类型更改为unsigned short,则:

_ _ sfr _ _ no _ initvolatileunsignedshortadc0@0x BD; 注: __no_init表示编译器不会初始化内存中的变量,@0x8A表示寄存器的地址。

要声明SFR的位变量,请按如下格式编写。

KEIL:

sfr IE=0xA8; //0000,0000中断控制寄存器sbit EA=IE^7; sbit ELVD=IE^6; sbit EADC=IE^5; sbit ES=IE^4; sbit ET1=IE^3; sbit EX1=IE^2; sbit ET0=IE^1; sbit EX0=IE^0;IAR:

_ _ sfr _ _ no _ initvolatileunion { unsigned charie;/* interrupt enable */struct { unsignedcharex 0:1; unsigned char ET0 : 1; unsigned char EX1 : 1; unsigned char ET1 : 1; 无符号角色es : 1; unsigned char EBOD : 1; 无符号角色eadc : 1; 无符号角色ea : 1; (} IE_bit; } @0xA8; 很明显,使用方法也不同。 必须带上前缀IE_bit。 另外,这个地方外侧的union的使用方法很特殊,就是所谓的匿名union。 匿名union成员可以在外面直接访问。 你不需要写xxx.IE。 当然也不需要写。 另外,不用担心访问效率。 程序集级别和Keil应该相同。

与Keil的要求一样,多字节寄存器变量的低位字节必须紧跟在高位字节之前,变量的地址必须是低位字节的地址。 写入变量时IAR和Keil的行为不同,IAR首先写入LSB,最后写入MSB。 也就是说,从低到高,Keil相反。 一般来说,读写顺序的差异可能会导致不同的硬件行为,因此在操作多字节SFR时需要小心。

注:以AVR单片机为例,读取16位ADC寄存器的低字节会自动触发数据锁定,读取高字节后解锁以避免数据错误。 如果先读取高位再读取低位,则无法解除锁定,因此ADC数据的更新将停止。

中断服务程序(ISR ) Keil使用interrupt关键字定义中断服务程序,IAR使用__interrupt。 Kei

l 的interrupt 使用数字参数自动翻译成中断向量地址,IAR 则要求使用#pragma vector= 预编译指令手动声明中断地址。方便起见,器件的头文件中都包含了对应中断地址的常量。以下是Keil 和IAR 的ISR 写法对比:

Keil:

void timer0_isr(void) interrupt 1 { ... }

IAR

#pragma vector=timer0 //timer0 是头文件定义的中断地址,即0x0B__interrupt void timer0_isr(void) { ... }

同时也可以为中断服务程序指定寄存器组。在Keil 中,可以给任何函数指定寄存器组,而在IAR 中则只能用于中断服务程序。Keil 中添加了using 关键字来做这件事,注:跟C++ 冲突了,而IAR 中同样,要使用预编译指令#pragma register_bank=,对比如下:

Keil:

void timer0_isr(void) interrupt 1 using 2{ ... }

IAR

#pragma register_bank=2 //写起来是有点麻烦,不过如果用VS code 的话,可以添加一个自定义代码片段#pragma vector=timer0__interrupt void timer0_isr(void) { ... } 内联汇编

内联汇编的处理方式在IAR 中与KEIL 不同。Keil 只能在预先配置了生成独立的汇编源文件时才能插入汇编代码,然后这些代码才会被编译进目标文件。而IAR 则直接将内联汇编代码集成进目标代码中,当然如果需要的话,也可以生成独立的汇编源文件。

Keil 使用的内联汇编语法是预编译指令#pragma ASM 和#pragma ENDASM,或者__asm 关键字。在IAR 中则使用了asm 关键字,也可以使用__asm。除了关键字,两者的写法也完全不同,IAR 相比之下更符合C/C++ 标准,对比如下:

Keil:

#pragma ASM MOV A, #33H MOV R1, #22H ADD A, R1 JMP $ #pragma ENDASM

IAR

__asm("MOV A, #0x33 \n" "MOV R1, #0x22 \n" "ADD A, R1 \n" "JMP $")

注:如果有机会写GCC 的内联汇编的话,会发现IAR 这个和那个基本差不多,都要求是纯字符串,然后手写换行符。

存储管理

Keil 的存储模式会同时应用到函数、变量和常量,而IAR 则做了区分,可以分别设置代码和数据的存储模式。项目的代码、数据存储模式用来分别设置函数和数据的默认存储模式。每个函数都可以使用函数存储属性设置独立的存储模式,覆盖默认的代码存储模式。每个指针或数据对象也可以使用数据存储属性覆盖默认的数据存储模式。数据存储属性和Keil 的变量存储类型是类似的概念。

string.h 中的很多库函数无法处理多个不同存储类型的参数,比如memcpy, memcmp, strcat 等。

多个字节的整型数据是按小端序存储的,而Keil 是大端序。因此涉及到多字节操作的Keil C51 代码可能需要重写以适配。

注:平时比较常见的环境中,只有Keil C51 和一些网络协议使用了大端序

位变量

在Keil 中,声明单个位的变量是用关键字bit 实现的,然后位变量会被放进可位寻址的区域。在IAR 中,位变量使用bool 作为类型声明,然后要加上__bit 存储属性,表示这是个要放进位寻址区的位变量。带有__bit 声明的位变量使用上存在限制:1. 它不能定义成局部变量;2. 它同时还必须使用_no_init 修饰。所以位变量只能作为全局变量,同时还必须在main() 函数内手动初始化。与Keil 等效的位变量要用以下形式声明:

__bit __no_init bool bit_flag;

在Keil 中可以用bit 修饰函数参数、函数局部变量和函数返回值,而在IAR 中,这些场合都只能使用bool,也就等同于unsigned char。

注:所以可能会多费点RAM。不过位变量一般也就是拿来当标志位,只能当全局变量这限制其实也不算苛刻。

从Keil 的bit 切换到bool 之后,除了用__bit 修饰的全局标志位以外,二者的底层类型完全不同,所以需要谨慎的审视相关的代码,因为对这些变量进行的位操作可能导致完全不同的结果。

linux ftp下载文件,linux ftp未找到命令