protel第五讲.docx
《protel第五讲.docx》由会员分享,可在线阅读,更多相关《protel第五讲.docx(13页珍藏版)》请在冰豆网上搜索。
protel第五讲
第五讲单片机C语言
(1)
1.C程序特性
①C程序是由函数构成的。
一个C源程序至少包括一个函数,一个C源程序有且只有一个名为main()的函数,也可能包含其它函数。
②一个C语言程序总是从main函数开始执行的,不管其物理位置如何。
③C语言区分大小写,必须遵守这一规定。
④C语言书写的格式自由,可以在一行写多个语句,也可把一个语句写在多行。
⑤每个语句和定义的最后必须有一个分号,分号是C语句的必要组成部分。
⑥可以用/*……*/的形式为C程序的任何一部分做注释,KeilC可以用“//”注释语句。
2.单片机C语言开发环境的建立
(1)Keil软件
目前,常用的单片机C语言编程环境是Keil软件,由德国Keil公司出品的一个商业软件,它是目前流行的用于开发51系列单片机的软件。
其特点有:
①其集成开发环境uVisionIDE包括一个工程管理器、一个源程序编辑器和一个程序调试器,其功能强大,可以自动完成编译、汇编、链接程序操作。
②C51编译器KeilC51编译器遵循ANSIC语言标准,并增加了一些支持80C51系列单片机结构的特性。
③A51汇编器KeilA51汇编器支持80C51及其派生系列的所有指令集。
④LIB51库管理器
⑤BL51链接器/定位器
⑥OH51目标文件生成器
⑦Monitor-51调试器
(2)Keil软件的使用
a.源文件的建立
uV2内集成一个文本编辑器,源文件可以由此直接输入。
选择File---New,在工程管理器的右侧打开一个新文件输入窗口,在该窗口中输入源程序,完了保存文件,文件名必须加上扩展名,汇编程序以”.ASM”或”.A51”为扩展名,C语言以”.C”为扩展名。
b.工程的建立
Keil使用工程(project)概念,将所需设置的参数和所有文件都加在一个工程中,只能对工程进行编译、链接等操作,而不能对单一的源程序操作。
选择Project---NewProject
c.工程的设置
在uVisionIDE界面中单击工程管理窗口中的Target1,然后选择Project—Optionfortarget‘target1’,打开工程设置对话框。
①Target选项卡
Xtal:
Xtal后面的数值是晶振频率值,默认值是所选目标CPU的最高可用频率值。
MemoryModel:
用于设置RAM使用情况
●Small所有变量都在单片机的内部RAM中。
●Compact可以使用一页外部扩展RAM。
●Large可以使用全部外部扩展RAM。
CodeRomSize:
用于设置ROM空间的使用
●Small只用低于2KB的程序空间。
●Compact单个函数的代码量不能超过2KB,整个程序可以使用64KB程序空间。
●Large可用全部64KB空间。
Useon—chipROM:
用于确认是否使用片内ROM。
Operating:
用于操作系统的选择。
Off—chipCodememory:
用以确定系统扩展ROM的地址范围。
Off---chipXdatamemory:
用于确定系统扩展RAM的地址范围。
CodeBanking:
设置代码分组情况,必须根据硬件决定。
②Output选项卡
CreateHexFile:
用于生成可执行代码文件,该文件用编程器写入单片机芯片,文件格式为IntelHEX,文件扩展名为.HEX。
默认情况下该项未被选中,如果要写片做硬件实验,必须选中此项。
DebugInfromation:
用于产生调试信息。
BrowseInformation:
用于产生浏览信息。
SelectFolderforObjects:
用于选择最终目标文件所在文件夹,默认是与工程文件在同一个文件夹中。
NameofExecutable:
用于指定最终生成的目标文件名字,默认与工程名字相同。
CreateLibrary:
用于确定是否将目标文件生成库文件。
③Listing选项卡
用于调整生成的列表文件选项,在汇编或编译完成后将产生(*.lst)列表文件,在链接完成后也将产生(*.m51)列表文件。
④C51选项卡
用于对KeilC51编译器的编译过程进行控制。
其中较常用的是CodeOptimization选项,其Level下拉列表框用于优化等级设置。
⑤Debug选项卡
用于设置调试方式。
⑥Utilities选项卡
用于设置Flash编程器。
(3)编译、链接
●编译或汇编当前文件:
根据当前文件是汇编语言程序文件还是C语言程序文件,使用A51汇编器对汇编语言源程序进行汇编处理,或使用Cx51编译器对C语言程序文件进行编译处理,得到可浮动地址的目标代码。
●建立目标文件:
根据汇编或编译得到的目标文件,并调用有关库模块,链接产生绝对地址的目标文件。
●重建全部:
对工程中的所有文件进行重新编译、汇编处理,然后进行链接产生目标代码。
●停止编译:
在建立目标文件的过程中,可单击该按钮停止这一工作。
●下载到FlashROM:
使用预设的工具将程序代码写入单片机的FlashROM中。
●设置工程:
用于对工程进行设置。
3.数据的类型、运算符与表达式
(1)常量与变量
在程序运行过程中,其值不能被改变的量称为“常量”;
在程序运行过程中,其值可以改变的量称为“变量”。
例在P1口接有8个LED,要求点亮P1.0所接LED。
#defineLight00xfe
#include“reg51.h”
voidmain()
{P1=Light0;}
分析:
程序中用”#defineLight00xfe”来定义符号Light0,以后程序中所有出现Light0的地方均会用0xfe来替代。
该程序执行结果就是P1=0xfe,即接在P1.0引脚上的LED被点亮。
归纳:
使用符号常量的好处:
①含义清楚。
②在需要改变一个常量时能做到“一改全改”。
(2)整型数据
●整型常量:
十进制整数、八进制整数、十六进制整数。
●整型变量的分类:
整型变量的数据类型
C语言中的变量须先定义,后使用。
定义整型变量的方式为:
修饰符变量名
●整型数据在内存中的存放形式:
KeilC规定使用2个字节表示int型数据,在内存中以补码形式存放。
(3)字符型数据
●字符型常量:
C语言中的字符型常量是单引号括起来的一个字符。
如‘a’,‘A’
●字符型变量:
一个变量只能存放一个字符
字符型变量的定义形式为:
修饰符变量名如charc1,c2;
●字符型数据在内存中的存放形式:
是将字符的ASCII码放到存储单元。
(4)实型数据
●实型常量(实数):
十进制小数形式、指数形式。
如123e3
●实型变量:
其定义形式为;修饰符变量名
定义实型变量的修饰符是float和double。
如floatf1;doublef2;
●实型数据在内存中的存放形式:
一个实型数据一般在内存中占4字节(32位),按指数形式存储。
其中1位符号位,8位指数位,23位尾数。
(5)Keil特有的数据类型
●位型数据:
使用一个二进制位来存储数据,其值只有0和1两种。
如bitflag=0;//定义一个位变量
所有的位变量存储在80C51单片机内部RAM中的位寻址区。
由于80C51只有16字节的位寻址区,所以程序中最多只能定义128个位变量。
●sfr型数据
80C51内部有一些特殊功能寄存器sfr,为此C51增加了sfr型数据,增加了sfr,sfr16和sbit这3个关键字。
sfr16是用来定义16位特殊功能寄存器,标准80C51单片机只有一个16位SFR,即DPTR,其定义形式为:
sfr16DPTR=0x82;
(6)80C51中数据的存储位置
80C51单片机的存储器类型较多,有片内ROM、片外ROM、片内RAM、片外RAM。
其中,片内RAM又分为低128字节和高128字节,高128字节只能用间接寻址方式来使用,低128字节又分位寻址区和工作寄存器区。
●程序存储器
在C51中,使用关键字code来说明存储于程序存储器中的数据。
如codeintx=100;//此时x的值在程序运行中不能修改。
内部数据存储器
C51使用3个新的关键字来表示内部RAM中的数据,
即:
data,idata和bdata
用data定义变量用于存取前128字节的内部RAM,
用idata定义变量用于全部256字节。
如果定义的变量与位操作有关,要使用bdata来定义,用bdata定义的变量将全部放在0x20开始的地址空间。
●外部数据存储器
C51提供了2个关键字用于对外部RAM的读/写操作,
即:
pdata和xdata。
pdata用于只有一页(256字节)的情况。
(7)运算符
C运算符分类表
﹪---取模运算符或求余运算符,其两侧均应为整型数据,其结果也为整数。
!
---逻辑非&&----逻辑与||----逻辑或
&---按位”与“|---按位”或“^---按位”异或“
~---按位取反<<---位左移>>----位右移
例1若a=0x4b,b=0xc8,分别求a&b,a|b,a^b,~a,a<<2,a>>2的值。
a&b:
原则:
“有0为0,全1为1”
a|b:
原则:
“有1为1,全0为0”
a^b:
原则:
“相同为0,不同为1”
~a:
原则:
“0变1,1变0”
a<<2:
原则:
”移出位丢失,后面用0填充“
a>>2:
原则:
“移出位丢失,后面用0填充”
●自增减运算符
++i先i值加1,再进行运算i++先运算,再i值加1
--i先i值减1,再进行运算i--先运算,再i值减1
●关系运算符
<小于<=小于等于>大于>=大于等于
==等于!
=不等于
前4种关系运算符高于后2种关系运算符。
●逻辑运算符
&&逻辑“与”||逻辑“或”!
逻辑“非”
●运算符优先次序
关系运算符的优先级低于算术运算符,高于赋值运算符(=)。
C语言逻辑运算符与算术运算符、关系运算符、赋值运算符之间的优先级为:
逻辑非(!
)优先级最高,算术运算符次之,关系运算符再次之,”&&”和”||”又次之,赋值运算符最低。
●条件运算符
一般形式为:
表达式1?
表达式2:
表达式3
例:
max=(a>b)?
a:
b;
其执行过程为:
如果(a>b)条件为”真”,则条件表达式取值a;否则取值b。
4.C51流程与控制
C语言是一种结构化的编程语言,由若干个模块组成,每个模块包含若干个基本结构,而每个基本结构可以有若干条语句。
C语言有3种基本结构:
●顺序结构;
●选择结构;
●循环结构;
(1)顺序结构程序
是最基本、最简单的编程结构。
程序由低地址向高地址顺序执行指令代码。
(2)选择结构程序
●选择语句if
if语句是用来判定所给定的条件是否满足,根据判定的结果(“真”或“假”)执行给出两种操作中的一种操作。
其3种基本形式如下:
①if(表达式)语句
描述:
如果表达式为“真”,则执行语句;否则执行if语句后面的语句。
如if(a>=3)b=0;
②if(表达式)
语句1
else
语句2
描述:
如果表达式的结果为“真”,则执行语句1;否则执行语句2。
如if(a>=3)
b=0;
else
b=100;
③if(表达式1)
语句1
elseif(表达式2)
语句2
elseif(表达式3)
语句3
……
elseif(表达式m)
语句m
……
else
语句n
描述:
如果表达式1的结果为“真”,则执行语句1,退出if语句;否则去判断表达式2,….,最后,如果表达式m也不成立,则执行else后面的语句n。
else和语句n也可省略。
switch/case语句
switch语句的一般形式如下:
switch(表达式)
{case常量表达式1:
语句1
case常量表达式2:
语句2
……
case常量表达式n:
语句n
default:
语句n+1
}
说明:
①switch后括号里的表达式可以是任何类型。
②若表达式的值与某一个case后面的常量表达式相等,就执行此case后面的语句;若所有case中常量表达式的值都没有与表达式相匹配,就执行default后面的语句。
③每一个case中常量表达式的值必须不相同。
④各个case和default的出现次序不影响执行结果。
⑤执行完一个case后面的语句后,系统不会自动跳出switch,转而去执行其后面的语句;而是紧接着执行这个case后面的语句。
(3)循环结构程序
构成循环结构主要有while,do-while和for等常用语句。
●while循环语句
while语句用来实现“当型”循环结构,其一般形式为:
while(表达式)语句
当表达式为非0(“真”)时,执行while语句中的内嵌语句。
即先判断表达式,后执行语句。
●do—while循环语句
用来实现“直到型”循环,是先执行循环体,后判断循环条件是否成立。
其一般形式为:
do
循环体语句
while(表达式)
●for循环语句
for语句既可用于循环次数已确定的情况,也可用于循环次数不确定而只给出循环结束条件的情况。
for语句的一般形式为:
for(表达式1;表达式2;表达式3)
{语句
}
for循环语句执行过程为:
①先求解表达式1。
②求解表达式2,其值为“真”时,则执行for语句中指定的内嵌语句(循环体),然后执行第③步;如果为“假”,则结束循环,转到第⑤步。
③求解表达式3。
④转回上面的第②步继续执行。
⑤退出for循环,执行循环语句的下一条语句。
for语句典型的应用是如下形式:
for(循环变量初值;循环条件;循环变量增值)语句
如inti,sum;
sum=0;
for(i=0;i<=10;i++)
sum+=i;//sum=sum+i;
●break语句
在循环程序中,可以通过循环语句中的表达式来控制循环程序的结束与否。
此外,还可通过break语句强行退出循环结构。
●continue语句
continue语句是结束本次循环,即跳过循环体中下面的语句,接着进行下一次是否执行循环的判定。
continue语句和break语句的区别是:
continue语句只结束本次循环,而不是终止整个循环的执行,而break语句是结束整个循环过程。
例180C52单片机的P1口接有8只发光二极管,P3.2~P3.5接有4个按键,如右图所示,要求按下K1键LED全亮,按下K2键LED全灭。
程序如下:
#include“reg51.h”
voidmain()
{unsignedcharKeyValue;
for(;;)
{P3|=0x3c;
KeyValue=P3|0xfb;
if(KeyValue!
=0xff)
P1=0;
KeyValue=P3|0xf7;
if(KeyValue!
=0xff)
P1=0xff;
}
}
例2如上例电路图,要求按住键K1时灯亮,松开K1后灯灭。
程序如下:
#include“reg51.h”
voidmain()
{for(;;)
{P3|=0x3c;
if((P3|0xfb)!
=0xff)
P1=0;
elseP1=0xff;}}
例3如上图,要求按K1键,P1.7和P1.3所接的LED亮;按K2键,P1.6和P1.2所接的LED亮;按K3键,P1.5和P1.1所接的LED亮;按K4键,P1.4和P1.0所接的LED亮。
程序如下:
#include“reg51.h”
voidmain()
{unsignedcharKeyValue;
for(;;)
{P3|=0x3c;
KeyValue=P3;
switch(KeyValue)
{case0xfb:
P1=0x77;break;
case0xf7:
P1=0xbb;break;
case0xef:
P1=0xdd;break;
case0xdf:
P1=0xee;break;}}}
例4如上图,编程实现:
若K1键被按下,流水灯工作;否则灯全部熄灭。
程序如下:
#include“reg51.h”
#include“intrins.h”
voidmDelay(unsignedintDelayTime)
{unsignedintj=0;
for(;DelayTime>0;DelayTime--)
{for(j=0;j<125;j++)
{;}
}
}
voidmain()
{unsignedcharOutData=0xfe;
while
(1)
{P3|=0x3c;
while((P3|0xfb)!
=0xff)
{P1=OutData;
OutData=_crol_(OutData,1);//循环左移
mDelay(1000);//延时1000ms
}
P1=0ff;
}
}