Transcript Document

现代电子技术实验
——综合实验之单片机部分
习友宝
目录
1. 本课程简介及要求
2. 实验开发板介绍
3. C51程序设计简介
4. 开发环境与实验例程
1. 本课程简介及要求
 1)课程性质
 必修课程:纳入本科培养方案。
 综合:先修课程的综合;体现在模拟与数字、硬件与软
件技术等的综合。
 实验:实践动手完成相应的设计。
 2)课程目的
 实践能力与工程素质的培养。
 3)教学方式
 学生为主,教师为辅:教师讲解后,学生自主完成,教
师值班指导。
 时间:2周(第1周讲课3次,第2周五考试,其余时间
开放,每天上午9:00~晚上9:00)。
 4)考核方式
 平时设计(含设计报告)50分;考试(现场完成,1小
时)50分。
 考虑完成时间因素。
 5)课程内容
 具有实际工程应用背景的小课题。
 模拟实际电子设备或系统的设计。
 目前,主要基于FPGA或单片机两种开发工具。这里主
要介绍基于单片机的综合应用。
 单片机选型:增强型51单片机。
 5)课程内容(续)
 硬件:提供统一的单片机开发实验板,但需理解其设计
原理、常用芯片、接口设计等。
 软件:完成基于开发板的程序设计。
 编程语言:C51(面向51单片机的C语言)。
 6)平时设计题目
 基本要求:
 (1)程序运行后,在8位数码管的高2位显示自己的学号;低4位显示“
秒表计时器”(定时中断实现),显示从“00.00”开始,即00秒00(
1/100秒,即10ms)。要求:用定时中断实现(不用Delay()函数)。
 (2)当“秒表计时器”显示到“10.00”(即10秒)时,启动TLC549
A/D转换器进行电压测量(输入电压来自电位器,调节范围
0~2.49V,单位:V),并将电压值显示在8位数码管的低3位。高2位仍
显示学号。
 (3)根据显示的电压值来调节一个发光二极管指示灯的亮度(如
LED1),即电压为零时,完全不亮,电压为最大2.49V时,全亮。

要求能够线性调节,即A/D转换器TLC549为8bit,理论上可对应
256级亮度。提示:用PWM控制,PWM波频率适当即可,建议取
2.56ms或25.6ms的周期,亮度等级为25级。
 (4)调节电位器,若电压超过2.00V,则声光报警,即用另一个发
光二极管指示灯(如LED2)闪烁(亮0.5s、灭0.5s);蜂鸣器响(用
500Hz方波驱动);若输入电压低于2.00V后,则撤销声光报警。
 (5)设置一个按键,当按下该按键时,蜂鸣器响0.1秒(按键提示音
),同时启动LM75A数字温度传感器完成温度的测量,并将温度值(
2位整数1位小数)显示在低3位数码管上。高2位仍显示学号。
 (6)再次按下该键时,蜂鸣器响0.1秒,同时再回到电压测量状态。
 扩展要求:
 (7)对电压测量值进行简单的数据处理,如去除尖峰干扰的平均滤波
:每12个测量值数据为一组,去掉最大值和最小值后的10个测量值进
行算术平均后,作为显示值。为不影响测量结果的实时性,还可进行
滚动滤波。
 (8)其他:LCD、扩展接口。
 设计报告要求:
 按科技论文规范。
 7)参考资料
 (1)51单片机参考书(主要了解单片机结构和内部资
源)
 (2)C语言、C51程序设计参考书
 (3)本课程的电子版资料,包括实验指导书、实验例
程、主要元器件数据手册(datasheet)、软件资料等
 (4)网络资源
2. 实验开发板介绍
 (1)开发板上单片机的选型
 P89LV51RD2:80C51 内核的ISP低功耗增强型单片机
 含64kB flash和1024字节的数据RAM;另8KB 引导 flash(用来支
持 ISP 和 IAP 功能)
 可选择X2方式:每个机器周期6个时钟
 3V工作电压,操作频率为0~33MHz,兼容TTL和CMOS逻辑电平
 SPI(串行外围接口)和增强型UART
 PCA(可编程计数器阵列),具有PWM和捕获/比较
 4个8位I/O口,3个高电流P1口(16mA)
 3个16位定时器/计数器
 可编程看门狗定时器(WDT)
 8个中断源,4个中断优先级
 2个DPTR寄存器
 低功耗模式、掉电模式,外部中断唤醒、空闲模式
 详见其datasheet。
P89LV51RD2内部功能图
 P89LV51RD2
 TQFP44封装
 引脚图
 (3)开发板主要特性和板载资源
 外接+5V供电,板上主电源为+3.3V。
 开发板在PC机 Windows 环境软件开发工具 Keil uVision
的支持下,不需要安装特别的驱动程序,通过RS232串口
就能够方便地进行硬件在线仿真、调试,支持单步、全速
、断点、跳出、变量观察、外围设备访问等仿真功能。
 设置跳线选择,所有4个端口P1、P3、P0、P2可作为普
通I/O口;或P3口第二功能、 P0、P2口作为数据/地址。
 晶振频率:为常用的11.0592MHz。
 复位方式:RC上电复位、按键复位
 外部32KB静态RAM(U9,IS62LV256),地址为
0x0000~0x7FFF,其中0x0000~0x03ff(1kB)可设置为片
内或片外。
 8个LED灯、8位拨动开关、8个按键、8个共阳极数码管、
蜂鸣器









扩展并行输出接口(74HC573)、输入(74HC245)
实时时钟(PCF8563)
64kb(8kB)EEPROM存储器(AT24LC64 )
1-Wire总线的数字温度计(DS18B20 )
I2C接口的数字温度计(LM75A )
8位串行接口的逐次比较式A/D转换器(TLC549 )
提供128x64 LCD模块接口,可并行连接或串行连接。
扩展功能连接(8位数据线、高8位地址线、3.3V电源线)。
可完成的主要实验内容有:
 基本:LED灯、拨动开关、键盘、蜂鸣器、LED动态扫描显示、液
晶屏、I2C总线、EEPROM数据存储、数字温度计、电压测量、频
率测量、电子钟,等等。
 扩展:LCD显示;其他测量与控制,如直流电机、步进电机应用
开发板主要芯片
标号
型号
功能描述
U1
P89LV51RD2
Philips增强型51单片机,3.3V供电
U4
DS18B20
1-Wire总线的数字温度计
U5
AT24LC64
64kb(8kB)EEPROM数据存储器
U6
LM75A
I2C接口的数字温度计
U7
PCF8563
实时时钟
U8、U17、
U18、U22
74HC573
锁存器,其中U8用于地址锁存器;
其他的用于扩展的输出接口
U23、U24
74HC245
双向数据缓冲器,用于扩展的输入接口
U9
IS62LV256
64kB静态数据存储器(RAM),地址
0x0000~0x7FFF
U16
TLC549
8位串行接口的逐次比较式A/D转换器
U10
SP3232
RS232接口驱动器
D410361SR
4位共阳极数码管
U19、U20
(4)开发板原理图-1
 (4)开发板原理图介绍
(4)开发板原理图-2
 地址分配
 外部扩展RAM: CS_=A15:0x0000~0x7fff
 I/O地址:0x8000~0xbfff, 0xc000~0xffff(可用于扩展)
 地址译码电路:
 各端口地址如下:
标号
接口芯片
端口地址
备注
LED1~LED8 U22 (74HC573)或P0 0xA000,输出
最高位对应LED8
0x8000,输入
最高位对应KEY8
KEY1~KEY8 U23 (74HC245)
SW1~SW8
U24 (74HC245)或P2 0x9000,输入
最高位对应SW8
U19/U20-1~8 U18 (74HC573)
0x8000,输出
8位数码管显示段驱动
U19/U20-1~8 U17 (74HC573)
0x9000,输出
8位数码管显示位驱动
0xB000,输入
/输出
LCD模块地址
LCM1
 P1口线
 的分配
跳线设置:
标号
功能
选择之一
选择之二
JP1
P0口功能选择
P00~P07(左侧):
普通I/O口
D0~D7(右侧):数据/地址线
JP2
P2口功能选择
P20~P27(左侧):
普通I/O口
A8~A15(右侧):高位地址线
JP6
8位发光二极管驱
动选择
P00~P07(上面):
用P0口驱动
D0~D7(下面):用扩展端口驱
动
JP7
8位微动开关驱动
选择
P20~P27(上面):
用P2口驱动
D0~D7(下面):用扩展端口驱
动
JP3
A/D转换器电压输
入选择
RP(左侧):
板上电位器
Vx(右侧):外部输入电压
(从J3输入)
JP5
LCD驱动方式选择
并(左侧):并行接口
串(右侧):串行接口
JP4
LCD接口信号线选 左侧:并行方式,
RS=A0,R/W=A1,
择
E=译码信号(0xB000)
右侧:串行方式,接口信号
来自于J4:RS=LCD_CS
,R/W=LCD_SCLK,
E=LCD_SIO
3. C51程序设计简介
 1)C51与标准C语言的差异
 兼容标准C:语法、结构、程序设计方法等相同
 具有特殊性:面向51单片机,与单片机的硬件资源相关
• 库函数:特定的库函数
• 数据类型:增加了面向单片机的特殊数据类型,如位操作的位
类型、寄存器类型等
• 变量存储模式:与51单片机的存储器密切相关
• 函数:增加了用于处理单片机中断的中断函数
 专用编译器:如常用的Keil,代码紧凑、使用方便。
 集成开发环境:编辑、编译、调试。如常用的Keil
uVision。
 2)C51的数据类型
 与标准C一样,有基本数据类型、组合数据类型;但
char型与short型相同,float型与double型相同。
 C51的特定数据类型(如特殊功能寄存器型、位类型)
 (1)字符型(“字节型”):char
 signed char(默认):带符号字节数据,补码表示的
数值范围:(1000 0000) -128~+127 (0111 1111)。
 unsigned char:无符号字节数据或字符(ASCII码)
,可表示0~255。
 因此,我们可称其为“字节型”。
 (2)整形:int
 singed int(默认):存放一个双字节数据, 补码表示
的数值范围为:-32768~+32767;
 unsigned int:存放一个双字节无符号数,数值范围为
0~65535。
 (3) 长整型:long
 singed long(默认):存放一个4字节数据;
 unsigned long:存放一个4字节无符号数据。
 注:由于所定义的不同类型的变量,需要占用单
片机内存,所以尽量选用满足变量范围的类型。
 (4) 浮点型:float
 float :4个字节表示,格式符合IEEE-754标准的单精度
浮点型数据;
 C51中,double双精度浮点型和long double与float相同;
 包含指数和尾数两部分,最高位为符号位,“1”表示负
数,“0”表示正数,其次的8位为阶码,最后的23位为
尾数的有效数位,由于尾数的整数部分隐含为“1”,所
以尾数的精度为24位。
 浮点数均为带符号数。
 注:单片机的数据处理尽量采用整数,而不用小数(浮点
型);对小数的处理,将其小数点移位变成整数即可。
 如:8位A/D转换器测电压:
 unsigned int Vx;
 unsigned char V100,V10,V1;
 NADC = ReadADC();
 Vx=[(NADC)/256]*2.50V,其中Vref=2.50V
 Vx=(NADC*250)/256;
 V100 = Vx/100;
//百位数
 V10 = (Vx-100*V100)/10; //十位数
 V1 = (Vx-100*V100)%10; //个位数
 小数点隐含在百位数。
 (5)指针型:*
 *:指针型变量中存放的是指向另一个数据的地址。
 如:int a, b,*p; //指针变量的声明,p是指向整形变量
的指针变量

p = &a; //指针变量赋初值

b = *p;
//相当于 b = a;
 实际应用中,常将单片机外部存储器或I/O端口的访问
用指针操作。
 (6)特殊功能寄存器型:sfr或sfr16
 C51扩展的数据类型。
 sfr:字节型特殊功能寄存器类型,可访问51单片机内部
所有特殊功能寄存器;
 sfr16: 双字节型特殊功能寄存器类型,可访问51单片
机内部所有双字节的特殊功能寄存器。
 在reg51.h(或reg52.h)头文件中,已有标准51单片机
寄存器的声明,因此,C51程序的开头都是:#include
<reg51.h>,这样,在程序中就可直接使用单片机的特
殊功能寄存器了。
 对于特定型号单片机的特殊功能寄存器,就需要用sfr或
sfr16重新定义。
 (7)位类型:bit型
 C51扩展的数据类型。可用于访问51单片机中的可寻址
的位单元,占一个二进制位,其值为’0’或’1’。
 bit型:bit定义的位变量,其位地址是可以变化的;
 sbit型:sbit定义的位变量与51单片机的一个可寻址位单元
或可位寻址的字节单元(如可位寻址的特殊功能寄存器
)中的某一位相联系,其对应的位地址是不可变化的。
 常用于设定程序中的一些“标志位”。如:
 bdata unsigned char flags; //定义可位寻址的字节
 sbit int10ms_flag = flags^0; //定义标志位
 或者:bit bdata int10ms_flag;
 又如:sbit LED = P1^0;
//定义LED由P1.0控制
C51的基本数据类型
基本数据类型
长度
取值范围
unsigned char
1字节
0~255
signed char
1字节
-128~+127
unsigned int
2字节
0~65535
signed int
2字节
-32768~+32767
unsigned long
4字节
0~4294967295
signed long
4字节
-2147483648~+2147483647
float
4字节
1.175494E-38~3.402823E+38
bit
1位
0或1
sbit
1位
0或1
sfr
1字节
0~255
sfr16
2字节
0~65535
 (8)变量类型的转换








数据运算中出现数据类型不一致时,就需要转换;
隐式转换,按如下优先级:
bitcharintlongfloat
signedunsigned
强制类型转换:“()”
如:unsigned char a;
unsigned int b=256;
a = (unsigned char)b; //此时,a=0
 (9)组合数据类型
 包括数组类型、结构类型、联合类型、枚举类型等。
 数组:





一维数据,如:
unsigned char disp_buf[8];
字符数组,如:unsigned char string[10];
数组常与指针一起用;
二维数组。
 联合:
 也称“共同体”,将不同数据类型组织成一个整体——联合变量;
这些不同类型变量存储在单片机同一存储区。典型应用
如:
 unsigned char ch_word_h,ch_word_l;
 union
//union后的联合体名可省略
 { unsigned char byte[2];

unsigned int word;
 }ch_word;
//定义联合变量ch_word,以存储一个汉字
 ch_word.word = 0x8090;
//一个汉字编码(双字节,高位’1’)
 ch_word_h = ch_word.byte[0];
//取编码的高字节,应为0x80
 ch_word_l = ch_word.byte[1];
//取编码的低字节,应为0x90
 可以看到,51单片机是以低字节在前、高字节在后存储的
 结构体:






将一类相关变量“归类”在一起。如:
struct date
{ unsigned int year;
unsigned char month , day;
}d1;
//定义结构体变量d1
注意与联合体的区别:结构体内变量分别独立存储(独
立存在);而联合体是共用同一存储区,对其中一个变
量赋值,另外的变量也就有了相应的值。
 枚举:
 对于具有固定取值范围的变量,将其值一一列出,并用相应符号表
示,这些符号具有从0开始的序列号值(整数,依次加1)。如:
 enum weekday //定义枚举类型,枚举名为weekday
 { Sun,
//枚举元素,其后用’,’
 Mon,
 Tue,
 Wed,
 Thu,
 Fri,
 Sat
//最后一个元素不用’,’
 } d1;
//定义枚举变量d1
 d1 = Sun;
//d1的值实际为0
 (10)变量引用
 当一个项目(project,即一个完整程序)中有多个源程
序文件时,如果在一个文件中定义的变量需要在另一个
文件中使用(“引用”),需在该变量定义前加“extern”
。
 如:在file1.c中,定义:

unsigned char key_value;
 若在file2.c中需要使用key_value,则:

extern unsigned char key_value;
 (11)数据类型的别名
 用typedef为已有数据类型取别名,可增加程序的可读
性,且简洁明了。如首先定义:
 typedef unsigned int uchar;
 typedef unsigned char uint;
 其后就可用uint和uchar 定义变量了,如:
 uchar a1=0x12;
 uint a2=0x1234;
 (12)变量名的命名
 规则:由字母、数字和下划线三种字符组成,且第一个
字母必须为字母或下划线。
 为提高程序的可读性,一般由多个英文单词(或缩写)
连接而成。
 注意规范:

多个英文单词的首字母大写,如:KeyValue

多个英文单词之间用下划线连接,如:key_value
 3)C51的常数
 整形常数:如100,-1;100L则为长整形——用4字节
存储;
 十六进制表示:如0x64;
 浮点数常数(实型常数):十进制表示,如1.23;指数
表示,如1.234e2。
 字符常数:对于可显示字符,加单引号表示,如’a’,
‘1’;对于不可显示字符,用转义字符(反斜杠“\”)
表示,如’\n’表示换行,也可用其ASCII码值表示:
’\x0a’。
 字符串常数:加双引号,如“abc123”,注:字符串后
有一个结束符’\x00’。
转义字符表
转义字符
含 义
ASCII码(十六进制数)
\o
空字符(null)
00H
\n
换行符(LF)
0AH
\r
回车符(CR)
0DH
\t
水平制表符(HT)
09H
\b
退格符(BS)
08H
\f
换页符(FF)
0CH
\‘
单引号
27H
\”
双引号
22H
\\
反斜杠
5CH
 定义符号常数:const
 如,在程序开头,定义:

const float PI = 3.14159;
 则程序中可用PI代替该常数。
 4)变量的存储
 程序中的变量,其在程序运行过程中,存在时间、作用
范围以及对于单片机实际物理存储区域有所不同。
 全局变量与局部变量:
 全局变量:在源程序开头定义的变量,其作用范围为本
文件中,其他文件需要引用的话,需加extern。
 局部变量:函数中定义的变量,其作用范围为本函数中
;函数执行时才分配(占用)内存空间,结束时释放。
 尽量少定义全局变量:占内存;可靠性
 有些固定的数据表(不需要改变其值),可加code,
存储于程序存储器。如LED七段码表:
 code unsigned char disp_seg[] =
{0x3F,0x06,0x5B,0x4F,0x66,0x6D,0x7D,0x07,0x7F,0x6F,0x77,0x
7c,0x39,0x5f,0x79,0x71};
 从作用范围来说,有自动(auto)、外部(extern)、静态(static)和寄存器
(register)等4种。
 自动变量,auto:
 函数中的变量,可省略auto关键字,缺省为auto。
 外部变量,extern:
 文件外;函数外;占用固定内存空间。
 静态变量,static:
 函数体内定义:内部静态变量。典型应用,如在定时中断服务函数
中,用一个静态变量来计定时中断的次数:
 static unsigned char int10ms_num=0;
 函数外部定义:外部静态变量,本文件中有效。
 寄存器变量,register:
 对应单片机寄存器,速度快。如,可用于for(;;)循环变量;
 可不专门声明,编译器可自动识别程序中频繁使用的变量。
 变量的存储器类型
 定义变量在单片机中的物理存储区域,缺省时编译器按具体编译模
式默认指定存储区。如下表:
存储器类型
描 述
data
bdata
idata
对应直接寻址的片内RAM低128B(访问速度快)
pdata
xdata
code
用Ri间接访问的片外RAM的低256B
片内RAM的可位寻址区(20H~2FH)
间接寻址访问的片内RAM,允许访问全部片内RAM
用DPTR间接访问的片外RAM,64kB
程序存储器ROM 64k空间
 3种编译模式默认的存储器类型
 small模式(小模式):编译时函数参数和变量被默认
在片内RAM中,存储器类型为data。
 compact模式(紧凑模式)。编译时函数参数和变量被
默认在片外RAM的低256字节空间,存储器类型为
pdata。
 large模式(大模式)。编译时函数参数和变量被默认
在片外RAM的64K字节空间,存储器类型为xdata。
 可在程序开头用预处理指令说明编译模式:

#pragma small
//编译模式:small
 或:开发环境中设置。
 一般均采用small模式。
 5)绝对地址访问
 对code、data、pdata和xdata空间进行绝对寻址(规定只能以无
符号数方式访问)。
 在absacc.h (absolute address access)头文件中,有如下宏定
义:
 #define CBYTE ((unsigned char volatile code *) 0)
 #define DBYTE ((unsigned char volatile data *) 0)
 #define PBYTE ((unsigned char volatile pdata *) 0)
 #define XBYTE ((unsigned char volatile xdata *) 0)
 #define CWORD ((unsigned int volatile code *) 0)
 #define DWORD ((unsigned int volatile data *) 0)
 #define PWORD ((unsigned int volatile pdata *) 0)
 #define XWORD ((unsigned int volatile xdata *) 0)
 以XBYTE为例,说明如下:
 #define XBYTE ((unsigned char volatile xdata *) 0)
 0为常数,(unsigned char xdata *)为强制类型转换,将0转
换为指向外部存储器的字节型指针;
 关键字volatile修饰的变量,可防止编译器优化;
 因此,XBYTE应该是一个指针,指向64kB外部存储器(
或I/O)的0x0000地址;
 对0x1234的访问(读/写、输入/输出)可用如下形式:

unsigned char a=10,b;

XBYTE[0x1234] = a; //读0x1234存储单元;或输入

b = XBYTE[0x1234] ; //写0x1234存储单元;或输出
 用XWORD每次可访问一个字(相邻地址的2个字节)。
 用指针实现绝对地址访问





#define pXBYTE (unsigned char xdata *)
unsigned char xdata *pbyte;//定义指向xdata的指针
pbyte = pXBYTE(0x1234); //指针赋值为访问地址;
//pbyte=0x1234也可,但加上强制类型转换更规范
*pbyte = 10;
//写操作
 用_at_访问



unsigned char xdata temp _at_ 0x1000; //在xdata
//的0x1000单元定义字节变量temp(全局变量)
temp = 10; //写操作
 6)C51的运算符与表达式






(1)赋值运算符:=
(2)算术运算符:+、-、*、/、%
(3)关系运算符:>、<、>=、<=、==、!=
(4)逻辑运算符:||、&&、!
(5)位运算符:&、|、~、^、<<、>>
(6)复合赋值运算符:在赋值运算符“=”的前面加上其它
运算符:
 +=、-=、*=、/=、%=, 如a+=2; 相当于a=a+2;
 &=、|=、^=、~=,
 >>=、<<=, 如a>>=2; 相当于a=a>>2;





(7)自加:++,自减:-如:a++; //相当于a=a+1;
(8)逗号运算符:,
将多个(两个以上)表达式连接起来;
按从左至右的顺序依次计算出各表达式的值,而整个逗
号表达式的值是最右边的表达式的值。
 如: x=(a=1,b=2);
//x的值为2
 (9)条件运算符:?:
 如:c=(a>b)?a:b; //当满足条件a>b时,c=a;否则c=b
 7)函数
 自定义函数和库函数。对自定义函数:
 (1)函数定义的一般格式









函数类型 函数名(形式参数表) [reentrant][interrupt m][using n]
形式参数说明
{
局部变量定义
函数体
}
函数类型:即函数返回值的类型,无返回值用void
函数名:程序利用函数名实现函数调用
形式参数:主调函数通过实参进行参数传递,一般将形参说明放在列
表中,实参与形参一一对应。
 函数示例:
 int max(int x,int y)
 {

int z;

z=(x>y)?x:y;

return(z);
 }
//函数定义
 reentrant修饰符
 定义该函数为可重入函数(允许被递归调用),即当一个函数正被
调用尚未返回时,又直接或间接调用该函数。
 需大量使用堆栈。
 interrupt n修饰符
 C51的中断(服务)函数,n为中断号,取值0~31






0——外部中断0(int0)
1——定时/计数器(T0)
2——外部中断1(int1)
3——定时/计数器(T1)
4——串行口中断(UART)
5——定时/计数器(T2)
 特别注意:中断函数无参数也无返回值;它是在中断
允许条件下,中断事件发生时,自动进入的,而不是
由主程序软件调用的!
 编译时,添加断点和现场保护(堆栈)的相应语句;并从绝对地
址8n+3处产生一个中断向量(中断入口地址)。
 利用1ms定时中断函数实现100ms定时示例:








bit bdata timer_100ms_flag = 0;
TMOD &= 0x0f;
//仅使用定时器/计数器1(只需设置TMOD高4位)
TMOD |= 0x10;
TH1 = 0xFC;
//设置定时器初值0xfc66,对应定时时间:1ms
TL1 = 0x66;
TR1 = 1;
//启动定时器T1
ET1 = 1;
//允许T1中断
EA =1;
//总开中断
 void T1INTSVC() interrupt 3
//中断号3:T1中断
 {

static unsigned char n = 100;
//静态变量n,计中断次数

TR1 = 0;

TH1 = 0xFC; //设置定时器初值0xfc66,对应定时时间:1ms

TL1 = 0x66;

TR1 = 1;

n--;

if(n==0) {n=100; timer_100ms_flag = 1;}
 }
 using n修饰符
 用于指定本函数内部使用的单片机R0~R7工作寄存器
组,n为组号,取值为0~3。
 注意: using n不能用于有返回值的函数,因为C51函
数的返回值是放在寄存器中的。
 一般不用。
 (2)函数的调用
 函数调用:函数名(实参列表);
 调用形式:

函数语句

函数表达式

函数参数
 (3)函数的声明
 函数原型一般形式:

[extern] 函数类型 函数名(形式参数表);
 函数声明示例:
 int max(int x, int y);
//函数声明
 void main(void)
 { int a,b,c;

c = max(a,b);
 }
//主函数
 int max(int x, int y)
 { int z;

z=(x>y)?x:y;

return(z);
 }
//函数定义
//函数调用
 (4)库函数
 安装keil软件时,在\Keil\C51\INC目录下,使用时在程
序开头用预处理命令: #include <xxx.h>
 C51常用库函数:
•
•
•
•
•
•
字符函数库:ctype.h
字符串函数库:string.h
输入/输出函数库:stdio.h
数学函数库:math.h
标准函数库:stdlib.h
内部函数库:intrins.h
 关于库函数的使用,可参考相关资料。
 8)C51程序基本结构与相关语句
 (1)顺序结构
A
 程序顺序执行
B
 (2)选择结构
 条件判断,跳转
 两个分支、多个分支
成立
语句A
否
条件P
语句B
 选择结构的相关语句
 if/else、或if语句嵌套











格式1:if (表达式) {语句;}
格式2:if (表达式) {语句1;} else {语句2;}
格式3:if (表达式1) {语句1;}
else if (表达式2) {语句2;}
else if (表达式3) {语句3;}
……
else if (表达式n-1) {语句n-1;}
else {语句n; }
如:前面c=(a>b)?a:b;相当于如下语句:
If(a>b) c=a;
else c=b;
 switch/case语句









多分支选择
switch (表达式)
{
case 常量表达式1:{语句1;} break;
case 常量表达式2:{语句2;} break;
……
case 常量表达式n:{语句n;} break;
default:{语句n+1;}
}
 (3)循环结构











当型循环结构(while)
while(表达式)
{语句;}
//循环体
示例: while(!TF0);
直到型循环结构(do while,for语句)
do
{语句;
//循环体, 至少执行一次
} while(表达式);
for语句
for(表达式1;表达式2;表达式3)
{语句;}
//循环体
 (4)循环的嵌套





多重循环,如:
void delay(unsigned char ms) //实现ms毫秒延时函数
{ while(ms--)
for(i=0;i<210;i++);
//约1ms,对fosc=11.0592MHz
}
 (5)循环结构中的break和continue语句
 break;从循环体中跳出,提前结束循环
 continue; 结束本次循环(而不是终止整个循环)
 (6)函数返回语句: return
 终止函数执行(返回),两种格式:
 return;
 return (表达式); //带回返回值
4. 开发环境与实验例程
 开发环境




Keil uVision。
集成开发环境:项目管理、程序编写、编译、调试。
特别注意在线仿真调试方法:单步、断点
以一个简单实例进行演示。
 实验例程
 20多个。
 全部在keil uVision下调试通过,有详细注释,供参考。
 在学习完单个例程后,完成综合设计。
 实验例程演示