FPGA基础学习之数字时钟设计1
2015-12-18 18:55
567 查看
先说明一下:1、本博文绝对原创,转载请注明。
2、小弟刚开始学习FPGA,博文如有什么不对的地方,恳请大家指出。
3、本文目的旨在与新手分享交流学习中的一些问题。
一、实验平台说明
硬件平台:使用的网上一块比较便宜的开发板,100多点。Altear EP4CE6E22C8芯片。
软件平台:quarters-ii 11.0
使用语言:verlog
二、模块层次说明
系统由顶层、数据转换模块、显示模块、时钟分频模块组成。
时钟模块:开发板使用的是50M晶振,在这里我们需要两种时钟,一个用于一秒钟计时(1HZ),一个用于数码管扫描(500HZ);
显示模块:用于在数码管上显示时钟数据,由于只有4位数码管,所以这里其实设计的并不是一个完整的数字时钟,应该叫计时器,;两个数码管显示秒数据,两个数码管显示分钟数据,知道溢出清零,不过大家可以在这个基础上自行添加设计。
数据转换模块:功能是讲0-9的数字转换成数码管显示的段码。
顶层:实例化时钟和显示模块,同时完成一些逻辑任务。这里的实例化大家可以类似的理解成C语言中的函数的调用,但实际上不是的,因为FPGA是硬件,一定要记住并发这个概念。
三、时钟分频模块
四、数据转换模块
五、数码管显示模块
六、顶层模块
下载后的效果图
系统整体机构图,这个是我用另一种方式做的,顶层用的原理图的方式设计的,发现这种方式有许多的优点,我会在下一篇文章张中分享。
八、心得分享与注意事项
最后说说过程中遇到的问题,也许也有人会遇到,这样可以帮助大家更快的解决问题。
1、并行!并行!并行!说三遍,使用硬件描述语言相当于是你在搭建电路一样,这个可以通过RTL图看出。
2、大家要注意“<<=”和“=”的使用,以及reg和wire,比如模块一得输出是reg类型了,那么输入到模块2中的输入就要是wire类型了。
3、verlog貌似暂时还不只是数组类型端口,这点要注意。(数组类型和位宽是两回事,不要搞混了哦)。
4、一定要注意数据宽度,特别是是在模块之间传递的时候。
5、暂时就想到这些,第一次写,有什么不足的地方往大家多多指点,下一篇文章使用原理图的方式来设计顶层。
2、小弟刚开始学习FPGA,博文如有什么不对的地方,恳请大家指出。
3、本文目的旨在与新手分享交流学习中的一些问题。
一、实验平台说明
硬件平台:使用的网上一块比较便宜的开发板,100多点。Altear EP4CE6E22C8芯片。
软件平台:quarters-ii 11.0
使用语言:verlog
二、模块层次说明
系统由顶层、数据转换模块、显示模块、时钟分频模块组成。
时钟模块:开发板使用的是50M晶振,在这里我们需要两种时钟,一个用于一秒钟计时(1HZ),一个用于数码管扫描(500HZ);
显示模块:用于在数码管上显示时钟数据,由于只有4位数码管,所以这里其实设计的并不是一个完整的数字时钟,应该叫计时器,;两个数码管显示秒数据,两个数码管显示分钟数据,知道溢出清零,不过大家可以在这个基础上自行添加设计。
数据转换模块:功能是讲0-9的数字转换成数码管显示的段码。
顶层:实例化时钟和显示模块,同时完成一些逻辑任务。这里的实例化大家可以类似的理解成C语言中的函数的调用,但实际上不是的,因为FPGA是硬件,一定要记住并发这个概念。
三、时钟分频模块
module clock_div(clk,clk_out1,clk_out2); input clk; output clk_out1; reg clk_out1; reg [27:0] DIV_cnt1 =0; parameter period1=50000000; //频率为1hz output clk_out2; reg clk_out2; reg [27:0] DIV_cnt2 =0; parameter period2=100000; //100000频率为500hz //////////////分频1//////////////// always @ (posedge clk) begin DIV_cnt1 <= DIV_cnt1 + 1; if(DIV_cnt1 == (period1>>1)-1)//高电平 clk_out1 <= #1 1'b1; else if(DIV_cnt1 == period1-1)//低电平 begin clk_out1 <= #1 1'b0; DIV_cnt1 <= #1 1'b0; end end //////////////分频2//////////////// always @ (posedge clk) begin DIV_cnt2 <= DIV_cnt2 + 1; if(DIV_cnt2 == (period2>>1)-1)//高电平 clk_out2 <= #1 1'b1; else if(DIV_cnt2 == period2-1)//低电平 begin clk_out2 <= #1 1'b0; DIV_cnt2 <= #1 1'b0; end end endmodule
四、数据转换模块
//////////////数字转换成数码管编码模块/////////////// module num_to_code(num,code); input num; //输入0-9的数据 output code; //输出0-9数据的数码管段码 wire[3:0] num; reg[7:0] code; always @ (num) //当数字变动一次就进行一次转换 begin case (num) 4'h0 : code <= 8'hc0; //显示"0" 4'h1 : code <= 8'hf9; //显示"1" 4'h2 : code <= 8'ha4; //显示"2" 4'h3 : code <= 8'hb0; //显示"3" 4'h4 : code <= 8'h99; //显示"4" 4'h5 : code <= 8'h92; //显示"5" 4'h6 : code <= 8'h82; //显示"6" 4'h7 : code <= 8'hf8; //显示"7" 4'h8 : code <= 8'h80; //显示"8" 4'h9 : code <= 8'h90; //显示"9" default : code <= 8'hff; endcase end endmodule
五、数码管显示模块
//////////////数码管显示模块////////////// module display(clk,seg0,seg1,seg2,seg3,seg_d,seg_w); input seg0,seg1,seg2,seg3; //输入的4位段码数据 input clk; //扫描时钟 output seg_d; //输出到管脚的段码数据 output seg_w; //输出到管脚的位选数据 wire[7:0] seg0,seg1,seg2,seg3; reg[7:0] seg_d; reg[3:0] seg_w; reg[3:0] scan_cnt; //位选扫描 always @ (posedge clk) //数码管扫描 begin scan_cnt = scan_cnt+1; if (scan_cnt == 3'd4) scan_cnt <= 0; end always @ (scan_cnt) //数码管位选 begin case (scan_cnt) 3'd0 : seg_w<=4'b0111; 3'd1 : seg_w<=4'b1011; 3'd2 : seg_w<=4'b1101; 3'd3 : seg_w<=4'b1110; default :seg_w<=4'b1111; endcase end always @ (scan_cnt) //数码管显示数据 begin case (scan_cnt) 3'd0 : seg_d<=seg3; // 3'd1 : seg_d<=seg2;// 3'd2 : seg_d<=seg1; 3'd3 : seg_d<=seg0;//8'hf9 default :seg_d<=8'hff; endcase end endmodule
六、顶层模块
module seg_clock(clock,led,seg_d,seg_w); input clock; //系统时钟50MHZ晶振输入 output led; //LED output seg_d; //数码管的段选 output seg_w; //数码管的位选 reg[3:0] led; //4位led灯 wire[7:0] seg_d; //段选8位 wire[3:0] seg_w; //位选4位 wire clk1; //分频后的时钟1 因为分频器输出为reg类型,故这里用wire wire clk2; //同上 reg[3:0] tim[0:3]; //4位数时间数据 wire[7:0] tim_d[0:3]; //4位时间数据的段码 initial //初始化时钟数据 begin tim[0]<=4'd0; tim[1]<=4'd0; tim[2]<=4'd0; tim[3]<=4'd0; end ////////////实例化分频模块//////////////// clock_div clock_div( .clk(clock), .clk_out1(clk1), .clk_out2(clk2) ); ////////////实例化数据转换模块//////////////// num_to_code num_to_code0( .num(tim[0]), .code(tim_d[0]) ); num_to_code num_to_code1( .num(tim[1]), .code(tim_d[1]) ); num_to_code num_to_code2( .num(tim[2]), .code(tim_d[2]) ); num_to_code num_to_code3( .num(tim[3]), .code(tim_d[3]) ); ////////////实例化显示模块//////////////// display display( .clk(clk2), .seg0(tim_d[0]), .seg1(tim_d[1]), .seg2(tim_d[2]), .seg3(tim_d[3]), .seg_d(seg_d), .seg_w(seg_w) ); always @ (posedge clk1) //clk为1hz 此处更新时间 begin led<=~led; tim[0]<=tim[0]+4'd1; if(tim[0]==4'd9) //秒的个位 begin tim[0]<=4'd0; tim[1]<=tim[1]+ 4'd1; //秒的十位 if(tim[1]==4'd5) begin tim[1]<=4'd0; tim[2]<=tim[2]+ 4'd1; //分的个位 if(tim[2]==4'd9) begin tim[2]<=4'd0; tim[3]<=tim[3]+ 4'd1;//分的十位 if(tim[3]==4'd9) begin tim[3]<=4'd0; end end end end end endmodule七、实验效果及系统结构图
下载后的效果图
系统整体机构图,这个是我用另一种方式做的,顶层用的原理图的方式设计的,发现这种方式有许多的优点,我会在下一篇文章张中分享。
八、心得分享与注意事项
最后说说过程中遇到的问题,也许也有人会遇到,这样可以帮助大家更快的解决问题。
1、并行!并行!并行!说三遍,使用硬件描述语言相当于是你在搭建电路一样,这个可以通过RTL图看出。
2、大家要注意“<<=”和“=”的使用,以及reg和wire,比如模块一得输出是reg类型了,那么输入到模块2中的输入就要是wire类型了。
3、verlog貌似暂时还不只是数组类型端口,这点要注意。(数组类型和位宽是两回事,不要搞混了哦)。
4、一定要注意数据宽度,特别是是在模块之间传递的时候。
5、暂时就想到这些,第一次写,有什么不足的地方往大家多多指点,下一篇文章使用原理图的方式来设计顶层。
相关文章推荐
- 第三课的课后练习
- #置换#Burnside引理Polya定理
- 第十一章
- [No00005B] word快速插入当前时间&怎样一次性删除文档中的全部链接
- android里Toast的用法
- SELinux policy问题解决思路总结
- 嵌入式开发之xml---xml解析
- php5.5以上版本编译扩展模块方法
- Xcode官方文档使用手册
- Xcode7.2之沙盒
- 高效率去掉js数组中重复项
- 给大家推荐几本经典技术书籍
- Mini2440裸机RTC时钟驱动转化为字符串显示
- android 获取屏幕大小和屏幕截图
- IOS 代码创建UI界面
- 【jQuery】使用post()方法以POST方式从服务器发送数据
- IOS NSString NSMutableString 不可变|可变字符串
- 手机端html5触屏事件(touch事件)
- php使用curl访问https
- NSDate iOS 日期