当前位置: 首页 > article >正文

江科大51单片机笔记【8】LED点阵屏显示图形及动画(下)

一.LED点阵屏显示图形

1.硬件知识

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个寄存器中,只有一个是可以位寻址的。对不可位寻址的寄存器,若要只操作其中一位而不影响其他位时,可用“&=”、“|=”、“^="的方式进行位操作

2.调试74HC595

普中的新板子需要 在 main 函数中加一句 P0_0 = 0; 然后确保 LEd 点阵屏左侧的 J24 跳线帽  OE 和 GND 连接在一起

#include <REGX52.H>

//为了使接口更易懂以及避免重复定义
sbit RCK=P3^5;  //RCLK
sbit SCK=P3^6;  //SRCLK
sbit SER=P3^4;  //SER


//不能以数字为开头
//目的:把参数写入到D0~D7的引脚,相当于赋值
//由原理图可知,第一位进来的是高位
void _74HC595_WriteByte(unsigned char Byte)
{
	unsigned char i;
	//循环一次即将8位数据都移进去
	for(i=0;i<8;i++)
	{
		SER=Byte&(0x80>>i);  //1000 0000 如果最高位为1则为1(非0即1).如果最高位为0则为0
		SCK=1; //给一个上升沿
		SCK=0;
	}
	RCK=1;  //把8位数据输出
	RCK=0;
}	
//	//把最高位移进去
//	SER=Byte&0x80;  //1000 0000 如果最高位为1则为1(非0即1).如果最高位为0则为0
//	SCK=1; //给一个上升沿
//	SCK=0;//给完马上置0
//	
//	//把次高位移进去
//	SER=Byte&0x40;  //0100 0000 如果最高位为1则为1(非0即1).如果最高位为0则为0
//	SCK=1; //给一个上升沿
//	SCK=0;//给完马上置0
//	
//	//....
	
	


void main()
{
	//一开始把这两个都置0
	SCK=0;
	RCK=0;
	_74HC595_WriteByte(0xF0);
    P0_0=0;
	while(1)
	{

	}
}

现象

 

3.开始写代码

这里我们可以参考数码管的代码,因为点阵屏和数码管操作方式差不多

验证一下显示函数

//节选,该部分为上文的代码改动而来

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

}



void main()
{
	//一开始把这两个都置0
	SCK=0;
	RCK=0;
	MatrixLED_ShowColumn(7,0xAA);
	while(1)
	{

	}
}

这里设计一个跟数码管一样的知识

残影问题:一般数码管运行都是 段选 位选  段选 位选  段选 位选。但会出现段选串位到上一个的位选的问题 ,就需要在位选后,延时,并位清零,即段选 位选 延时 位清零 段选 位选 延时 位清零 段选 位选 延时 位清零。

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

}

利用Excel表格编写笑脸的代码

按列扫描转换为二进制即为

0x3C 0x42 0xA9 0x85  0x85 0xA9 0x42 0x3C

下面为main完整代码

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

//为了使接口更易懂以及避免重复定义
sbit RCK=P3^5;  //RCLK
sbit SCK=P3^6;  //SRCLK
sbit SER=P3^4;  //SER


//不能以数字为开头
//目的:把参数写入到D0~D7的引脚,相当于赋值
//由原理图可知,第一位进来的是高位
void _74HC595_WriteByte(unsigned char Byte)
{
	unsigned char i;
	//循环一次即将8位数据都移进去
	for(i=0;i<8;i++)
	{
		SER=Byte&(0x80>>i);  //1000 0000 如果最高位为1则为1(非0即1).如果最高位为0则为0
		SCK=1; //给一个上升沿
		SCK=0;
	}
	RCK=1;  //把8位数据输出
	RCK=0;
}	

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

}



void main()
{
	//一开始把这两个都置0
	SCK=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);		
	}
}

现象

 4.优化代码

把P0口给定义

给函数注释

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

//为了使接口更易懂以及避免重复定义
sbit RCK=P3^5;  //RCLK
sbit SCK=P3^6;  //SRCLK
sbit SER=P3^4;  //SER

#define MATRIX_LED_PORT   P0

/**
  * @brief  74HC595写入一个字节
  * @param  要写入的字节
  
  * @retval 无

   */

void _74HC595_WriteByte(unsigned char Byte)
{
	unsigned char i;
	//循环一次即将8位数据都移进去
	for(i=0;i<8;i++)
	{
		SER=Byte&(0x80>>i);  //1000 0000 如果最高位为1则为1(非0即1).如果最高位为0则为0
		SCK=1; //给一个上升沿
		SCK=0;
	}
	RCK=1;  //把8位数据输出
	RCK=0;
}	


/**
  * @brief  LED点阵屏显示一列数据
  * @param  Column 要选择的列,范围:0~7,0在最左边
  * @param  Data 选择的列显示的数据,高位在上,1为亮,0为灭  
  * @retval 无

   */

void MatrixLED_ShowColumn(unsigned char Column,Data)
{
	_74HC595_WriteByte(Data);
	MATRIX_LED_PORT=~(0x80>>Column);
	Delay(1);
	MATRIX_LED_PORT=0xFF;

}



void main()
{
	//一开始把这两个都置0
	SCK=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);		
	}
}

二、LED点阵屏显示动画

1.把上面的函数模块化

//MatrixLED.h

#ifndef __MATRIXLED_H_
#define __MATRIXLED_H_


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

#endif
//MatrixLED.c


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

//为了使接口更易懂以及避免重复定义
sbit RCK=P3^5;  //RCLK
sbit SCK=P3^6;  //SRCLK
sbit SER=P3^4;  //SER

#define MATRIX_LED_PORT   P0

/**
  * @brief  74HC595写入一个字节
  * @param  要写入的字节
  
  * @retval 无

   */

void _74HC595_WriteByte(unsigned char Byte)
{
	unsigned char i;
	//循环一次即将8位数据都移进去
	for(i=0;i<8;i++)
	{
		SER=Byte&(0x80>>i);  //1000 0000 如果最高位为1则为1(非0即1).如果最高位为0则为0
		SCK=1; //给一个上升沿
		SCK=0;
	}
	RCK=1;  //把8位数据输出
	RCK=0;
}	



/**
  * @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);
	MATRIX_LED_PORT=~(0x80>>Column);
	Delay(1);
	MATRIX_LED_PORT=0xFF;

}
//main.c

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


void main()
{
  void MatrixLED_Init();

	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.开始写代码

思路:做一个长条的数组存储,从左往右移动就是数组

这里用到一个工具,取字模软件,在下面这里有

https://jiangxiekeji.com/download.html

0xFF,0x08,0x08,0x08,0xFF,0x00,0x0E,0x15,0x15,0x15,0x08,0x00,0x7E,0x01,0x02,0x00,
0x7E,0x01,0x02,0x00,0x06,0x09,0x09,0x06,0x00,0x7D,0x00,0x00,0x00,0x00,0x00,0x00,

把前8项全部显示在点阵屏上

		for(i=0;i<8;i++)
		{
			MatrixLED_ShowColumn(i,Animation[i]);
		}

当选择数据时,带上后面7个数据,这样在递增的过程(从第一个往右选择数据),就会一直带上后面7个数据,这样就会形成整体8个数据一起移动的效果。

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

unsigned char Animation[]={
	// 前后加上八个00,这样确保最后一个字符在移动完后再开始下一次显示
	0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
	0xFF,0x08,0x08,0x08,0xFF,0x00,0x0E,0x15,
	0x15,0x15,0x08,0x00,0x7E,0x01,0x02,0x00,
    0x7E,0x01,0x02,0x00,0x06,0x09,0x09,0x06,
	0x00,0x7D,0x00,0x00,0x00,0x00,0x00,0x00,
	0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,	
};

void main()
{
	unsigned char i,Offset,Count=0;
  MatrixLED_Init();
	while(1)
	{
		for(i=0;i<8;i++)
		{
			MatrixLED_ShowColumn(i,Animation[i+Offset]);
		}
		Count++;  //这里不能直接用延时函数延时,因为在一直扫描
		if(Count>10)  //这里相当于每隔1帧扫描10次
		{
			Count=0;
			Offset++;
			if(Offset>40)  //防止Offset溢出,数组48个-选择8个=40个,让“!”移除点阵屏再开始下一次循环
			{
				Offset=0;
			}
		}
	}
}

到这里已经完成了流动字幕的动画

如果想实现逐帧的动画,下面还有

3.变式

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



unsigned char code Animation[]={
	// 加上八个00循环一次后再回来
	0x3C,0x42,0xA9,0x85,0x85,0xA9,0x42,0x3C,
	0x3C,0x42,0xA1,0x85,0x85,0xA1,0x42,0x3C,
	0x3C,0x42,0xA5,0x89,0x89,0xA5,0x42,0x3C,

};

void main()
{
	unsigned char i,Offset=0,Count=0;
  MatrixLED_Init();
	while(1)
	{
		for(i=0;i<8;i++)
		{
			MatrixLED_ShowColumn(i,Animation[i+Offset]);
		}
		Count++;  //这里不能直接用延时函数延时,因为在一直扫描
		if(Count>15)  //这里相当于每隔1帧扫描10次
		{
			Count=0;
			Offset+=8; //这里直接加8,每一次显示完一帧后直接跳到下一帧
			if(Offset>16)  //防止Offset溢出,数组48个-选择8个=40个
			{
				Offset=0;
			}
		}
	}
}

这里写的是这三帧在一直跳动形成动画

如果想要加更多的帧就要在Animation[]数组里加

这里设计一个小知识

我们单片机有两个暂存器

一种是程序运行时的暂存器叫RAM

另一种是放在Flash里面的程序存储器,这里的空间会很大,但是不可以再改变数组的内容,不过我们动画一般都不会更改,所以我们一直会放在Flash里面

即在上图中数组前加上“code”关键字


http://www.kler.cn/a/573918.html

相关文章:

  • Hive-优化(参数优化篇)
  • 扩散语言模型:从图像生成到文本创造的范式跃迁
  • 随手记录第十六话 -- Go 语言入门:基础知识与常用框架
  • 计算机网络开发(2)TCP\UDP区别、TCP通信框架、服务端客户端通信实例
  • 每天一个Flutter开发小项目 (13) : 本地数据随心存取 - 构建SQLite ToDo 应用,掌握Flutter本地数据库操作
  • 算法·搜索
  • 《张一鸣,创业心路与算法思维》
  • 汽车AI识别及处理解决方案,引领未来驾驶新风尚
  • MybatisPlus从入门到精通
  • Linux基础 IO 和文件
  • Git安装与配置
  • 游戏树搜索与优化策略:Alpha-Beta剪枝及其实例分析
  • AI自动化应用的影响
  • IDC权威认证!永洪科技入选 IDC「GBI图谱」,点亮生成式 BI 价值灯塔
  • Redis的CPU高达90%时如何处理
  • STM32G030F6P6详细解读
  • upload-labs靶场 1-21通关
  • Go 语言中 panic 和 recover 的代价:性能与设计的权衡
  • css的毛玻璃效果backdrop-filter: blur()
  • 力扣hot100刷题——栈