开发环境的搭建
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