
3.7 51单片机-LED 16*16点阵-腾讯云开发者社区-腾讯云
7.4 单片机 LED 点阵的图形显示 - 单片机教程(二) - UDN开源文档

点阵的优势:就是8+8个IO口独立控制8*8个LED灯亮灭

要驱动8*8的点阵需要2个IO端口,(16个IO口),要驱动16*16点阵需要4个IO端口(32个IO口)

SER 10101100 同一个引脚不同的时间送进来,串入(串行输入)--》在一个一个进入的时候其他位是不会改变的
QA 1 同时在不同引脚输出,并出(并行输出)--》一起出去
QB 0
QC 1
QD 0
QE 1
QF 1
QG 0
QH 0

因为74HC595中有一个输入端口“SER”,这个端口是一个一个的输入,一共输入8个二进制数,在一次性输入完8个二进制数后,将其分配给QA-QH这8个端口,这时候这8给段码端就有了IO口,就不需要再去连接mcu的端口。
使用串转并移位锁存驱动。要驱动16*16点阵只需要4个74HC595+1个IO端口。
实际上只需要(数据口SRE,SCLK(寄存器时钟信号),SRCLK(串行时钟信号)+4个74HC595就可以点亮点阵)


串行数据输入(DS): 数据从外部输入到74HC595的DS引脚。数据以串行方式按位传输到芯片中。在传输数据时,通过SRCLK(Serial Clock)信号控制数据的移位。
时钟信号(SRCLK): SRCLK是串行时钟信号,它控制数据的串行输入时序。每次SRCLK信号的上升沿,串行输入的数据就会按位移动到移位寄存器中。
存储寄存器时钟(RCLK): RCLK是寄存器时钟信号,也称为存储寄存器时钟。一旦所有的串行数据被移位到移位寄存器中,通过RCLK信号的上升沿,将整个移位寄存器的数据一次性加载到存储寄存器中。
并行数据输出(Q7'~Q0): 74HC595有8个并行输出引脚(Q7'~Q0),它们连接到外部电路。一旦数据被加载到存储寄存器中,通过并行时钟信号PCLK(Parallel Clock)的上升沿,将存储寄存器的数据并行输出到这些引脚上。
清零引脚(MR): 74HC595通常还有一个清零引脚(MR,Master Reset),通过对MR引脚的操作可以清零寄存器中的数据。

(1)POS就是Positive 正极 ,NEG:negetive负极

(1)QA-QH8路并行输出接到点阵的一个端口
(2)【QH’】这个串行输出口接下一个74HC595的串行输入SER(串联顺序按照ABCD)
(3)SER串行输入接:第一个595的SER通过接J24的SER,后面的每一个SER都接入前面的【QH‘】。这样构成了ABCD4个595芯片依次串联。【所以将来编程整个4个74HC595的串行数据都是从J24的SER出来的】
(4)SCLK(SRCLK)接J24的2
(5)RCLK接J24的1
(1)SCLK和RCLK是一样的接法,都接再J24上
(2)总共涉及到的IO端口就3个(J24连接mcu的三个,可以自己连接)
(3)外部接线重点:2个8pin杜邦线+3个端口连接muc接口


(1)芯片与芯片之间的通信,都是通过一定的时序进行的。
(2)时序就是芯片与芯片之间的通信引脚上电平变化以时间轴为参考的变化顺序。
(3)时序是通信双方事先定义好的,通信的发送方必须按照时序来发送有意义的信息,通信的接收方按照时序去接收解析发送方发来的电平变化信息,然后就知道发送方要给我们发送什么东西。
(4)我们编程时候:发送方是单片机,接收方是74HC595。因为595芯片本身是不能编程的,他的时序芯片出厂时候已经设置好,因此我们单片机必须按照595芯片的时序来发送信息
(5)所以我们要先搞清楚74HC595的时序规则。595芯片手册上有它的时序描述(时序图),参考描述就可以明白595芯片的时序规则,然后将其编程语言表达出来即可。
(6)74HC595的时序的关键:SCLK和RCLK。
SCLK是移位时钟,595芯片再每一个SCKL的上升沿会对SER引脚进行依次采样输入【判断此时是高电平还是低电平】。就向595内部输入1位,如此循环8次就输入了8位二进制。RCLK是锁存时钟,QA-QH的8位并行输出信号再RCLK的上升沿进行一次锁存更新。
RCLK是锁存时钟,QA-QH的8位并行输出信号再RCLK的上升沿进行一次锁存更新。【要4个8bit全部输入后才可以进行一次锁存】
SER:进行数据的串行输入
SCLK:提供移位时钟【就是对上升沿的读取,判断是高电平还是低电平】---不进行锁存,数据还是会输出,但是数据不会再变,除非再锁存一次,才会改变。
RCLK:提供锁存时钟【如果SER输入满8位二进制,则就进行一次锁存,第9位进入时,只能通过【QH’】将新进入的二进制移动到下一个74HC595上。】--->锁存是等四个HC595的并行数据存放好才可以锁存--->4个595芯片同时再进行锁存,各自锁存住了自己的数据--->才会亮
SER进行数据的串行输入
SCLK提供移位时钟--->上升沿移动
RCLK提供锁存时钟---->上升沿锁存
(1)之前的编程都是直接操作一个IO端口,可以用端口号(P0,P1)来整体操作一个IO端口中的8个引脚。但是这种方法不能操作单独一个IO口。
(2)今天需要单独操作一个IO引脚,比如要操作P1.3,但是直接写P1.3C语言不认识,而必须使用sbit关键字来定义一个引脚。
sbit SER = P1^3;//SER引脚名字

- #include
-
- sbit RCLK =P0^0; //74HC595的串行输入端
- sbit SCLK=P0^1; //锁存时钟
- sbit SER=P0^2; //移位时钟
-
- /**
- 点亮整个LED灯
- */
-
- int main(){
-
- unsigned char i=0;
- //一个值是8位
- unsigned char d1,d2,d3,d4;//要给4个595进行输出端输出的值
-
- //根据原理图可以知道d1和d2是连接负极,所以要输入d1和d2的是0才会亮
- d1=0;
- d2=0;
- //因为根据原理图中可以知道d3和d4连接的是正极,所以输入的d3和d4要为全1才亮
- d3=0xff;
- d4=0xff;
-
- //一开始就将两个置为低电平
- //防止一进来就是高电平
- SCLK=0;
- RCLK=0;
-
- for(i=0;i<8;i++){
-
- //SCLK=0;---》可以的
- SER=d1>>7;//将d1的最高bit取出来给SER
- SCLK=0;
- //这句话:是上升沿,只要再上上升沿前出去最后一位,就可以
- SCLK=1; //这2步制造了一个SCLK上升沿,在此时记录下这个数值,后面推进QA-QH中
-
- //将第二个进来的位数,变成最高位
- d1=d1<<1;
-
- }
- //至此已经再8个SCLK上升沿把d1的8位依次全部发出去了
- //但是还没有进行锁存,所以QA-QH还没有东西
-
-
- for(i=0;i<8;i++){
-
- SER=d2>>7;//将d2的最高bit取出来给SER
- SCLK=0;
- SCLK=1; //这2步制造了一个SCLK上升沿
-
- //将第二个进来的位数,变成最高位
- d2=d2<<1;
-
- }
- //至此已经把d1和d2都已经发出去了,并且d1已经被d2挤到第2个595芯片里面去了
- //此时595A中存放的是d2,595B中存放的是d1
- //但是还没有进行锁存,所以QA-QH还没有东西
-
- for(i=0;i<8;i++){
-
- SER=d3>>7;//将d3的最高bit取出来给SER
- SCLK=0;
- SCLK=1; //这2步制造了一个SCLK上升沿
-
- //将第二个进来的位数,变成最高位
- d3=d3<<1;
-
- }
- //至此已经把d1和d2和d3都已经发出去了,并且d1已经被d2和d3挤到第3个595芯片里面去了
- //此时595A中存放的是d3,595B中存放的是d2,595c中存放的是d1
- //但是还没有进行锁存,所以QA-QH还没有东西
-
- for(i=0;i<8;i++){
-
- SER=d4>>7;//将d4的最高bit取出来给SER
- SCLK=0;
- SCLK=1; //这2步制造了一个SCLK上升沿
-
- //将第二个进来的位数,变成最高位
- d4=d4<<1;
-
- }
- //至此已经把d1和d2和d3和d4都已经发出去了,并且d1已经被d2和d3和d4挤到第4个595芯片里面去了
- //此时595A中存放的是d4,595B中存放的是d3,595C中存放的是d2,595D中存放的是d1,
- //但是还没有进行锁存,所以QA-QH还没有东西
-
- //截至到这里,4个字节的数据d1,d2,d3,d4已经顺着74HC595的SER-》QH‘的串行输出
- //串行输出电路,已经爬满了4个74HC595(最先送出去的到了最后没一个595中)
- //但是到目前为止,4个595的QA-QH还没有出现锁存,点阵自然不会亮
-
- //然后要进行一次锁存,4个595芯片同时再进行锁存,各自锁存住了自己的数据
- RCLK=0;
- RCLK=1;
- //这两句之后595就完成了锁存,d1-d4就会影响4个595芯片的并行输出端,
- //进而会影响LED的正负极的值,然后LED就会亮或者灭
-
- //按照我们写的程序,d1和d2是负极,d3和d4是正极【原理图中有】
-
- }

- #include
-
- sbit RCLK =P0^0; //74HC595的串行输入端
- sbit SCLK=P0^1; //锁存时钟
- sbit SER=P0^2; //移位时钟
-
-
- //如果函数写在main后面,记得声明
- void SendData(unsigned char d1,unsigned char d2,unsigned char d3,unsigned char d4);
-
-
-
- void SendData(unsigned char d1,unsigned char d2,unsigned char d3,unsigned char d4){
-
- unsigned char i=0;
-
- //一开始就将两个置为低电平
- SCLK=0;
- RCLK=0;
-
- for(i=0;i<8;i++){
-
- //SCLK=0;---》可以的
- SER=d1>>7;//将d1的最高bit取出来给SER
- SCLK=0;
- //这句话:是上升沿,只要再上上升沿前出去最后一位,就可以
- SCLK=1; //这2步制造了一个SCLK上升沿,在此时记录下这个数值,后面推进QA-QH中
-
- //将第二个进来的位数,变成最高位
- d1=d1<<1;
-
- }
- //至此已经再8个SCLK上升沿把d1的8位依次全部发出去了
- //但是还没有进行锁存,所以QA-QH还没有东西
-
-
- for(i=0;i<8;i++){
-
- SER=d2>>7;//将d2的最高bit取出来给SER
- SCLK=0;
- SCLK=1; //这2步制造了一个SCLK上升沿
-
- //将第二个进来的位数,变成最高位
- d2=d2<<1;
-
- }
- //至此已经把d1和d2都已经发出去了,并且d1已经被d2挤到第2个595芯片里面去了
- //此时595A中存放的是d2,595B中存放的是d1
- //但是还没有进行锁存,所以QA-QH还没有东西
-
- for(i=0;i<8;i++){
-
- SER=d3>>7;//将d3的最高bit取出来给SER
- SCLK=0;
- SCLK=1; //这2步制造了一个SCLK上升沿
-
- //将第二个进来的位数,变成最高位
- d3=d3<<1;
-
- }
- //至此已经把d1和d2和d3都已经发出去了,并且d1已经被d2和d3挤到第3个595芯片里面去了
- //此时595A中存放的是d3,595B中存放的是d2,595c中存放的是d1
- //但是还没有进行锁存,所以QA-QH还没有东西
-
- for(i=0;i<8;i++){
-
- SER=d4>>7;//将d4的最高bit取出来给SER
- SCLK=0;
- SCLK=1; //这2步制造了一个SCLK上升沿
-
- //将第二个进来的位数,变成最高位
- d4=d4<<1;
-
- }
- //至此已经把d1和d2和d3和d4都已经发出去了,并且d1已经被d2和d3和d4挤到第4个595芯片里面去了
- //此时595A中存放的是d4,595B中存放的是d3,595C中存放的是d2,595D中存放的是d1,
- //但是还没有进行锁存,所以QA-QH还没有东西
-
- //截至到这里,4个字节的数据d1,d2,d3,d4已经顺着74HC595的SER-》QH‘的串行输出
- //串行输出电路,已经爬满了4个74HC595(最先送出去的到了最后没一个595中)
- //但是到目前为止,4个595的QA-QH还没有出现锁存,点阵自然不会亮
-
- //然后要进行一次锁存,4个595芯片同时再进行锁存,各自锁存住了自己的数据
- RCLK=0;
- RCLK=1;
- //这两句之后595就完成了锁存,d1-d4就会影响4个595芯片的并行输出端,
- //进而会影响LED的正负极的值,然后LED就会亮或者灭
-
- //按照我们写的程序,d1和d2是负极,d3和d4是正极【原理图中有】
- }
-
- void main(){
-
- //因为d1和d2在595芯片中连接的是正电极,所以我们要输入0才会形成电压差
- //d3和d4是连接负电极,所以我们要输入1才会形成电压差
- SendData(0x00,0x00,0xff,0xff);
- }
#define u8 unsigned char
#define u16 unsigned short
#define u32 unsigned int
- /**
- 使用自定义的宏定义
- */
-
- //自定义宏定义
- #define uchar unsigned char //#define 要尽量靠前,而且没有分号
- #define u8 unsigned char
- #define u16 unsigned short
- #define u32 unsigned int
-
-
- //如果函数写在main后面,记得声明
- //void SendData(unsigned char d1,unsigned char d2,unsigned char d3,unsigned char d4);
-
- void SendData(uchar d1,uchar d2,uchar d3,uchar d4);

P1,P2控制列,P3,P4控制行的




因为d1和d2在原理图上是对应负极,d3和d4应该输入正极
d1对应着NEG9-16,d2对应着NEG1-8,d3对应着POS9-16,d4对应着POS1-8
- #include
- /**
- 使用自定义的宏定义
- */
-
- //自定义宏定义
- #define uchar unsigned char
-
- sbit RCLK =P0^0; //74HC595的串行输入端
- sbit SCLK=P0^1; //锁存时钟
- sbit SER=P0^2; //移位时钟
-
-
- //如果函数写在main后面,记得声明
-
- void SendData(uchar d1,uchar d2,uchar d3,uchar d4);
-
-
-
- void SendData(uchar d1,uchar d2,uchar d3,uchar d4){
-
- uchar i=0;
-
- //一开始就将两个置为低电平
- SCLK=0;
- RCLK=0;
-
- for(i=0;i<8;i++){
-
- //SCLK=0;---》可以的
- SER=d1>>7;//将d1的最高bit取出来给SER
- SCLK=0;
- //这句话:是上升沿,只要再上上升沿前出去最后一位,就可以
- SCLK=1; //这2步制造了一个SCLK上升沿,在此时记录下这个数值,后面推进QA-QH中
-
- //将第二个进来的位数,变成最高位
- d1=d1<<1;
-
- }
-
-
- for(i=0;i<8;i++){
-
- SER=d2>>7;//将d2的最高bit取出来给SER
- SCLK=0;
- SCLK=1; //这2步制造了一个SCLK上升沿
-
- //将第二个进来的位数,变成最高位
- d2=d2<<1;
-
- }
-
- for(i=0;i<8;i++){
-
- SER=d3>>7;//将d3的最高bit取出来给SER
- SCLK=0;
- SCLK=1; //这2步制造了一个SCLK上升沿
-
- //将第二个进来的位数,变成最高位
- d3=d3<<1;
-
- }
-
- for(i=0;i<8;i++){
-
- SER=d4>>7;//将d4的最高bit取出来给SER
- SCLK=0;
- SCLK=1; //这2步制造了一个SCLK上升沿
-
- //将第二个进来的位数,变成最高位
- d4=d4<<1;
-
- }
- RCLK=0;
- RCLK=1;
- }
-
- void main(){
- SendData(0x00,0x00,0x00,0xff);//亮上半屏
- }
- //亮四角的四颗
- //四颗:则d1对应9-16列,要求亮16列【最大的那个】(0亮1灭)
- //d2对应1-8列,要求亮第一列【最小的那个】(0亮1灭)
- //d3对应9-16行,要求亮最后一行【最大的那个】(1亮0灭)
- //d4对应1-8行,要求最上一行【最小的那个】(1亮0灭)
- SendData(0x7f,0xfe,0x80,0x01);

(1)编写硬件控制代码,时序理解是关键。只要时序理解正确的,并且代码按照时序写
(2)d1-d4都是最低bit位表示编号小是数字,比如d4的bit0对应1
(3)d3和d4是正极,1亮0灭;d1和d2是负极,1灭0亮。
1)先判断d1-d4应该输入什么值才能点亮【比如我们d1和d2是输入到595D和595C,我们查看原理图分析可知道,对应的是负极,则我们要输入0才会点亮led;d3和d4是对应595B和595D,对应的是正极,则输入0xff才会点亮led】
2)SCLK:移位时钟。分析原理图,分别在什么时候才可以将数据输入并且存储到移动寄存器中。查看SCLK【移位时钟】。---》百度查看,只有在SCLK为上升沿的时候,才会将数据输入。
3)RCLK:锁存时钟。这个是针对并行数据。当我们将四个并行寄存器都存储后,就需要将其锁起来,防止数据被修改。
(1)如何记录组成字的LED点阵亮灭信息(16*16点阵一共有256点,显示一共特定的字需要其中有一些点亮而另外一些不亮,如何记录哪些点亮哪一些点不亮?用字模)
(2)字模如何工作?256个点用256个二进制位表示,1表示这个点亮,0表示不亮。256个点就是256个二进制位,也就是256/8=32个字节,所以一个大小位16*16的字的字模的32个字节大小。所以字模的表现形式就是32个unsigned char型数据。
(1)一般通过专门的字模软件去提取,这种软件的可以得到这个字对应的32个字节的字模编码。
(2)字模的结果不是唯一的,和你提取字模的方式有关(横向纵向)
(3)提取字模时是没有标准的,怎么做都是对的或者都是错的,关键是你提取的这个字模的方式和你用来在点阵上显示这个字模的函数必须对应。
(1)使用方式:
第一步:先选择字形(实际开发板多大就选择多大)
第二步:选择合适的字体,字号等
第三步:选择编码方式和实际取模方式【D7-->D0】
第四步:直接将得到的结果取走
(1)手工对比字模内容和屏幕显示,从进行验证

因为我们横向取模是一行一行展示
d1和d2是控制列,控制这列要显示哪一个点
d3和d4是控制行,控制要显示哪一行--》则我们可以一行一行的遍历16次(行)
SendData(~code[2*i+1],~code[2*i],hang[2*i],hang[2*i+1])

取模软件得出的结果是:1亮,0灭,但是我们d1和d2是接负极【应该是1灭0亮】,与我们想要的结果相反


上面代码出现的问题:
1)本来应该就亮一颗,结果就1颗不亮其他亮----》将取模结果取反
2)亮的位置也不正确----》将2个8bit的位置对调位置
原来为1,取反变0;反之


因为点在最右边,则可能是我们d1和d2的位置取反,则我们试着将其转换过来。



- /*-- 文字: 林 --*/
- /*-- 宋体12; 此字体下对应的点阵为:宽x高=16x16 --*/
- //分析可知:
- //取模软件得出的结果是:1表示亮,0表示灭
- uchar zhu[32] = {
- 0x08,0x04,0x08,0x04,0x08,0x04,0x08,0x04,0xBF,0x7F,0x08,0x04,0x0C,0x0E,0x1C,0x0E,
- 0x2A,0x15,0x0A,0x15,0x89,0x24,0x48,0x44,0x28,0x04,0x08,0x04,0x08,0x04,0x08,0x04,
- };
-
-
-
- int main() {
- //显示第一行
- //取模结果与我们想要的相反
- //SendData(0x80, 0x00, 0x00, 0x01);
- //则我们将结果取反
- //SendData(~0x80, ~0x00, 0x00, 0x01);
- //将d1与d2两者的值调换一下
- SendData(~0x04, ~0x08, 0x00, 0x01); //第一行
- SendData(~0x04,~0x08,0x00,0x02); //第二行
-
- SendData(~0x04,~0x08,0x00,0x04); //第三行
- SendData(~0x04,~0x08,0x00,0x08); //第四行
- SendData(~0x7F,~0xBF,0x00,0x10); //第五行
-
- SendData(~0x04,~0x08,0x00,0x20); //第6行
-
- SendData(~0x0E,~0x0C,0x00,0x40); //第7行
-
- SendData(~0x0E,~0x1C,0x00,0x80); //第8行
-
- SendData(~0x15,~0x2A,0x01,0x00); //第9行
-
- SendData(~0x15,~0x0A,0x02,0x00); //第10行
-
- SendData(~0x24,~0x89,0x04,0x00); //第11行
-
- SendData(~0x44,~0x48,0x08,0x00); //第12行
-
- SendData(~0x04,~0x28,0x10,0x00); //第13行
-
- SendData(~0x04,~0x08,0x20,0x00); //第14行
-
- SendData(~0x04,~0x08,0x40,0x00); //第15行
-
- SendData(~0x04,~0x08,0x80,0x00); //第16行
- }
- /*-- 文字: 林 --*/
- /*-- 宋体12; 此字体下对应的点阵为:宽x高=16x16 --*/
- //分析可知:
- //取模软件得出的结果是:1表示亮,0表示灭
- uchar zhu[32] = {
- 0x08,0x04,0x08,0x04,0x08,0x04,0x08,0x04,0xBF,0x7F,0x08,0x04,0x0C,0x0E,0x1C,0x0E,
- 0x2A,0x15,0x0A,0x15,0x89,0x24,0x48,0x44,0x28,0x04,0x08,0x04,0x08,0x04,0x08,0x04,
- };
(1)d1和d2用字模来填充,填充时要取反【d1=0x00,d2=0x80】-->因为d1和d2对应的是负极【0亮1灭】与取模软件【1亮0灭】给的相反
(2)d3和d4来选择哪一个行被点亮,而d1和d2选择这行中哪一列被点亮
(3)SendData一次送16个LED的亮灭信息(2字节),所以必须调用256/16=16次SendData函数,才能把整个点阵全部点亮完毕。
(4)每一次调用SendData时,d1-d4变化是有规律的,因此有希望通过函数来调用SendData而不需要手工调用16次。

- #include
- /**
- 横向取模:使用数组进行字的展示
- */
-
- //自定义宏定义
- #define uchar unsigned char
-
- sbit RCLK = P0 ^ 0; //74HC595的串行输入端
- sbit SCLK = P0 ^ 1; //锁存时钟
- sbit SER = P0 ^ 2; //移位时钟
-
-
- //如果函数写在main后面,记得声明
-
- void SendData(uchar d1, uchar d2, uchar d3, uchar d4);
-
-
-
- void SendData(uchar d1, uchar d2, uchar d3, uchar d4) {
-
- uchar i = 0;
-
- //一开始就将两个置为低电平
- SCLK = 0;
- RCLK = 0;
-
- for (i = 0;i < 8;i++) {
-
- //SCLK=0;---》可以的
- SER = d1 >> 7;//将d1的最高bit取出来给SER
- SCLK = 0;
- //这句话:是上升沿,只要再上上升沿前出去最后一位,就可以
- SCLK = 1; //这2步制造了一个SCLK上升沿,在此时记录下这个数值,后面推进QA-QH中
-
- //将第二个进来的位数,变成最高位
- d1 = d1 << 1;
-
- }
-
-
- for (i = 0;i < 8;i++) {
-
- SER = d2 >> 7;//将d2的最高bit取出来给SER
- SCLK = 0;
- SCLK = 1; //这2步制造了一个SCLK上升沿
-
- //将第二个进来的位数,变成最高位
- d2 = d2 << 1;
-
- }
-
- for (i = 0;i < 8;i++) {
-
- SER = d3 >> 7;//将d3的最高bit取出来给SER
- SCLK = 0;
- SCLK = 1; //这2步制造了一个SCLK上升沿
-
- //将第二个进来的位数,变成最高位
- d3 = d3 << 1;
-
- }
-
- for (i = 0;i < 8;i++) {
-
- SER = d4 >> 7;//将d4的最高bit取出来给SER
- SCLK = 0;
- SCLK = 1; //这2步制造了一个SCLK上升沿
-
- //将第二个进来的位数,变成最高位
- d4 = d4 << 1;
-
- }
- RCLK = 0;
- RCLK = 1;
- }
-
- /*-- 文字: 铧 --*/
- /*-- 宋体12; 此字体下对应的点阵为:宽x高=16x16 --*/
- //分析可知:
- //取模软件得出的结果是:1表示亮,0表示灭
- uchar zhu[32] = {
- 0x08,0x09,0x08,0x29,0xBC,0x28,0x84,0x18,0xC2,0x08,0xBD,0x4C,0x88,0x4A,0x88,0x70,
- 0xBF,0x04,0x08,0x04,0xC8,0x7F,0x08,0x04,0x28,0x04,0x18,0x04,0x08,0x04,0x00,0x04,};
-
- //2个一组,代表d3和d4--【1-16行】
- unsigned char hang[32]={
- 0x00,0x01,0x00,0x02,0x00,0x04,0x00,0x08,
- 0x00,0x10,0x00,0x20,0x00,040,0x00,0x80,
- 0x01,0x00,0x02,0x00,0x04,0x00,0x08,0x00,
- 0x10,0x00,0x20,0x00,0x40,0x00,0x80,0x00,
- };
-
- int main() {
-
- uchar i=0;
- //因为每一次调用senddata的时候输入16位,但是一共有256,所以要输入16次
- for(i=0;i<16;i++){
-
- SendData(~zhu[2*i+1],~zhu[2*i],hang[2*i],hang[2*i+1]);//每一次亮一行
- }
-
-
- }
- void Display(uchar zimu[32],uchar hang[32]){
-
-
- uchar i=0;
- //因为每一次调用senddata的时候输入16位,但是一共有256,所以要输入16次
- for(i=0;i<16;i++){
-
- SendData(~zimu[2*i+1],~zimu[2*i],hang[2*i],hang[2*i+1]);//每一次亮一行
- }
-
-
- }
-
- int main() {
-
- Display(zhu,hang);
-
- }
(d1,d2,d3,d4)
纵向取模则要修改的是列
则d1和d2是控制显示哪一列--》所以我们可以使用一次数16列来进行递归
d3和d4是控制要显示这一列的哪几个点
SendData(lie[2*1],lie[2*i+1],code[i+16],code[i]);

普通的显示最左边一列:SendData(0xff,0xfe,0xff,0xff)
- #include
- /**
- 纵向取模:使用数组进行字的展示
- */
-
- //自定义宏定义
- #define uchar unsigned char
-
- sbit RCLK = P0 ^ 0; //74HC595的串行输入端
- sbit SCLK = P0 ^ 1; //锁存时钟
- sbit SER = P0 ^ 2; //移位时钟
-
-
- //如果函数写在main后面,记得声明
-
- void SendData(uchar d1, uchar d2, uchar d3, uchar d4);
- void Display(uchar zimu[32],uchar lie[32]);
-
-
-
- void SendData(uchar d1, uchar d2, uchar d3, uchar d4) {
-
- uchar i = 0;
-
- //一开始就将两个置为低电平
- SCLK = 0;
- RCLK = 0;
-
- for (i = 0;i < 8;i++) {
-
- //SCLK=0;---》可以的
- SER = d1 >> 7;//将d1的最高bit取出来给SER
- SCLK = 0;
- //这句话:是上升沿,只要再上上升沿前出去最后一位,就可以
- SCLK = 1; //这2步制造了一个SCLK上升沿,在此时记录下这个数值,后面推进QA-QH中
-
- //将第二个进来的位数,变成最高位
- d1 = d1 << 1;
-
- }
-
-
- for (i = 0;i < 8;i++) {
-
- SER = d2 >> 7;//将d2的最高bit取出来给SER
- SCLK = 0;
- SCLK = 1; //这2步制造了一个SCLK上升沿
-
- //将第二个进来的位数,变成最高位
- d2 = d2 << 1;
-
- }
-
- for (i = 0;i < 8;i++) {
-
- SER = d3 >> 7;//将d3的最高bit取出来给SER
- SCLK = 0;
- SCLK = 1; //这2步制造了一个SCLK上升沿
-
- //将第二个进来的位数,变成最高位
- d3 = d3 << 1;
-
- }
-
- for (i = 0;i < 8;i++) {
-
- SER = d4 >> 7;//将d4的最高bit取出来给SER
- SCLK = 0;
- SCLK = 1; //这2步制造了一个SCLK上升沿
-
- //将第二个进来的位数,变成最高位
- d4 = d4 << 1;
-
- }
- RCLK = 0;
- RCLK = 1;
- }
-
- /*-- 文字: 朱 --*/
- /*-- 宋体12; 此字体下对应的点阵为:宽x高=16x16 --*/
- unsigned char zhu[32]={
- 0x80,0xA0,0x90,0x8E,0x88,0x88,0x88,0xFF,0x88,0x88,0x88,0x88,0x88,0x80,0x80,0x00,
- 0x20,0x20,0x10,0x08,0x04,0x02,0x01,0xFF,0x01,0x02,0x04,0x08,0x10,0x20,0x20,0x00};
-
-
-
- unsigned char lie[32]={
- 0xff,0xfe,0xff,0xfd,0xff,0xfb,0xff,0xf7,
- 0xff,0xef,0xff,0xdf,0xff,0xbf,0xff,0x7f,
- 0xfe,0xff,0xfd,0xff,0xfb,0xff,0xf7,0xff,
- 0xef,0xff,0xdf,0xff,0xbf,0xff,0x7f,0xff
-
-
- };
-
- void display(uchar zimu[32],uchar lie[32]){
- SendData(lie[2*i],lie[2*i+1],zimu[i+16],zimu[i]);
- }
-
- int main() {
- //普通方法
-
- //原来亮最左边一列
- //SendData(0xff,0xfe,0xff,0xff);
- //第一列的上半部分是字符串中的第一个
- //第一列的下半部分是字符串中的第17个
- //SendData(0xff,0xfe,0x80,0x20);//最左边一列
- //调换d3和d4的位置
- //SendData(0xff,0xfe,0x20,0x80);//最左边一列
-
- //使用递归
- uchar i=0;
- for(i=0;i<16;i++){
- SendData(lie[2*i],lie[2*i+1],zhu[i+16],zhu[i]);
-
- }
- }
(1)获取取模软件输入进来的数组
(2)最左边是:SendData(0xff,0xfe,0xff,0xff)
(3)因为纵向排序是
所以,我们列数的第一个的对应取模软件的第一个数值,第二列应该对应着取模软件的第十七个数值。