51单片机从点亮单个LED点阵到动态扫描的几种算法改进和思考(个人学习过程中的相关思考和总结)

1 篇文章 0 订阅
1 篇文章 0 订阅

首先,此次算法的改进和思考是基于以下单个LED点阵的代码(此时已经默认你已经了解74HC595芯片的功能和用法,以及8*8LED点阵的原理)

#include "reg51.h"
#include "intrins.h"
typedef unsigned int u16;
typedef unsigned char u8;

#define GPIO_ROW P0

sbit SER=P3^4;      //串行数据输入
sbit RCLK=P3^5;		//存储寄存器时钟输入
sbit SRCLK=P3^6;	//移位寄存器时钟输入
sbit KEY=P3^1;

void HC595Send(u8 dat)
{
	u8 i;
	SRCLK=0;
	RCLK=0;
	for(i=0;i<8;i++)
	{
		SER=dat>>7;
		dat<<=1;
		SRCLK=1;
		_nop_();
		_nop_();
		SRCLK=0;
	}
	RCLK=1;
	_nop_();
	_nop_();
	RCLK=0;
}

void main()
{
	while(KEY==0)
	{
		HC595Send(0x01);
		GPIO_ROW=0x7f;
	}	   
}

紧接着,使用点亮单个LED点阵的原理利用动态扫描点亮事先设计好的图形或文字。在此使用图片简要说明点阵的行、列的高位和低位(个人设计实验过程中根据个人板子的LED点阵的高低位适当修改代码)
在这里插入图片描述
其次,我们以两种算法的思考为主,设计程序并让其显示一个爱心的图案。两种算法的核心思路如下:

利用定义的GPIO_ROW控制LED点阵的列(即控制8列中每一列的开启和关闭情况,也就是电位的高低),在利用HC595芯片原理编写的位运算函数HC595Send()去实现对行的控制(即决定8行的开关情况,也就是电位高低情况)。根据原理图,只要使某行处于高位1,某列处于低位0,即可点亮该行该列所对应的单个LED灯。
这里学过线性代数矩阵的同学就知道,通过对8行8列的控制可以点亮任意的LED灯。我们将使用列逐次扫描,在点亮扫描列下对应的行的LED灯,所以循环周期为8列。

以上是基本的共性原理,下面就提出对两种不同算法的思考:

  • 将控制各行、各列的8位二进制数(实际传递过程中使用十六进制)依次传递给GPIO_ROW和HC595Send()函数,并使其嵌套在一个循环周期位8的循环语句中。此处循环要考虑延时和消影的影响:若要使用for循环则务必要进行延时和消影,否则写入程序后可能会看到重影现象;若要规避考虑这两种情况,我们可以选用switch语句分别去case执行8种情况。最后再将循环嵌套在大循环while(1)中,否则只能看到一闪的现象,而不是长时间点亮。
  • 分别将需要显示的图案构成的二进制数以十六进制的形式分别保存在行数组和列数组中,再通过简单的for循环依次执行GPIO_ROW和HC595Send()函数(此处要注意的是数组元素务必从高位到低位依次排布,并且总数为8个元素,就算有相同也要再次键入,这也是为了后面main函数中控制行列时候两条语句的一一对应)。

现就将两种算法代码展示如下:
第一种:

#include "reg51.h"
#include "intrins.h"
typedef unsigned int u16;
typedef unsigned char u8;

#define GPIO_ROW P0

sbit SER=P3^4;      //串行数据输入
sbit RCLK=P3^5;		//存储寄存器时钟输入
sbit SRCLK=P3^6;	//移位寄存器时钟输入
sbit KEY=P3^1;


void delay(u16 i)
{
	while(i--);	
}

void HC595Send(u8 dat)
{
	u8 i;
	SRCLK=0;
	RCLK=0;
	for(i=0;i<8;i++)
	{
		SER=dat>>7;
		dat<<=1;
		SRCLK=1;
		_nop_();
		_nop_();
		SRCLK=0;
	}
	RCLK=1;
	_nop_();
	_nop_();
	RCLK=0;
}

void main()
{
	u8 j;
	while(1)
	{	
		while(KEY==0)
		{
			for(j=0;j<8;j++)
			{
				switch(j)
				{
					case 0:
						GPIO_ROW=0x7f;
						HC595Send(0x38);
						delay(100);
						HC595Send(0x00);
						break;
					case 1:
						GPIO_ROW=0xbf;
						HC595Send(0x44);
						delay(100);
						HC595Send(0x00);
						break;
					case 2:
						GPIO_ROW=0xdf;
						HC595Send(0x42);
						delay(100);
						HC595Send(0x00);
						break;
					case 3:
						GPIO_ROW=0xef;
						HC595Send(0x21);
						delay(100);
						HC595Send(0x00);
						break;
					case 4:
						GPIO_ROW=0xf7;
						HC595Send(0x21);
						delay(100);
						HC595Send(0x00);
						break;
					case 5:
						GPIO_ROW=0xfb;
						HC595Send(0x42);
						delay(100);
						HC595Send(0x00);
						break;
					case 6:
						GPIO_ROW=0xfd;
						HC595Send(0x44);
						delay(100);
						HC595Send(0x00);
						break;
					case 7:
						GPIO_ROW=0xfe;
						HC595Send(0x38);
						delay(100);
						HC595Send(0x00);
						break;
				}			
			}		
		}
	}	   
}

第二种:

#include "reg51.h"
#include "intrins.h"
typedef unsigned int u16;
typedef unsigned char u8;

#define GPIO_ROW P0

sbit SER=P3^4;      //串行数据输入
sbit RCLK=P3^5;		//存储寄存器时钟输入
sbit SRCLK=P3^6;	//移位寄存器时钟输入
sbit KEY=P3^1;

u8 ledrow[]={0x7f,0xbf,0xdf,0xef,0xf7,0xfb,0xfd,0xfe};
u8 ledline[]={0x38,0x44,0x42,0x21,0x21,0x42,0x44,0x38};

void delay(u16 i)
{
	while(i--);	
}

void HC595Send(u8 dat)
{
	u8 i;
	SRCLK=0;
	RCLK=0;
	for(i=0;i<8;i++)
	{
		SER=dat>>7;
		dat<<=1;
		SRCLK=1;
		_nop_();
		_nop_();
		SRCLK=0;
	}
	RCLK=1;
	_nop_();
	_nop_();
	RCLK=0;
}

void main()
{
	u8 j;
	while(1)
	{	
		while(KEY==0)
		{
			for(j=0;j<8;j++)
			{
				GPIO_ROW=ledrow[j];
				HC595Send(ledline[j]);
				delay(100);
				HC595Send(0x00);
			}
		}	
	}	   
}

忙里抽时间简单写了这篇文章,
更多相关内容后续补更!!!

  • 8
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值