http://mp.weixin.qq.com/mp/homepage?__biz=MzU3OTczMzk5Mg==&hid=7&sn=ad5d5d0f15df84f4a92ebf72f88d4ee8&scene=18#wechat_redirect
--------------------------------------------------------------------------------------------------------------------------
一、LED点阵发光原理
8*8单色单片机结构图如下:
https://blog.csdn.net/weixin_42625444/article/details/90897605
从电路图中很简单的就可以看出来,想要点亮点阵中的某一个LED灯。只要使得那个灯所在的行输出高电平,所在列输出低电平就好。
二、点阵扫描实验
/***********************************************
实验名称: 点阵扫描
实验说明: 扫描每个LED灯,检查点阵是否完好
实验时间:
***********************************************/
#include
#include
#define uchar unsigned char
#define uint unsigned int
sbit MOSIO = P3^4;//输入口
sbit R_CLK = P3^5;//锁存器时钟
sbit S_CLK = P3^6;//移位寄存器时钟
//data3:右边半块列数据;data2:左边半块列数据
//data1:下边半块行数据;data0:上边半块行数据
void HC595Pro(uchar data3,uchar data2,uchar data1,uchar data0);
void main()
{
uint i,j;
uchar d;
while(1)
{
//全亮
HC595Pro(0x00,0x00,0xFF,0xFF);
for(i=0;i<40000;i++); //延时40ms
/*行扫描*/
//上半块行扫描
d = 0x01;
for(i=0;i<8;i++)
{
HC595Pro(0x00,0x00,0x00,d);
d <<= 1;
for(j=0;j<20000;j++); //延时20ms
}
//下半块行扫描
d = 0x01;
for(i=0;i<8;i++)
{
HC595Pro(0x00,0x00,d,0x00);
d <<= 1;
for(j=0;j<20000;j++); //延时20ms
}
/*列扫描*/
//左半快列扫描
d = 0xFE;
for(i=0;i<8;i++)
{
HC595Pro(0xFF,d,0xFF,0xFF);
//如果还想用跟行扫描一样的形式,看main()最下面注释行
d = _crol_(d,1); //循环左移
for(j=0;j<20000;j++); //延时20ms
}
//右半块列扫描
d = 0xFE;
for(i=0;i<8;i++)
{
HC595Pro(d,0xFF,0xFF,0xFF);
d = _crol_(d,1);
for(j=0;j<20000;j++); //延时20ms
}
/******************************************************
b1 = 0x01;
for(i = 0; i<8; i++)
{
HC595Pro(0xFF, ~b1, 0xFF, 0xFF);
b1 <<= 1;
for(j=0; j<20000; j++);
}
b1 = 0x01;
for(i = 0; i<8; i++)
{
HC595Pro(~b1, 0xFF, 0xFF, 0xFF);
b1 <<= 1;
for(j=0; j<20000; j++);
}
******************************************************/
}
}
void HC595Pro(uchar data3,uchar data2,uchar data1,uchar data0)
{
uchar i;
//先移入的会被后面移入的数据推移到后面的595中,所以需要先移入data3
for(i=0;i<8;i++)
{
//先移入高位再移入低位,移位寄存器移入的第一位就是输出的最高位
MOSIO = data3 >> 7;
data3 <<= 1;
S_CLK = 0;//给一个上升沿,移位
S_CLK = 1;
}
for(i=0;i<8;i++)
{
MOSIO = data2 >> 7;
data2 <<= 1;
S_CLK = 0;
S_CLK = 1;
}
for(i=0;i<8;i++)
{
MOSIO = data1 >> 7;
data1 <<= 1;
S_CLK = 0;
S_CLK = 1;
}
for(i=0;i<8;i++)
{
MOSIO = data0 >> 7;
data0 <<= 1;
S_CLK = 0;
S_CLK = 1;
}
//上升沿时将移位寄存器数据移到锁存器中用于显示,平时保持低电平,数据不变
R_CLK = 0;
R_CLK = 1;
R_CLK = 0;
}
这里我用到的是16*16的点阵。其实也就是4个8*8的小点阵组成起来的。其结构图如下:
1 | 2 |
3 | 4 |
这里只是简单示意一下。。。其中4个小块都是与一个相对应的74HC595相连。每个74HC595又是级联的,入口只有一个,我们需要输入相对应的行,列电平情况来控制LED灯的亮灭。
根据74HC595的结构可以知道,输入的数据是8位8位的输入的。最开始输入的8位数据会被后面的输入数据推移到第四个74HC595中。
所以实际输入时,是先输入2和4的列数据,再输入1和3的列数据,然后再是3和4的行数据,最后才是1和2的行数据。
三、16*16点阵倒计时
/***********************************************************************
实验名称: 16*16点阵数字倒计时
实验时间:
***********************************************************************/
#include
#include
#define uchar unsigned char
#define uint unsigned int
sbit MOSIO = P3^4;
sbit R_CLK = P3^5;
sbit S_CLK = P3^6;
void HC595Pro(uchar data3,uchar data2,uchar data1,uchar data0);
void main()
{
uint i,c;
uchar j;
i = 100;
while(1)
{
//显示数字10
for(c=i;c>0;c--)//延时
for(j=0;j<16;j++)
{
//字模取出来的数据是跟实际实际所需数据相反的,所以要取反。
//函数对应的参数分别表示列2,列1,行2,行1
HC595Pro(~tab1[2*j+1],~tab1[2*j],tab0[2*j],tab0[2*j+1]);
}
HC595Pro(0xFF,0xFF,0x00,0x00);//清屏
//显示数字09
for(c=i;c>0;c--)
for(j=0;j<16;j++)
{
HC595Pro(~tab2[2*j+1],~tab2[2*j],tab0[2*j],tab0[2*j+1]);
}
HC595Pro(0xFF,0xFF,0x00,0x00);//清屏
//显示数字08
for(c=i;c>0;c--)
for(j=0;j<16;j++)
{
HC595Pro(~tab3[2*j+1],~tab3[2*j],tab0[2*j],tab0[2*j+1]);
}
HC595Pro(0xFF,0xFF,0x00,0x00);//清屏
//显示数字07
for(c=i;c>0;c--)
for(j=0;j<16;j++)
{
HC595Pro(~tab4[2*j+1],~tab4[2*j],tab0[2*j],tab0[2*j+1]);
}
HC595Pro(0xFF,0xFF,0x00,0x00);//清屏
//显示数字06
for(c=i;c>0;c--)
for(j=0;j<16;j++)
{
HC595Pro(~tab5[2*j+1],~tab5[2*j],tab0[2*j],tab0[2*j+1]);
}
HC595Pro(0xFF,0xFF,0x00,0x00);//清屏
//显示数字05
for(c=i;c>0;c--)
for(j=0;j<16;j++)
{
HC595Pro(~tab6[2*j+1],~tab6[2*j],tab0[2*j],tab0[2*j+1]);
}
HC595Pro(0xFF,0xFF,0x00,0x00);//清屏
//显示数字04
for(c=i;c>0;c--)
for(j=0;j<16;j++)
{
HC595Pro(~tab7[2*j+1],~tab7[2*j],tab0[2*j],tab0[2*j+1]);
}
HC595Pro(0xFF,0xFF,0x00,0x00);//清屏
//显示数字03
for(c=i;c>0;c--)
for(j=0;j<16;j++)
{
HC595Pro(~tab8[2*j+1],~tab8[2*j],tab0[2*j],tab0[2*j+1]);
}
HC595Pro(0xFF,0xFF,0x00,0x00);//清屏
//显示数字02
for(c=i;c>0;c--)
for(j=0;j<16;j++)
{
HC595Pro(~tab9[2*j+1],~tab9[2*j],tab0[2*j],tab0[2*j+1]);
}
HC595Pro(0xFF,0xFF,0x00,0x00);//清屏
//显示数字01
for(c=i;c>0;c--)
for(j=0;j<16;j++)
{
HC595Pro(~tab10[2*j+1],~tab10[2*j],tab0[2*j],tab0[2*j+1]);
}
HC595Pro(0xFF,0xFF,0x00,0x00);//清屏
//显示数字00
for(c=i;c>0;c--)
for(j=0;j<16;j++)
{
HC595Pro(~tab11[2*j+1],~tab11[2*j],tab0[2*j],tab0[2*j+1]);
}
HC595Pro(0xFF,0xFF,0x00,0x00);//清屏
//显示字母GO
for(c=i;c>0;c--)
for(j=0;j<16;j++)
{
HC595Pro(~tab12[2*j+1],~tab12[2*j],tab0[2*j],tab0[2*j+1]);
}
HC595Pro(0xFF,0xFF,0x00,0x00);//清屏
}
}
void HC595Pro(uchar data3,uchar data2,uchar data1,uchar data0)
{
uchar i;
//先移入的会被后面移入的数据推移到后面的595中,所以需要先移入data3
for(i=0;i<8;i++)
{
//先移入高位再移入低位,移位寄存器移入的第一位就是输出的最高位
MOSIO = data3 >> 7;
data3 <<= 1;
S_CLK = 0;//给一个上升沿,移位
S_CLK = 1;
}
for(i=0;i<8;i++)
{
MOSIO = data2 >> 7;
data2 <<= 1;
S_CLK = 0;
S_CLK = 1;
}
for(i=0;i<8;i++)
{
MOSIO = data1 >> 7;
data1 <<= 1;
S_CLK = 0;
S_CLK = 1;
}
for(i=0;i<8;i++)
{
MOSIO = data0 >> 7;
data0 <<= 1;
S_CLK = 0;
S_CLK = 1;
}
//上升沿时将移位寄存器数据移到锁存器中用于显示,平时保持低电平,数据不变
R_CLK = 0;
R_CLK = 1;
R_CLK = 0;
}
array.h头文件如下:
//点阵显示数组
//用于行扫描
unsigned char code tab0[] = {0x00, 0x01, 0x00, 0x02, 0x00, 0x04, 0x00, 0x08, 0x00, 0x10, 0x00, 0x20, 0x00, 0x40, 0x00, 0x80,
0x01, 0x00, 0x02, 0x00, 0x04, 0x00, 0x08, 0x00, 0x10, 0x00, 0x20, 0x00, 0x40, 0x00, 0x80, 0x00};
//1数字10的字模
unsigned char code tab1[] = {0, 0, 0, 0, 0, 0, 8, 24, 14, 36, 8, 66, 8, 66, 8, 66,
8, 66, 8, 66, 8, 66, 8, 36, 62, 24, 0, 0, 0, 0, 0, 0};
//数字09的字模
unsigned char code tab2[] = {0, 0, 0, 0, 0, 0, 24, 24, 36, 36, 66, 66, 66, 66, 66,
66, 66, 100, 66, 88, 66, 64, 66, 64, 36, 36, 24, 28, 0, 0, 0, 0} ;
//数字08的字模
unsigned char code tab3[] = {0, 0, 0, 0, 0, 0, 24, 60, 36, 66, 66, 66, 66, 66, 66, 36,
66, 24, 66, 36, 66, 66, 66, 66, 36, 66, 24, 60, 0, 0, 0, 0};
//数字07的字模
unsigned char code tab4[] = {0, 0, 0, 0, 0, 0, 24, 126, 36, 34, 66, 34, 66, 16, 66, 16,
66, 8, 66, 8, 66, 8, 66, 8, 36, 8, 24, 8, 0, 0, 0, 0};
//数字06的字模
unsigned char code tab5[] = {0, 0, 0, 0, 0, 0, 24, 56, 36, 36, 66, 2, 66, 2, 66, 26, 66,
38, 66, 66, 66, 66, 66, 66, 36, 36, 24, 24, 0, 0, 0, 0};
//数字05的字模
unsigned char code tab6[] = {0, 0, 0, 0, 0, 0, 24, 126, 36, 2, 66, 2, 66, 2, 66, 26, 66,
38, 66, 64, 66, 64, 66, 66, 36, 34, 24, 28, 0, 0, 0, 0};
//数字04的字模
unsigned char code tab7[] = {0, 0, 0, 0, 0, 0, 24, 32, 36, 48, 66, 40, 66, 36, 66, 36, 66,
34, 66, 34, 66, 126, 66, 32, 36, 32, 24, 120, 0, 0, 0, 0};
//数字03的字模
unsigned char code tab8[] = {0, 0, 0, 0, 0, 0, 24, 60, 36, 66, 66, 66, 66, 32, 66, 24, 66,
32, 66, 64, 66, 64, 66, 66, 36, 34, 24, 28, 0, 0, 0, 0};
//数字02的字模
unsigned char code tab9[] = {0, 0, 0, 0, 0, 0, 24, 60, 36, 66, 66, 66, 66, 66, 66, 32, 66,
32, 66, 16, 66, 8, 66, 4, 36, 66, 24, 126, 0, 0, 0, 0};
//数字01的字模
unsigned char code tab10[] = {0, 0, 0, 0, 0, 0, 24, 8, 36, 14, 66, 8, 66, 8, 66, 8, 66, 8, 66,
8, 66, 8, 66, 8, 36, 8, 24, 62, 0, 0, 0, 0};
//数字00的字模
unsigned char code tab11[] = {0, 0, 0, 0, 0, 0, 24, 24, 36, 36, 66, 66, 66, 66, 66, 66, 66, 66,
66, 66, 66, 66, 66, 66, 36, 36, 24, 24, 0, 0, 0, 0};
//数字GO的字模
unsigned char code tab12[] = {0, 0, 0, 0, 0, 0, 60, 28, 34, 34, 34, 65, 1, 65, 1, 65, 1, 65, 113,
65, 33, 65, 34, 65, 34, 34, 28, 28, 0, 0, 0, 0};
头文件的数据是通过字模软件得出的。字模软件的工作原理就是对于一个点阵,你想要什么样的图像,然后就在相应位置数据为1。然后再通过从左到右,从上到下的顺序,组成一个个8位数据。
这些8位数据就是头文件的内容。
由此我们就可以知道,通过字模取出来的数据,而我们实际运用过程中对于列来说是相反的。
因为我们想要点亮对应的LED灯是将它所在行输出高电平,所在列输出低电平。所以取出来的字模数据作为列的值的话是相反的。所以这里用了取反。