单片机 第七章课件.docx
《单片机 第七章课件.docx》由会员分享,可在线阅读,更多相关《单片机 第七章课件.docx(12页珍藏版)》请在冰豆网上搜索。
单片机第七章课件
第九讲
课题:
MCS-51单片机控制与C语言一
教学目的:
掌握C51的语法和编程方法
学习C51程序设计
教学难点、重点:
C51程序设计
I、课程复习、引入
C语言是一种编译型程序设计语言,它兼顾了多种高级语言的特点,并具备汇编语言的某些特点,用C语言进行程序设计已经成为软件开发的一个主流。
单片机开发也适应了这个潮流。
II、本课内容
第七章MCS-51单片机控制与C语言
7.1C语言与MCS-51
用C语言开发单片机的优点:
●优于汇编语言的开发速度。
●软件的可读性和维护性显著改善。
●提供的库函数包含许多标准子程序,具有较强的数据处理能力。
●关键字及控制转移方式更接近于人的思维方式。
●方便地进行多人联合开发,进行模块化软件设计。
●方便进行同一硬件平台的软件设计和移植
●方便跨硬件平台软件移植。
●适合运行嵌入式实时操作系统。
本章是针对这种被广泛运用的MCS-51的C语言编译器KeilC51,介绍MCS-51单片机C语言程序设计。
7.1.1C语言提要
1)C语言的注释
(1)//(双斜杠)注释,表示从双斜杠开始到本
行结尾是注释,不参加编释,多见于C++。
(2)/**/(斜杠星号对)之间是注释,可以允许多行。
KeilC51同时可上面两种注释。
2)C的数据类型
数据类型
基本类型:
整型、字符型、枚举类型、实型:
单精度型和双精度型
构造类型
括数组类型、结构体类型、共用体类型。
指针类型
空类型
Bitsbit
3)C的运算符
算术运算符+、-、*、/、%(整除求余)、++(自加)、--(自减)
关系运算符>、<、==、>=、<=、!
=
逻辑运算符!
、&&、||
位运算符<<(左移)、>>(右移)、~、|、^、&
赋值运算符=及其扩展赋值运算符
条件运算符?
;
逗号运算符,
指针运算符*&
求字节数运算符sizeof
强制类型转换运算符类型
分量运算符.→
下标运算符[]
其他如函数调用运算符()
C语言可以分为以下五类:
控制语句完成一定的控制功能。
C只有9种控制语句,它们是:
if()~else~条件语句
for()~循环语句
while()~循环语句
do~while()循环语句
continue结束本次循环语句
break中止执行switch或循环语句
switch多分支选择语句
goto转向语句
return从函数返回语句
②函数调用语句由一次函数调用加一个分号构成一个语句,例如:
Printf(“ThisisaCstatement,”);INIT-SCI();
表达式语句由一个表达式构成一个语句。
最典型的是由赋值表达式构成一个赋值语句。
A=3//是一个表达式
a=3;//是一个赋值语句,一个语句必须在最后出现分号。
表达式能构成语句是C语言的一个特色。
C程序中大多数语句是表达式语句(包括函数调用语句)。
④空语句下面是一个空语句:
;
即只有一个分号的语句,它什么也不做。
不是MCS-51汇编语言中的NOP。
⑤可以用{}把一些语句括起来成为复合语句,如下面是一个复合语句。
{z=jx+y;
t=z/100;P1=0xff;}
注意:
复合语句中的最后一个语句的分号不能忽略不写。
4)程序的三种基本结构
结构化程序由若干个基本结构组成。
每一个基本结构可以包括一个或若干个语句。
有三种基本结构。
(1)顺序结构,按次序从上往下执行程序。
(2)选择结构,当满足条件时执行一条语句,不满足时,执行另外一条语句。
if()~else~条件语句
(3)循环结构,有两种循环结构:
1当型循环结构(while)。
2直到型循环结构(do~while)。
3for()~循环语句
5)数据输入和输出方法
输入和输出是由函数来实现的。
在C的标准函数库中提供了一些输入和输出函数,如printf函数和scanf函数。
在使用它们时,千万不要简单地认为它们是C语言的“输入输出语句”。
C51的输入/输出也可以对芯片的IO口进行操作,见例7-1。
6)关系运算符及其优先次序
<(小于),<=(小于或等于),>(大于),>=(大于或等于),优先级相同(高)
==(等于),!
=(不等于),优先级相同(低)
在C语言中可以用以下语句来实现循环:
(1)用goto语句和if语句构成循环
1与if语句一起构成循环结构;
2从循环体中跳到循环体外,但在C语言中一般会用break或者continue跳出循环,所以goto很少用
(2)用while语句:
它用来实现“当型”。
其一般形式如下:
While(表达式)语句
当表达式为非0(“真”)时执行while语句中的内嵌语句。
其特点是:
先判断表达式,后执行语句。
while
(1){……}死循环结构,单片机的主程序一般必有的语句。
(3)用do~while语句:
它用来实现“直到型”循环结构。
其一般形式为:
Do语句
While(表达式)
其特点是:
首先执行语句,后判断表达式。
先执行一次指定的内嵌的语句,然后判别表达式,当表达式的值为非0(“真”)时,返回重新执行该语句,如此反复,直到表达式的值等于0为止,此时循环结束。
(4)用for语句
for(表达式1;表达式2;表达式3)语句,例:
for(j=0;j<30000;j++){……};
它的执行过程如下:
1先求解表达式1。
2求解表达式2,若其值为真(非0),则执行for语句中指定的内嵌语句,然后执行下面步骤③;若为假(0),则结束循环,转到第⑤步。
3若表达式为真,在执行指定的语句后,求解表达式3。
4转回上面步骤②继续执行。
5执行for语句下面的一个语句。
7)数组和一维数组的定义
一维数组的定义方式为
类型说明符数组名[常量表达式];
例如inta[10];
它表示数组名为a,此数组有10个元素。
说明:
(1)数组名定名规则和变量名相同,遵循标识符定名规则。
(2)数组名后是用方括弧括起来的常量表达式,不能用圆括弧。
(3)常量表达式表示元素的个数,即数组长度。
(4)常量表达式中可以包括常量和符号常量,不能包含变量;也就是说,C不允许对数组的大小做动态定义,即数组的大小不依赖于程序运行过程中变量的值。
字符串在C语言中,将字符串作为字符数组来处理。
8)函数
(1)一个源程序文件由一个或多个函数组成。
一个源程序文件是一个编译单位,即以源文件为单位进行编译,而不是以函数为单位进行编译。
(2)一个C语言程序由一个或多个源程序文件组成。
对较大的程序,一般不希望全放在一个文件中,而将函数和其他内容(如预定义)分别放到若干个源文件中,再由若干源文件组成一个C程序。
这样可以分别编写,分别编译,提高调试效率。
一个源文件可以为多个C语言共用。
(3)C语言的执行从main函数开始,调用其他函数后流程回到main函数,在main函数中结束整个程序的运行。
main函数是系统定义的。
(4)所有函数都是平行的,即在定义函数时是相互独立的。
一个函数并不从属于另一函数,即函数不能嵌套定义,但可以相互调用。
不能调用main函数。
(5)从用户使用的角度看,函数有两种:
1标准函数,即库函数这是由系统提供的,用户不必自己定义这些函数,可以直接使用它们。
应该说明,每个系统提供的库函数的数量和功能不同,但有一些基本的main函数是共同的。
2用户自己定义的函数以解决用户的专门需要。
(6)从函数的形式看,函数分为两类:
1无参函数在调用无参函数时,主调函数并不将数据传送给被调用函数,一般用来执行指定的一组操作。
无参函数可以带回或不带回函数值,但是一般以不带回函数值的居多。
2有参函数在调用函数时,在主调函数和被调函数之间有参数传递,也就是说,主调函数可以将数据传给被调用函数使用,被调用函数中的数据也可以带回来供主调函数使用。
9)函数调用的一般形式
函数调用的一般形式为:
函数名(实参列表);
10)局部变量和全局变量
1局部变量在一个函数内部定义的变量,它只在本函数范围内有效,也就是说只有在本函数内才能使用它们,在此范围以外是不能使用这些变量的,这称为“局部变量”。
说明:
239
2全局变量程序的编译单位是源程序文件,一个源程序可以包含一个或若干个函数。
在函数内定义的变量是局部变量,而在函数之外定义的变量称为外部变量,外部变量是全局变量。
全局变量可以为本文件中其他函数所共用。
它的有效范围为:
从定义变量的位置开始到本源文件结束。
7.1.2C51程序的开发过程
P240
7.2用C语言写51单片机软件的一般方法
7.2.1C语言控制8051单片机的I/O口(241)
电路图描述如下:
在89C52的P1.3脚上接一个发光二极管和限流电阻,见图7-2,编写一段程序程序使这个发光二极管每隔约0.3s闪烁一次。
下面将直接给出源程序,请读者仔细阅读它的注释。
例7-1发光二极管每隔约0.3s闪烁一次。
//文件名:
LED1.C
#include//标准8051头文件,定义了所有的特殊寄存器SFR
sbitLED=P1^3;
sbitbutton=P3^2;
Voidmain(void)//主函数无返回值
{
intj;//定义了一个整型变量
While
(1)//一个完整的单片机程序必须是死循环
{
LED=0;//将引脚清0,因此点亮发光二极管
For(j=0;j<30000;j++);//空循环延时
LED=1;
For(j=0;j<30000;j++);
}
}
这是一个完整的8051的C源程序,请注意主函数中的闭合循环(死循环),因为单片机中没有其他软件,也就没有PC机C语言中所谓退到DOS或Windows的概念,如果程序中没有闭合循环,程序执行的结果将不可预计。
●只要在C语言函数中的变量定义部分用sbit定义引脚,能够用C51使MCS-51单片机32根I/O引脚的任何一根输出高或低电平
●用8051的准双向进行输入操作,务必以下两步:
(1)把要进行输入的引脚置成高电平。
(2)进行输入操作。
如例7-1中的button,还定义了一个变量j,则:
button=1;//第一步,拉高button引脚
If(button)j=1;elsej=0;//第二步
这时button引脚如果是高电平,则j的值就是1;如果是低电平,则j的值就是0。
如需8根端口线作为输出P1=0x5E;后P1端口上八根线的电平从P1.7~P1.0依次为01011110。
如需8根端口线作为输入,则:
(1)把要输入的所有引脚置1,如P1=0xff。
(2)进行输入操作。
执行j=P1;指令,这时j的值就是P1端口线当时的状态,如果当时P1端口上的电平从P1.7~P1.0依次为11001010,那么执行j=P1;后j的值就是0xCA。
7.2.2C语言对MCS-51单片机位处理器的运用
KeilC51扩展了标准C语言,很好地支持了8051特有的位处理功能。
如上文提到的sbit关键字,除了定义引脚以外还可以定义所有的特殊功能寄存器中可以位寻址的变量。
如定义
sbitspcialbit=0xe1;//这时spcialbit就代表了累加器的第一位ACC.1。
KeilC51也可以通过扩展扩展关键字bit来定义位变量。
如
bitbitval;//这时bitval的值是0或1,它的实际物理地址将位于8051内部20H~2FH
//的可位寻址区。
举例:
bitval=spcialbit;//将ACC.1的值赋给了bitval
If(bitval)button=0;elsebutton=1;
Button=!
Bitval;//含义同上一句
7.2.3C语言管理MCS-51单片机内部定时器
将单片机内部的两个定时器进行初始化,给定时器1设置初始值,并启动定时器1:
VoidInitTimer1(void)
{
TMOD=0x15;
/*初始化定时器1为定时器工作方式,即对由系统晶振决定的机器周期进行计数,模式1,16位计数,由TMOD的高4位决定;初始化定时器0为定时器工作方式,即对T0(P3.4)引脚上的脉冲进行计数,模式1,16位计数,由TMOD的低4位决定*/
TH1=0;TL1=0;//定时器1设初始值
TR1=1;//位处理指令,启动定时器1
}
TMOD复位值00H
7
6
5
4
3
2
1
0
GATE1
CD/T
M1
M0
GATE0
C/T
M1
M0
TCON复位值00H
7
6
5
4
3
2
1
0
TF1
TR1
TF0
TR0
IE0
IT1
IE0
IT0
如果要在运行中查询定时器1是否溢出,就必须用位处理指令查询TF1。
下面的程序段用查询方法在LED口上输出10Hz的方波。
`例7-2用查询方法在LED口上输出10Hz的方波。
//文件名:
TF1.c
//定时器查询.系统晶体频率11.0592MHz
#include
SbitLED=P1^3;
VoidINIT-TMR1(void)
{
TMOD=0x11;
TH1=0x4C;//(65536-50000us/(12cyc/11.0592MHz))/256
TL1=0;//(65536-50000us/(12cyc/11.0592MHz))%256
TR1=1;
}
Voidmain(void)
{
INIT-TMR1();
While
(1)
{
If(TF1==1)
{LED=~LED;
TF1=0;
TH1=0x4C;
TL1=0;//TL0在溢出时正好为0,可以不写
}
}
}
再举一计算定时器常数的例子:
已知P89C51RD2的机器周期为6个时钟周期,晶体用12MHz,要求产生10ms定时,计算如下:
(TMOD=0x11;)
TH0=(65536-10000us/(6cyc/12MHz))/256=177.875……取整177
TL0=(65536-10000us/(6cyc/12MHz))%256=224……取余数
7.2.4C语言管理MCS-51单片机中断系统
标准的MCS-51有5个中断源,分别是外中断0、定时计数器0、外中断1、定时计数器1和串行接口。
这些中断源的管理有一个共同点,就是必须在主函数中先写初始化指令,然后再写中断服务程序。
例7-3用中断方式实现在LED口上输出10Hz的方波的完整源程序:
//文件名:
TINT.C
//定时器中断方式,在LED上输出10Hz的方波.系统晶体频率为11.0592MHz
#include
SbitLED=P1^3;
VoidINIT-TMR1(void)
{
TMOD=0x11;
TH1=0x4C;//(65536-50000us/(12cyc/11.0592MHz))/256
TL1=0;//(65536-50000us/(12cyc/11.0592MHz))%256
TR1=1;
}
VoidINIT-TMR1INT(void)
{
ET1=1;EA=1;
}
//定时器1中断服务程序,注意其句尾的关键字interrupt和中断号3
VoidTMR1-INT-SRV(void)interrupt3
{
TH1=0x4C;LED=~LED;
}
//主函数中没有调用中断服务程序,由硬件自动调用
Voidmain(void)
{
INIT-TMR1();
INIT-TMR1INT();
While
(1)
{
}
}
软件调试TINT.C:
表7-1MCS-51中断系统相关参数
中断名
中断向量
开中断初始化命令串
KeilC51中断号
优先级控制,如置1为高优先级,置0为低优先级
外中断0
0003H
EX0=1;IT0=1;
0
PX0
定时器0
000BH
ET0=1;
1
PT0
外中断1
0013H
EX1=1;IT1=1;
2
PX1
定时器1
001BH
ET1=1;
3
PT1
串行接口
0023H
ES=1;
4
PS
注:
开放中断还应把中断总开关EA打开。
注意,表格中的第四列KeilC51中断号,在中断服务程序的书写格式中,它是紧跟在关键字interrupt后面的,这个号码是C编译器编译中断服务程序的惟一依据,中断服务程序名字只对程序员有意义。
例7-4将一个按键接到外中断0的端口线上,按键接通(按下)将端口线接地,按下后将引起8051外中断。
中断服务程序中CPU将点亮LED一会儿,然后关闭,等待下次中断。
硬件图如图7-6所示。
//文件名:
EXTINT.C
#include
SbitLED=P1^3;
VoidEXT0-INIT(void)
{
EX0=1;//允许外中断0
IT0=1;//下跳沿响应外中断
EA=1;
}
VoidEXT0-INT-SRV(void)interrupt0
{
Dataintj;//关键字Data将变量j定义在片内RAM
LED=0;//将引脚清0,因此点亮发光二极管
For(j=0;j<30000;j++);//空循环延时
For(j=0;j<30000;j++);//空循环延时
LED=1;/关闭LED,退出中断
}
Voidmain(void)
{
EXT0-INIT();
While
(1){};
}
软件调试EXTINT.C:
III、本课小结
学习了C51语言
学习了C51对位寻址、内部定时器、中断系统的应用编程
IV、作业:
实验准备