开发环境的搭建
Keil的下载
Keil软件的官网下载地址如下:
https://www.keil.com/download/product/
由不同版本的文字提示可知,应下载C51(development tools for all 8051 devices)。并且,要获得Keil C51的全部功能,需要current license,否则只能运行其Lite/Evaluation edition。
STC-ISP烧录软件的下载
使用STC-ISP软件进行烧录。STC-ISP6.87S版本(来自STC公司)的官网下载地址如下:
http://www.stcmcudata.com/STCISP/stc-isp-15xx-v6.87S.zip
(若使用Google Chrome打开,会有安全警告)
硬件介绍
LED阵列
LED阵列是由发光二极管与限流电阻有规律地排布而成,示意图如下。
发光二极管的亮灭通过ROW与COL的电平关系决定,仅当ROW为HIGH且COL为LOW时,二极管导通。
此外,LED阵列还包括两颗串-并变换、SOIC-16封装的74HC595D,、2颗0603封装的电源去耦电容、2个5管脚直插的连接器,示意图如下。
其中第一个74HC595D的输出通过npn型三极管S9013的基级与集电极与COL耦合(如下图),第二个74HC595D的输出直接耦合ROW。
可知,第一个74HC595D的输出C通过三极管后反相后得到COL,即当C为1,ROW为1时,有COL为LOW,ROW为HIGH,此时发光二极管导通。
8051最小系统
8051最小系统(下文简称为最小系统)的主要硬件包括:基于STC的STC15W204内核为8051的8位单片机,MicroUSB供电并基于沁恒的CH340E(USB转UART), LED灯(电源状态指示)。
最小系统的电路原理图如下:
最小系统的3D效果图的俯视图如下:
连接
由于软件部分是基于王安然老师提供的全亮测试工程,故保留了王安然老师对寄存器与引脚的分配。
代码部分:
sbit SRCLK=P5^4;
sbit RCLK=P3^3;
sbit SER=P5^5;
参照阵列与最小系统的原理图,将二者引脚通过杜邦线连接。
可知,阵列的P1的1号引脚(3V3)应与最小系统的VCC相连,阵列P1的2号引脚(GND)应与最小系统的GND相连,阵列P1的3号引脚(SER1)应与最小系统的P55相连,阵列P1的4号引脚(SCK)应与最小系统的P54相连,阵列P1的5号引脚(RCK)应与最小系统的P33相连。
软件部分
亮灯控制
为避免对角线所在矩形上的其他LED被点亮,采取逐行刷新的方式来进行控制。首先以实验的方式来确定两位16进制的数分别是如何对应行与列的。
代码部分:
void main()
{			
	while(1)
	{
        Hc595OneRow(0x12,0x41); // row:0x12   col:0x41
        }
}
所调用函数的代码:
void Hc595OneRow(u8 R, u8 C)
{
	u16 cnt;
	SRCLK=0;
	RCLK=0;
	for(cnt=0;cnt<16;cnt++)
		{
			if (cnt<=7)
			{
			SER=R>>7;
		  R<<=1;
			}
			else
			{
			SER=C>>7;
		  C<<=1;
			}
			SRCLK=1;
			_nop_();
			_nop_();
			SRCLK=0;
		}
			_nop_();
			RCLK=1;
			_nop_();
			_nop_();
			RCLK=0;			
}其中,u8是变量类型,定义代码:
typedef unsigned char u8;LED点亮效果如图:
则可知,两位十六进制与LED点阵的对应关系如下图:
部分函数与代码
void Hc595OneRow(unsigned char R, unsigned char C)
代码:
void Hc595OneRow(u8 R, u8 C)
{
	u16 cnt;
	SRCLK=0;
	RCLK=0;
	for(cnt=0;cnt<16;cnt++)
		{
			if (cnt<=7)
			{
			SER=R>>7;
		  R<<=1;
			}
			else
			{
			SER=C>>7;
		  C<<=1;
			}
			SRCLK=1;
			_nop_();
			_nop_();
			SRCLK=0;
		}
			_nop_();
			RCLK=1;
			_nop_();
			_nop_();
			RCLK=0;			
}
代码解释:为避免亮灯对角线所在矩形区域灯的误亮,决定采取逐行点亮的方式。第一个74HC595D的串口输入每读取十六个二进制数据(即四个16进制数据),分别分配到第一个与第二个74HC595D的并行输出,确定某一行灯的亮灭,并视其余诸行为灭。由于各行灯的亮灭间隔很短以及大脑的视觉暂离效应,不同行该亮的灯看起来同时一直再亮。
void Hc595RowScanUp(unsigned char dat[8],unsigned int m)
代码:
void Hc595RowScanUp(u8 dat[8],u16 m)
{
	u16 i;
	u8 row=0x80;
		for(i=0;i<8;i++)
		{   	 
			
			Hc595OneRow(row,dat[(i-m)%8]);            //if -m, the pic rises; if +m, the pic falls
			
			RCLK=1;
			_nop_();
			_nop_();
			RCLK=0;
			
			row>>=1;                                  //row is initialized as 0x80 && row>>=1, means the pic is scanned row by row from bottom to top 
		}
}代码解释:将图案进行单行扫描。可在main函数值里与循环结合实现逐行扫描。
代码:
while(1)
	{ 
		for (cnt=0;cnt<4000;cnt++)
		{
			Hc595RowScanUp(rising_one_col,m);
			s++;
			if(s==250)
			{
				 if(m==7) m=0;
				 else m++;
				 s=0;
			}
		}
代码解释:将图案进行逐行扫描,并实现上升的效果。对于每个图案:每经过250次单行扫描,开始扫描下一行。形成一个完整周期需要250乘8=2000个单行扫描周期。当每个图案被完整扫描4000次后,开始扫描下个图案。
完整的main.c
代码:
#include "stc15w204.h"		
#include<intrins.h>
//#include "shifting_up.h"
typedef unsigned int u16;	 
typedef unsigned char u8;
sbit SRCLK=P5^4;
sbit RCLK=P3^3;
sbit SER=P5^5;
/*-------------------------Elevator Simulation-----------------------*/
//--------------------------------ONE----------------------------------
u8 rising_one_col[]={0x00,0xE0,0x40,0x60,0x40,0x1F,0x0E,0x04};
u8 falling_one_col[]={0x00,0xE0,0x40,0x60,0x40,0x04,0x0E,0x1F};
//--------------------------------TWO----------------------------------
u8 rising_two_col[]={0xF0,0x20,0x40,0x90,0x60,0x1F,0x0E,0x04};
u8 falling_two_col[]={0xF0,0x20,0x40,0x90,0x60,0x04,0x0E,0x1F};
//-------------------------------THREE---------------------------------
u8 rising_three_col[]={0x60,0x90,0x40,0x90,0x60,0x1f,0x0e,0x04};
u8 falling_three_col[]={0x60,0x90,0x40,0x90,0x60,0x04,0x0E,0x1F};
//--------------------------------FOUR---------------------------------
u8 rising_four_col[]={0x40,0x40,0xf8,0x50,0x60,0x5f,0x0e,0x04};
u8 falling_four_col[]={0x40,0x40,0xf8,0x50,0x60,0x44,0x0E,0x1F};
//--------------------------------FIVE---------------------------------
u8 rising_five_col[]={0xe0,0x80,0xe0,0x20,0xe0,0x1f,0x0e,0x04};
u8 falling_five_col[]={0xe0,0x80,0xe0,0x20,0xe0,0x04,0x0E,0x1F};
////--------------------------------SIX----------------------------------
//u8 rising_six_col[]={0xe0,0xa0,0xe0,0x20,0xe0,0x1f,0x0e,0x04};
//u8 falling_six_col[]={0xe0,0xa0,0xe0,0x20,0xe0,0x04,0x0E,0x1F};
////--------------------------------SEVEN--------------------------------
//u8 rising_seven_col[]={0x00,0x80,0x80,0x80,0xe0,0x1f,0x0e,0x04};
//u8 falling_seven_col[]={0x00,0x80,0x80,0x80,0xe0,0x04,0x0E,0x1F};
////--------------------------------EIGHT--------------------------------
//u8 rising_eight_col[]={0xe0,0xa0,0xe0,0xa0,0xe0,0x1f,0x0e,0x04};
//u8 falling_eight_col[]={0xe0,0xa0,0xe0,0xa0,0xe0,0x04,0x0E,0x1F};
////--------------------------------NINE---------------------------------
//u8 rising_nine_col[]={0xe0,0x80,0xe0,0xa0,0xe0,0x1f,0x0e,0x04};
//u8 falling_nine_col[]={0xe0,0x80,0xe0,0xa0,0xe0,0x04,0x0E,0x1F};
/*-----------generate one row at one time------------*/
void Hc595OneRow(u8 R, u8 C)
{
	u16 cnt;
	SRCLK=0;
	RCLK=0;
	for(cnt=0;cnt<16;cnt++)
		{
			if (cnt<=7)
			{
			SER=R>>7;
		  R<<=1;
			}
			else
			{
			SER=C>>7;
		  C<<=1;
			}
			SRCLK=1;
			_nop_();
			_nop_();
			SRCLK=0;
		}
			_nop_();
			RCLK=1;
			_nop_();
			_nop_();
			RCLK=0;			
}
void Hc595RowScanUp(u8 dat[8],u16 m)
{
	u16 i;
	u8 row=0x80;
		for(i=0;i<8;i++)
		{   	 
			
			Hc595OneRow(row,dat[(i-m)%8]);            //if -m, the pic rises; if +m, the pic falls
			
			RCLK=1;
			_nop_();
			_nop_();
			RCLK=0;
			
			row>>=1;                                  //row is initialized as 0x80 && row>>=1, means the pic is scanned row by row from bottom to top 
		}
}
	void Hc595RowScanDown(u8 dat[8],u16 m)
{
	u16 i;
	u8 row=0x80;
		for(i=0;i<8;i++)
		{   	 
			
			Hc595OneRow(row,dat[(i+m)%8]);            //if -m, the pic rises; if +m, the pic falls
			
			RCLK=1;
			_nop_();
			_nop_();
			RCLK=0;
			
			row>>=1;                                   //row is initialized as 0x80 && row>>=1, means the pic is scanned row by row from bottom to top 
		}
}
	void main()
{			
	u16 m=0,s=0; 
	u16 cnt;
	while(1)
	{ 
		for (cnt=0;cnt<4000;cnt++)
		{
			Hc595RowScanUp(rising_one_col,m);
			s++;
			if(s==250)
			{
				 if(m==7) m=0;
				 else m++;
				 s=0;
			}
		}
		//rising one
		for (cnt=0;cnt<4000;cnt++)
		{
			Hc595RowScanUp(rising_two_col,m);
			s++;
			if(s==250)
			{
				 if(m==7) m=0;
				 else m++;
				 s=0;
			}
		}
		//rising two
		for (cnt=0;cnt<4000;cnt++)
		{
			Hc595RowScanUp(rising_three_col,m);
			s++;
			if(s==250)
			{
				 if(m==7) m=0;
				 else m++;
				 s=0;
			}
		}
		//rising three
		for (cnt=0;cnt<4000;cnt++)
		{
			Hc595RowScanUp(rising_four_col,m);
			s++;
			if(s==250)
			{
				 if(m==7) m=0;
				 else m++;
				 s=0;
			}
		}
		//rising four
		for (cnt=0;cnt<4000;cnt++)
		{
			Hc595RowScanUp(rising_five_col,m);
			s++;
			if(s==250)
			{
				 if(m==7) m=0;
				 else m++;
				 s=0;
			}
		}
		//rising five
//		for (cnt=0;cnt<4000;cnt++)
//		{
//			Hc595RowScanUp(rising_six_col,m);
//			s++;
//			if(s==250)
//			{
//				 if(m==7) m=0;
//				 else m++;
//				 s=0;
//			}
//		}
//		//rising six
//		for (cnt=0;cnt<4000;cnt++)
//		{
//			Hc595RowScanUp(rising_seven_col,m);
//			s++;
//			if(s==250)
//			{
//				 if(m==7) m=0;
//				 else m++;
//				 s=0;
//			}
//		}
//		//rising seven
//		for (cnt=0;cnt<4000;cnt++)
//		{
//			Hc595RowScanUp(rising_eight_col,m);
//			s++;
//			if(s==250)
//			{
//				 if(m==7) m=0;
//				 else m++;
//				 s=0;
//			}
//		}
//		//rising eight
//		for (cnt=0;cnt<4000;cnt++)
//		{
//			Hc595RowScanUp(rising_nine_col,m);
//			s++;
//			if(s==250)
//			{
//				 if(m==7) m=0;
//				 else m++;
//				 s=0;
//			}
//		}
//		//rising nine
//		for (cnt=0;cnt<4000;cnt++)
//		{
//			Hc595RowScanDown(falling_nine_col,m);
//			s++;
//			if(s==250)
//			{
//				 if(m==7) m=0;
//				 else m++;
//				 s=0;
//			}
//		}
//		//falling nine
//		for (cnt=0;cnt<4000;cnt++)
//		{
//			Hc595RowScanDown(falling_eight_col,m);
//			s++;
//			if(s==250)
//			{
//				 if(m==7) m=0;
//				 else m++;
//				 s=0;
//			}
//		}
//		//falling eight
//		for (cnt=0;cnt<4000;cnt++)
//		{
//			Hc595RowScanDown(falling_seven_col,m);
//			s++;
//			if(s==250)
//			{
//				 if(m==7) m=0;
//				 else m++;
//				 s=0;
//			}
//		}
//		//falling seven
//		for (cnt=0;cnt<4000;cnt++)
//		{
//			Hc595RowScanDown(falling_six_col,m);
//			s++;
//			if(s==250)
//			{
//				 if(m==7) m=0;
//				 else m++;
//				 s=0;
//			}
//		}
//		//falling six
		for (cnt=0;cnt<4000;cnt++)
		{
			Hc595RowScanDown(falling_five_col,m);
			s++;
			if(s==250)
			{
				 if(m==7) m=0;
				 else m++;
				 s=0;
			}
		}
		//falling five
		for (cnt=0;cnt<4000;cnt++)
		{
			Hc595RowScanDown(falling_four_col,m);
			s++;
			if(s==250)
			{
				 if(m==7) m=0;
				 else m++;
				 s=0;
			}
		}
		//falling four
		for (cnt=0;cnt<4000;cnt++)
		{
			Hc595RowScanDown(falling_three_col,m);
			s++;
			if(s==250)
			{
				 if(m==7) m=0;
				 else m++;
				 s=0;
			}
		}
		//falling three
		for (cnt=0;cnt<4000;cnt++)
		{
			Hc595RowScanDown(falling_two_col,m);
			s++;
			if(s==250)
			{
				 if(m==7) m=0;
				 else m++;
				 s=0;
			}
		}
		//falling two
		for (cnt=0;cnt<4000;cnt++)
		{
			Hc595RowScanDown(falling_one_col,m);
			s++;
			if(s==250)
			{
				 if(m==7) m=0;
				 else m++;
				 s=0;
			}
		}
		//falling one
	}
}
部分代码被注释的原因:程序数据块太大,已超出片上的ROM。实际上,本人曾尝试CSDN网友提出的解决方案:配置Project->option for target->target选项中memory model 选择compact/large,但并不好用,若要保留数据,应使用外部数据存储器。
联系作者: 邮箱: 642296016@qq.com


