基于FPGA的嵌入式51核的数字钟设计.docx
《基于FPGA的嵌入式51核的数字钟设计.docx》由会员分享,可在线阅读,更多相关《基于FPGA的嵌入式51核的数字钟设计.docx(19页珍藏版)》请在冰豆网上搜索。
基于FPGA的嵌入式51核的数字钟设计
摘要
此次设计的数字钟具有年、月、日、时、分、秒计数显示功能,以24小时循环计时显示;具有清零,调节小时、分钟功能;具有整点提示、定时报警功能,使用蜂鸣器报警;由键盘输入进行数字钟设计的校时、清零、启停功能。
数字钟在日常生活中经常用到,可利用现在所学知识自行设计一个数字钟。
我们在本次实验中采用了基于FPGA的嵌入51软核的设计方法。
基于EDA技术,在QuartusII工具软件环境下,采用自顶向下的设计方法,在FPGA中嵌入51软核。
在FPGA中嵌入51软核后,FPGA就有了51单片机所有的功能,就相当于在51单片机上进行数字钟的设计。
系统主芯片采用EP2C5T144C8,由时钟模块、控制模块、显示以及报时模块组成。
经编译和仿真所设计的程序,在可编程逻辑器件上下载验证。
关键字:
FPGA;51软核;整点提示;定时报警;对时
目录
第一章题目分析3
1.1、功能要求及指标3
1.2、设计思路3
第二章方案比较与选择4
2.1方案一4
2.2方案二4
2.3方案三5
第三章系统各模块设计6
3.1、8051IP软核的嵌入6
3.1.1基本结构和功能6
3.1.28051软核系统构建和软件测试7
3.2系统软件设计8
第四章系统测试9
第五章结论10
参考文献10
第一章题目分析
1.1、功能要求及指标
本设计是基于FPGA嵌入式51软核的设计性实验。
在FPGA中嵌入51软核后,FPGA就有了51单片机所有的功能,就相当于在51单片机上进行数字钟的设计。
此次设计的数字钟具有年、月、日、时、分、秒计数显示功能,以24小时循环计时显示;具有清零,调节小时、分钟功能;具有整点提示、定时报警功能,使用蜂鸣器报警。
1.2、设计思路
本设计首先要解决的就是嵌入51软核的问题。
现在网络上有很多现成的51软核的VQM程序,可以直接拿来使用。
把CPU、锁相环、数据RAM、程序ROM,都放在同一片FPGA内,从而构成SOC系统,这将使系统的设计效率和系统性能获得极大的提高,这也是现代电子设计技术的发展方向。
其次就是单片机程序编写的问题。
在了解数字钟所要实现的功能之后就可以用C来编写程序,只要有一定的单片机编程基础就可以很快写出。
图1是总体设计思路框图。
图1总体设计思路框图
第二章方案比较与选择
2.1方案一
利用EDA技术自顶向下的设计方法,完全由VHDL/VerilogHDL硬件描述语言,在QuartusII开发平台下进行编译、仿真、下载,实现基本计时显示和设置、调整时间、闹钟和秒表功能。
系统主要由计数器组成,再加上控制及显示电路实现数字钟的设计。
系统框图如图2所示。
图2基于FPGA控制的系统框图
采用硬件描述语言和PLD器件相结合进行数字集成电路的设计简单方便,EDA技术的发展在一定程度上实现了硬件设计的软件化。
但是此方法很难实现整点提示这一功能,不能完全实现题目的要求,在定时和对时时也很麻烦,显示界面太单一,不够直观。
2.2方案二
采用AT89C51为控制核心,使用单片机的T0定时器来实现秒的计数,T1产生1KHZ的报警频率。
结合相关的元器件(LCD1602液晶显示器、4*4键盘等),再通过编写单片机程序语言,达到制作数字钟的目的。
使用此方法价格便宜,但与使用FPGA相比,前者系统集成度低,外围电路复杂,功耗高。
系统框图如图3所示。
图3基于单片机控制的系统框图
2.3方案三
在FPGA中嵌入51软核,软核在接上ROM、RAM和PLL等外围电路之后就成为一个完整的8051单片机。
此单片机CPU核与传统MCS-51单片机完全兼容,但速度约为传统单片机的20倍,优化良好的条件下,主频最高可达250MHz;同样用C或汇编语言完成软件设计,而且系统集成度高,稳定。
使用LCD1602作显示器,可以使显示界面更加的直观,多样化。
系统框图如图4所示。
图4基于51IP软核控制的系统框图
综合以上分析、比较,此处选择方案三进行设计。
第三章系统各模块设计
3.1、8051IP软核的嵌入
3.1.1基本结构和功能
图58051结构模块框图图68051原理图元件
8051的指令系统与8051/2、8031/2等完全兼容,硬件部分也基本相同,例如可接64KB外部存储器,可接256字节内部数据RAM,含两个16位定时/计数器,全双工串口,含节省功耗工作模式,中断响应结构等等。
结构模块框图和原理图元件分别如图5和6所示。
与普通8051不同之处主要有:
1、8051是以网表文件的方式存在的,只有通过编译综合,并载入FPGA中才以硬件的方式工作,而普通8051总是以硬件方式存在的;
2、8051无内部ROM和RAM,所有程序ROM和内部RAM都必须外接。
3、以软核方式存在能进行硬件修改和编辑;能对其进行仿真和嵌入式逻辑分析仪实现实时时序测试;能根据设计者的意愿将CPU、RAM、ROM、硬件功能模块和接口模块等实现于同一片FPGA中(即SOC)。
4、与普通8051不同,8051的4个I/O口是分开的。
例如P1口,其输入端P1I和输出端P1O是分开的,如果需要使用P1口的双向口功能,必须外接一些电路才能实现。
图7所示的是单片机中的一个端口构成的双向口(P1口)电路连接方法。
图78051单片机I/O口设置成双向口的电路
3.1.28051软核系统构建和软件测试
图8是8051核实用系统的最基本构建顶层原理图,主要由4个部件构成:
1、8051核。
由VQM原码表述:
CPU_Core.vqm,可以直接调用。
该元件可以与其他不同语言表述的元件一同综合与编译。
2、嵌入式锁相环PLL50。
本实验锁相环的频率设置为24MHz。
3、程序ROM,LPM_ROM。
图8中设置的ROM容量是4K字节,对于一般的应用足够了。
此ROM可以加载HEX格式文件作为单片机的程序代码。
这里HEX程序代码由KEIL程序编译器生成(图中已加载了1.HEX)。
4、数据RAM,LPM_RAM。
图8中设置的LPM_RAM容量是256字节。
高128字节须用间接寻址方式访问。
图88051核实用系统的最基本构建顶层原理图
向软核中下载程序代码有两种方法,如下:
1、QuartusII打开的工程,在工程管理窗,双击图左侧rom4KB,在右侧出现该元件文件,其初始化文件路径指示在1.HEX上(图9)。
下载SOF文件后可以测试数字钟的功能了。
图9ROM初始化文件路径
2、利用In-SystemMemoryContentEditor下载。
在单片机程序编译环境KEIL中修改程序Text1.c,编译,并用“Tools”菜单中的工具:
In-SystemMemoryContentEditor(图10)下载编译代码:
1.hex,再观察软硬件的工作情况。
8051的软件调试也可以使用In-SystemMemoryContentEditor来完成。
图10利用In-SystemMemoryContentEditor下载程序HEX代码
3.2系统软件设计
本程序是在KEIL中,使用C语言编写。
以LCD1602为显示器,4*4键盘为输入设备,很好的完成了数字钟的所有功能。
软件流程图如下所示:
图11系统软件流程图
第四章系统测试
本次设计完全实现了题目的所有要求,系统的实物图见附录1。
系统测试方法及结果如下所述:
1、系统上电后,开机界面显示“welcometouse!
”5s。
5s之后清屏,并显示软件初始化时的年、月、日、时、分、秒。
系统自动走时。
实物图见附录2所示。
2、当按下4*4键盘上的“定时”键后,LCD上出现提示“Settime:
”,然后在键盘上输入要定时的时间,按下确定键LCD上显示“Settime:
”+输入的时间。
如果输入错误,可以按下“删除”键删除当前输入值。
实物图见附录2所示。
3、当按下键盘上的“对时”键后,LCD上出现提示“Adjusttime:
”,然后输入要对时的时间,按下确定键LCD上显示当前输入的时间,“Adjusttime:
”消失。
如果输入错误,可以按下“删除”键删除当前输入值。
实物图见附录2所示。
4、按下键盘上的“取消”键可以取消任意时刻的对时或定时操作。
5、按下键盘上的“切换”键可以切换年、月、日和定时时间的显示。
6、当时间到达之前定时时间后,开始报警。
由蜂鸣器发出1KHZ的报警声音,只有按下取消键报警才会停止。
7、具有整点报时功能。
整点报时时间如果同报警时间一致,则只报警,不会整点报时。
整点报时时间持续1s,也是由蜂鸣器发出1KHZ的报警声音。
第五章结论
经过两个礼拜的努力,设计出了完全符合此次题目要求的数字钟。
此数字钟操作简单、方便、稳定,显示界面也很清晰、明了。
把CPU、锁相环、数据RAM、程序ROM、接口模块、通信模块、显示控制模块、数据采样和信号发生模块等等,都放在同一片FPGA内,从而构成SOC系统,这将使系统的设计效率和系统性能获得极大的提高,这也是现代电子设计技术的发展方向。
参考文献
[1]康华光《电子技术基础》数字部分[M]北京.高教出版社2006.1
[2]潘松《EDA技术实用教程》[M].北京.科学出版社.2002.10
[3]潘松.《EDA技术与VHDL》[M].北京.清华大学出版社,2005.7
附录1:
实物总体图
附录2:
功能演示图
附录3:
源程序
#include
#include
#include
#include
voidset_time();
voidadjust_time();
voiddisplay_day();
voiddisplay_time();
voiddisplay_Settime();
voidmain(void)
{
unsignedchartemp1=0;
init();
Lcd_Init();
DisplayString(0,0,"Welcometouse!
");
display_time();//调用显示时间函数
Delay(65535);Delay(65535);Delay(65535);Delay(65535);
clear_lcd(15,0);
display_day();//调用显示日期
while
(1)
{
temp1=KeyScan();
switch(temp1)
{
case10:
temp1=0;if(flag==0){display_day();flag=1;}elseif(flag==1){display_Settime();flag=0;}break;//切换定时和日期显示
case11:
temp1=0;flag2=0;clear_lcd(15,0);display_day();TR1=0;ts=0;break;//取消报警时间
case14:
temp1=0;clear_lcd(15,0);set_time();break;//14为定时键,只清屏一次
case15:
temp1=0;clear_lcd(15,0);adjust_time();break;//15为对时键
default:
break;
}
}
}
voidset_time(void)//时间设定子函数
{
unsignedchari=0,temp;
unsignedcharl_hour,l_minite;
unsignedchars_temp[]={0,0,0,0};//定时
DisplayString(0,0,"Set:
00:
00");
while
(1)
{
temp=KeyScan();
if(temp<10&&i<4)
{
s_temp[i]=temp;
l_hour=s_temp[0]*10+s_temp[1];
l_minite=s_temp[2]*10+s_temp[3];
if(i==0)DisplayOneChar(5,0,l_hour/10+0x30);//将时间显示出来
elseif(i==1)DisplayOneChar(6,0,l_hour%10+0x30);
elseif(i==2)DisplayOneChar(8,0,l_minite/10+0x30);
elseif(i==3)DisplayOneChar(9,0,l_minite%10+0x30);
i++;
}
elseif(temp==13)//有确认键,确认输入
{
DisplayString(0,0,"Time:
");flag=0;
s_hour=l_hour;s_minite=l_minite;
break;
}
elseif(temp==11)//输入过程中有取消键,退出输入
{
clear_lcd(15,0);display_day();flag=1;
break;
}
}
}
voidadjust_time()
{
unsignedchartemp,i=0;
unsignedchara_temp[]={0,0,0,0};//对时
DisplayString(0,0,"Adjust:
00:
00");
while
(1)
{
temp=KeyScan();
if(temp<10&&i<4)
{
a_temp[i]=temp;
a_hour=a_temp[0]*10+a_temp[1];
a_minite=a_temp[2]*10+a_temp[3];
if(i==0)DisplayOneChar(8,0,a_hour/10+0x30);//将时间显示出来
elseif(i==1)DisplayOneChar(9,0,a_hour%10+0x30);
elseif(i==2)DisplayOneChar(11,0,a_minite/10+0x30);
elseif(i==3)DisplayOneChar(12,0,a_minite%10+0x30);
i++;
}
elseif(temp==13)//有确认键,确认输入
{
clear_lcd(15,0);clear_lcd(15,0);//TR0=1;
hour=a_hour;minite=a_minite;display_time();
display_day();
break;
}
elseif(temp==11)//输入过程中有取消键,退出输入
{
clear_lcd(15,0);display_day();flag=1;
break;
}
}
}
voiddisplay_time()
{
DisplayOneChar(8,1,hour/10+0x30);//将时间显示出来
DisplayOneChar(9,1,hour%10+0x30);
DisplayOneChar(10,1,0x3a);
DisplayOneChar(11,1,minite/10+0x30);
DisplayOneChar(12,1,minite%10+0x30);
DisplayOneChar(13,1,0x3a);
DisplayOneChar(14,1,second/10+0x30);
DisplayOneChar(15,1,second%10+0x30);
}
voiddisplay_day()
{
clear_lcd(15,0);
DisplayOneChar(0,0,year/1000+0x30);
DisplayOneChar(1,0,year%1000/100+0x30);
DisplayOneChar(2,0,year%100/10+0x30);
DisplayOneChar(3,0,year%10+0x30);
DisplayOneChar(4,0,0x2e);
DisplayOneChar(5,0,month/10+0x30);
DisplayOneChar(6,0,month%10+0x30);
DisplayOneChar(7,0,0x2e);
DisplayOneChar(8,0,day/10+0x30);
DisplayOneChar(9,0,day%10+0x30);
DisplayString(10,0,"");
}
voiddisplay_Settime()
{
clear_lcd(15,0);DisplayString(0,0,"Time:
");//提示用户
DisplayOneChar(5,0,s_hour/10+0x30);DisplayOneChar(6,0,s_hour%10+0x30);
DisplayOneChar(7,0,0x3a);
DisplayOneChar(8,0,s_minite/10+0x30);DisplayOneChar(9,0,s_minite%10+0x30);
DisplayString(10,0,"");
}
voidt0(void)interrupt1
{
tcnt++;
if(tcnt==7999)
{
tcnt=0;
second++;
if(second>59)
{
second=0;minite++;
if(hour==s_hour&&minite==s_minite)TR1=1;//闹铃报警,按下取消键才会停止报警
if(minite>59)
{
minite=0;hour++;
if(hour==s_hour&&minite==s_minite)TR1=1;//闹铃报警,按下取消键才会停止报警
else{TR1=1;flag1=1;}/*整点报时2s*/
if(hour>23)
{
hour=0;day++;
display_day();
if(day>30)
{
day=1;month++;
display_day();
if(month>12)
{
month=1;year++;
display_day();
}
}
}
}
}
display_time();//将时间显示出来
}
TH0=0x06;
TL0=0x06;
}
voidt1(void)interrupt3//起报警作用
{
ts=~ts;if(flag1==1){tcount++;if(tcount==500){TR1=0;tcount=0;flag1=0;}}
TH1=(65535-4000)/256;
TL1=(65535-4000)%256;
}
.