基于51单片机的流水灯及点阵设计报告.docx
《基于51单片机的流水灯及点阵设计报告.docx》由会员分享,可在线阅读,更多相关《基于51单片机的流水灯及点阵设计报告.docx(27页珍藏版)》请在冰点文库上搜索。
基于51单片机的流水灯及点阵设计报告
目录
1.引言2
1.1背景2
1.2设计目的2
1.3参考资料2
2.方案设计与比较论证
2.1设计任务2
2.2设计要求2
2.3方案的选择3
3.总体设计3
3.1开发与运行环境3
3.2系统软件工作流程图3
3.3硬件结构4
4.系统功能测试与整体指标6
4.1系统各模块功能的性能测试6
4.1.1LED小灯模块6
4.1.2点阵模块9
4.1.3按键模块10
4.2系统功能测试12
4.3系统误差与问题分析12
5.总结13
附录1;详细程序14
1.引言
1.1背景
随着电子技术的飞速发展,电子行业和社会上的各行各业息息相关,从家用电器到航空航天,无一不与电子产业的发展密切相关。
当我们看到大街小巷都是变幻多彩的霓虹灯时,心中是否会感到很新奇?
当我们看到绚丽多彩的广告牌时,心中是否会觉得很神奇?
这些神奇的流水灯只是电子产业的冰山一角,更多的知识需要我们在以后的道路上慢慢探索。
在单片机上实现流水灯很简单,只需要几条指令就可以完成,大部分学生都可以完成任务。
于是我们就思考一个新的问题,能不能实现一个亮度渐变的、按规律移动的超酷流水灯?
这就是本次设计的背景及意义。
1.2设计目的
本次基于51单片机的流水灯设计主要是为了让我们增进对80C51单片机电路的感性认识,加深对理论方面的理解。
了解软硬件的有关知识,并掌握软硬件设计过程、方法及实现,为以后设计和实现应用系统打下良好基础。
虽然本次设计较为简单,但是涵盖的内容较为丰富,运用了单片机的动态扫描、定时器、中断,用for循环来实现彗星灯的效果,PWM波控制LED的亮灭程度,独立按键的应用等等,另外,通过简单课题的设计练习,使我们了解必须提交的各项工程文件,达到巩固、充实和综合运用所学知识解决实际问题的目的。
1.3参考资料
【1】单片机原理及应用·马永杰主编·清华大学出版社2011.8
【2】51单片机C语言教程·郭天祥主编·电子工业出版社2009.12
【3】模拟电子技术基础·康华光主编·高等教育出版社2006.01
2.方案设计与比较论证
2.1设计任务
(1)基于51单片机实现一个亮度渐变的、按规律移动的超酷流水灯;
(2)基于51单片机实现在点阵上动态显示“心”型和依次显示“西北师大”;
(3)通过独立按键实现流水灯和点阵显示的切换。
2.2设计要求
(1)应用STC89C51单片机;
(2)将LED亮度渐变和按规律移动相结合;
(3)通过独立按键实现流水灯和点阵的切换;
2.3方案的选择
本系统以STC89C51单片机为核心,通过独立按键来实现LED小灯和点阵显示的切换,所以整个系统可以包括以下的几个模块:
点阵模块;键盘模块;LED小灯点亮模块。
下面一一来说明三种模块的选择。
点阵模块:
点阵模块我选择的是51单片机上自带的8×8点阵,用动态扫描技术可以很好的在点阵上显示出“心”型和文字;
键盘模块:
方案一、利用矩阵键盘,矩阵键盘可以很好的实现LED小灯和点阵显示的切换,但利用的单片机的资源太多;
方案二、利用独立键盘,独立键盘在本系统中是物尽其才,在本系统中,按键少,独立键盘原理简单,所以本系统选择了独立键盘;
LED点亮模块:
LED点亮模块我是用PWM波控制LED小灯的明暗程度,用定时器、中断技术以及动态扫描实现按一定的规律移动。
3.总体设计
3.1开发与运行环境
本设计采用的是STC89C51单片机,该单片机采用的MCU51内核,因此具有很好的兼容性,内部带有8KB的ROM,能够存储大量的程序,在KeiluVision4上编写程序,通过STC_ISP_V483烧录到STC89C51芯片里,KeiluVision4支持汇编和C语言平台,最突出特点是具有ISP在系统烧写功能,使得烧写程序更加方便。
3.2系统软件工作流程图
本次设计是通过按不同按键来实现流水灯和点阵显示的,当按下按键1时,单片机执行超级流水灯的程序;当按下按键2时,单片机执行第二套程序,点阵中依次显示“西北师大”的静态字样;当按下按键3时,单片机执行第三套程序,点阵中动态的画出“心”型。
系统软件工作流程图如下所示:
3.3硬件结构
STC89C51单片机LED灯模块、点阵模块、独立按键模块电路图分别如下:
8×8LED点阵模块
独立按键模块
STC89C52单片机实物图如下:
4.系统功能测试与整体指标
4.1系统各模块功能的性能测试
4.1.1LED小灯模块
本次设计的超级流水灯是用PWM波调光和流水灯行走花案相结合,在实现LED灯光移动中同时实现灯光的逐渐变亮的过程,在这个过程中用到了for循环,子程序调用,中断和定时器的使用等等,演示效果较好。
以下是超级流水灯的部分程序,我将以备注的形式分析整个过程。
//定时器0中断过程实现PWM调光
voidLedLum_isr(void)interrupt1//125HzPWM
{
staticuchari=0;
if(LedLum[0]>i)Led1=1;
elseLed1=0;
if(LedLum[1]>i)Led2=1;
elseLed2=0;
if(LedLum[2]>i)Led3=1;
elseLed3=0;
if(LedLum[3]>i)Led4=1;
elseLed4=0;
if(LedLum[4]>i)Led5=1;
elseLed5=0;
if(LedLum[5]>i)Led6=1;
elseLed6=0;
if(LedLum[6]>i)Led7=1;
elseLed7=0;
if(LedLum[7]>i)Led8=1;
elseLed8=0;
i++;
if(i==64)i=0;
Time_1ms_Count++;
if(Time_1ms_Count>=8)
{
Time_1ms_Flag=1;
Time_1ms_Count=0;
}
}
//延时程序
voidDelayNms(uintTick)
{
Time_1ms_Count=0;
for(;Tick>0;Tick--)
{
Time_1ms_Flag=0;
while(Time_1ms_Flag==0);
}
}
//==========================================
//
(1)第1,3,5,7个灯半亮,其余的全亮。
voidJob1(void)
{
LedLum[0]=LedLum[2]=LedLum[4]=LedLum[6]=32;
LedLum[1]=LedLum[3]=LedLum[5]=LedLum[7]=64;
DelayNms(1000);//保持1S
}
//==========================================
//
(2)第1个亮1/8,第2个亮2/8,第3个亮3/8,第4个亮4/8,
//第5个亮5/8,第6个亮6/8,第7个亮7/8,第8个全亮。
//这个就是彗星灯拖尾的程序
voidJob2(void)
{
uchari;
for(i=0;i<8;i++)
LedLum[i]=(i+1)*8;
DelayNms(1000);
}
//==========================================
//(3)所有的灯逐渐从暗到全亮,再由全亮到暗。
voidJob3(void)
{
uchari,j;
for(i=0;i<8;i++)//所有的灯全暗
LedLum[i]=0;
for(j=0;j<64;j++)//所有的灯逐渐从暗到全亮
{
for(i=0;i<8;i++)
LedLum[i]=j+1;
DelayNms(50);//延时
}
for(j=64;j>0;j--)//再由全亮到暗
{
for(i=8;i>0;i--)
LedLum[i-1]=j-1;
DelayNms(20);
}
}
//==========================================
//(4)8个灯从第一个开始依次渐亮,直到最后一个。
//再从最后一个起渐暗,直到第一个。
voidJob4(void)
{
uchari,j;
for(i=0;i<8;i++)//8个灯从第一个开始依次渐亮,直到最后一个。
{
for(j=0;j<64;j++)
{
LedLum[i]=j+1;
DelayNms(10);
}
//LedLum[i]=0;
}
for(i=8;i>0;i--)//再从最后一个起渐暗,直到第一个。
{
for(j=64;j>0;j--)
{
LedLum[i-1]=j-1;
//LedLum[i-1]=j;
DelayNms(10);
}
//LedLum[i-1]=0;
}
}
4.1.2点阵模块
点阵显示分为两部分,一部分是依次显示“西北师大”静态字样,另一部分是动态显示“心”型图案。
“西北师大”每个字在点阵中显示的原理相同,所以我就拿“西”字显示的原理来讲解。
显示“西”的程序如下:
ucharcodeseg1[]={0xfe,0x82,0xce,0xaa,0xaa,0xfe,0x28,0xfe};//点阵显示"西"字
ucharcodewei[]={0x7f,0xbf,0xdf,0xef,0xf7,0xfb,0xfd,0xfe};//分别对应相应的段亮位选选中为0
for(i=0;i<8;i++)
{
P0=0xff;
LATCH1=1;LATCH1=0;
P0=wei[i];//取显示数据
LATCH2=1;LATCH2=0;
P1=seg1[i];//取段码
//LATCH2=1;LATCH2=0;
delayus(200);//扫描间隙延时
}
在整个过程中,单片机就是在不断的对程序进行扫描,在很短的时间内,人眼无法感觉到LED在闪烁,所以觉得LED一直亮着,从而在点阵上形成一个字。
再在这个循环外加个外循环,加上延时,从而实现文字的不断更换。
在点阵上动态显示“心”型原理和静态显示文字的原理差不多,只不多把文字的更换变成了“心”型下一步要出现的图案,外循环延时缩短一点,人眼看上去就觉得“心”型是动态出现的。
具体程序见附录1.
4.1.3按键模块
按键模块选择是四个独立按键中的其中三个,它操作简单、方便,利用的资源少,我是通过按键扫描函数,通过对返回值的判断从而决定执行哪套程序,需要注意的是,在按键扫描函数中要加延时实现去抖,否则有时会检测错误。
键盘扫描函数程序如下,我以备注的形式详细分析:
unsignedcharKeyScan(void)
{
if(!
KEY1)//如果检测到低电平,说明按键按下
{
delayms(10);//延时去抖,一般10-20ms
if(!
KEY1)//再次确认按键是否按下,没有按下则退出
{
while(!
KEY1);//如果确认按下按键等待按键释放,没有则退出
{
return1;
}
}
}
elseif(!
KEY2)//如果检测到低电平,说明按键按下
{
delayms(10);//延时去抖,一般10-20ms
if(!
KEY2)//再次确认按键是否按下,没有按下则退出
{
while(!
KEY2);//如果确认按下按键等待按键释放,没有则退出
{
return2;
}
}
}
elseif(!
KEY3)//如果检测到低电平,说明按键按下
{
delayms(10);//延时去抖,一般10-20ms
if(!
KEY3)//再次确认按键是否按下,没有按下则退出
{
while(!
KEY3);//如果确认按下按键等待按键释放,没有则退出
{
return3;
}
}
}
elseif(!
KEY4)//如果检测到低电平,说明按键按下
{
delayms(10);//延时去抖,一般10-20ms
if(!
KEY4)//再次确认按键是否按下,没有按下则退出
{
while(!
KEY4);//如果确认按下按键等待按键释放,没有则退出
{
return4;
}
}
}
else
return0;
}
4.2系统功能测试
启动系统,按下按键1,执行第一套程序,超级流水灯启动,运行正常;按下按键2,执行第二套程序,点阵中依次显示“西北师大”四个字样,运行正常;按下按键3,执行第三套程序,点阵中动态显示“心”型图案,运行正常。
通过测试,本设计的功能基本都能达到。
4.3系统误差与问题分析
我在调试本系统的时候出现了一下几点问题。
错误1:
当我按下独立键盘后,再去按另一个按键,单片机不执行后面按键的程序;
原因:
只有当前一个程序完整的执行完之后,再按下按键,系统才会去执行后面的程序;
错误2:
当我按下按键1后,LED灯一直亮着,没有想预想的那样显示出来;
原因:
延时时间太短,肉眼无法识别它的闪烁,将延时调长一点就好了。
错误3:
当一套程序执行完之后我再按其他的键,希望它执行另一套程序,但是没有实现,系统一直在执行前一套程序。
原因:
在内循环上出现错误,变成了死循环,无法跳出内循环。
错误4:
我想在按键按下去之后,如果不按其他键了,系统能一直执行循环执行前一套程序,比如,我按下按键1,如果我不再按按键2或3的话,系统能一直执行第一套程序,执行完之后再循环,所以我在里面加了一个while
(1),希望它能一直循环下去,因为它的外循环已经判断了按键的值,所以我想当改变按键值时这个循环还是跳出来的,但是确实跳不出这个死循环,这个问题我始终没有解决。
最后,保险起见,我选择了按键后只执行一次程序。
错误5:
在我调试过程中,单独调试点阵显示的时候,点阵中的LED特别亮,但是将这个程序和按键模块、流水灯模块加到一起时,运行起来,点阵中的LED显示就特别暗,这个问题始终没有解决。
5.总结
这次课程设计使我掌握了很多实践知识,对单片机有了进一步的了解。
通过这次课程设计使我懂得了理论与实际相结合是很重要的,只有理论知识是远远不够的,只有把所学的理论知识与实践相结合起来,从理论中得出结论,进而提高自己的实际动手能力和独立思考的能力。
这次设计也使我学会了方案的选择,对于实现同一种效果的方案可能会很多很多,我们要学会选择最优方案,比如同样的效果哪个程序所占的存储空间最少,运行速度最快等等,都是需要我们考虑的。
此外,对于书本上的知识,我们不能死守教条,要学会变通,这样更有利于我们学习和创新。
整个设计过程可以说不是很顺利,因为有很多知识已经淡忘,还有很多新的东西没有掌握,所以这次设计在不断的复习、学习中度过,使我受益匪浅,也使我对单片机的运用有了进一步的了解和掌握,也为今后的学习生活和工作打下良好的基础。
附录1;详细程序
#include
#defineuintunsignedint
#defineucharunsignedchar
#defineTime_125us(0x100-125)//Fosc=12M
sbitKEY1=P3^2;
sbitKEY2=P3^3;
sbitKEY3=P3^4;
sbitKEY4=P3^5;
sbitLed1=P1^0;
sbitLed2=P1^1;
sbitLed3=P1^2;
sbitLed4=P1^3;
sbitLed5=P1^4;
sbitLed6=P1^5;
sbitLed7=P1^6;
sbitLed8=P1^7;
sbitLATCH1=P2^6;
sbitLATCH2=P2^7;
ucharcodeseg1[]={0xfe,0x82,0xce,0xaa,0xaa,0xfe,0x28,0xfe};//点阵显示"西"字
ucharcodeseg2[]={0x2e,0xaa,0x6a,0x28,0x2c,0xea,0x28,0x28};//点阵显示"北"字
ucharcodeseg3[]={0x84,0x44,0x55,0xd7,0xd5,0xdf,0x44,0x5f};//点阵显示"师"字
ucharcodeseg4[]={0x82,0x44,0x28,0x10,0x10,0xfe,0x10,0x10};//点阵显示"大"字
ucharcodewei[]={0x7f,0xbf,0xdf,0xef,0xf7,0xfb,0xfd,0xfe};
ucharcodeseg11[]={0x00,0x00,0x00,0x00,0x00,0x10,0x00,0x00};
ucharcodeseg12[]={0x00,0x00,0x00,0x00,0x00,0x10,0x24,0x00};
ucharcodeseg13[]={0x00,0x00,0x00,0x00,0x00,0x10,0x6c,0x00};
ucharcodeseg14[]={0x00,0x00,0x00,0x00,0x00,0x92,0x6c,0x00};
ucharcodeseg15[]={0x00,0x00,0x00,0x00,0x82,0x92,0x6c,0x00};
ucharcodeseg16[]={0x00,0x00,0x00,0x44,0x82,0x92,0x6c,0x00};
ucharcodeseg17[]={0x00,0x00,0x28,0x44,0x82,0x92,0x6C,0x00};
ucharcodeseg18[]={0x00,0x10,0x28,0x44,0x82,0x92,0x6C,0x00};//心的形状
voiddelayus(uintt);//us级延时函数声明
voiddelayms(uintt);//ms级延时函数声明
ucharKeyScan(void);//键盘扫描
voidDelayNms(uintTick);
bitTime_1ms_Flag;
ucharTime_1ms_Count=0,LedLum[8]={0,0,0,0,0,0,0,0};
voidLedLum_isr(void)interrupt1//125HzPWM
{
staticuchari=0;
if(LedLum[0]>i)Led1=1;
elseLed1=0;
if(LedLum[1]>i)Led2=1;
elseLed2=0;
if(LedLum[2]>i)Led3=1;
elseLed3=0;
if(LedLum[3]>i)Led4=1;
elseLed4=0;
if(LedLum[4]>i)Led5=1;
elseLed5=0;
if(LedLum[5]>i)Led6=1;
elseLed6=0;
if(LedLum[6]>i)Led7=1;
elseLed7=0;
if(LedLum[7]>i)Led8=1;
elseLed8=0;
i++;
if(i==64)i=0;
Time_1ms_Count++;
if(Time_1ms_Count>=8)
{
Time_1ms_Flag=1;
Time_1ms_Count=0;
}
}
voidDelayNms(uintTick)
{
Time_1ms_Count=0;
for(;Tick>0;Tick--)
{
Time_1ms_Flag=0;
while(Time_1ms_Flag==0);
}
}
//
(1)第1,3,5,7个灯半亮,其余的全亮。
voidJob1(void)
{LedLum[0]=LedLum[2]=LedLum[4]=LedLum[6]=32;
LedLum[1]=LedLum[3]=LedLum[5]=LedLum[7]=64;
DelayNms(1000);//保持3S
}
//
(2)第1个亮1/8,第2个亮2/8,第3个亮3/8,第4个亮4/8,
//第5个亮5/8,第6个亮6/8,第7个亮7/8,第8个全亮。
voidJob2(void)
{
uchari;
for(i=0;i<8;i++)
LedLum[i]=(i+1)*8;
DelayNms(1000);
}
//(3)所有的灯逐渐从暗到全亮,再由全亮到暗。
voidJob3(void)
{
uchari,j;
for(i=0;i<8;i++)//所有的灯全暗
LedLum[i]=0;
for(j=0;j<64;j++)//所有的灯逐渐从暗到全亮
{
for(i=0;i<8;i++)
LedLum[i]=j+1;
DelayNms(50);//延时
}
for(j=64;j>0;j--)//再由全亮到暗
{
for(i=8;i>0;i--)
LedLum[i-1]=j-1;
DelayNms(20);
}
}
//(4)8个灯从第一个开始依次渐亮,直到最后一个。
//再从最后一个起渐暗,直到第一个。
voidJob4(void)
{
uchari,j;
for(i=0;i<8;i++)//8个灯从第一个开始依次渐亮,直到最后一个。
{
for(j=0;j<64;j++)
{
LedLum[i]=j+1;
DelayNms(10);
}
//LedLum[i]=0;
}
for(i=8;i>0;i--)//再从最后一个起渐暗,直到第一个。
{
for(j=64;j>0;j--)
{
LedLum[i-1]=j-1;
//LedLum[i-1]=j;
DelayNms(10);
}
//LedLum[i-1]=0;
}
}
voidmain(void)
{TMOD|=0x02;
TMOD&=0x52;
TH0=Time_125us;
TR0=1;
EA=1;
ET0=1;//定时器开关打开
while
(1)
{uchari,j,num;
num=KeyScan();
if(num==1)
{
Job1();
Job2();
Job3();
Job4();
}
if(num==2)
{
for(j=0;j<100;j++)
{for(i=0;i<8;i++)
{
P0