这一章,我们正式进入代码的编写。
读者需清楚的是,硬件代码(特别是51单片机)与软件代码大有不同,对于这块板子,简要来说,就是先指定模块,再声明模块要做的事。
那如何知道应该怎样让硬件工作呢?让我们先看原理图。
一、先编LED
1.选中
让我们先看LED,打开“SCH_V31_原理图.pdf”(如果你发现后期的学习中有差别,可以看看V40的),在原理图看看有没有发光二极管,我们可以找到下面这个模块。
那么我们可以看到,LED 的左下角有个叫 Y4C 的引脚。
让我们继续搜索 Y4C(按 Ctrl+F 查找),看看它到底连到哪里。(见下图)
这个 WR 是:当写入时,单片机自动拉低电平,如果选中 Yx,则 Yx 相应被拉低,经过或非门后 Y4C 输出高电平,达到选中作用。
根据上面表述,我们要继续追溯 Y4。直接看旁边的三线至八线译码器(三八译码器),有 Y4。
74HC138 是一个三八译码器,即将 3 位编码变为 8 个控制。
举例:我想控制 Y4,而 4 的二进制是 100,则分别对应
A2 | A1 | A0
1 | 0 | 0
又根据上面表述,我们看看 A012 对到哪里。直接来到第一页。
可以看到,对应关系为
P25 -> A0
P26 -> A1
P27 -> A2
P26,指 P2 口的第 6 引脚,其他同理。在软件中,我们可以直接控制 Px 的任意数值。
也就是说,我们只需要让 P2 = 100x xxxx(x = 0 or 1)就能选中 Y4。但是,既然前三位可以控制硬件,其他 5 位数字一定也行。所以,我们想要选中 Y4,就需要在不改变末 5 位的情况下,修改前三位。
第一步,不改变末五位,先重置前三位,方便下一步操作:P2' = P2 与 0001 1111(0x1F)
第二步,将首三位更改成 100,最终达到效果:100x xxxx:P2'' = P2' 或 1000 0000(0x80)
但我们不能写 P2'',单片机不理解。怎么办呢?我们将上面两个思路组合写成代码。
P2 = ( P2 & 0x1F ) | 0x80
这样我们就选中了 LED 模组。选中了,然后呢?
2.声明
让我们再回到 LED 这块。
不难注意,左边有 D01234567,有端联想,它们分别控制 L12345678 灯。LED 灯的右上角,接着 +5V,这代表着,当给予 LED 一个低电平信号(类似接地 0V)时,灯就会亮。
那怎么控制 D01234567 呢,我们再来到第一页,找它们。
可见控制 P0,就能控制 D。
比如说我们想让 L3 灯亮起,则有对应的
| D | 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 |
| P | 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 |
| LED | 8 | 7 | 6 | 5 | 4 | 3 | 2 | 1 |
| 应给数字 | 1 | 1 | 1 | 1 | 1 | 0 | 1 | 1 |
即令 P0 = 0xFB
那么这个时候我们就完成了整个链路闭环:
指定 LED 模块 -> 指定哪个灯打开
总结起来,代码如下:
P0 = 0xFB; P2 = ( P2 & 0x1F ) | 0x80;将它转换为完整 C 代码:
#include <STC15F2K60S2.H> void main(){ /*这一段为了初始化所有引脚,下一章会说*/ P0 = 0x00; P2 = (P2&0x1f)|0x80; P2 &= 0X1F; P2 = (P2&0x1f)|0xa0; P2 &= 0X1F; P2 = (P2&0x1f)|0xc0; P2 &= 0X1F; P2 = (P2&0x1f)|0xe0; P2 &= 0X1F; while(1){ /*这里开始为本章转换内容。*/ P0 = 0xFB; P2 = (P2&0x1f) | 0x80; P2 &= 0X1F; } }这里回到开头,我讲述的是“先指定模块,再声明模块要做的事”,其实是错误的,只是为了便于读者理解。
真正的,是先指定模块内的应用【P0=0xFB】,再通过选中开放寄存器【P2 = (P2&0x1f) | 0x80】,修改模块内的译码,达到目的,最后取消选中(关闭)寄存器,使数据保留在模块内。
二、再编蜂鸣器
不是,你不会真的以为我会再打一遍蜂鸣器吧?你猜为什么蜂鸣器和 LED 放一块。
LED 与蜂鸣器原理相同,特此作为技巧训练,要求是让蜂鸣器响起来。
下面是参考答案。
参考答案
#include <STC15F2K60S2.H> void main(){ /*初始化,下章讲。*/ P0 = 0x00; P2 = (P2&0x1f)|0x80; P2 &= 0X1F; P2 = (P2&0x1f)|0xa0; P2 &= 0X1F; P2 = (P2&0x1f)|0xc0; P2 &= 0X1F; P2 = (P2&0x1f)|0xe0; P2 &= 0X1F; while(1){ /*要求达到的代码*/ P0 = (P0&0xBF)| 0x40; P2 = (P2&0x1f) | 0xa0; P2 &= 0X1F; } }