版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领
文档简介
第5章08C语言及第一个08C工程本章首先讲述了嵌入式中选用C语言编程的优越性,讲述嵌入式C语言的编程方法,比较了08C语言和标准C的差异,然后阐述了08C的一些特殊用法,接下来通过实例讲述08C语言编程框架,最后结合我们的实际开发经验,总结了08C中的一些编程技巧。使用C语言进行嵌入式程序开发,它的编程方法和编程手段与PC机上使用C语言还是有很大差别,只有对嵌入式体系结构和硬件资源作详尽了解,才能写出高质量高效率的C语言程序。读者在实际学习过程中,要多加练习,从实际编程中体会嵌入式的C语言编程方法。第5章08C语言及第一个08C工程本章首先讲述了嵌入式中选15.1标准C语言的基本语法
C语言是在70年代初问世的。1978年美国电话电报公司(AT&T)贝尔实验室正式发表了C语言。同时由B.W.Kernighan和D.M.Ritchit合著了著名的《THECPROGRAMMINGLANGUAGE》,简称为《K&R》,也有人称之为K&R标准。但是,在《K&R》中并没有定义一个完整的标准C语言,后来由美国国家标准学会在此基础上制定了一个C语言标准,于1983年发表,通常称之为ANSIC或标准C。本节简要介绍C语言的基本知识,特别是一些和单片机编程密切相关的基本知识,未学过标准C语言的读者可以通过本节了解C语言,对于C语言很熟悉的读者,可以跳过本节。
5.1标准C语言的基本语法C语言是在70年代初问世的。25.1.1数据类型
C语言的数据类型有基本类型和构造类型两大类。基本数据类型如表5-1所示。
注:08C语言的double类型长度为4字节。构造类型有数组、结构、联合、枚举、指针和空类型。结构和联合是基本数据类型的组合。枚举是一个被命名为整型常量的集合。空类型字节长度为0,主要有两个用途:一是明确地表示一个函数不返回任何值;二是产生一个同一类型指针(可根据需要动态地分配给其内存)。表5-1C语言基本数据类型数据类型简明含义位数字节数值域signedchar有符号字节型81-128~+127unsignedchar无符号字节型810~255signedshort有符号短整型162-32768~+32767unsignedshort无符号短整型1620~65535signedint有符号短整型162-32768~+32767unsignedint无符号短整型1620~65535signedlong有符号长整型324-2147483648~+2147483647unsignedlong无符号长整型3240~4294967295float浮点型3243.4E-38~3.4E+38double双精度型6481.7E-312~1.7E+3125.1.1数据类型
C语言的数据类型有基本类型和构造类型两3嵌入式系统学习5.1.2运算符
C语言的运算符与大多数计算机语言基本相同,分为算术、逻辑、关系和位运算及一些特殊的操作符。表5-2列出了C语言的部分运算符及使用方法举例。
嵌入式系统学习5.1.2运算符45.1.3
流程控制
在程序设计中主要有三种基本控制结构:顺序结构、选择结构和循环结构。(1)顺序结构顺序结构就是从前向后依次执行语句。从整体上看,所有程序的基本结构都是顺序结构,中间的某个过程可以是选择结构或循环结构。(2)选择结构在大多数程序中都会包含选择结构。它的作用是,根据所指定的条件是否满足,决定从给定的两组操作选择其一。在C语言中选择结构可以用两种语句来实现:if语句和switch语句。
(3)循环结构C语言中的循环结构常用for循环,while循环与do...while循环。
5.1.3流程控制在程序设计中主要有三种基本控制结构:55.1.4
函数所谓函数,即子程序,也就是“语句的集合”,就是说把经常使用的语句群定义成函数,供其他程序调用,这样就可以避免重复编写程序的麻烦,也可以缩短程序的长度。当一个程序太大时,建议将其中的一部分程序改成用函数的方式调用较好,因为大程序过于繁杂容易出错,而小程序容易调试,也易于阅读和修改。函数定义的一般形式如下所示:类型标识符
函数名(类型参数1,类型参数2,类型参数3,……){说明部分语句}(1)使用函数的注意事项①函数定义时要同时声明其类型。②调用函数前要先声明该函数。③传给函数的参数值,其类型要与函数原定义一致。④接收函数返回值的变量,其类型也要与函数类型一致。嵌入式系统学习5.1.4函数所谓函数,即子程序,也就是“语句的集65.1.4函数(2)(2)函数的声明voidfunction1(void)此函数无返回值,也不传参数。voidfunction2(unsignedchari,intj)此函数无返回值,但需要unsignedchar类型的参数i和int类型的参数j。unsignedcharfunction3(unsignedchari)此函数有返回值,其类型为unsignedchar。(3)函数的返回值
return表达式;return语句用来立即结束函数,并返回一确定给调用程序。如果函数的类型和return语句中表达式的值不一致,则以函数类型为准。对数值型数据,可以自动进行类型转换。即函数类型决定返回值的类型。5.1.4函数(2)75.1.5
指针指针是C语言中广泛使用的一种数据类型,运用指针是C语言最主要的风格之一。指针是一种特殊的数据类型,在其它语言中一般没有。指针是指向变量的地址,实质上指针就是存储单元的地址。根据所指的变量类型不同,可以是整型指针(int*)、浮点型指针(float*)、字符型指针(char*)、结构指针(struct*)和联合指针(union*)。(1)指针变量的定义其一般形式为:类型说明符*变量名;其中,*表示这是一个指针变量,变量名即为定义的指针变量名,类型说明符表示本指针变量所指向的变量的数据类型。例如:int*point_1;表示point_1是一个指向整型的指针变量,它的值是一个整型变量的地址。5.1.5指针指针是C语言中广泛使用的一种数据类型,运用指85.1.5
指针(2)(2)指针变量的赋值指针变量同普通变量一样,使用之前不仅要定义说明,而且必须赋予具体值。未经赋值的指针变量不能使用,否则将造成系统混乱,甚至死机。指针变量的赋值只能赋予地址。①指针变量初始化的方法inta;int*point=&a;a②给指针赋值的方法inta;int*point;point=&a;将数值赋给指针将导致错误,例如:int*point;point=1000;是错误的。被赋值的指针变量前不能再加“*”说明符,如写为*point=&a也是错误的。(3)指针的运算①取地址运算符&取地址运算符&是单目运算符,其结合性为自右至左,其功能是取变量地址。5.1.5指针(2)(2)指针变量的赋值95.1.5
指针(3)②取内容运算符*取内容运算符*是单目运算符,其结合性为自右至左,用来表示指针变量所指的变量。在*运算符之后跟的变量必须是指针变量。注意:指针运算符*和指针变量说明中的指针说明符*并非相同。在指针变量说明中,“*”是类型说明符,表示其后的变量是指针类型。而表达式中出现的“*”则是一个运算符用以表示指针变量所指的变量。main(){inta=5,*point=&a;printf("%d",*point);}表示指针变量point取得了整型变量a的地址。本语句表示输出变量a的值。③
加减算术运算对于指向数组的指针变量,可以加上或减去一个整数n。设pa是指向数组a的指针变量,则pa+n,pa-n,pa++,++pa,pa--,--pa运算都是合法的。指针变量加或减一个整数n的意义是把指针指向的当前位置(指向某数组元素)向前或向后移动n个位置。5.1.5指针(3)②取内容运算符*105.1.5
指针(4)注意:数组指针变量向前或向后移动一个位置和地址加1或减1在概念上是不同的。因为数组可以有不同的类型,各种类型的数组元素所占的字节长度是不同的。如指针变量加1,即向后移动1个位置表示指针变量指向下一个数据元素的首地址。而不是在原地址基础上加1。例如:inta[5],*pa;pa=a;/*pa指向数组a,也是指向a[0]*/pa=pa+2;/*pa指向a[2],即pa的值为&pa[2]*/指针变量的加减运算只能对数组指针变量进行,对指向其它类型变量的指针变量作加减运算是毫无意义的。(4)void指针类型顾名思义,void*为“无类型指针”,即用来定义一个指针变量,不指定它是指向哪一种类型数据,但可以把它强制转化成任何一种类型的指针。对于void*类型的指针变量不能进行取内容运算和加减算术运算,因为编译器不知道它指向的具体类型。5.1.5指针(4)注意:数组指针变量向前或向后移动一个位115.1.5
指针(5)众所周知,如果指针p1和p2的类型相同,那么我们可以直接在p1和p2间互相赋值;如果p1和p2指向不同的数据类型,则必须使用强制类型转换运算符把赋值运算符右边的指针类型转换为左边指针的类型。例如:float*p1;int*p2;p1=(float*)p2;而void*则不同,任何类型的指针都可以直接赋值给它,无需进行强制类型转换:void*p1;int*p2;p1=p2;但这并不意味着,void*也可以无需强制类型转换地赋给其它类型的指针,也就是说p2=p1这条语句编译就会出错,而必须将p1强制类型转换成“void*”类型的。因为“无类型”可以包容“有类型”,而“有类型”则不能包容“无类型”.5.1.5指针(5)众所周知,如果指针p1和p2的类型相同125.1.6结构体
结构体是由基本数据类型构成的,并用一个标识符来命名的各种变量的组合。结构体中可以使用不同的数据类型。(1)结构体的说明和结构体变量的定义定义一个结构体的一般形式为:
在①方式中,仅定义了一个结构体。如果要使用这种类型的结构体还需要使用变量定义语句。②方式在定义结构体的同时,定义了结构体变量。例如下面左右两边的代码是等价的。
①struct结构体名
{成员列表};
②struct结构体名{成员列表}结构体变量;或
结构体的使用5.1.6结构体结构体是由基本数据类型构成的,并用一个135.1.6结构体(2)structstudent/*定义一个student结构体*/{charname[8];intage;charsex[2];};structstudentstudent1;/*定义一个student结构变量student1*/structstudent{charname[8];intage;charsex[2];}student1;/*定义一个student结构体,同时定义一个student结构变量student1*/结构体是一个新的数据类型,因此结构体变量也可以象其它类型的变量一样赋值运算,不同的是结构体变量以成员作为基本变量。结构体成员的表示方式为:结构体变量.成员名
如果将“结构体变量.成员名”看成一个整体,则这个整体的数据类型与结构体中该成员的数据类型相同,这样就像前面所讲的变量那样使用。例如:student1.age=18;5.1.6结构体(2)structstudentst145.1.6结构体(3)(3)结构体指针结构体指针是指向结构体的指针。它由一个加在结构体变量名前的“*”操作符来定义。例如用上面已说明的结构体定义一个结构体指针如下:structstudent*Pstudent;使用结构体指针对结构体成员的访问,与结构体变量对结构体成员的访问在表达方式上有所不同。结构体指针对结构体成员的访问表示为:结构体指针名->结构体成员其中"->"是两个符号"-"和">"的组合,好象一个箭头指向结构体成员。例如要给上面定义的结构体中name和age赋值,可以用下面语句:strcpy(Pstudent->name,"LiuYuZhang");Pstudent->age=18;结构体的使用5.1.6结构体(3)(3)结构体指针结构体的使用155.1.6结构体(4)实际上,Pstudent->name就是(*Pstudent).name的缩写形式。需要指出的是结构体指针是指向结构体的一个指针,即结构体中第一个成员的首地址,因此在使用之前应该对结构体指针初始化,即分配整个结构体长度的字节空间。这可用下面函数完成,例如:Pstudent=(structsudent*)malloc(sizeof(structstudent));sizeof(structstudent)自动求取student结构体的字节长度,malloc()函数定义了一个大小为结构体长度的内存区域,然后将其地址作为结构体指针返回。结构体的使用5.1.6结构体(4)结构体的使用165.1.7共用体有时需要将几种不同类型的变量存放到同一段内存单元中。嵌入式系统为了减少内存使用,内存单元不同时刻作不同的用途,即内存复用,共用体数据类型就非常适合于这种情况。例如,可把一个整型变量、一个字符型变量和一个长整型变量放在同一个地址开始的内存单元,如图5-6所示。以上3个变量在内存中占的字节数不同,但都从同一地址开始(图中设地址为$0080)存放。这种几个不同的变量共同占用同一段的结构,称为“共用体”类型结构。如右图,为共用体的内存使用。图5-6共用体的内存“共用”
0080地址整型变量b字符型变量a长整型变量c5.1.7共用体有时需要将几种不同类型的变量17(1)共用体的定义定义一个联合类型的一般形式为:
union共用名{成员表}共用变量名;成员表中含有若干成员,成员的一般形式为:
类型说明符
成员名例如:
unionabc{inta;charb;longc;}u1;(2)共用体的使用在共用体变量u1被分配的内存单元数量等于长整型变量c的长度(4字节)中。如果整型变量c的赋值为:
u1.c=0x12345678;则u1.a和u1.b的值也被修改。本例中,它们的值为:
u1.a=0x12;u1.b=0x1234;(1)共用体的定义18
5.1.8位域
有些信息在存储时,并不需要占用一个完整的字节,而只需占几个或一个二进制位。例如在存放一个开关量时,只有0和1两种状态,用一位二进位即可。为了节省存储空间,并使处理简便,C语言又提供了一种数据结构,称为“位域”或“位段”。所谓“位域”是把一个字节中的二进制位划分为几个不同的区域,并说明每个区域的位数。每个域有一个域名,允许在程序中按域名进行操作。这样就可以把几个不同的对象用一个字节的二进制位域来表示。(1)位域的定义位域定义与结构定义相仿,其形式为:
strict位域结构名{位域列表};位域列表格式为:类型说明符位域名:位域长度
5.1.8位域
有些信息在存储时,并不需19例如:
structbs{inta:8;intb:2;intc:6;}b1;(2)位域的使用位域的使用和结构成员的使用相同,其一般形式为:位域变量名·位域名位例如在上面定义的位域b1可以这样调用:b1.a=1;//将b1的第0位置1b1.b=7;//将b1的第3~5位置111通过位域定义位变量,是实现单个位操作的重要途径和方法,采用位域定义位变量,产生的代码紧凑、高效。例如:20
5.1.9编译预处理
C语言提供编译预处理的功能,“编译预处理”是C编译系统的一个重要组成部分。C语言允许在程序中使用几种特殊的命令(它们不是一般的C语句)。在C编译系统对程序进行通常的编译(包括语法分析,代码生成,优化等)之前,先对程序中的这些特殊的命令进行“预处理”,然后将预处理的结果和源程序一起再进行常规的编译处理,以得到目标代码。C提供的预处理功能主要有宏定义、条件编译和文件包含。(1)宏定义
#define宏名表达式表达式可以是数字、字符、也可以是若干条语句。在编译时,所有引用该宏的地方,都将自动被替换成宏所代表的表达式。例如:
#definePI3.1415926#defineS(r)PI*r*r(2)条件编译
5.1.9编译预处理
C语言提供编译预处21通常源程序的所有行参加编译。但是有时希望对其中一部分内容只在满足一定条件才进行编译,这就是“条件编译”。条件编译有三种形式①#if表达式程序段1#else表达式程序段2#endif②#ifdef标识符程序段1#else程序段2#endif③#ifndef标识符程序段1#else程序段2#endif
形式①在表达式为真时,则编译#if下的程序,否则编译#else下的程序。形式②是当所指定的标识符已经被#define命令定义过,则编译程序段1,否则编译程序段2。形式③是当所指定的标识符未被#define命令定义过,则编译程序段1,否则编译程序段2。通常源程序的所有行参加编译。但是有时希望对其中一部22
5.1.10用typedef定义类型
除了可以直接使用C提供的标准类型名(如int、char、float、double、long等)和自己定义的结构体、共用体、指针、枚举类型外,还可以用typedef定义新的类型名来代替已有的类型名。例如:
typedefunsignedcharINT8U;用法说明:①用typedef可以定义各种类型名,但不能用来定义变量。②用typedef只是对已经存在的类型增加一个类型名,而没有创造新的类型。③typedef与#define有相似之处,如:
typedefunsignedintINT16U;#defineINT16Uunsignedint④当不同源文件中用到各种类型数据(尤其是像数组、指针、结构体、共用体等较复杂数据类型)时,常用typedef定义一些数据类型,并把它们单独存放在一个文件中,而后在需要用到它们的文件中用#include命令把它们包含进来。⑤使用typedef有利于程序的通用与移植。
5.1.10用typedef定义类型
除了可以直23
5.208C语言的使用
08C语言适用于Freescale08系列微控制器,它的语法与标准C语法基本相同,但它的函数库和标准C的函数库有些差异,而且用08C在编程时涉及的硬件知识比较多,需要注意一些编程技巧。5.2.1寄存器和I/O口的使用(1)I/O口和寄存器的定位普通变量的定义和访问同标准C语言,在嵌入式C语言中我们主要要解决寄存器变量和某些特殊变量的定位问题,即把这些变量存放在RAM中指定的位置。(2)I/O与寄存器的操作使用上面定义的I/O口或寄存器宏,可以方便对I/O置高低电平或读取I/O的状态,读写寄存器。例如:unsignedcharsPortA=PTA;//将A口的状态赋给sPortA变量
PTA=0xff;//将0xff赋给A口,A口将全为高电平
T1SC&=0xdf;//对TT1SC寄存器进行位操作
5.208C语言的使用
08C语言适用于Freesca24
5.2.2位操作方法
在嵌入式系统中,主控MCU的内存资源很宝贵,为了减少内存的使用量,常常将一些取值为0或1的标志位组合到一个字节中,而不是使用整个字节来保存一个只能为0或1的值。例如:在开发一款水表控制的软件中,定义了一个状态标志字节Flag,其各位的含义如表5-1所示。表5-1嵌入式软件中位定义实例Bit7Bit6Bit5Bit4Bit3Bit2Bit1Bit0备用QLQYZFFMZT3FMZT2FMZT1CGR第0位:磁干扰标志(=0,无干扰;=1,有干扰)第1位:阀门状态标志1(=0,正常;=1,阀门关不上,卡住)第2位:阀门状态标志2(=0,阀开着;=1,阀关着)第3位:阀门状态标志3(=0,正常;=1,阀门关不上,打滑)第4位:剩余水量正负标志(=0,正;=1,负)第5位:欠压标志位(=0,电压正常;=1,欠电压)第6位:欠量标志(=0,未欠量;=1,已欠量)第7位:备用
5.2.2位操作方法
在嵌入式系统中,主控251.用位运算符实现位操作C语言中提供了6种基本的位运算符:按位与(&)、按位或(|)、按位取反(~)、按位异或(^)、左移(<<)及右移(>>)。嵌入式系统编程常常需要寄存器或内存内单个二制位。在大多数情况下,最好的方法是读出整个寄存器值,改变二进制位,然后把整个值写回到设备寄存器中。2.测试位按位“与”运算最常用于测试单个位(或位域)的值,在需要关注的“位”所在位置由单独一个1组成的特征码与操作数作“与”运算,当关注的“位”是1时,结果才是非0值,即逻辑真值。在实际书写时,特征码通常用十六进制、二进制数或移位表达式。例如:要测试第4位是否为1,有以下几种写法:
if((bits&0x10)!=0)if(bits&0x10)if(bits&0b00010000)if(bits&(1<<4))1.用位运算符实现位操作26由于任意非0值都解释为值,所以条件中可以省略对0的冗余比较。表5-3给出了08C位操作语句编译后的所对应的指令,从表中可以看出编译器在编译时,已经做了优化,将这些C语句变成了08CPU中的位指令,达到和汇编相同的执行效率。表5-308C中的位操作语句及对应的编译后的指令C语句编译后的汇编指令PTA|=(1<<7);//PTA的第7位置1Bset7,0x00PTA&=~(1<<7);//PTA的第7位清0Bclr7,0x00PTA^=0x80;//PTA的第7位取反LDA0x00EOR#-128STA0x00if((PTA&0x81)==0)//检查第7位和第0位是否为0LDA0x00BIT#-127BNE0x××××08C中除了上述的位操作的方法外,还可以综合共用体和位域等多种数据类型,很直观地实现位操作,关于这部分的讲述读者参考本章的进一步讨论部分。由于任意非0值都解释为值,所以条件中可以省略对0的冗余比较。27
5.2.3中断处理
首先,ISR与C中的正常子函数是有差别的:第一,正常子函数被编译后的返回指令为RTS,而ISR被编译后的返回指令为RTI。第二,正常子函数是通过调用方式进入的,而ISR是通过中断机制进入的。第三,ISR的参数和返回类型总是void。现在,就可以带着ISR的这些独有的特性编写它了:①新建一个Vectors08.c,并加入工程中。②定义中断向量表。
5.2.3中断处理
首先,ISR与C中的正常子函数是有差285.2.408C的常用库函数08C提供一系列函数库供程序员使用,其中囊括了标准C所具有的大部分库函数和一些08C特有的函数,但是08C中的有些函数和标准C中的函数的功能不一样。这些函数的头文件位于安装目录的include目录下,库文件位于安装目录的lib目录下。下面对08C中一些常用的库函数做简要说明,更多的函数库说明参见附录D。(1)串口操作类函数函数的声明如下:①intprintf(char*fmt,…)格式化输出printf函数是一个标准库函数,它的函数原型在头文件“stdio.h”中。但作为一个特例,不要求在使用printf函数之前必须包含stdio.h文件。printf函数调用的一般形式为:printf(“格式控制字符串”,输出列表)其中格式控制字符串用于指定输出格式。格式控制串可由格式字符串和非格式字符串两种组成。格式字符串是以%开头的字符串,在%后面跟有各种格式字符,以说明输出数据的类型、形式、长度、小数位数等。如“%d”表示按十进制整型输出,“%ld”表示按十进制长整型输出,“%c”表示按字符型输出等。所有的输出都是发送至串口,而不是屏幕。5.2.408C的常用库函数08C提供一系列函数库供程序29表5-308C中的位操作语句及对应的编译后的指令C语句编译后的汇编指令PTA|=(1<<7);//PTA的第7位置1Bset7,0x00PTA&=~(1<<7);//PTA的第7位清0Bclr7,0x00PTA^=0x80;//PTA的第7位取反LDA0x00EOR#-128STA0x00if((PTA&0x81)==0)//检查第7位和第0位是否为0LDA0x00BIT#-127BNE0x××××表5-308C中的位操作语句及对应的编译后的指令C语句编译30例如:voidmain(){inta=88,b=89;printf("%d%d\n",a,b);printf("%c,%c\n",a,b);printf("a=%d,b=%d",a,b);}②intputc(charc)putc也是stdio.h中的函数,它只能发送一个字符。例如:putc(‘a’);//串口发送字符a③intputs(char*s)puts比putc功能强一些,可以发送一个字符串,但无法像printf那样做格式化输出。例如:puts(“hello”);//串口发送hello④intgetchar(void)通过串行模块接收一个字符。例如:receive=getchar();例如:31(2)内存操作类函数memcpy声明:void*memcpy(void*s1,void*s2,size_tn)将以s2为起始地址的n个字节复制到以s1为起始地址的内存中。例如://在0x50上存放着‘hello’5个字符memcpy((void*)0x0120,(void*)0x50,5);//此时,hello已被复制到0x0120起始的内存单元中(2)内存操作类函数325.2.508C语言与汇编语言的混合编程在绝大多数场合采用C语言编程即可完成预期的目的,但是对一些特殊情况进行编程时要结合汇编语言。(1)在08C中使用汇编
①调用汇编指令构成的子程序定义汇编子程序,定义格式如下:_子程序名
代码…rts这种使用方法要注意以下几点:第一,在子程序名前加‘_’;第二,汇编子程序只能放在*.s文件中,然后将该文件加入到工程中;第三,在C代码中调用汇编子程序时可直接调用:子程序名();第四,在子程序中不能使用映象寄存器的宏定义,只能用它们的直接地址。5.2.508C语言与汇编语言的混合编程在绝大多数场33第五,汇编子程序的编写时,对于使用过的寄存器需要进行保护。08C的编译器把寄存器封装在下层,不需要用户管理,如果汇编子程序没有保存这些寄存器,在返回时将造成不可预测的后果。②嵌入汇编语句
对于嵌入式汇编,可以在C程序中使用一些关键字嵌入一些汇编程序,这种方法主要用于实现数学运算或中断处理,以便生成精练的代码,减少运行时间。当汇编函数不大,且内部没有复杂的跳转时,可以用嵌入式汇编实现。使用关键字asm可以嵌入一条或多条汇编语句。例如:asm(“SEI”);//单条指令asm(“LDA$0000\n”//多条指令“AND#1\n”“STA$0000\n”);第五,汇编子程序的编写时,对于使用过的寄存器需要进行保护。034(2)在汇编中使用C语言在前面已经讲述了C代码中嵌入汇编程序的方法,实际上汇编中也可以调用C代码中的变量与子程序。使用C代码中定义的变量:在变量名前加’_’或’%’,例如:unsignedcharPortA;asm(“LDA%PortA”)或asm(“LDA_PortA”)调用C代码中定义的函数:在函数名前加
‘_’,例如:function1();asm(“JSR_function1”);(2)在汇编中使用C语言35
5.2.608C与标准C的其他一些不同之处
08C语言与标准C语言的语法基本相同,但是也存在一些不同之处,使用时应该注意。(1)部分数据类型不同标准C中,double类型长度为8字节;而08C中,double类型长度为4字节。(2)地址分配不同标准C语言在分配数据存放地址时,高字节的数据存放在高地址处,低字节的数据存放在低地址处,符合“高高低低”的分配原则。08C语言在分配数据存放地址时,高字节的数据存放在低地址处,低字节的数据存放在高地址处,符合高低低高”的分配原则。(3)共用体使用不同由于地址分配的不同,08C语言与标准C语言在共用体的使用上存在着一些差异。
5.2.608C与标准C的其他一些不同之处
08C语言与36
5.308C工程文件组织
第一个08C工程”PrgFrame.prj”给出了FreescaleMCUC编程框架,同时它也是一个很好的编程规范示例:PrgFrame.prjGP32映像寄存器名定义头文件(GP32C.h)开放或禁止MCU模块中断头文件(EnDisInt.h)芯片初始化文件(MCUinit.c)中断处理子程序与中断向量表文件(Vectors08.c)芯片相关程序文件主函数文件(Main.c)小灯驱动头文件(LED.h)小灯驱动文件(LED.c)硬件对象控制文件总头文件(Includes.h)类型别名定义头文件(Type.h)通用函数头文件(GeneralFun.h)通用函数文件(GeneralFun.c)通用程序文件
5.308C工程文件组织
第一个08C工程”PrgFra37
5.4进一步讨论
5.4.1变量的定义1.全局变量和局部变量全局变量为整个程序而定义,在整个程序运行期间,它们占用固定的RAM资源。在C语言中,在所有函数外部声明的变量都认为具有全局作用域,这些声明通常置于源文件的顶部。“全局”实际上仅仅意味着标识符从声明点到文件末尾的范围内是可访问的,当程序包含多个源文件时,则在一个文件中定义的全局变量在其他文件引用时,需要使用extern关键字声明。在引用文件内部,标识符的作用域是由extern声明的位置确定的。如果该声明是全局的,那么该标识符对于文件是全局的;如果该声明是放在块内的,则它对于那个块就是局部的。局部变量为某个函数或子程序而定义,只在函数运行时,从堆栈空间中分配存储空间;函数运行结束,所占用堆栈空间释放。
5.4进一步讨论
5.4.1变382.变量修饰符
变量定义有三个修饰符值得注意,虽然它们与标准C是相同的,但是在嵌入式C语言中又有不同的含义。(1)volatile大多数编译器对源程序编译时做优化操作,其中一种优化方法是基于这种假设:除非明确地把某值写到内存,否则内存中的值不会改变。所以如果源程序中频繁使用某个内存,编译器会把这个内存放到CPU寄寄存器或高速缓存中,提高代码运行速度。(2)static在子函数中static用声明的变量是局部变量,局部的范围可能是一个文件、函数、过程中,在局部的范围内,变量可以调用,变量值可以共享。(3)const修饰符const可以用在任何变量之前,用于声明变量值不会被改变,即“只读的”。这提供了一种保护性编程,编译器会将任何想修改这种变量的行为看成是违犯语法的行为。const声明的变量必须包含一个初值,不允许在以后的使用中修改它的值。2.变量修饰符395.4.2变量存储空间分配嵌入式内部数据存储器RAM只有几百字节,如果通过扩展外部存储器RAM来提高数据存储量必将会增加了硬件成本,使系统更加的复杂,访问外部存储器比访问内部存储器所需的代码也要长得多。有效地使用片内存储器、提高存储器空间的利用率对开发者来说十分关键。内部处理器、内部堆栈、压缩栈、所有程序变量和所有包含进来的库函数都将使用数量有限的内部数据存储器RAM。因为C语言采用了存储器的覆盖技术,可以在程序进行连接时,它将那些已经被其它程序段释放了的存储器空间重新定义给另一个程序段的变量使用,当这个程序运行结束时再将这些存储器释放以供其它程序段使用。全局变量的作用范围是整个程序,因此不能被释放;静态变量由于在函数的调用中也不能被释放;只有局部变量中的动态变量可以被释放。因此在进行程序设计时应该尽量的使用局部变量,提高内部数据存储器的使用率。5.4.2变量存储空间分配嵌入式内部数据存储器RAM只有几405.4.3数据类型的选用
嵌入式C语言编程不同于一般C语言编程的一个显著特点,就是要和程序存储器资源结合起来,虽然其提供的数据类型十分丰富,但是只有bit和char等数据类型是机器语言直接支持的数据类型,用此类数据类型的语句所生成的代码较短;而其它的数据类型如整型、浮点型等数据要有一定的内部程序或内部函数的支持,相对来说用该类数据类型的语句生成的代码要长。有些C语言程序表面上看起来十分的简单,但在实际编译时,生成的代码却相当长。因此我们要按照实际需要,尽量选用占用存储空间少的数据类型,可以大大的减少所生成的代码长度。例如在08C中用不同的数据类型定义i时,语句:for(i=0;i<10;i++);经编译后生成的代码长度如表5-4所示。5.4.3数据类型的选用嵌入式C语言编程不同于一般41通过表5-3我们知道,不同的数据类型所生成的机器代码长度相差很大,相同类型的数据类型有无符号对机器代码长度也有影响。在程序编译时生成机器代码长的数据类型的优先级越高,不同的数据类型在进行程序运算时要转化为高优先级的数据类型,相应的代码长度也会增长。因此我们应尽可能地使用bit,char等机器语言直接支持的数据类型,无符号数的变量应声明为无符号数,尽可能地减少程序中使用的数据类型的种类。表5-4不同数据类型占用存储器字节数和代码长度对比数据类型unsignedcharcharunsingedintintUnsignedlonglongfloat字节数1122444代码长度12194343134134508通过表5-3我们知道,不同的数据类型所生成的机器代码长度42通过表5-3我们知道,不同的数据类型所生成的机器代码长度相差很大,相同类型的数据类型有无符号对机器代码长度也有影响。在程序编译时生成机器代码长的数据类型的优先级越高,不同的数据类型在进行程序运算时要转化为高优先级的数据类型,相应的代码长度也会增长。因此我们应尽可能地使用bit,char等机器语言直接支持的数据类型,无符号数的变量应声明为无符号数,尽可能地减少程序中使用的数据类型的种
通过表5-3我们知道,不同的数据类型所生成的机器代码长度435.4.4位操作的其他实现方法
1.用共用体和位域实现位操作综合共用体和位域等多种数据类型,可以实现很直观的位操作方法。下面以A口的数据寄存器位操作方法来说明。(1)定义//A口数据寄存器及位定义typedefunion{unsignedcharByte;struct{intPTA_0:1;/*PortA数据Bit0*/intPTA_1:1;/*PortA数据Bit1*/intPTA_2:1;/*PortA数据Bit2*/intPTA_3:1;/*PortA数据Bit3*/intPTA_4:1;/*PortA数据Bit4*/intPTA_5:1;/*PortA数据Bit5*/
5.4.4位操作的其他实现方法1.用共用体和位域实现位44#definePTA6_PTA.Bits.PTA_6#definePTA7_PTA.Bits.PTA_7}Bits;}PTASTR;#define_PTA(*(volatilePTASTR*)0x00)#definePTA_PTA.Byte#definePTA0_PTA.Bits.PTA_0#definePTA1_PTA.Bits.PTA_1#definePTA2_PTA.Bits.PTA_2#definePTA3_PTA.Bits.PTA_3#definePTA4_PTA.Bits.PTA_4#definePTA5_PTA.Bits.PTA_5#definePTA6_PTA.Bits.PTA_6#definePTA6_PTA.Bits.PT45#definePTA7_PTA.Bits.PTA_7(2)使用对A口整个口的使用,则直接对PTA赋值。如:PTA=0xFF;对A口的某一位的使用,则直接对PTAx赋值。如:PTA4=1;很显然这样定义了以后,操作很方便,程序的可读性也很好。但这种方法08C编译器编译后的效率比第1种方法要差。如上面用到的PTA4=1编译后的代码为:8089B600ldA0x00808BAA10orA#16808DB700stA0x00本来用1条位操作指令来实现的操作,现在用了3条指令,在执行效率和存储空间上都比较差,对于接口编程时对时序要求很高的时候要特别注意这个问题。
#definePTA7_PTA.Bits.PT462.用宏定义+“按位与、按位或运算”的方法实现位操作
在5.2.2节所讲述的位操作方法效率高,但程序的易读性不强。在有些情况下,将5.2.2节的位操作语句再来一次宏定义,就能兼顾程序的效率和可读性。例如:串行模块(SCI)的控制寄存器2(SCC2)的第5位控制接收中断的开放(=1时)和禁止(=0时),此时可以定义两个宏:#defineEnableSCIReInt()SCC2|=(1<<5)//令SCC2.5=1,开放SCI接收中断#defineDisableSCIReInt()SCC2&=~(1<<5)//令SCC2.5=0,禁止SCI接收中断这样在程序中开放串行接收中断就用如下语句:EnableSCIReInt();2.用宏定义+“按位与、按位或运算”的方法实现位操作
在5475.4.5算法设计问题
嵌入式C语言和标准C语言存在着很大差别,在计算机上进行C语言程序设计时可以不必考虑程序代码的长短,只需考虑程序功能实现,但是在嵌入式上进行C语言程序设计就必须考虑系统的硬件资源。有时并不是程序的算法越简单、长度越短越好,因为有一些算法要调用一些内部的子程序和函数,生成的机器代码可能非常长。不同的算法对程序代码长度影响十分大,因此在进行程序设计时,就尽量采用程序生成代码短的算法,在不影响程序功能实现的情况下可以采用一些优化算法。在嵌入式C语言编译成机器代码时,不同的运算生成的机器代码的长度相差很大,尽可能地减少程序中对某种数据类型的运算种类,越复杂的数据类型效果越明显。在进行数据计算时,在一定的精度范围内,可以用一些近似的计算来完成一些运算,既不损失精度又能减少大量的代码。比如:用逻辑AND/&取模比MOD/%操作更有效。5.4.5算法设计问题嵌入式C语言和标准C语言存在48在用热敏电阻测量温度时,可根据热敏电阻—温度特性公式来求值。数学表达式表示为:
RT=RT0e(B(1/T-1/T0))
其中:RT----T℃时的阻值RT0----T0℃(基准温度)时的阻值B----热敏电阻特性参数如果直接按照公式计算RT时程序结构简单,算法复杂度不高,但是程序将调用<math.h>文件中的对数函数,在编译成机器码时函数有1K多字节,对于一般只有几K字节的嵌入式系统来说,这是十分不合适的。考虑到系统资源问题可以用一种替代方法—查表法来实现算法。只要给出一定温度范围内不同温度值对应热敏电阻的电阻值,然后建立表格,只要按照系统求出的阻值,进行查表、插值,就可以求出相应的温度值。这种算法相比前面的公式法的算法复杂高,C语言程序代码也长,但在编译成机器码时,代码长度却很短,只有一、二百字节。在用热敏电阻测量温度时,可根据热敏电阻—温度特性公式来求值。49第5章08C语言及第一个08C工程本章首先讲述了嵌入式中选用C语言编程的优越性,讲述嵌入式C语言的编程方法,比较了08C语言和标准C的差异,然后阐述了08C的一些特殊用法,接下来通过实例讲述08C语言编程框架,最后结合我们的实际开发经验,总结了08C中的一些编程技巧。使用C语言进行嵌入式程序开发,它的编程方法和编程手段与PC机上使用C语言还是有很大差别,只有对嵌入式体系结构和硬件资源作详尽了解,才能写出高质量高效率的C语言程序。读者在实际学习过程中,要多加练习,从实际编程中体会嵌入式的C语言编程方法。第5章08C语言及第一个08C工程本章首先讲述了嵌入式中选505.1标准C语言的基本语法
C语言是在70年代初问世的。1978年美国电话电报公司(AT&T)贝尔实验室正式发表了C语言。同时由B.W.Kernighan和D.M.Ritchit合著了著名的《THECPROGRAMMINGLANGUAGE》,简称为《K&R》,也有人称之为K&R标准。但是,在《K&R》中并没有定义一个完整的标准C语言,后来由美国国家标准学会在此基础上制定了一个C语言标准,于1983年发表,通常称之为ANSIC或标准C。本节简要介绍C语言的基本知识,特别是一些和单片机编程密切相关的基本知识,未学过标准C语言的读者可以通过本节了解C语言,对于C语言很熟悉的读者,可以跳过本节。
5.1标准C语言的基本语法C语言是在70年代初问世的。515.1.1数据类型
C语言的数据类型有基本类型和构造类型两大类。基本数据类型如表5-1所示。
注:08C语言的double类型长度为4字节。构造类型有数组、结构、联合、枚举、指针和空类型。结构和联合是基本数据类型的组合。枚举是一个被命名为整型常量的集合。空类型字节长度为0,主要有两个用途:一是明确地表示一个函数不返回任何值;二是产生一个同一类型指针(可根据需要动态地分配给其内存)。表5-1C语言基本数据类型数据类型简明含义位数字节数值域signedchar有符号字节型81-128~+127unsignedchar无符号字节型810~255signedshort有符号短整型162-32768~+32767unsignedshort无符号短整型1620~65535signedint有符号短整型162-32768~+32767unsignedint无符号短整型1620~65535signedlong有符号长整型324-2147483648~+2147483647unsignedlong无符号长整型3240~4294967295float浮点型3243.4E-38~3.4E+38double双精度型6481.7E-312~1.7E+3125.1.1数据类型
C语言的数据类型有基本类型和构造类型两52嵌入式系统学习5.1.2运算符
C语言的运算符与大多数计算机语言基本相同,分为算术、逻辑、关系和位运算及一些特殊的操作符。表5-2列出了C语言的部分运算符及使用方法举例。
嵌入式系统学习5.1.2运算符535.1.3
流程控制
在程序设计中主要有三种基本控制结构:顺序结构、选择结构和循环结构。(1)顺序结构顺序结构就是从前向后依次执行语句。从整体上看,所有程序的基本结构都是顺序结构,中间的某个过程可以是选择结构或循环结构。(2)选择结构在大多数程序中都会包含选择结构。它的作用是,根据所指定的条件是否满足,决定从给定的两组操作选择其一。在C语言中选择结构可以用两种语句来实现:if语句和switch语句。
(3)循环结构C语言中的循环结构常用for循环,while循环与do...while循环。
5.1.3流程控制在程序设计中主要有三种基本控制结构:545.1.4
函数所谓函数,即子程序,也就是“语句的集合”,就是说把经常使用的语句群定义成函数,供其他程序调用,这样就可以避免重复编写程序的麻烦,也可以缩短程序的长度。当一个程序太大时,建议将其中的一部分程序改成用函数的方式调用较好,因为大程序过于繁杂容易出错,而小程序容易调试,也易于阅读和修改。函数定义的一般形式如下所示:类型标识符
函数名(类型参数1,类型参数2,类型参数3,……){说明部分语句}(1)使用函数的注意事项①函数定义时要同时声明其类型。②调用函数前要先声明该函数。③传给函数的参数值,其类型要与函数原定义一致。④接收函数返回值的变量,其类型也要与函数类型一致。嵌入式系统学习5.1.4函数所谓函数,即子程序,也就是“语句的集555.1.4函数(2)(2)函数的声明voidfunction1(void)此函数无返回值,也不传参数。voidfunction2(unsignedchari,intj)此函数无返回值,但需要unsignedchar类型的参数i和int类型的参数j。unsignedcharfunction3(unsignedchari)此函数有返回值,其类型为unsignedchar。(3)函数的返回值
return表达式;return语句用来立即结束函数,并返回一确定给调用程序。如果函数的类型和return语句中表达式的值不一致,则以函数类型为准。对数值型数据,可以自动进行类型转换。即函数类型决定返回值的类型。5.1.4函数(2)565.1.5
指针指针是C语言中广泛使用的一种数据类型,运用指针是C语言最主要的风格之一。指针是一种特殊的数据类型,在其它语言中一般没有。指针是指向变量的地址,实质上指针就是存储单元的地址。根据所指的变量类型不同,可以是整型指针(int*)、浮点型指针(float*)、字符型指针(char*)、结构指针(struct*)和联合指针(union*)。(1)指针变量的定义其一般形式为:类型说明符*变量名;其中,*表示这是一个指针变量,变量名即为定义的指针变量名,类型说明符表示本指针变量所指向的变量的数据类型。例如:int*point_1;表示point_1是一个指向整型的指针变量,它的值是一个整型变量的地址。5.1.5指针指针是C语言中广泛使用的一种数据类型,运用指575.1.5
指针(2)(2)指针变量的赋值指针变量同普通变量一样,使用之前不仅要定义说明,而且必须赋予具体值。未经赋值的指针变量不能使用,否则将造成系统混乱,甚至死机。指针变量的赋值只能赋予地址。①指针变量初始化的方法inta;int*point=&a;a②给指针赋值的方法inta;int*point;point=&a;将数值赋给指针将导致错误,例如:int*point;point=1000;是错误的。被赋值的指针变量前不能再加“*”说明符,如写为*point=&a也是错误的。(3)指针的运算①取地址运算符&取地址运算符&是单目运算符,其结合性为自右至左,其功能是取变量地址。5.1.5指针(2)(2)指针变量的赋值585.1.5
指针(3)②取内容运算符*取内容运算符*是单目运算符,其结合性为自右至左,用来表示指针变量所指的变量。在*运算符之后跟的变量必须是指针变量。注意:指针运算符*和指针变量说明中的指针说明符*并非相同。在指针变量说明中,“*”是类型说明符,表示其后的变量是指针类型。而表达式中出现的“*”则是一个运算符用以表示指针变量所指的变量。main(){inta=5,*point=&a;printf("%d",*point);}表示指针变量point取得了整型变量a的地址。本语句表示输出变量a的值。③
加减算术运算对于指向数组的指针变量,可以加上或减去一个整数n。设pa是指向数组a的指针变量,则pa+n,pa-n,pa++,++pa,pa--,--pa运算都是合法的。指针变量加或减一个整数n的意义是把指针指向的当前位置(指向某数组元素)向前或向后移动n个位置。5.1.5指针(3)②取内容运算符*595.1.5
指针(4)注意:数组指针变量向前或向后移动一个位置和地址加1或减1在概念上是不同的。因为数组可以有不同的类型,各种类型的数组元素所占的字节长度是不同的。如指针变量加1,即向后移动1个位置表示指针变量指向下一个数据元素的首地址。而不是在原地址基础上加1。例如:inta[5],*pa;pa=a;/*pa指向数组a,也是指向a[0]*/pa=pa+2;/*pa指向a[2],即pa的值为&pa[2]*/指针变量的加减运算只能对数组指针变量进行,对指向其它类型变量的指针变量作加减运算是毫无意义的。(4)void指针类型顾名思义,void*为“无类型指针”,即用来定义一个指针变量,不指定它是指向哪一种类型数据,但可以把它强制转化成任何一种类型的指针。对于void*类型的指针变量不能进行取内容运算和加减算术运算,因为编译器不知道它指向的具体类型。5.1.5指针(4)注意:数组指针变量向前或向后移动一个位605.1.5
指针(5)众所周知,如果指针p1和p2的类型相同,那么我们可以直接在p1和p2间互相赋值;如果p1和p2指向不同的数据类型,则必须使用强制类型转换运算符把赋值运算符右边的指针类型转换为左边指针的类型。例如:float*p1;int*p2;p1=(float*)p2;而void*则不同,任何类型的指针都可以直接赋值给它,无需进行强制类型转换:void*p1;int*p2;p1=p2;但这并不意味着,void*也可以无需强制类型转换地赋给其它类型的指针,也就是说p2=p1这条语句编译就会出错,而必须将p1强制类型转换成“void*”类型的。因为“无类型”可以包容“有类型”,而“有类型”则不能包容“无类型”.5.1.5指针(5)众所周知,如果指针p1和p2的类型相同615.1.6结构体
结构体是由基本数据类型构成的,并用一个标识符来命名的各种变量的组合。结构体中可以使用不同的数据类型。(1)结构体的说明和结构体变量的定义定义一个结构体的一般形式为:
在①方式中,仅定义了一个结构体。如果要使用这种类型的结构体还需要使用变量定义语句。②方式在定义结构体的同时,定义了结构体变量。例如下面左右两边的代码是等价的。
①struct结构体名
{成员列表};
②struct结构体名{成员列表}结构体变量;或
结构体的使用5.1.6结构体结构体是由基本数据类型构成的,并用一个625.1.6结构体(2)structstudent/*定义一个student结构体*/{charname[8];intage;charsex[2];};structstudentstudent1;/*定义一个student结构变量student1*/structstudent{charname[8];intage;charsex[2];}student1;/*定义一个student结构体,同时定义一个student结构变量student1*/结构体是一个新的数据类型,因此结构体变量也可以象其它类型的变量一样赋值运算,不同的是结构体变量以成员作为基本变量。结构体成员的表示方式为:结构体变量.成员名
如果将“结构体变量.成员名”看成一个整体,则这个整体的数据类型与结构体中该成员的数据类型相同,这样就像前面所讲的变量那样使用。例如:student1.age=18;5.1.6结构体(2)structstudentst635.1.6结构体(3)(3)结构体指针结构体指针是指向结构体的指针。它由一个加在结构体变量名前的“*”操作符来定义。例如用上面已说明的结构体定义一个结构体指针如下:structstudent*Pstudent;使用结构体指针对结构体成员的访问,与结构体变量对结构体成员的访问在表达方式上有所不同。结构体指针对结构体成员的访问表示为:结构体指针名->结构体成员其中"->"是两个符号"-"和">"的组合,好象一个箭头指向结构体成员。例如要给上面定义的结构体中name和age赋值,可以用下面语句:strcpy(Pstudent->name,"LiuYuZhang");Pstudent->age=18;结构体的使用5.1.6结构体(3)(3)结构体指针结构体的使用645.1.6结构体(4)实际上,Pstudent->name就是(*Pstudent).name的缩写形式。需要指出的是结构体指针是指向结构体的一个指针,即结构体中第一个成员的首地址,因此在使用之前应该对结构体指针初始化,即分配整个结构体长度的字节空间。这可用下面函数完成,例如:Pstudent=(structsudent*)malloc(sizeof(structstudent));sizeof(structstudent)自动求取student结构体的字节长度,malloc()函数定义了一个大小为结构体长度的内存区域,然后将其地址作为结构体指针返回。结构体的使用5.1.6结构体(4)结构体的使用655.1.7共用体有时需要将几种不同类型的变量存放到同一段内存单元中。嵌入式系统为了减少内存使用,内存单元不同时刻作不同的用途,即内存复用,共用体数据类型就非常适合于这种情况。例如,可把一个整型变量、一个字符型变量和一个长整型变量放在同一个地址开始的内存单元,如图5-6所示。以上3个变量在内存中占的字节数不同,但都从同一地址开始(图中设地址为$0080)存放。这种几个不同的变量共同占用同一段的结构,称为“共用体”类型结构。如右图,为共用体的内存使用。图5-6共用体的内存“共用”
0080地址整型变量b字符型变量a长整型变量c5.1.7共用体有时需要将几种不同类型的变量66(1)共用体的定义定义一个联合类型的一般形式为:
union共用名{成员表}共用变量名;成员表中含有若干成员,成员的一般形式为:
类型说明符
成员名例如:
unionabc{inta;charb;longc;}u1;(2)共用体的使用在共用体变量u1被分配的内存单元数量等于长整型变量c的长度(4字节)中。如果整型变量c的赋值为:
u1.c=0x12345678;则u1.a和u1.b的值也被修改。本例中,它们的值为:
u1.a=0x12;u1.b=0x1234;(1)共用体的定义67
5.1.8位域
有些信息在存储时,并不需要占用一个完整的字节,而只需占几个或一个二进制位。例如在存放一个开关量时,只有0和1两种状态,用一位二进位即可。为了节省存储空间,并使处理简便,C语言又提供了一种数据结构,称为“位域”或“位段”。所谓“位域”是把一个字节中的二进制位划分为几个不同的区域,并说明每个区域的位数。每个域有一个域名,允许在程序中按域名进行操作。这样就可以把几个不同的对象用一个字节的二进制位域来表示。(1)位域的定义位域定义与结构定义相仿,其形式为:
strict位域结构名{位域列表};位域列表格式为:类型说明符位域名:位域长度
5.1.8位域
有些信息在存储时,并不需68例如:
structbs{inta:8;intb:2;intc:6;}b1;(2)位域的使用位域的使用和结构成员的使用相同,其一般形式为:位域变量名·位域名位例如在上面定义的位域b1可以这样调用:b1.a=1;//将b1的第0位置1b1.b=7;//将b1的第3~5位置111
温馨提示
- 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
- 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
- 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
- 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
- 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
- 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
- 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。
最新文档
- 智慧城市项目PPP模式设计方案
- 浙教版2021-2022学年度七年级数学上册模拟测试卷 (693)【含简略答案】
- 教师辨认方向课程设计
- 教师节节日特色课程设计
- 教师科目二课程设计
- 教师房子改造方案
- 教师团队研修课程设计
- 教学评价对课程设计
- 药品备案采购工作制度
- 电路课程设计遇到的问题
- 周志华-机器学习-Chap01绪论-课件
- 孙子兵法中的思维智慧2065203 知到智慧树网课答案
- 劳动课学期教学计划
- 辽宁省沈阳市铁西区2023-2024学年七年级下学期期中考试地理试卷+
- 小学校园反恐防暴安全
- 2023体育知识竞赛题库及参考答案
- 泰山学院辅导员考试试题2024
- 多图中华民族共同体概论课件第十三讲先锋队与中华民族独立解放(1919-1949)根据高等教育出版社教材制作
- 120急救中心-检伤分类专项试题及答案
- Module4ThingsweenjoyUnit11Chinesefestivals第1课时(课件)牛津上海版英语五年级下册
- 异位妊娠PPT医学课件
评论
0/150
提交评论