“流水灯”程序设计说明
1 工程文件下载:
2 程序设计思路
流水灯是测试发光二极管是否正常工作和学习使用发光二极管经典的案例。为点亮发光二极管,首先需要把P0口和P2.3设置为推挽输出,然后将P2.3置“1”,使能发光二极管电路;然后再对P0口赋值,即可点亮对应的led灯。要实现“流水灯”的效果,则可以点亮一个led灯,等待一定时间,将其熄灭,同时点亮下一个led灯,然后如此一直循环下去,即能看到“流水灯”的效果。
3 关键代码设计说明
本程序主要由三个函数组成:
l voidInit();
函数void Init()主要是对发光二极管电路进行初始化设置,只要将P0口和P2.3工作模式设置为推挽输出,同时将P2.3置“1”,使能发光二极管电路即可。其中对P0口和P2口的工作模式设置,可通过设置对应的P0口模式配置寄存器和P2口模式配置寄存器来实现。(具体细节请参照STC15F2K60S2数据手册)

表1 I/O口工作模式设置
其他I/O口工作模式设置类似。
l voiddelay_ms(uint n);
函数delay_ms(uint n)实现的是延时n毫秒的功能,但是延时的时间可能不是很准确。单片机工作时,是在统一的时钟脉冲控制下有序进行的。这个脉冲是由单片机控制器中的时钟电路产生的。时钟电路由振荡器和分频器组成,振荡器产生基本的振荡信号,然后进行分频,得到相应的时钟。振荡电路通常有内部振荡和外部振荡两种方式。STC15F2K60S2单片机内部集成高精度R/C时钟,工作时钟可以使用内部振荡器或者外部晶体振荡器(简称晶振)产生的时钟。外部振荡信号通过内部时钟电路,经过分频,得到相应的时钟信号。

图2外部振荡模式工作原理示意图
说明:
(1) 振荡周期: 晶体振荡器的周期。
(2) 状态周期: 振荡信号经二分频后形成的时钟脉冲信号,用S表示。一个状态周期的两个振荡周期作为两个节拍分别称为节拍P1和节拍P2。P1有效时,通常完成算术逻辑操作;P2有效时,一般进行内部寄存器之间的传输。
(3) 机器周期: 完成一个基本操作所需的时间称为机器周期。一个机器周期包含6个状态周期,用S1、S2、….、S6表示;共12个节拍,依次可表示为S1P1、S1P2、S2P1、S2P2、……、S6P1、S6P2。
(4) 指令周期:CPU执行一条指令所需要的时间。CPU执行指令是在时钟脉冲控制下一步一步进行的,由于指令的功能和长短各不相同,因此,指令执行所需的时间也不一样。一个指令周期通常含有1~4个机器周期。

MCS-51单片机各种周期的相互关系
例:若MCS-51单片机外接晶振为12MHz时,则单片机的四个周期的具体值为:
振荡周期=1/12MHz=1/12μs=0.0833μs
时钟周期=1/6μs=0.167μs
机器周期=1μs
指令周期=1~4μs
单片机晶体振荡器M的频率可以在4MHz~48MHz之间选择,典型值是11.0592MHz(因为使用这个频率的晶振可以准确地得到9600bits/s和19200bits/s的波特率)。
根据指令执行的时间,可计算出1ms可以相应执行多少条指令,函数中可通过循环执行空指令来达到延时1ms的效果。
此外延时函数也可以在STC-ISP中通过“软件延时计算器”功能自动生成指定延时时间的延时函数代码,如下:

l main();
每个程序都是从主函数main()开始执行,在主函数中,我们首先要调用函数Init()对电路进行初始化,再循环地对P0口进行赋值,点亮流水灯。
void main()
{
Init();
led=0x01;
while(1)
{
P0=led; //点亮第一个灯
delay_ms(200); //延时200ms
if(led==0x80) //再从头开始亮灯
led=0x01;
else
led=led<<1; //左移一位
}
}

