江科大51单片机学习笔记之LED点阵屏

一、LED点阵屏介绍

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

LED点阵屏分类:

按颜色:单色、双色、全彩

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

本开发板是单色8*8的点阵屏

二、LED点阵屏工作原理

LED点阵屏的结构类似于数码管,只不过是数码管把每一列的像素以“8”字型排列而已。原理图如下

51-LED点阵屏原理图

每一行的阳极连在一起,每一列的阴极连在一起

LED点阵屏需要进行逐行或逐列扫描(扫描的速度很快),才能使所有LED同时显示

例如,要想显示第二行第二列的LED灯,只需将DPg置1,其余行置0,P06置0,其余列置1,即可

尽管使用8*8的矩阵来控制64个LED等,但16个IO口还是比较多的,并且也不能直接使用16个IO口,因为本单片机IO口输出是弱上拉的,输出高电平的电流较小,输出低电平的电流较大(正常),所以如果直接用16个IO口的话,LED点阵屏的每一行的输出的电流较小,会是的灯光较暗。

于是本开发板使用了74HC595模块来控制A1-A8这8行的IO口,74HC595模块原理图如下,使用P34、P35、P36三个IO口来控制8个IO口的输出。J24模块在LED点阵屏的左上方。

三、74HC595

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

51-74HC595原理图

OE ‾ \overline{\text{OE}} OE:输出使能,低电平有效,接GND,即使用跳线帽将J24的OE和GND连起来(开发板默认用跳线帽连接OE和GCC,需要将跳线帽连接左边两个口

RCLK:寄存器时钟

SRCLR ‾ \overline{\text{SRCLR}} SRCLR:串行清零,接VCC,表示不清空数据

SRCLK:串行时钟,用于输入串行数据

SER:串行数据输入端

QH’:用于多片级联,接到下一个74HC595的SER口

74HC595工作原理:

74HC595工作原理简图如下:

image-20230706171314815

该模块可用于数据串行输入,并行输出

左边是个移位寄存器,SER输入一位数据,SERCLK在上升沿到来时,将移位寄存器的数据向下移动一位,之后SER再输入一位数据,在SERCLK时钟的上升沿时移位,数据填满移位寄存器后,在RCLK的上升沿到来时,将该寄存器的数据复制到右边的数据缓冲寄存器中,即为输出的数据。同时数据也可以通过QH‘输出到下一个74HC595的SER口作为串行数据输入。

开发板引脚对应关系:

image-20230801202331647

LED点阵屏的列直接接在IO口上,通过P0口直接输入,行通过74HC595来进行数据输入

四、实验1

LED点阵屏显示静态图形

补充:C51的sfr、sbit

•sfr(special function register):特殊功能寄存器声明

例:sfr P0 = 0x80;

声明P0口寄存器,物理地址为0x80

•sbit(special bit):特殊位声明

例:sbit P0_1 = 0x81; 或 sbit P0_1 = P0^1;

声明P0寄存器的第1位

•可位寻址/不可位寻址:在单片机系统中,操作任意寄存器或者某一位的数据时,必须给出其物理地址,又因为一个寄存器里有8位,所以位的数量是寄存器数量的8倍,单片机无法对所有位进行编码,故每8个寄存器中,只有一个是可以位寻址的。对不可位寻址的寄存器,若要只操作其中一位而不影响其它位时,可用“&=”、“|=”、“^=”的方法进行位操作

1、位声明

根据原理图,将IO口进行位声明,方面之后使用

sbit SER = P3^4;
sbit SERCLK = P3^6;
sbit RCK = P3^5;	//RCLK
2、74HC595写入字节函数
/**
  * @brief  74HC595写入一个字节
  * @param  byte 要写入的字节
  * @retval 无
  */
void _74HC595_WriteByte(unsigned char byte)
{
	unsigned char i;
	for(i = 0;i < 8;i++)
	{
		//以byte&0x80为例,byte和0x80与运算后,首位不变,其余位变为0;若最高位为1,则与运算的结果不为0,
		//即SER为1(SER是一个位,赋值时非0即为1),若最高位为0,则与运算的结果为0,即SER为0
		//这样就可以获取byte的最高位
		//其余位的获取,同理
		SER = byte&(0x80 >> i);
		
		SERCLK = 1;//一开始SERCLK为0,这里置为1,就产生了上升沿
	
		SERCLK = 0;//为下一次移位做准备
	}
	
	RCK = 1;
	RCK = 0;
}
3、测试写入字节函数
#include <REGX52.H>

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

/**
  * @brief  74HC595写入一个字节
  * @param  byte 要写入的字节
  * @retval 无
  */
void _74HC595_WriteByte(unsigned char byte)
{
	unsigned char i;
	for(i = 0;i < 8;i++)
	{
		//以byte&0x80为例,byte和0x80与运算后,首位不变,其余位变为0;若最高位为1,则与运算的结果不为0,
		//即SER为1(SER是一个位,赋值时非0即为1),若最高位为0,则与运算的结果为0,即SER为0
		//这样就可以获取byte的最高位
		//其余位的获取,同理
		SER = byte&(0x80 >> i);
		
		SERCLK = 1;//一开始SERCLK为0,这里置为1,就产生了上升沿
	
		SERCLK = 0;//为下一次移位做准备
	}
	
	RCK = 1;
	RCK = 0;
}

void main()
{
	//上电时为高电平
	SERCLK = 0;
	RCK = 0;
	_74HC595_WriteByte(0xF0);
	while(1)
	{
		
	}
}

注意:这个板子没有江科大视频中的LED灯,所以无法验证函数的正确性

4、显示数据函数

与数码管类似,以列为单位进行显示

同时,为了消除残影,需要在函数的最后进行P0口的清零

/**
  * @brief  LED点阵屏显示一列数据
  * @param  column 要选择的列,范围:0~7,0在最左边
  * @param  myData 选择列显示的数据,高位在上,1为亮,0为灭
  * @retval 无
  */
void MatrixLED_ShowColumn(unsigned char column, myData)
{
	_74HC595_WriteByte(myData);
    //选中某一列
	P0 = ~(0x80>>column);//列,低电平有效,故要取反
    Delayms(1);
	MATRIX_LED_PORT=0xFF;//位清零
}
5、LED点阵屏显示笑脸(实验最终现象)

通过控制每一列的灯的亮灭来显示整个图像

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

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

#define MATRIX_LED_PORT		P0

/**
  * @brief  74HC595写入一个字节
  * @param  Byte 要写入的字节
  * @retval 无
  */
void _74HC595_WriteByte(unsigned char byte)
{
	
	unsigned char i;
	for(i = 0;i < 8;i++)
	{
		//以byte&0x80为例,byte和0x80与运算后,首位不变,其余位变为0;若最高位为1,则与运算的结果不为0,
		//即SER为1(SER是一个位,赋值时非0即为1),若最高位为0,则与运算的结果为0,即SER为0
		//这样就可以获取byte的最高位
		//其余位的获取,同理
		SER = byte&(0x80 >> i);
		
		SERCLK = 1;//一开始SERCLK为0,这里置为1,就产生了上升沿
	
		SERCLK = 0;//为下一次移位做准备
	}
	
	RCK = 1;
	RCK = 0;
}

/**
  * @brief  LED点阵屏显示一列数据
  * @param  column 要选择的列,范围:0~7,0在最左边
  * @param  myData 选择列显示的数据,高位在上,1为亮,0为灭
  * @retval 无
  */
void MatrixLED_ShowColumn(unsigned char column, myData)
{
	_74HC595_WriteByte(myData);
	MATRIX_LED_PORT = ~(0x80>>column);//列,低电平有效
    Delayms(1);
	MATRIX_LED_PORT=0xFF;//位清零
}

void main()
{
	//上电时为高电平
	SERCLK = 0;
	RCK = 0;
	
	while(1)
	{
		MatrixLED_ShowColumn(0,0x3C);
		MatrixLED_ShowColumn(1,0x42);
		MatrixLED_ShowColumn(2,0xA9);
		MatrixLED_ShowColumn(3,0x85);
		MatrixLED_ShowColumn(4,0x85);
		MatrixLED_ShowColumn(5,0xA9);
		MatrixLED_ShowColumn(6,0x42);
		MatrixLED_ShowColumn(7,0x3C);
	}
}
四、实验2

LED点阵屏显示动画

1、点阵屏模块化

将实验1的代码进行模块化

MatrixLED.h

#ifndef _MATRIXLED_H__
#define _MATRIXLED_H__

void _74HC595_WriteByte(unsigned char byte);
void MatrixLED_ShowColumn(unsigned char column, myData);
void MatrixLED_Init();

#endif

MatrixLED.c

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

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

#define MATRIX_LED_PORT		P0

/**
  * @brief  74HC595写入一个字节
  * @param  Byte 要写入的字节
  * @retval 无
  */
void _74HC595_WriteByte(unsigned char byte)
{
	
	unsigned char i;
	for(i = 0;i < 8;i++)
	{
		//以byte&0x80为例,byte和0x80与运算后,首位不变,其余位变为0;若最高位为1,则与运算的结果不为0,
		//即SER为1(SER是一个位,赋值时非0即为1),若最高位为0,则与运算的结果为0,即SER为0
		//这样就可以获取byte的最高位
		//其余位的获取,同理
		SER = byte&(0x80 >> i);
		
		SERCLK = 1;//一开始SERCLK为0,这里置为1,就产生了上升沿
	
		SERCLK = 0;//为下一次移位做准备
	}
	
	RCK = 1;
	RCK = 0;
}

/**
  * @brief  LED点阵屏显示一列数据
  * @param  column 要选择的列,范围:0~7,0在最左边
  * @param  myData 选择列显示的数据,高位在上,1为亮,0为灭
  * @retval 无
  */
void MatrixLED_ShowColumn(unsigned char column, myData)
{
	_74HC595_WriteByte(myData);
	MATRIX_LED_PORT = ~(0x80>>column);//列,低电平有效
	Delayms(1);
	MATRIX_LED_PORT=0xFF;//位清零
}

/**
  * @brief  LED点阵屏初始化
  * @param  无
  * @retval 无
  */
void MatrixLED_Init()
{
	//上电时为高电平
	SERCLK = 0;
	RCK = 0;
}
2、利用文字取模软件生成图像数据

点击“基本操作”,再点击“新建图像”,高度选8,宽度随意,这里选32

之后点击“参数设置”,再点击“其他选项”,在这里选择纵向取模,不选择字节倒序,其余不变

image-20230801221805350

点击“模拟动画”,再点击“放大格点”,将图像进行放大

描绘自己想要的图像

image-20230801222337843

点击“取模方式“,选择C51格式,将生成的数据保存

3、保存图像数据

将数据保存在数组中,数组的每一个元素表示一列LED的数据

//动画数据
unsigned char code Animation[]={
0xFF,0x08,0x08,0x08,0xFF,0x00,0x00,0x1C,0x2A,0x2A,0x1A,0x00,0x00,0x7F,0x01,0x01,
0x01,0x00,0x00,0x7F,0x01,0x01,0x00,0x00,0x1C,0x22,0x22,0x1C,0x00,0x00,0x7D,0x00,
};
4、主函数
#include <REGX52.H>
#include "Delay.h"
#include "MatrixLED.h"

//动画数据
unsigned char Animation[]={
0xFF,0x08,0x08,0x08,0xFF,0x00,0x00,0x1C,0x2A,0x2A,0x1A,0x00,0x00,0x7F,0x01,0x01,
0x01,0x00,0x00,0x7F,0x01,0x01,0x00,0x00,0x1C,0x22,0x22,0x1C,0x00,0x00,0x7D,0x00,
};

void main()
{
	//Offset:偏移量  Count:扫描次数
	unsigned char i,Offset=0,Count=0;
	MatrixLED_Init();
	while(1)
	{
		for(i=0;i<8;i++)	//循环8次,显示8列数据
		{
			MatrixLED_ShowColumn(i,Animation[i+Offset]);
		}
		Count++;			
		if(Count>10)		//扫描10次时,相当于延时
		{
			Count=0;
			Offset++;	//显示下一列数据	
			if(Offset>24) //32-8=24
			{
				Offset=0;
			}
		}
	}
}

此时,LED点阵屏流动显示完字幕后会立刻从头开始,为了显示出流动的效果,在数组的前面和后面添加0x00

#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,0x00,0x1C,
	0x2A,0x2A,0x1A,0x00,0x00,0x7F,0x01,0x01,
	0x01,0x00,0x00,0x7F,0x01,0x01,0x00,0x00,
	0x1C,0x22,0x22,0x1C,0x00,0x00,0x7D,0x00,
	0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
};

void main()
{
	//Offset:偏移量  Count:扫描次数
	unsigned char i,Offset=0,Count=0;
	MatrixLED_Init();
	while(1)
	{
		for(i=0;i<8;i++)	//循环8次,显示8列数据
		{
			MatrixLED_ShowColumn(i,Animation[i+Offset]);
		}
		Count++;			
		if(Count>10)		//扫描10次时,相当于延时
		{
			Count=0;
			Offset++;	//显示下一列数据	
			if(Offset>40)//48-8=40
			{
				Offset=0;
			}
		}
	}
}

补充:闪屏动画(逐帧)

逐帧显示HELLO

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

//动画数据
unsigned char code Animation[]={
	0x00,0xFF,0x08,0x08,0x08,0x08,0xFF,0x00,
	0x00,0xFF,0x89,0x89,0x89,0x89,0x00,0x00,
	0x00,0xFF,0x01,0x02,0x02,0x04,0x00,0x00,
	0x00,0xFF,0x01,0x02,0x02,0x04,0x00,0x00,
	0x00,0x3E,0x41,0x41,0x41,0x41,0x3E,0x00,
};

void main()
{
	//Offset:偏移量  Count:扫描次数
	unsigned char i,Offset=0,Count=0;
	MatrixLED_Init();
	while(1)
	{
		for(i=0;i<8;i++)	//循环8次,显示8列数据
		{
			MatrixLED_ShowColumn(i,Animation[i+Offset]);
		}
		Count++;			
		if(Count>40)		//扫描10次时,相当于延时
		{
			Count=0;
			Offset+=8;	//显示下一列数据	
			if(Offset>32)
			{
				Offset=0;
			}
		}
	}
}

补充:Animation数组是存储在RAM中,当要显示的图像很多时,数据量会很大,RAM可能会不够,所以可以将数据保存在Flash里面,在char后面添加一个code就行。但是定义之后便不能更改(ROM的特性)。

unsigned char code Animation[]={};

更多51单片机笔记见主页

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值