拓之

拓之

点阵屏与74Hc595模块

2024-11-26

1. 点阵屏

  • LED点阵屏由若干个独立的LED组成,LED以矩阵的形式排列,以灯珠亮灭来显示文字、图片、视频等。
  • LED点阵屏广泛应用于各种公共场合,如汽车报站器、广告屏以及公告牌等。
  • LED点阵屏分类
    • 按颜色:单色、双色、全彩
    • 按像素:8x8、16x16等(大规模的LED点阵通常由很多个小点阵拼接而成)

点阵屏由于接口很多,一般是采用扫描的方式来显示,逐行或者逐列快速显示,和数码管很像,也是位选然后段选

需要注意:段选 位选之后 先延时对位进行清零 然后在进行段选, 否则位选过去之后,段选还没过来,就会有残影出来

2. 74HC595芯片

因为点阵屏需要的引脚数量比较多,所以一般会采用串转并芯片来控制引脚扫描

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

也就是可以用三根线,并行输出8位,后面还可以进行级联。

下面是一个简单示意图(取自江协)

1732596095248.png

简单来说传输一个字节的数据就是

  1. 先给SER最高位数据
  2. 给SERCLK置1,也就是把SER数据推进寄存器,然后在清空SERCLK
  3. 继续1-2操作把剩下的数据都推进去
  4. 最后所有数据都进去了,给RCLK置1,把这8位数据一次性推给输出

代码方面就是这样的操作

/// @brief 向74HC595写入一个字节的数据
/// @param byte 要写入的数据
void _74Hc595_writeByte(unsigned char byte)
{
    unsigned char i;
    RCK = 0;
    SCK = 0;
    for (i = 0; i < 8; i++)
    {
        SER = byte & (0X80 >> i);
        SCK = 1;
        SCK = 0;
    }
    RCK = 1;
    RCK = 0;
}

3. 控制74HC595扫描显示点阵屏

刚才说到要显示,需要扫描进行,这里逐列扫描显示,因为74HC595是控制行显示

首先单独显示一列

/// @brief 显示某一列的数据
/// @param col 要显示的列,取值范围为1-8
/// @param dataValue 要显示的数据,低位有效,8位,每一位代表一个LED的亮灭
/// 注意:本函数只能显示一列的数据,且只显示一瞬间,需要循环调用,扫描使用
void matrixLED_showCol(unsigned char col, unsigned char dataValue)
{
    if (col<1 || col>8)
    {
        return;
    }
    _74Hc595_writeByte(dataValue);
    MATRIX_LED_PROT = ~(0x80 >> (col-1));
    Delay(1);
    MATRIX_LED_PROT = 0xff; // 位选清空
}

然后再进行扫描,可以用主循环扫描,也可以用时钟扫描

/// @brief 显示整个8*8点阵的数据
/// @param data 要显示的数据,8个字节,每个字节代表一列的数据
void matrixLED_show(unsigned char Font_data[])
{
    unsigned char i;
    for (i = 0; i < 8; i++)
    {
        matrixLED_showCol(i + 1, Font_data[i]);
        Delay(1);
    }
}

主循环扫描

unsigned char code Font_Data[] ={0x00, 0x7f, 0x08, 0x08, 0x08, 0x7f, 0x00, 0x00, /* H */};
int main()
{
	while (1)
	{
		matrixLED_show(Font_Data); 
	}
}

逐帧显示或者滚动显示

实现逐帧显示或者滚动显示,只需要定义一个装有所有数据的数组,然后采取不同的跳跃策略就可以做到,但是这个跳跃就需要在时钟中断中做了

unsigned char code Font_Data[] =
	{
		0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /*   */
		0x00, 0x7f, 0x08, 0x08, 0x08, 0x7f, 0x00, 0x00, /* H */
		0x00, 0x7f, 0x49, 0x49, 0x49, 0x41, 0x02, 0x00, /* E */
		0x00, 0x7f, 0x01, 0x01, 0x01, 0x01, 0x02, 0x00, /* L */
		0x00, 0x7f, 0x01, 0x01, 0x01, 0x01, 0x02, 0x00, /* L */
		0x00, 0x3e, 0x41, 0x41, 0x41, 0x22, 0x1c, 0x00, /* O */
		0x00, 0x00, 0x00, 0x7d, 0x00, 0x00, 0x00, 0x00, /* ! */
		0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /*   */
};

unsigned char i, offset;
int main()
{
	Time0_Init();
	// matrixLED_showCol(1, 0x55);

	while (1)
	{
		// 每次显示8列数据
		matrixLED_show(Font_Data + offset); // 流动显示
		// matrixLED_show(Font_Data + i * 8); // 逐帧显示
	}
}

void Time0_Rountine() interrupt 1 // 定时器0中断函数
{
	static unsigned int T0count = 0;
	// 由于是溢出计时,且没有自动重装,每次进入中断要重新赋值
	TL0 = 0x66; // 设置定时初始值 低8位 当前为100us中断一次
	TH0 = 0xFC; // 设置定时初始值 高8位
	T0count++;

	if (T0count >= 300) //
	{
		T0count = 0;
		// i = (i + 1) % (sizeof(Font_Data)/8);
		offset = (offset + 1) % (sizeof(Font_Data)-8);
	}
}