51单片机点阵实验(74HC595)

  • Post author:
  • Post category:其他

51单片机LED点阵实验(74HC595)
使用74HC595 点亮LED 点阵
(以普中开发板为例)

关于74HC595(串转并)

74HC595的原理图

74HC595的原理图如下所示(PS:图中二极管的方向错了)
在这里插入图片描述

HC595芯片的功能:串行输入,并行输出。

各个引脚的功能在这里插入图片描述

看如何给芯片接线,并使用:(注:引脚上加一个“非横线”,表示低有效)

1、D0~D7,并行输出,接LED。
2、16号和8号引脚,分别接Vcc,Gnd。
3、OE,13号引脚,低电平才输出有效,让它接地。
4、10号引脚,主复位引脚,低有效。目前不需要复位,直接接VCC就好.
5、14号引脚SER,接在集成板的P3^4,为串行输入端。
6、11号引脚SRCLK,接在集成板的P3^6;上升沿时,将串行口RCLK的一位,移位输入。
7、12号引脚RCLK,接在集成板的P3^5;上升沿时,将移入的8位数据,送到存储寄存器。

高位在这里插入图片描述注释:SDI先发送高位,在发送低位,高位发送到对应的Q管脚的相应位置,每一次的发送为伴随着一个上升沿。

上面的只是使用方法,如果还想继续深究,可以查看数电当中的串并行输入输出。

关于点阵

点阵的实际原理图

在这里插入图片描述
(列的标号从上到下依次为为1-7,行的标号从左到右依次为a-h)

8*8 点阵共由 64 个发光二极管组成,且每个发光二极管是放置在行线和列线
的交叉点上,当对应的某一行置 1 电平,某一列置 0 电平,则相应的二极管就亮;
如要将第一个点点亮,则 1 脚接高电平 a 脚接低电平,则第一个点就亮了;如果
要将第一行点亮,则第 1 脚要接高电平,而(a、b、c、d、e、f、g、h )这些
引脚接低电平,那么第一行就会点亮;如要将第一列点亮,则第 a 脚接低电平,
而(1、2、3、4、5、6、7、8)接高电平,那么第一列就会点亮。

在这里插入图片描述

代码


#include <reg51.h>		 //此文件中定义了单片机的一些特殊功能寄存器
#include <intrins.h>

typedef unsigned int u16;	  //对数据类型进行声明定义
typedef unsigned char u8;

//--定义使用的IO口--//
sbit SRCLK=P3^6;
sbit RCLK=P3^5;
sbit SER=P3^4;
sbit LED=P0^7;
                                                 /* 函 数 名         : Hc595SendByte(u8 dat1,u8 dat2)
                                                  * 函数功能		   : 通过595发送2个字节的数据
                                                  * 输    入         : dat1:第2个595输出数值
                                                  *                  * dat2: 第1个595输出数值
                                                  * 输    出         : 无
                                                  **************************/
void Hc595SendByte(u8 dat)               // 调用函数SendByte
{
	u8 a;

	SRCLK = 1;
	RCLK = 1;

	

	for(a=0;a<8;a++)		 //发送8位数
	{
		SER = dat >> 7;		 //从最高位开始发送
		dat <<= 1;          

		SRCLK = 0;			 //发送时序
		_nop_();           //调用nop函数,进行一个机器周期的延时
		_nop_();            // 延时两个机器周期
		SRCLK = 0;	        //初始化SRCLK,重回低电平,为下一个上升沿输入做准备
	}

	RCLK = 0;             //RCLK从0到1,上升沿到达,输出前面接收的段码数据
	_nop_();
	_nop_();
	RCLK = 1;             //初始化RCLK,重回低电平,为下一个上升沿输出做准备
}


void main()
{	
	
	Hc595SendByte(0x01);  		// 0000 0001
	
       P0= 0X7F ;              // 0111 1111
      while(1)	;
}

实物展示略

用点阵显示爱心

代码:
(实现的是空心的爱心,代码来自网络)

#include "reg51.h"    //注意这里使用“reg52.h"可能会出现重复定义错误,因为52.h中已定义过RCLK
#include<intrins.h>
typedef unsigned int u16;	 
typedef unsigned char u8;
sbit SRCLK=P3^6;
sbit RCLK=P3^5;
sbit SER=P3^4;
u8 ledduan[]={0x38,0x44,0x42,0x21,0x42,0x44,0x38,0x00};//每一列的7~0二极管状态
u8 ledwei[]={0x7f,0xbf,0xdf,0xef,0xf7,0xfb,0xfd,0xfe};//第1列到第8列位选

void delay(u16 i)     
{
	while(i--);	
}

void Hc595SendByte(u8 dat)                
{
	u8 a;
	SRCLK=0;
	RCLK=0;
	for(a=0;a<8;a++)		//重复发送ledduan[i]中的段码,使每一列对应二极管亮
	{
		SER=dat>>7;			//从最高位开始发送
		dat<<=1;            //左移依次左移1位,发送次高位,


		SRCLK=1;			//0-1,上升沿到达,发送一位数据(段码中的1位二进制值)
		_nop_();            
		_nop_();            // 内置延时函数
		SRCLK=0;	        //初始化SRCLK,重回低电平,为下一个上升沿输入做准备
	}


	RCLK=1;					//RCLK从0到1,上升沿到达,输出前面接收的段码数据
	_nop_();                
	_nop_();                
	RCLK=0;                 //初始化RCLK,重回低电平,为下一个上升沿输出做准备
}

void main()
{			
	u8 i;
	while(1)
	{
		P0=0x7f;
		for(i=0;i<8;i++)
		{
			P0=ledwei[i];		  //位选
			
			Hc595SendByte(ledduan[i]);	//发送段选数据
			
			delay(100);		   //时间足够短,视觉暂留
			Hc595SendByte(0x00);  //消隐,将dat置回初值隐
		}	
	}		
}

实物展示略

字模软件

如何显示自己心仪的图形

在这里我们要借助于取字模软件,借助这个软件我们可以轻松的得到控制显示图案的段码。点阵就是由64个led灯组成的,所以他的发光原理其实和数码管差不多。接下来就是取字模软件的使用。

1. 下载取字模软件
在这里插入图片描述
软件下载地址:添加链接描述
链接:https://pan.baidu.com/s/1-Zm8lmzGhydn_cSaZ-7-IQ
提取码:cop8
2. 单击“新建图像”命令,根据开发板上的点阵,把宽度和高度调成 8 x 8 ,然后点击“确定” 。

  1. 单击左侧的“模拟动画”命令,再单击“放大格点”,一直放大到最大,就可以在 8 x 8的点阵图形中用鼠标填充黑色画图形了。

4.可以按照自己的喜好画出图形或字
(此处可以结合开发板上面的点阵原理图设置“纵向取模”、“字节倒序”等方式取出符合自己要求的图形)

5.点击“取模命令”,单击“C51格式”后,在“点阵生成区”自动生成了8个字节的数据。

  1. 将生成的代码放入下面数组中
    (例如0x78,0xFC,0x7E,0x3F,0x3F,0x7E,0xFC,0x78)
u8 ledduan[]={0x78,0xFC,0x7E,0x3F,0x3F,0x7E,0xFC,0x78};

其余的程序代码与上面爱心的代码基本差不多,只需要替换 ” ledduan ” 的数组即可。

点阵的显示运用

点阵的循环显示

**·**点阵的循环显示可以用二维数组来实现,利用二维数组和延时函数,可以让点阵按照要循环显示。
例如下列代码:

//循环显示0123456789SNOW
#include<reg51.h>
#include<intrins.h>

typedef unsigned int u16;
typedef unsigned char u8;

sbit DS = P3^4;      //数据输入(0或1)
sbit RCLK = P3^5;    //并行输出开关
sbit SRCLK = P3^6;   //串行输入开关

unsigned char code ledwei[8]  = {0x7f,0xbf,0xdf,0xef,0xf7,0xfb,0xfd,0xfe}; //列选通控制
unsigned char code ledduan[14][8]=                                         //点阵字码   二维数组
{

{0x00,0x00,0x3e,0x41,0x41,0x41,0x3e,0x00}, //0

{0x00,0x00,0x00,0x00,0x21,0x7f,0x01,0x00}, //1

{0x00,0x00,0x27,0x45,0x45,0x45,0x39,0x00}, //2

{0x00,0x00,0x22,0x49,0x49,0x49,0x36,0x00}, //3

{0x00,0x00,0x0c,0x14,0x24,0x7f,0x04,0x00}, //4

{0x00,0x00,0x72,0x51,0x51,0x51,0x4e,0x00}, //5

{0x00,0x00,0x3e,0x49,0x49,0x49,0x26,0x00}, //6

{0x00,0x00,0x40,0x40,0x40,0x4f,0x70,0x00}, //7

{0x00,0x00,0x36,0x49,0x49,0x49,0x36,0x00}, //8

{0x00,0x00,0x32,0x49,0x49,0x49,0x3e,0x00}, //9

{0x00,0x00,0x24,0x52,0x4A,0x24,0x00,0x00}, //S

{0x00,0x00,0x7E,0x20,0x18,0x04,0x7E,0x00}, //N 

{0x00,0x00,0x3e,0x41,0x41,0x41,0x3e,0x00}, //O

{0x00,0x70,0x08,0x14,0x60,0x14,0x08,0x70}, //W

};
void delay(u16 time);
void Hc595SendByte(u8 dat);

void main()
{	
 	u8 tab, j = 0;
	u16 i;

	while(1)
	{	
		for(i= 0; i<50; i++ )                        //两个字之间的扫描间隔时间
		{
			for(tab=0;tab<8;tab++)                   //每一个字符对应8列
			{	
				Hc595SendByte(0x00);			     //消隐																
			    P0 = ledwei[tab];				     //位选,选通某一列
				Hc595SendByte(ledduan[j][tab]);	     //通过HC595发送序列i对应的段选的真值
				delay(2);		
			}		 
		}
		j++;
		if(j == 14)
		{
			j = 0;
		}
	}	
}

void delay(u16 time)               //延时函数
{
  u16 i,j;
  for(i=0;i<time;i++)
    for(j=0;j<121;j++);
}

void Hc595SendByte(u8 dat)
{
    u8 a=0;
    RCLK = 0;          //输出寄存器状态保持
    SRCLK = 0;         //移位寄存器状态保持
    for(a = 0;a<8;a++) //循环8次,存进8位进制二进制数字
    {
        DS = dat>>7;   //串行输入最高位数据化
        dat = dat<<1;  //次高位移向最高位
        SRCLK = 1;     //移位寄存器存储
        _nop_();       //延时,保证脉冲宽度足够
		_nop_();
        SRCLK = 0;     //移位寄存器状态保持,为下一次上升沿到来做准备
    }
    RCLK = 1;          //输入移位寄存器数据
    _nop_();           //延时,保证脉冲宽度足够
    _nop_();
    RCLK = 0;          //输出寄存器状态保持,为下一次上升沿到来做准备
}

点阵的纵向移动

示例代码如下:
(仅写出主函数部分的代码,但是不要忘了改前面函数相关声明)

void main()
{			
	int i,b=0;
	while(1)
	{
		int num = 12;
		while(num --)
		{
		P0=0x7f;
		for(i=0;i<8;i++)
		{
			P0=ledwei[i];		  //位选      先位选后段选
			
			Hc595SendByte(ledduan[i+b]);	//发送段选数据,而且 “i+b”能够实现对duan 数组里面的循环运行从而实现纵向的循环移动
			
			delay(100);		   //时间足够短,视觉暂留
			Hc595SendByte(0x00);  //消隐,将dat置回初值隐
		}	
	}
		b++;                
	if(b>=24)                                     
		b=0;                      /* 至于为什么是24而不是32,目前还不清楚,但是我认为是这样的:当为32时运行时最后会出现整个点阵都是亮的现象,因此用24是为了消除此现象 (目前我还没有搞清楚这个问题,目前只是个人的猜测) */
	}		
}

点阵的横向移动

方法一:因为点阵的横向移动比较麻烦,所以我们可以采用纵向移动的方法来实现,将板子横着侧过来,纵向取模就可以完成了

方法二:主要是运用二维数组。在横向显示的时候需要将所需要的效果把需要的图片都给画下来,再逐一进行取模,比如通过程序每250ms改变一张图片,一张图片为一帧,逐一作出来,即可完成横向显示的效果。每一张的取模取出8个字节的数据,需要存放在一个二维数组内。
例如:
在这里插入图片描述


版权声明:本文为qq_47433315原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。