利用AT89C52单片机开发板结合4个8×8点阵(即16×16)模块+4个74HC595芯片+取模软件+C语言编制的程序显示汉字
1.点阵模块如图所示,这里还需要4片74HC595芯片。
(1)单片机端口直接驱动。要驱动8×8的点阵需要2个IO端口(16个IO口)、要驱动16×16的点阵需要4个IO端口(32个IO口)。
(2)使用串转并移位锁存器驱动。要驱动16×16点阵只需要4个74HC595+3个IO口即可(数据口、SCLK、RCLK)。
显然在点阵足够大时,我们需要使用串转并移位锁存器驱动。
2.74HC595芯片特点是8位串行输入/输出或并行输出移位寄存器,具有高阻关状态。
(1)74HC595有三态,SER(数据输入),SRCLK(移位寄存器时钟)和RCLK(锁存器时钟);且SER、SRCLK和RCLK均需连接到52单片机I/O引脚上,SER连接到P3-4,SRCLK连接到P3-6,RCLK连接到 P3-5,QA-QH8路并行输出接到点阵的一个端口且QH’串行输出口接下一个74HC595的串行输入SER(串联顺序按照0123),所以将来编程时整个4个74HC595的串行数据都是从P3.4出来的。
(2)它的时序规则,发送方是单片机,接收方是74HC595,根据595芯片手册上的时序描述,SER进行数据的串行输入,SRCLK是移位时钟,595芯片内部在每个SRCLK的上升沿会对SER引脚进行一次采样输入,就向595内部输入了1位,如此循环8次就输入了8位二进制。RCLK是锁存时钟,QA-QH的8位并行输出信号在RCLK的上升沿进行一次锁存更新。
需要注意POS1-16和NEG1-16分别接移位锁存器并行输出端,POS就是Positive正极,NEG是negetive负极。QA-QH为低到高位
void SenData(uchar d1,uchar d2,uchar d3,uchar d4)
{
uchar i = 0,j = 0;
SCLK = 0;//起初位移、锁存给低电平
LCLK = 0;//锁存时钟,原本为RCLK,与reg52中的T2CON冲突了
for(i = 0;i <8;i++)
{
SER = d1 >> 7;//将d1的最高bit取出给SER
SCLK = 0;
SCLK = 1;//2步制造了一个SCLK上升沿
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发送出去,并且d2把d1挤入第二个595芯片
//但是还没有进行锁存,所以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挤入第三个595芯片,d3把d2挤入第二个595芯片
//但是还没有进行锁存,所以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发送出去
//但是还没有进行锁存,所以QA-QH还没有东西
//注意最先进入的会被挤到最后一个芯片中,四个字节数据沿着SER->OH'串行输出线进入四个芯片,但此时没有锁存,不会点亮
LCLK = 0;
LCLK = 1;//一次跳变(上升沿)四个芯片同时进行锁存
}
16×16点阵,256个点用256个二进制位表示,1表示这个点亮,0表示不亮。256个点就是256个二进制位,也就是256/8=32个字节。所以一个大小为16×16的字的字模是32个字节大小。所以字模的表现形式就是32个unsigned char型数据。注意字模的结果不是唯一的,关键看取模方式
这里我们将C代码数组保存下来,后续根据需要是否取反
unsigned char code ji[] =
{
16,0,17,240,17,16,17,16,
253,16,17,16,49,16,57,16,
85,16,85,16,145,16,17,18,
17,18,18,18,18,14,20,0
};
行的数组如下所示
unsigned char code ss[] =
{
0x7f,0xff,0xbf,0xff,0xdf,0xff,0xef,0xff,
0xf7,0xff,0xfb,0xff,0xfd,0xff,0xfe,0xff,
0xff,0x7f,0xff,0xbf,0xff,0xdf,0xff,0xef,
0xff,0xf7,0xff,0xfb,0xff,0xfd,0xff,0xfe
};
(1)程序如下:
#include
#define uint unsigned int
#define uchar unsigned char
sbit SER = P3^4;//74HC595的串行输入端
sbit LCLK = P3^5;//锁存时钟,原本为RCLK,与reg52中的冲突了
sbit SCLK = P3^6;//移位时钟
uchar d1,d2,d3,d4;//给四个595并行输出端输出的值
uchar code ji[]=
{
16,0,17,240,17,16,17,16,
253,16,17,16,49,16,57,16,
85,16,85,16,145,16,17,18,
17,18,18,18,18,14,20,0
};
uchar code ss[] =
{
0x7f,0xff,0xbf,0xff,0xdf,0xff,0xef,0xff,
0xf7,0xff,0xfb,0xff,0xfd,0xff,0xfe,0xff,
0xff,0x7f,0xff,0xbf,0xff,0xdf,0xff,0xef,
0xff,0xf7,0xff,0xfb,0xff,0xfd,0xff,0xfe
};
void senData(uchar d1,uchar d2,uchar d3,uchar d4)
{
uchar i = 0,j = 0;
SCLK = 0;//起初位移、锁存给低电平
LCLK = 0;
for(i = 0;i <8;i++)
{
SER = d1 >> 7;//将d1的最高bit取出给SER
SCLK = 0;
SCLK = 1;//2步制造了一个SCLK上升沿
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发送出去,并且d2把d1挤入第二个595芯片
//但是还没有进行锁存,所以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挤入第三个595芯片,d3把d2挤入第二个595芯片
//但是还没有进行锁存,所以QA-QH还没有东西
for(i =0;i < 8;i++)
{
SER = d4 >> 7;//将d4的最高bit取出给SER
SCLK = 0;
SCLK = 1;//2步制造了一个SCLK上升沿
d4 = d4 << 1;
}
//注意最先进入的会被挤到最后一个芯片中,四个字节数据沿着SER->OH'串行输出线进入四个芯片,但此时没有锁存,不会点亮
LCLK = 0;
LCLK = 1;//一次跳变四个芯片同时进行锁存
}
void main()
{
uchar a = 0;
for(a = 0;a <= 15 ;a++)
{
senData(ji[2*a],ji[2*a+1],ss[2*a],ss[2*a+1]);
};
}
这里我是直接清屏,当然也可以一格一格左移或右移等;定义一个指针数据指向汉字,因为汉字有多个,所以借用指针。主函数代码和数组如下所示,SenData()在上述程序已说明。
// 没
unsigned char code tab1[]={0,0,33,240,17,16,17,16,129,16,66,16,84,14,24,0,19,248,34,8,225,8,33,16,32,160,32,64,33,176,14,14};
// 有
unsigned char code tab2[]={2,0,2,0,255,254,4,0,4,0,15,240,8,16,24,16,47,240,72,16,136,16,15,240,8,16,8,16,8,80,8,32};
// 伞
unsigned char code tab3[]={1,0,1,0,2,128,4,64,8,32,48,24,193,6,17,16,9,16,9,32,1,0,255,254,1,0,1,0,1,0,1,0};
// 的
unsigned char code tab4[]={16,64,16,64,32,64,126,124,66,132,66,132,67,4,66,68,126,36,66,36,66,4,66,4,66,4,126,4,66,40,0,16};
// 孩
unsigned char code tab5[]={0,32,252,16,4,16,11,254,16,32,16,66,20,132,25,248,48,16,208,34,16,196,19,8,16,16,16,40,80,196,35,2};
// 子
unsigned char code tab6[]={0,0,127,248,0,16,0,32,0,64,1,128,1,0,255,254,1,0,1,0,1,0,1,0,1,0,1,0,5,0,2,0};
// 必
unsigned char code tab7[]={0,0,4,0,2,16,1,16,1,32,8,32,40,72,40,68,40,132,73,2,74,2,140,18,8,16,24,16,39,240,64,0};
// 须
unsigned char code tab8[]={8,0,9,254,16,32,32,64,65,252,137,4,9,36,17,36,33,36,69,36,133,36,9,68,16,80,32,136,65,4,130,2};
// 努
unsigned char code tab9[]={16,0,16,0,254,252,34,132,68,136,40,80,16,32,40,88,197,134,2,0,2,0,127,248,4,8,8,8,16,80,96,32};
// 力
unsigned char code tab10[]={2,0,2,0,2,0,2,0,127,248,2,8,2,8,2,8,2,8,4,8,4,8,8,8,8,8,16,136,32,80,64,32};
// 奔
unsigned char code tab11[]={2,0,2,0,127,252,4,64,9,32,49,24,207,230,1,0,9,32,8,32,127,252,8,32,8,32,16,32,16,32,32,32};
// 跑
unsigned char code tab12[]={0,128,124,128,69,252,69,4,70,4,125,244,17,20,17,20,93,20,81,244,81,4,81,40,93,18,225,2,0,254,0,0};
void main()
{
int k = 0, i = 0, ms;
//定义一个指针数据指向汉字
uchar *p[] = {tab1, tab2, tab3, tab4, tab5, tab6,tab7, tab8,tab9, tab10, tab11,tab12};
while(1)
{
for(i = 0; i < 12; i++) //总共12个字
{
for(ms = 50; ms > 0; ms--) //显示50次,即肉眼可识别的停留时间
{
for(k = 0; k < 16; k++) //显示一个字
{
SenData((*(p[i] + 2*k )),(*(p[i] + 2*k + 1)),ss[2*k],ss[2*k + 1]);
}
SenData(0,0,0xff,0xff); //清屏
}
}
}
}