您的位置:首页 > 其它

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是硬件,一定要记住并发这个概念。

三、时钟分频模块

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、暂时就想到这些,第一次写,有什么不足的地方往大家多多指点,下一篇文章使用原理图的方式来设计顶层。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: