51 单片机[9]:LED点阵屏

一、目标

  1. LED点阵屏显示静态图案
  2. LED点阵屏显示滚动字幕

二、LED点阵屏和74HC595介绍

LED点阵屏由若干个独立的LED组成,LED以矩阵的形式排列,以灯珠亮灭来显示文字、图片、视频等。LED点阵屏广泛应用于各种公共场合,如汽车报站器、广告屏以及公告牌等。

LED点阵屏分类:

  • 按颜色:单色、双色、全彩
  • 按像素:8*8、16*16等(大规模的LED点阵通常由很多个小点阵拼接而成)

img

可以看到普中A2开发板LED点阵模块,由P0和DP控制。

img

DP是74HC595输出的。

img

因为OE上面有一个横线,代表只有OE为低电平时,74HC595才能工作。想让74HC595工作,就得把OE接地。即:把点阵屏左上角的跳线帽放到左边两个针上。

img

74HC595是串行输入并行输出的移位寄存器,可用3根线输入串行数据,8根线输出并行数据,多片级联后,可输出16位、24位、32位等,常用于IO口扩展。

RCLK:表示寄存器时钟,上升沿锁存
SRCLR ‾ \overline{\text{SRCLR}} SRCLR:表示串行清零
SRCLK:表示串行时钟,上升沿移位
SER:用于输入串行数据
QH’:表示多片级联。若有多片级联,则接到下一片的SER

主要通过SER、SRCLK、RCLK控制。

img

三、LED点阵屏显示图形

sfr(special function register):特殊功能寄存器声明
例:sfr P0 = 0x80;
声明P0口寄存器,物理地址为0x80
sbit(special bit):特殊位声明
例:sbit P0_1 = 0x81;sbit P0_1 = P0^1;
声明P0寄存器的第1位

在main.c中,定义一下要用的三个位。

#include <REGX52.H>

sbit RCLK = P3^5;
sbit SRCLK = P3^6;
sbit SER = P3^4;

void main()
{
	while(1)
	{
		
	}
}

编译一下,发现报错:RCLK重定义了。

main.c(3): error C231: 'RCLK': redefinition

打开REGX52.H的184行,发现

sbit RCLK = 0xCD;

所以,把main.c中的RCLK改为RCK。
为了简洁,把SRCLK改为SCK

#include <REGX52.H>

sbit RCK = P3^5;	//RCLK
sbit SCK = P3^6;	//SRCLK
sbit SER = P3^4;	//SER

void main()
{
	while(1)
	{
		
	}
}

再次编译,发现没有错误。

SER是一位数据,无论给什么数据,非0即1。

写一个移位的程序

void _74HC595_WriteByte(unsigned char Byte)
{
	SER = Byte&0x80;	//取出最高位
	SCK = 1;	//SRCLK上升沿,移位
	SCK = 0;	//置0,为下一次移位做准备
	SER = Byte&0x40;	//取出第二位
	SCK = 1;	//SRCLK上升沿,移位
	SCK = 0;	//置0,为下一次移位做准备
	SER = Byte&0x20;	//取出第三位
	SCK = 1;	//SRCLK上升沿,移位
	SCK = 0;	//置0,为下一次移位做准备
    //... 直到第八位
}

一直写到第8位,太麻烦了,可以写一个for循环简化一下

void _74HC595_WriteByte(unsigned char Byte)
{
	unsigned char i;
	for(i=0;i<8;i++)
	{
		SER = Byte&(0x80>>i);
		SCK = 1;	//SRCLK上升沿,移位
		SCK = 0;	//置0,为下一次移位做准备
	}
}

当8为全都到寄存器中,就可以给RCLK一个上升沿,把数据移过去了

void _74HC595_WriteByte(unsigned char Byte)
{
	unsigned char i;
	for(i=0;i<8;i++)
	{
		SER = Byte&(0x80>>i);
		SCK = 1;	//SRCLK上升沿,移位
		SCK = 0;	//置0,为下一次移位做准备
	}
	RCK = 1;
	RCK = 0;
}

现在测试一下_74HC595_WriteByte。由于新版普中2板只有一个LED模块,所以在函数体内加P2 = ~Byte;来测试。

main函数如下:

void main()
{
	SCK = 0;
	RCK = 0;
	
	while(1)
	{
		_74HC595_WriteByte(0xAA);
	}
}

编译一下,可以看到D2, D4, D6, D8被点亮。这说明_74HC595_WriteByte函数没问题。可以继续写点阵屏的代码。

可以参考数码管的代码。

把Delay.c和Delay.h复制到本项目。

定义一个函数

void MatrixLED_ShowColumn(unsigned char Column, Data)
{
	_74HC595_WriteByte(Data);
	if(Column==0){P0=~0x80;}
	if(Column==1){P0=~0x40;}
	//...
}

简化一下代码

void MatrixLED_ShowColumn(unsigned char Column, Data)
{
	_74HC595_WriteByte(Data);
	P0=~(0x80>>Column);
}

main函数:

void main()
{
	SCK = 0;
	RCK = 0;
	MatrixLED_ShowColumn(0, 0xAA);
	while(1)
	{
		
	}
}

编译一下,可以看到如图所示的现象
img
把0改为7就会亮最后一列。
如果是MatrixLED_ShowColumn(7, 0xF0);就会亮最后一列,上面四个。

理论上来说,要实现点阵屏动态显示,应该是段选、位选、段选、位选……这样的操作。但是当次段选容易和上次位选混在一起,所以需要“延时+位清零”操作。即,段选、位选、延时+位清零、段选、位选、延时+位清零……

MatrixLED_ShowColumn()可以写为:

void MatrixLED_ShowColumn(unsigned char Column, Data)
{
	_74HC595_WriteByte(Data);
	P0=~(0x80>>Column);
	Delay(1);//延时
	P0 = 0xFF;//位清零
}

测试一下,可以看到MatrixLED_ShowColumn(7, 0xF0);如果不放while(1)循环里,LED闪一下就灭了。

现在在while(1)循环里调用MatrixLED_ShowColumn()

void main()
{
	SCK = 0;
	RCK = 0;
	
	while(1)
	{
		MatrixLED_ShowColumn(0, 0x80);
		MatrixLED_ShowColumn(1, 0x40);
		MatrixLED_ShowColumn(2, 0x20);
		MatrixLED_ShowColumn(3, 0x10);
	}
}

编译一下,可以看到如图所示现象
img

现在画个心形

void main()
{
	SCK = 0;
	RCK = 0;
	
	while(1)
	{
		MatrixLED_ShowColumn(0, 0x38);
		MatrixLED_ShowColumn(1, 0x44);
		MatrixLED_ShowColumn(2, 0x42);
		MatrixLED_ShowColumn(3, 0x21);
		MatrixLED_ShowColumn(4, 0x21);
		MatrixLED_ShowColumn(5, 0x42);
		MatrixLED_ShowColumn(6, 0x44);
		MatrixLED_ShowColumn(7, 0x38);
	}
}

编译一下,可以看到:
img

四、模块化

新建MatrixLED.c和MatrixLED.h
在MatrixLED.c中写入:

#include <REGX52.H>
#include "Delay.h"

sbit RCK = P3^5;	//RCLK
sbit SCK = P3^6;	//SRCLK
sbit SER = P3^4;	//SER
/**
  * @brief	74HC595写入一个字节
  * @param	Byte 要写入的字节
  * @retval	无
  */
void _74HC595_WriteByte(unsigned char Byte)
{
	unsigned char i;
	for(i=0;i<8;i++)
	{
		SER = Byte&(0x80>>i);
		SCK = 1;	//SRCLK上升沿,移位
		SCK = 0;	//置0,为下一次移位做准备
	}
	RCK = 1;
	RCK = 0;
	//P2 = ~Byte;
}

/**
  * @brief  点阵屏初始化
  * @param  无
  * @retval 无
  */
void MatrixLED_Init()
{
	SCK = 0;
	RCK = 0;
}

/**
  * @brief  LED点阵屏显示一列数据
  * @param  Column 要选择的列,范围:0~7,0在最左边
	* @param  Data 所选列显示的数据,高位在上,1亮0灭
  * @retval 无
  */
void MatrixLED_ShowColumn(unsigned char Column, Data)
{
	_74HC595_WriteByte(Data);
	P0=~(0x80>>Column);
	Delay(1);//延时
	P0 = 0xFF;//位清零
}

在MatrixLED.h中写入:

#ifndef __MATRIX_LED__H__
#define __MATRIX_LED__H__

void _74HC595_WriteByte(unsigned char Byte);
void MatrixLED_Init();
void MatrixLED_ShowColumn(unsigned char Column, Data);

#endif

此时,main.c中就简化为:

#include <REGX52.H>
#include "Delay.h"
#include "MatrixLED.h"


void main()
{
	MatrixLED_Init();
	
	while(1)
	{
		MatrixLED_ShowColumn(0, 0x38);
		MatrixLED_ShowColumn(1, 0x44);
		MatrixLED_ShowColumn(2, 0x42);
		MatrixLED_ShowColumn(3, 0x21);
		MatrixLED_ShowColumn(4, 0x21);
		MatrixLED_ShowColumn(5, 0x42);
		MatrixLED_ShowColumn(6, 0x44);
		MatrixLED_ShowColumn(7, 0x38);
	}
}

五、LED点阵屏显示动画

打开文字取模软件
img

新建宽度32、高度8的图像
img

然后放大格点
img

在格点中画个“Hello !”
img

在取模方式中点击C51格式,然后把生成的点阵位置复制
img

在main.c中定义一个unsigned char Animation[]={};用来存储这些点阵位置。

unsigned char Animation[]={0xFF,0x08,0x08,0x08,0xFF,0x00,0x0E,0x15,0x15,0x0D,0x00,0x7F,0x01,0x00,0x7F,0x01,
0x00,0x0E,0x11,0x11,0x0E,0x00,0x7D,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00};

main.c的程序为:

#include <REGX52.H>
#include "Delay.h"
#include "MatrixLED.h"

unsigned char Animation[]={
	0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
	0xFF,0x08,0x08,0x08,0xFF,0x00,0x0E,0x15,
	0x15,0x0D,0x00,0x7F,0x01,0x00,0x7F,0x01,
	0x00,0x0E,0x11,0x11,0x0E,0x00,0x7D,0x00,
	0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00};
void main()
{
	unsigned char i;
	unsigned char Offset=0;//偏移量
	unsigned char Count=0;//计次
	MatrixLED_Init();
	while(1)
	{
		for(i=0;i<8;i++)
		{
			MatrixLED_ShowColumn(i, Animation[i+Offset]);
		}
		Count++;
		if(Count>10)
		{
			Count = 0;
			Offset++;
			if(Offset>32)
			{
				Offset=0;
			}
		}
	}
}

编译一下,可以看到“Hello !”字样滚动显示。

  • 3
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值