0%

流水灯实验

流水灯实验

程序设计思路

流水灯是经典实验。要点亮发光二极管,要把P0端口和P2.3端口设置成推挽输出,然后

  • 将P2.3设成“1”,这表示使能发光二极管
  • 对P0端口赋值,就可以点亮对应的led灯了

而对于流水灯,基本思路就是点亮一个led灯,等待一段时间,然后熄灭它,同时点亮下一个led灯,然后如此循环下去,就可以看到流水效果如下

1
2
3
4
5
6
7
8
9
10
00000001
00000010
00000100
00001000
00010000
00100000
01000000
10000000
00000001
...

关键代码说明

相关定义以及头文件

1
2
3
4
5
6
7
8
9
10
11
/* 这个是我们的单片机的端口的定义 */
/* 如果仔细阅读头文件,可以看到就是用唯一的整数标识每一个端口 */
#include<STC15F2K60S2.H>

/* 定义类型,简写 */
#define uchar unsigned char
#define uint unsigned int

/* 选择位 */
sbit led_sel=P2^3; // 端口P2.3
uchar led; // 用一个uchar表示8个LED,每一个是1位

本程序主要是三个函数组成

对二级管初始化

void Init();

这个函数主要是发光二极管的初始化设置:

只要将P0口和P2.3工作模式设置为推挽输出,同时将P2.3置“1”,使能发光二极管电路。(这里的置“1”是P2的bit3置为1)

image-20220626175135866

image-20220626175208809

其中P0、P2这两个端口的设置通过对对应的寄存器赋值来设置实现。

看看上面两个表,其中第一列,也就是通道1为0(八个位都是0),通道0为1(特定位为1),表示处于推挽模式。STC15F2K60S2数据手册4.1章节(322页)有详细的介绍,下面简单介绍进一步如何配置。

image-20220626174347225

上面是STC-B的部分电路原理图。由于处于推挽输出模式,要求通道0为1,通道1为0。通道1为0,就把通道一八个位全部设置成低电平。但是通道0为1就要对特定位进行赋1。对于P0端口,我们可以在电路图中看到是红色框框,它对应了八个发光二极管的正极端,所以要让8个发光二极管统统发光,就要全部设置使能。所以对于P0的通道0,进行赋1,就要把八个位全部设置成1。另一方面,对于P2端口。我们看到上面对于这个实验的led灯,只有一个LED负极开漏端有一个LED_SEL选择信号,表示选择哪一个LED发光。可以看到蓝色框框,只是P2.3,也就是端口P2的0通道的第三个位赋1就好。

因此我们得到如下初始化代码:

1
2
3
4
5
6
7
8
9
10
11
12
void Init() {
// P0的通道1全0
P0M1=0x00;
// P0的通道0全1
P0M0=0xff;
// P2的通道1全0
P2M1=0x00;
// P2的通道0只要bit3为1
P2M0=0x08;
// 流水灯从L0开始(00000001)
led_sel=1;
}

延时函数

void delay_ms(uint n);

函数delay_ms的功能是延时n毫秒,但时间不一定特别准确。单片机工作在同一的时钟脉冲控制下。这个脉冲式单片机控制器的时钟电路产生的。时钟电路由振荡器和分频器构成,振荡器产生基本振荡信号,然后分频,得到相应时钟。(这玩意了解一下就好了)

关于单片机中周期的说明:

  • 振荡周期: 晶体振荡器的周期。

  • 状态周期: 振荡信号经二分频后形成的时钟脉冲信号,用S表示。一个状态周期的两个振荡周期作为两个节拍分别称为节拍P1和节拍P2。P1有效时,通常完成算术逻辑操作;P2有效时,一般进行内部寄存器之间的传输。

  • 机器周期: 完成一个基本操作所需的时间称为机器周期。一个机器周期包含6个状态周期,用S1、S2、….、S6表示;共12个节拍,依次可表示为S1P1、S1P2、S2P1、S2P2、……、S6P1、S6P2。

  • 指令周期:CPU执行一条指令所需要的时间。CPU执行指令是在时钟脉冲控制下一步一步进行的,由于指令的功能和长短各不相同,因此,指令执行所需的时间也不一样。一个指令周期通常含有1~4个机器周期。

img

上图是MCS-51单片机各种周期的相互关系。

因此,根据指令执行的时间,可计算出1ms可以相应执行多少条指令,函数中可通过循环执行空指令来达到延时1ms的效果。此外延时函数也可以在STC-ISP中通过“软件延时计算器”功能自动生成指定延时时间的延时函数代码,如下:

image-20220626184218824

直接用ISP串口助手生成延时200ms对应的代码即可

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
void Delay200ms()		//@11.0592MHz
{
unsigned char i, j, k;
//_nop_();
//_nop_();
i = 9;
j = 104;
k = 139;
do
{
do
{
while (--k);
} while (--j);
} while (--i);
}

主函数

void main();

首先要调用函数Init()对电路进行初始化,再循环地对P0口进行赋值,点亮流水灯。

每一次流水灯对应点亮的位向左移动一位,具体就如“程序设计思路”的演示图所示。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
void main()
{
// 初始化LED灯
Init();
// 从L0开始亮
led=0x01;
// 无休止闪烁
while(1)
{
// P0端口连接LED灯,所以把寄存器LED给P0
P0=led;
// 延时200ms
Delay200ms();
// LED寄存器状态赋值
if(led==0x80) // 如果到了L7灯,下一个状态又从L0开始
led=0x01;
else // 否则左移一位
led=led<<1;
}

}

下载程序

在学习资料里面下载相关工具。主要是keil uvision 4

image-20220627112449125

新建工程uprojx,然后编译生成hex文件,烧入程序,运行。

如果编译没有生成.hex文件可以进行如下设置

image-20220627112712761

成功效果如下

image-20220627112808166