51单片机学习(四)用点阵LED显示I LOVE YOU!

转自我的单片机博客:


先看看效果:

这段时间一直在折腾单片机的显示设备,今天折腾到了点阵LED。板子上配的是8X8的点阵LED,不过学会了8X8的之后更大的点阵LED也可以套用这个模式进行编程啦。

点阵LED的电路图如下:

 

     Y1到Y8就不多说了,D24和D25控制一个8 位串入、并出移位寄存器,也就是74HC164,这个东西的作用一开始我不明白,后来自己做了几个小实验之后就明白是怎么回事了。资料中如是说:数据通过两个输入端(DSA 或 DSB)之一串行输入;任一输入端可以用作高电平使能端,控制另一输入端的数据输入。两个输入端或者连接在一起,或者把不用的输入端接高电平,一定不要悬空。时钟 (CP) 每次由低变高时,数据右移一位,输入到 Q0, Q0 是两个数据输入端(DSA 和 DSB)的逻辑与,它将上升时钟沿之前保持一个建立时间的长度。

 

按照图中的接法,DSA和DSB的逻辑与,也就是D25本身。而它的输出Q0~Q7就是一个队列,输出这样一个8位二进制数  [Q7Q6Q5Q4Q3Q2Q1Q0],Q0这端是新值进入的地方,每进入一个新元素,队列整体左移,原来的Q6的值移到Q7的位置,依此类推,新插入的值就是新的Q0。那输入的是什么值呢,就是DSA和DSB的逻辑与,在这里也就是D25。      那知道了插入的顺序和结果,那怎样控制呢?就是让CP从0变到1,也就是D24从0变到1。

模拟一下:Q0到Q7初始值都是0,那么原来的输出就是0000,0000

       D25         D24 输出
1 0->1 0000,0001
0 0->1 0000,0010
1 0->1 0000,0101
1 0->1 0000,1011

这输出的8位,每一位对应图3中的某一列,假如Y1到Y8输入的都是低电平,而74HC164输出的是0000,1011,那么这时点阵LED中会有3列是全亮的,这么干是不行的,不想办法的话又会遇到8个数码管一起亮的那种情况。用动态扫描!这里扫描的方法是:

(一)P0输入0xff

(二)   74HC164 输出清零

(三) 将1移到指定的列

(四)输入这列对应的P0并延迟一小段时间,让LED亮度高点,继续第一步

要计算出8X8的所有P0还真不是件容易的事,有种软件叫字模软件,能让你花的图形输出成16进制数。有了这个就大大减少了计算这些数值的时间。

额,突然发现也没什么好讲的了,完整源代码如下:

#include 
#include 
typedef unsigned char uint8;
typedef unsigned int  uint16;

 sbit   D24 = P2^4;
 sbit   D25 = P2^5;
 sbit   U1 = P2^6;
 sbit   U2 = P2^7;

uint8 counter = 0;
uint8 offset = 0;

 code  uint8  table[]={ 0xFF,0xC3,0xBD,0xBD,0xAD,0x9D,0x83,0x7F,		//Q
 						0xFF,0xFF,
 						0xFF,0x81,0x81,0xE7,0xE7,0xE7,0xE7,0xFF,		//T
 						0xFF,0xFF,
 						0xC1,0xC1,0xF9,0xF9,0xC1,0xC1,0xF9,0xF9,		//F
						0xFF,0xFF,
 						0x81,0xC3,0xE7,0xE7,0xE7,0xE7,0xC3,0x81,
						0xFF,0xFF,				//插入2行空行
						0x99,0x0,0x0,0x0,0x81,0xC3,0xE7,0xFF,
						0xFF,0xFF,
						0xFF,0x99,0xDB,0xDB,0xDB,0xDB,0xE7,0xFF,
						0xFF,0xFF,										};	   //分别是 I和爱心,还有U三个图形

  void init_timer0()
 {
   TH0 = 0xB1;
   TL0 = 0xE0;
   TR0 = 1;

   TMOD |= 0x01;			   //计时模式选01模式

 }

void init_interrupt()
{
	EA = 1;        //中断总开关
	ET0 = 1;		//定时器1中断
}

 delay(uint8 t)
{
while (t--)
{;}
}

void init_74hc164()
{
	uint8 i =0;
	D25 = 0;
	for(;i<8;i++)
	{
	   D24 = 0;
	   D24 = 1;
	}
}

void refresh_led(uint8 offset)
{
		int i = 0;
		int j = 0;
		init_74hc164();	   			//把74HC164里的高电平全清掉。

		for(;i<8;i++)
		{
			P0 = 0xff;						//消隐
			U1 = 1;
			U1 = 0;
			init_74hc164();

			D25 = 1;
			for(j = 0; j<=i; j++)		//把高电平定位到想要的位置
			{
				D24 = 0;
				D24 = 1;
				D25 = 0;
			}
			P0 = table[offset++];
			U1 = 1;
			U1 = 0;
			delay(50);
			if(offset  == 60)
			{
				offset = 0;
			}
		}

}

 void main(void)
 {
	P0 = 0xff;
    U2 = 1;
	U2 = 0;
	P0 = 0xff;
   	D25 = 1;

	P0 =0xff;
	U1 = 1;
	U1 = 0;
	P0 = 0xff;
	init_timer0();
    init_interrupt();
	init_74hc164();
    while(1)
	{

		refresh_led(offset);
	}

 }

  void timer0_interrupt() interrupt 1
 {
	 			  //每次计时是20ms,达到20ms后计时器0的溢出位位1,进行软件清零和计时器初始化. 

	     counter++;
		 TF0=0;
		 TH0 = 0xB1;         //12MHZ的晶振算出来是从45536开始计时,十六进制就是 0xB1E0
		 TL0 = 0xE0;		 //高位取0xB1,低位取0xE0

        P0 = 0xff;
		U1 = 1;
		U1 = 0;
		if(counter == 10)
		{
			counter = 0;
			offset++;
			if(offset == 60)
			{
				offset = 0;
			}
		}

 }


你可能感兴趣的:(单片机)