【51单片机】8. 矩阵LED显示自定义图案、动画

发布于:2025-06-19 ⋅ 阅读:(19) ⋅ 点赞:(0)

1. 显示原理

  • LED点阵屏与数码管类似,只是将数码管每一列的像素以8字型排列

  • 与数码管一样,有共阴和共阳两种接法,不同接法对应电路结构不同

  • LED点阵需要逐行或逐列扫描,才能使所有LED同时显示

在这里插入图片描述

2. 74HC595电路图原理

在这里插入图片描述

看OE,是低电平有效,所以要弄一下J24这个接线帽

  • RCLK:Register Clock

  • SRCLR:Serial 串行清零端

  • SRCLK:串行时钟

  • SER:串行数据

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

在这里插入图片描述

数据通过SER一位一位地进来,上升沿移位SERCLK脉冲来一次就SER写一次数据,最后经上升沿锁存RCLK,将数据从左侧挪到右侧。

(弹匣装弹,霰弹枪出来的原理)

扩展多位的原理如下:

在这里插入图片描述

第一片板子SER里面的数据满了,就经过线送到下一片板子里,SERCLK和RCLK接在同一个位置。这样可以形成多片级联,形成更多位的输出。

3. 单片机

单片机输出端口是弱上拉的,给1的时候电流小,给0的时候VCC流回负极电流更大,如果想要将点阵直接接在单片机的端口上是不可行的,需要加一个三极管,三极管作为放大电路使用。

4. 74HC595的使用

江科大使用的单片机上74HC595模块是有接LED灯,以观察输出情况的,我买的普中板子上没有,所以只是按照看视频的理解写了相应的函数。

#include <REGX52.H>

// 重新命名,会更清晰一些,要不然容易不清楚每个口的具体含义
// P3^X:这不是异或的意思,这样的形式表示选中P3的第5位
sbit RClK = P3^5;  // 上升沿锁存,置1时将SER的内容全部写入输出口
sbit SRCLK = P3^6;  // 上升沿移位,置1时写入SER的内容
sbit SER = P3^4;

void _74HC595_WriteByte(unsigned char byteData)
{
    unsigned char i = 0;
    for (i = 0; i < 8; i++)
    {
        SER = byteData & (0x80 >> i); // 通过这种方式取出第i位
        // byteData & 0x80相当于选出最高位的数据,结果要么是1000 0000,要么是0000 0000
        // 因为SER的类型是sbit,所以要么为1要么为0
        // 如果结果1000 0000,SER就会被置为1
        // 如果结果0000 0000,SER就会被置为0

        // SRCLK原本为0,置1给一个电平写入,然后置0
        SRCLK = 1; 
        SRCLK = 0;
    }
    // RClK原本为0,置1给一个电平统一转移数字,然后置0
    RClK = 1;
    RClK = 0;
}

void main()
{
    SRCLK = 0; // 初始置0,后面才更容易给电平
    RClK = 0; // 初始置0,后面才更容易给电平
    while(1)
    {

    }
}

5. 点阵屏的显示

在4中函数的基础上,选中列后再对行进行选中,就可以实现点阵屏显示

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

// 重新命名,会更清晰一些,要不然容易不清楚每个口的具体含义
// P3^X:这不是异或的意思,这样的形式表示选中P3的第5位
sbit RClK = P3^5;  // 上升沿锁存,置1时将SER的内容全部写入输出口
sbit SRCLK = P3^6;  // 上升沿移位,置1时写入SER的内容
sbit SER = P3^4;

void _74HC595_WriteByte(unsigned char byteData)
{
	unsigned char i = 0;
	for (i = 0; i < 8; i++)
	{
		SER = byteData & (0x80 >> i); // 通过这种方式取出第i位
		// byteData & 0x80相当于选出最高位的数据,结果要么是1000 0000,要么是0000 0000
		// 因为SER的类型是sbit,所以要么为1要么为0
		// 如果结果1000 0000,SER就会被置为1
		// 如果结果0000 0000,SER就会被置为0
		
		// SRCLK原本为0,置1给一个电平写入,然后置0
		SRCLK = 1; 
		SRCLK = 0;
	}
	// RClK原本为0,置1给一个电平统一转移数字,然后置0
	RClK = 1;
	RClK = 0;
}

void MatrixLED_ShowColumn(unsigned char column, byteData)
{
	_74HC595_WriteByte(byteData); // 选中列
	P0 = ~(0x80) >> column; // 选中指定行,给低电平点灯,column表示点亮第几行,做一个右移
	// 避免显示下一个的时候出现残影,Delay后置灭
	Delay(1);
	P0 = 0xFF;
}

void main()
{
	SRCLK = 0; // 初始置0,后面才更容易给电平
	RClK = 0; // 初始置0,后面才更容易给电平
	MatrixLED_ShowColumn(7,0xAA);
	while(1)
	{	
		
	}
}

对于为什么要Delay和置灭,是因为这通常是一个:

段选→位选→段选→位选→…的过程

这会导致一个问题,在执行第三个段选的时候,上一次的位选还没改变,从而导致上一次的位选和下一次的段选结合,呈现错误的结果/残影,所以正确的是:

段选→位选→延时→位清零→段选→位选→…的过程

6. 矩阵LED屏显示自定义图案

有了上面的基础,显示笑脸就很简单了,用EXCEL画出需要亮灯的部分:

在这里插入图片描述

第一列:0011 1100 → 3C

第二列:0100 0010 → 42

第三列:1010 1001 → A9

第四列:1000 0101 → 85

第五列:1000 0101 → 85

第六列:1010 1001 → A9

第七列:0100 0010 → 42

第八列:0011 1100 → 3C

主函数修改为:

void main()
{
	SRCLK = 0; // 初始置0,后面才更容易给电平
	RClK = 0; // 初始置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);
	}
}

效果如下(长曝光):

在这里插入图片描述

类似的如果是一个爱心:

在这里插入图片描述

第一列:0001 1000 → 18

第二列:0010 0100 → 24

第三列:0100 0010 → 42

第四列:0010 0001 → 21

第五列:0010 0001 → 21

第六列:0100 0010 → 42

第七列:0010 0100 → 24

第八列:0001 1000 → 18

主函数修改为:

void main()
{
	SRCLK = 0; // 初始置0,后面才更容易给电平
	RClK = 0; // 初始置0,后面才更容易给电平
	while(1)
	{
		MatrixLED_ShowColumn(0, 0x18);
		MatrixLED_ShowColumn(1, 0x24);
		MatrixLED_ShowColumn(2, 0x42);
		MatrixLED_ShowColumn(3, 0x21);
		MatrixLED_ShowColumn(4, 0x21);
		MatrixLED_ShowColumn(5, 0x42);
		MatrixLED_ShowColumn(6, 0x24);
		MatrixLED_ShowColumn(7, 0x18);
	}
}

效果如下(长曝光):

在这里插入图片描述

7. 矩阵LED屏显示动画

我们的LED一共是8列,显示动画的原理实际上是将每列要显示内容组成一个数组,然后每次显示其中8列,例如第一次显示数组的0-7,第二次显示数组的1-8,以此类推。

具体显示的字符动画可以利用字模提取软件获得对应的结果,使用步骤如下:

第一步:新建图像,高度为8(开发板上的高度,宽度选择对应字符长度)

在这里插入图片描述

第二步:模拟动画里放大格点

在这里插入图片描述

第三步:绘制格点:

在这里插入图片描述

第四步:生成点阵

在这里插入图片描述

接下来就可以写代码,实际上就是用循环来遍历上面的这些内容:

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

unsigned char Animation[] = {
	0x00,0x00,0x00,0x00,0x00,0xFF,0x81,0x42,0x3C,0x00,0x0C,0x12,0x12,0x0E,0x01,0x00,
  0xFF,0x81,0x42,0x3C,0x00,0x0C,0x12,0x12,0x0E,0x01,0x00,0xFD,0x00,0x00,0x00,0x00, 
}; // 字符提取软件生成

void main()
{
	unsigned int i = 0, offset = 0, count = 0; 
	Init_Matrix_LED();
	while(1)
	{
		for (i = 0; i < 8; i++) // for循环,8位循环显示
		{
			MatrixLED_ShowColumn(i, Animation[i+offset]); // offset表示数组中的便宜
		}
		// count这里实际上起到一个控制速度的作用,大于号后面的数字越大则动的越慢
		count++;
		if (count > 10)
		{
			count = 0;
			offset++; // 增加偏移量
			if (offset > 24) offset = 0; // 偏移量到临界时需要重置,避免乱码
		}
	}
}

这里控制速度不能用Delay,用Delay的话点阵屏上的结果会消失,这应该是我们的点亮函数会置0导致的。

效果如下:

在这里插入图片描述

附上MatrixLED的内容:

MatrixLED.c:

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

// 重新命名,会更清晰一些,要不然容易不清楚每个口的具体含义
// P3^X:这不是异或的意思,这样的形式表示选中P3的第5位
sbit RClK = P3^5;  // 上升沿锁存,置1时将SER的内容全部写入输出口
sbit SRCLK = P3^6;  // 上升沿移位,置1时写入SER的内容
sbit SER = P3^4;

#define MATRIX_LED_PORT P0

/**
  * @brief 矩阵LED初始化
  * @param 无
  * @retval 无
  */
void Init_Matrix_LED()
{
	SRCLK = 0; // 初始置0,后面才更容易给电平
	RClK = 0; // 初始置0,后面才更容易给电平
}


/**
  * @brief 74HC595 写入一个字节
  * @param 要写入的字节
  * @retval 无
  */
void _74HC595_WriteByte(unsigned char byteData)
{
	unsigned char i = 0;
	for (i = 0; i < 8; i++)
	{
		SER = byteData & (0x80 >> i); // 通过这种方式取出第i位
		// byteData & 0x80相当于选出最高位的数据,结果要么是1000 0000,要么是0000 0000
		// 因为SER的类型是sbit,所以要么为1要么为0
		// 如果结果1000 0000,SER就会被置为1
		// 如果结果0000 0000,SER就会被置为0
		
		// SRCLK原本为0,置1给一个电平写入,然后置0
		SRCLK = 1; 
		SRCLK = 0;
	}
	// RClK原本为0,置1给一个电平统一转移数字,然后置0
	RClK = 1;
	RClK = 0;
}

/**
  * @brief LED点阵屏显示一列数据
  * @param 
  * @retval
  */
void MatrixLED_ShowColumn(unsigned char column, byteData)
{
	_74HC595_WriteByte(byteData); // 选中列
	MATRIX_LED_PORT = ~(0x80) >> column; // 选中指定行,给低电平点灯,column表示点亮第几行,做一个右移
	// 避免显示下一个的时候出现残影,Delay后置灭
	Delay(1);
	MATRIX_LED_PORT = 0xFF;
}

MatrixLED.h:

#ifndef __MATRIXLED_H__
#define __MATRIXLED_H__

void Init_Matrix_LED();
void _74HC595_WriteByte(unsigned char byteData);
void MatrixLED_ShowColumn(unsigned char column, byteData);

#endif

Delay.c:

#include <INTRINS.H>

void Delay(unsigned int ms)		//@11.0592MHz
{
	
	unsigned char i, j;
	while (ms)
	{

		_nop_();
		i = 2;
		j = 199;
		do
		{
			while (--j);
		} while (--i);
		
		ms--;
	}
}

Delay.h:

#ifndef __DELAY_H__
#define __DELAY_H__

void Delay(unsigned int ms);

#endif

网站公告

今日签到

点亮在社区的每一天
去签到