电路及驱动原理

在这里插入图片描述

上图是CS1088B的8x8
LED点阵的部分技术文档截图,最下面就是这个点阵模块的基本电路图。

其实很简单,每一横行控制LED的一极,每一竖列又控制LED的另一极。又因为是一个矩阵,所以每一个LED都有一个控制其单独发光的一个二进制值,能控制8x8坐标轴上任意一个LED的亮灭。

举个例子,假设每一横行我都接LED的正极,即基本电路图中的位置9、14、8、12、1、7、2、5位置,都接主机(如第一片74HC595D)的正极(如第一片74HC595D的8个并出口QA~QH),每一列我都接LED的负极即基本电路中
的位置13、3、4、10、6、11、15、16,都接主机(如第二片)的负极(如第二片74HC595D的8个并出口QA~QH)。

连接好以后,等于构成了完全控制LED正负极电平的能力,在程序中给8x8坐标轴内对应的LED点发送指定的高低电平信号就可以灵活控制其的亮灭。

电路图
在这里插入图片描述

以上为两片74HC595D串联后和8x8点阵连接的电路图,单片机和74HC595D连接省略。

注意:

控制LED点阵行(正极)的,第一片的QA要从LED点阵的正向的从上往下数,第一行开始连接,一直连接到第一片的QH结束

控制LED点阵列(负极)的,第二片的QA要从LED点阵正向从左往右数,第一列开始连接,一直连接到第二片的QH结束

这里的连接开始和结束顺序直接决定了后面程序中向74HC595D芯片送入的16位数据中,每个二进制位对应控制的行和列,所以一定要连接正确

规律:每颗LED的正极都接横行,每颗LED的负极都接竖列

规律:第一片74HC595D控制LED点阵的横行,第二片74HC595D控制LED点阵的竖列

电路图和实物电路对照
对应实际焊接完成的电路,方向、位置对应如下图:

在这里插入图片描述

此电路板是7cmx9cm的,底部标有“7CM*9CM”字样的,就是将来显示汉字的底边,对应的一边就是汉字的顶边。这幅图就是字体正确的显示方向。

红色字标出的位置分别接第一片74HC595D的8个并出口,来控制ELD点阵的正极;蓝色字标出的位置分别接第二片74HC595D的8个并出口,来控制ELD点阵的负极。

电路图和实物电路对照:
在这里插入图片描述

这样将实物和电路图对照一下,就很清晰了。在焊接上为了方便和美观,接第二片的负极(列)做了个右侧的走向。

理解74HC595D工作原理
常规情况下,电路中使用单颗74HC595D芯片,从串行数据的输入到并行数据的输出,要经历以下3个步骤:

向74HC595D的SI引脚输送一个数据并向SCK引脚做上升沿后,数据将会进入移位寄存器中,数据依次从QH引脚逐个向QA引脚方向移动,直到8位数据全部输入完毕
输入完毕后,向RCK引脚做上升沿,将移位寄存器中的8位数据拷贝到锁存器中固化、锁定
如果OE引脚一直是输出使能的,则会立即并行输出8位数据到QA~QH引脚上
注意:

第1步中向SI输送8位串行数据时,最先送入的数据在最高位,即QH引脚对应的移位寄存器中,而不是QA引脚。第二送入的数据在次高位,即QH引脚对应的以为寄存器中。最后送入的一位数据在最低位,即QA引脚对应的移位寄存器中。
74HC595D的串行数据移位遵循“先送高位,再送低位,由高位至低位输送”的原则。
这一点一定要理解清楚,这对后面理解16位数据每一位如何控制LED点阵的行和列至关重要
16位二进制数控制点阵的行与列
刚才有提到,后面写程序控制点阵时,要向74HC595D发送16位二进制数据。
两片74HC595D串联后,就有16个并出引脚,正好对应这16位二进制数据。其中的8位数据控制行,另外8位数据控制列。

下面来看一个示意图,看看16位二进制数中的每一位是如何控制行和列的:

在这里插入图片描述

再次回顾电路图:

第一片74HC595D的8个并出引脚,分别连接LED点阵每一行的正极位置,即:第一片74HC595D控制行

第二片74HC595D的8个并出引脚,分别连接LED点阵每一列的负极位置,即:第二片74HC595D控制列

注意:

由于两片74HC595D是串联的,也就是说,如果先发送了一个8位数据,那么是先会进到第一片74HC595D的锁存器中的。**同时遵循“先送高位,再送低位,由高位至低位输送”的原则,最先送入的数据在最高位(QH引脚对应的移位寄存器中),最后送入的数据再最低位(QA引脚对应的移位寄存器中)。

此时第一片74HC595D中已有8位数据了。再继续发送8位数据,那么在第一片74HC595D中的8位数据,会被逐次挤到第二片74HC595D中。也就是说,第一片74HC595D移位寄存器中的8位数据是第二次发送的新的8位数据。

实验分析:让LED点阵第二行第二列的LED单独亮起
在这里插入图片描述

再来分析一下这个电路图。

第一片74HC595D的8个并行输出引脚,分别连接LED点阵每一行的正极位置。
即:第一片74HC595D控制行。那么想要某个LED亮,这个LED所在行必须要输入高电平

第二片74HC595D的8个并行输出引脚,分别连接LED点阵每一列的负极位置。
即:第二片74HC595D控制列。那么想要某个LED亮,这个LED所在行必须要输入低电平
上面两个条件必须同时成立,某个LED才会因为两端有电位差而亮起。
在这里插入图片描述

再回顾上图,总结如下:

16位二进制数中的第1~第8位,依次控制LED点阵的列。
16位二进制数中的第9~第16位,依次控制LED点阵的行。
因为两片74HC595D串联后,第一次8位串行数据输入完毕后,再输入另外8位串行数据,第一次输入的8位穿行数据会被挤进第二片74HC595D的移位寄存器中。再结合电路图中,LED点阵的每一横行接第一片74HC595D,LED点阵的每一竖列接第二片74HC595D,所以,在16位二进制数中,我们要先把前8位先输入进去,就能控制列(因为先输入8位数据会挤进第二片74HC595D中,第二片74HC595D连着每颗LED的负极),再把后8位输入进去,就能控制行(因为后输入的8位数据会进到第一片74HC595D中,第一片74HC595D连着每颗LED的正极)。
再根据电路图,先绘制一下如果要单独点亮第二行第二列的LED,每行每列二进制的值是多少:
上面提到过,LED接正极的位置,提供高电平,并且LED接负极的位置提供低电平,两个条件都满足,才能使LED点亮。那么可以得出:
行(从上到下)(对应第一片74HC595D)值依次为:0 1 0 0 0 0 0 0
列(从左到右)(对应第二片74HC595D)值依次为:1 0 1 1 1 1 1 1

以上16位值就是单独点亮第二行第二列的LED的正确值。但是顺序还需要验证一下,要和电路图对应。

按照“先输入列,后输入行”的规律,先要输入第二片74HC595D的8位串行数据。那么每一次输入到芯片内的原理释义如下:
第二片74HC595D – 第1次输入串行数据:1                                
并出引脚符号    QH    QG    QF    QE    QD    QC    QB    QA
锁存器(存储寄存器)                                
移位寄存器                                
SI串行输入数据    1    空    空    空    空    空    空    空
第二片74HC595D – 第2次输入串行数据:0                                
并出引脚符号    QH    QG    QF    QE    QD    QC    QB    QA
锁存器(存储寄存器)                                
移位寄存器                                
SI串行输入数据    1    0    空    空    空    空    空    空
第二片74HC595D – 第3次输入串行数据:1                                
并出引脚符号    QH    QG    QF    QE    QD    QC    QB    QA
锁存器(存储寄存器)                                
移位寄存器                                
SI串行输入数据    1    0    1    空    空    空    空    空
第二片74HC595D – 第4次输入串行数据:1                                
并出引脚符号    QH    QG    QF    QE    QD    QC    QB    QA
锁存器(存储寄存器)                                
移位寄存器                                
SI串行输入数据    1    0    1    1    空    空    空    空
第二片74HC595D – 第5次输入串行数据:1                                
并出引脚符号    QH    QG    QF    QE    QD    QC    QB    QA
锁存器(存储寄存器)                                
移位寄存器                                
SI串行输入数据    1    0    1    1    1    空    空    空
第二片74HC595D – 第6次输入串行数据:1                                
并出引脚符号    QH    QG    QF    QE    QD    QC    QB    QA
锁存器(存储寄存器)                                
移位寄存器                                
SI串行输入数据    1    0    1    1    1    1    空    空
第二片74HC595D – 第7次输入串行数据:1                                
并出引脚符号    QH    QG    QF    QE    QD    QC    QB    QA
锁存器(存储寄存器)                                
移位寄存器                                
SI串行输入数据    1    0    1    1    1    1    1    空
第二片74HC595D – 第8次输入串行数据:1                                
并出引脚符号    QH    QG    QF    QE    QD    QC    QB    QA
锁存器(存储寄存器)                                
移位寄存器                                
SI串行输入数据    1    0    1    1    1    1    1    1

可以看到上面8次输入串行数据,每一次输入进去的新数据用红色加粗字体表示。确实是由高向低位逐个送入的。

按照“先输入列,后输入行”的规律,再输入第一片74HC595D的8位串行数据。那么每一次输入到芯片内的原理释义如下:

第一片74HC595D – 第9次输入串行数据:0                                
并出引脚符号    QH    QG    QF    QE    QD    QC    QB    QA
锁存器(存储寄存器)                                
移位寄存器                                
SI串行输入数据    0    空    空    空    空    空    空    空
第一片74HC595D – 第10次输入串行数据:0                                
并出引脚符号    QH    QG    QF    QE    QD    QC    QB    QA
锁存器(存储寄存器)                                
移位寄存器                                
SI串行输入数据    0    0    空    空    空    空    空    空
第一片74HC595D – 第11次输入串行数据:0                                
并出引脚符号    QH    QG    QF    QE    QD    QC    QB    QA
锁存器(存储寄存器)                                
移位寄存器                                
SI串行输入数据    0    1    0    空    空    空    空    空
第一片74HC595D – 第12次输入串行数据:0                                
并出引脚符号    QH    QG    QF    QE    QD    QC    QB    QA
锁存器(存储寄存器)                                
移位寄存器                                
SI串行输入数据    0    1    0    0    空    空    空    空
第一片74HC595D – 第13次输入串行数据:0                                
并出引脚符号    QH    QG    QF    QE    QD    QC    QB    QA
锁存器(存储寄存器)                                
移位寄存器                                
SI串行输入数据    0    1    0    0    0    空    空    空
第一片74HC595D – 第14次输入串行数据:0                                
并出引脚符号    QH    QG    QF    QE    QD    QC    QB    QA
锁存器(存储寄存器)                                
移位寄存器                                
SI串行输入数据    0    1    0    0    0    0    空    空
第一片74HC595D – 第15次输入串行数据:1                                
并出引脚符号    QH    QG    QF    QE    QD    QC    QB    QA
锁存器(存储寄存器)                                
移位寄存器                                
SI串行输入数据    0    1    0    0    0    0    1    空
第一片74HC595D – 第16次输入串行数据:0                                
并出引脚符号    QH    QG    QF    QE    QD    QC    QB    QA
锁存器(存储寄存器)                                
移位寄存器                                
SI串行输入数据    0    1    0    0    0    0    0    0
可以看到上面8次输入串行数据,每一次输入进去的新数据用红色加粗字体表示。确实是由高向低位逐个送入的。

注意:

要深刻理解为什么会这样变化,并且这样位移后是怎么对应到下图的LED点阵中的
以上规律,如下图所示:
在这里插入图片描述

图中,游泳圈位置就是要单独点亮的第二行第二列的LED。
图中,底部和右侧分别写着“行 rows”和“列
cols”箭头指向的顺序,就是行和列上二进制数字排列的顺序,以此构成16位二进制数。
每一位对应控制的行和列都用彩色线条对应连接表示。
实验验证,编写程序:让LED点阵右上角的LED单独亮起
源代码:

/**
 * 单文件实验程序
 * 两片74HC595D串联后,控制5*6LED点阵
 *
 * Created by SteveJrong on 2019/12/22.
 * Version: 1.0
 *
 * Copyright 2019 SteveJrong. All rights reserved.
 */

#include<reg52.h>

// 定义STC89C52RC给74HC595D输入串行数据的引脚(物理编号:14)
sbit SI_DS = P1 ^2;

// 定义STC89C52RC连接74HC595D存储寄存器的引脚(物理编号:12)
sbit RCK_STCP = P1 ^3;

// 定义STC89C52RC连接74HC595D移位寄存器的引脚(物理编号:11)
sbit SCK_SHCP = P1 ^4;

// 定义STC89C52RC连接74HC595D移位寄存器清零输入的引脚(物理编号:10)
sbit SCLR_MR = P1 ^5;

// 定义STC89C52RC连接74HC595D输出使能控制端的引脚(物理编号:13)
sbit G_OE_SHCP = P1 ^6;

void delay(unsigned int n) {
    int i, j;
    for (i = n; i > 0; i--)
        for (j = 110; j > 0; j--);
}

/**
 * 并行输出数据
 * 向74HC595D的锁存器(存储寄存器)时钟输入引脚发送高低电平信号,通知74HC959D将存在锁存器内的数据并行输出到QA~QH引脚上
 */
void lighting() {
    RCK_STCP = 1;
    delay(1);
    RCK_STCP = 0;
}

void disable_output() {
    G_OE_SHCP = 1;
}

void enable_output() {
    G_OE_SHCP = 0;
}

/**
 * 发送串行数据到74HC595D
 *
 * @param inputData 要传入的数据
 */
void send_data(int binaryArray[]) {
    int i = 0;

    for (; i < 16; i++) {
        SI_DS = binaryArray[i];

        SCK_SHCP = 0;
        SCK_SHCP = 1;
    }
}

/**
 * 主入口
 */
void main() {
    int i = 0, j = 0, binaryArray[1][16] = {
            {1, 0, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 1, 0},
    };

    // 初始时,存储寄存器置为低电平
    RCK_STCP = 0;
    // 初始时,移位寄存器置为低电平
    SCK_SHCP = 0;
    enable_output();

    for (; i < 1; i++) {
        send_data(binaryArray[i]);
        lighting();
    }
}

实验验证,效果:让LED点阵右上角的LED单独亮起

在这里插入图片描述

可以看到,程序预期执行,点亮了第二行第二列的LED。

汉字程序
项目仓库地址:

https://gitee.com/stevejrong1024/festive-lantern.git

文件:

labs / lab5.c

另外在以下位置增加了一个8x8点阵的16位二进制数生成器,就不用一个个对着电路图去手写了。网页上勾选好checkbox以后,直接粘贴进ten这个三维数组中即可。注意要改三维数组中一维和二维的数组总长度:

labs / lab5-led-font-generator / led-font-generator.html

已知问题:

如果同时显示的LED点较多,整体显示时的闪烁频率会稍慢一些,不知道是什么原因,STC
89C52RC性能不足?
STC 89C52RC RAM太小,显示的文字多了会造成编译后的文件过大,写不进单片机中,提示空间不足。后期计划使用STC89C516替换之。
直接写二进制的办法挺笨的。原来想着直接写16进制数,写一些方法转换成二进制数,就不用写这么多0和1了,但是试了很多种方法,在电脑的IDE上跑的没毛病,但是烧录进单片机后,就不是IDE中的结果了。可能单片机还是有局限性吧,有些功能不能被很好的支持?!
总结
想要循环显示汉字,不能用任何延时函数,延时可以用空循环。
原先看到网上的一个74HC595D的位移原理,理解成了先送低位再送高位,这也符合正常人的理解逻辑。但后来在写文档的时候总发现16进制数和引脚的接法对不上,但是LED确实又亮起了。后来正确的是先送高位再送低位,这样才对的上。
焊功差,焊接51最小系统时出了不少问题,需要多焊接。
脑子想不出来时,纸上画一画,什么都有了。