小梅哥FPGA设计思想与验证方法视频教程之数码管动态扫描设计与实现
大家好,今天,小梅哥继续连载本人精心录制和编辑的FPGA学习系列教程——《小梅哥FPGA设计思想与验证方法视频教程》。教程充分考虑0基础朋友的实际情况,手把手带领学习者分析思路、编写代码、仿真验证、板级调试。教语法,学仿真,一步一步,直到最后设计若干较为综合的逻辑系统。
教程以我们自主开发的芯航线FPGA学习板为实验平台,通过若干基础和综合的系统设计讲解,一步一步掌握FPGA设计与验证的思想和方法,希望了解芯航线FPGA学习板的,请点击这里:
http://z.elecfans.com/1?ck=snow
今天是视频第十讲,主要通过讲解数码管动态扫描原理,并提取出实现的电路结构,从电路结构入手编写代码,仿真对设计进行验证,最终板级调试时,使用In system sources and probes editor调试工具设置需要显示的内容,则数码管显示对应的数值。本节课与前面课程的风格稍有不同,本节课代码不再是核心,核心是电路结构,电路结构确定后编写代码只是照图施工的过程。这也是越来越接近FPGA设计的底层思维。希望大家仔细体会。
接下来,大家请看视频教程,由于视频中有部分网络的链接,因此上传优酷会被屏蔽,这里就直接分享在百度云盘中了。欢迎大家转载观看。(1280*720分辨率,MP4格式,用手机观看效果非常爽哦,建议大家下载了再观看)
好消息:
从此再也不需要一个一个回复才能看下载地址了
全部开源视频下载地址:
http://pan.baidu.com/s/1kUs0vkF
视频教程中配套源码下载地址:
http://pan.baidu.com/s/1qX5hz9y
觉得好的,记得回来帮忙顶个帖哦
?欢迎加入芯航线FPGA技术支持群:472607506
小梅哥
2015年9月30日星期三
芯航线电子工作室
按照梅总的思路,将案件消抖+7段数码管结合起来做一个随机数产生的小玩具,输入两个按钮,一个start,按下开始以50mhz频率计数,一个pause按钮,按下暂停计数,得到的数马马虎虎就算作随机数。
上代码,这个是顶层模块
- module key_hex8 (
- clk,
- rst_n,
- key_start,
- key_pause,
- sel,
- seg
- );
- input clk;
- input rst_n;
- input key_start;
- input key_pause;
- output [7:0] sel;
- output [6:0] seg;
- wire start_key_flag;
- wire pause_key_flag;
- wire[31:0] disp_data;
- key_filter start_key(
- .Clk(clk),
- .Rst_n(rst_n),
- .key_in(key_start),
- .key_flag(start_key_flag),
- .key_state()
- );
- key_filter pause_key(
- .Clk(clk),
- .Rst_n(rst_n),
- .key_in(key_pause),
- .key_flag(pause_key_flag),
- .key_state()
- );
- ctrl my_ctrl(
- .clk(clk),
- .rst_n(rst_n),
- .key_start_flag(start_key_flag),
- .key_pause_flag(pause_key_flag),
- .disp_data(disp_data)
- );
- HXE8 my_Hxe8(
- .Clk(clk),
- .Rst_n(rst_n),
- .En(1),
- .disp_data(disp_data),
- .sel(sel),
- .seg(seg)
- );
- endmodule
这个是梅总的按键消抖模块,中文注释乱码。请梅总自己解决
- module key_filter(Clk,Rst_n,key_in,key_flag,key_state);
- input Clk;
- input Rst_n;
- input key_in;
-
- output reg key_flag;
- output reg key_state;
-
- localparam
- IDEL = 4'b0001,
- FILTER0 = 4'b0010,
- DOWN = 4'b0100,
- FILTER1 = 4'b1000;
-
- reg [3:0]state;
- reg [19:0]cnt;
- reg en_cnt; //浣胯兘璁℃暟瀵勫瓨鍣?
-
- //瀵瑰閮ㄨ緭鍏ョ殑寮傛淇″彿杩涜鍚屾澶勭悊
- reg key_in_sa,key_in_sb;
- always@(posedge Clk or negedge Rst_n)
- if(!Rst_n)begin
- key_in_sa <= 1'b0;
- key_in_sb <= 1'b0;
- end
- else begin
- key_in_sa <= key_in;
- key_in_sb <= key_in_sa;
- end
-
- reg key_tmpa,key_tmpb;
- wire pedge,nedge;
- reg cnt_full;//璁℃暟婊℃爣蹇椾俊鍙?
-
- //浣跨敤D瑙﹀彂鍣ㄥ瓨鍌ㄤ袱涓浉閭绘椂閽熶笂鍗囨部鏃跺閮ㄨ緭鍏ヤ俊鍙凤紙宸茬粡鍚屾鍒扮郴缁熸椂閽熷煙涓級鐨勭數骞崇姸鎬?
- always@(posedge Clk or negedge Rst_n)
- if(!Rst_n)begin
- key_tmpa <= 1'b0;
- key_tmpb <= 1'b0;
- end
- else begin
- key_tmpa <= key_in_sb;
- key_tmpb <= key_tmpa;
- end
- //浜х敓璺冲彉娌夸俊鍙?
- assign nedge = !key_tmpa & key_tmpb;
- assign pedge = key_tmpa & (!key_tmpb);
-
- always@(posedge Clk or negedge Rst_n)
- if(!Rst_n)begin
- en_cnt <= 1'b0;
- state <= IDEL;
- key_flag <= 1'b0;
- key_state <= 1'b1;
- end
- else begin
- case(state)
- IDEL :
- begin
- key_flag <= 1'b0;
- if(nedge)begin
- state <= FILTER0;
- en_cnt <= 1'b1;
- end
- else
- state <= IDEL;
- end
-
- FILTER0:
- if(cnt_full)begin
- key_flag <= 1'b1;
- key_state <= 1'b0;
- en_cnt <= 1'b0;
- state <= DOWN;
- end
- else if(pedge)begin
- state <= IDEL;
- en_cnt <= 1'b0;
- end
- else
- state <= FILTER0;
-
- DOWN:
- begin
- key_flag <= 1'b0;
- if(pedge)begin
- state <= FILTER1;
- en_cnt <= 1'b1;
- end
- else
- state <= DOWN;
- end
-
- FILTER1:
- if(cnt_full)begin
- key_flag <= 1'b1;
- key_state <= 1'b1;
- state <= IDEL;
- end
- else if(nedge)begin
- en_cnt <= 1'b0;
- state <= DOWN;
- end
- else
- state <= FILTER1;
-
- default:
- begin
- state <= IDEL;
- en_cnt <= 1'b0;
- key_flag <= 1'b0;
- key_state <= 1'b1;
- end
-
- endcase
- end
-
-
- always@(posedge Clk or negedge Rst_n)
- if(!Rst_n)
- cnt <= 20'd0;
- else if(en_cnt)
- cnt <= cnt + 1'b1;
- else
- cnt <= 20'd0;
-
- always@(posedge Clk or negedge Rst_n)
- if(!Rst_n)
- cnt_full <= 1'b0;
- else if(cnt == 999_999)
- cnt_full <= 1'b1;
- else
- cnt_full <= 1'b0;
- endmodule
这个是梅总的7段显示模块
- module HXE8(Clk,Rst_n,En,disp_data,sel,seg);
- input Clk; //50M
- input Rst_n;
- input En; //鏁扮爜绠℃樉绀轰娇鑳斤紝1浣胯兘锛?鍏抽棴
-
- input [31:0]disp_data;
-
- output [7:0] sel;//鏁扮爜绠′綅閫夛紙閫夋嫨褰撳墠瑕佹樉绀虹殑鏁扮爜绠★級
- output reg [6:0] seg;//鏁扮爜绠℃閫夛紙褰撳墠瑕佹樉绀虹殑鍐呭锛?
-
- reg [14:0]divider_cnt;//25000-1
-
- reg clk_1K;
- reg [7:0]sel_r;
-
- reg [3:0]data_tmp;//鏁版嵁缂撳瓨
- // 鍒嗛璁℃暟鍣ㄨ鏁版ā鍧?
- always@(posedge Clk or negedge Rst_n)
- if(!Rst_n)
- divider_cnt <= 15'd0;
- else if(!En)
- divider_cnt <= 15'd0;
- else if(divider_cnt == 24999)
- divider_cnt <= 15'd0;
- else
- divider_cnt <= divider_cnt + 1'b1;
- //1K鎵弿鏃堕挓鐢熸垚妯″潡
- always@(posedge Clk or negedge Rst_n)
- if(!Rst_n)
- clk_1K <= 1'b0;
- else if(divider_cnt == 24999)
- clk_1K <= ~clk_1K;
- else
- clk_1K <= clk_1K;
-
- //8浣嶅惊鐜Щ浣嶅瘎瀛樺櫒
- always@(posedge clk_1K or negedge Rst_n)
- if(!Rst_n)
- sel_r <= 8'b0000_0001;
- else if(sel_r == 8'b1000_0000)
- sel_r <= 8'b0000_0001;
- else
- sel_r <= sel_r << 1;
-
- always@(*)
- case(sel_r)
- 8'b0000_0001:data_tmp = disp_data[3:0];
- 8'b0000_0010:data_tmp = disp_data[7:4];
- 8'b0000_0100:data_tmp = disp_data[11:8];
- 8'b0000_1000:data_tmp = disp_data[15:12];
- 8'b0001_0000:data_tmp = disp_data[19:16];
- 8'b0010_0000:data_tmp = disp_data[23:20];
- 8'b0100_0000:data_tmp = disp_data[27:24];
- 8'b1000_0000:data_tmp = disp_data[31:28];
- default:data_tmp = 4'b0000;
- endcase
-
- always@(*)
- case(data_tmp)
- 4'h0:seg = 7'b1000000;
- 4'h1:seg = 7'b1111001;
- 4'h2:seg = 7'b0100100;
- 4'h3:seg = 7'b0110000;
- 4'h4:seg = 7'b0011001;
- 4'h5:seg = 7'b0010010;
- 4'h6:seg = 7'b0000010;
- 4'h7:seg = 7'b1111000;
- 4'h8:seg = 7'b0000000;
- 4'h9:seg = 7'b0010000;
- 4'ha:seg = 7'b0001000;
- 4'hb:seg = 7'b0000011;
- 4'hc:seg = 7'b1000110;
- 4'hd:seg = 7'b0100001;
- 4'he:seg = 7'b0000110;
- 4'hf:seg = 7'b0001110;
- endcase
-
- assign sel = (En)?sel_r:8'b0000_0000;
- endmodule
这个是我写的控制模块
- module ctrl(
- clk,
- rst_n,
- key_start_flag,
- key_pause_flag,
- disp_data
- );
- input clk;
- input rst_n;
- input key_start_flag;
- input key_pause_flag;
- output[31:0] disp_data;
- reg pause;//0计数,1停止
- always @(posedge clk or negedge rst_n)begin
- if(rst_n==1'b0)begin
- pause <= 1'b1;
- end
- else begin
- if( key_start_flag ) pause <= 1'b0;
- else if( key_pause_flag ) pause <= 1'b1;
- else ;
- end
- end
- reg[31:0] cnt;
- always @(posedge clk or negedge rst_n)begin
- if(rst_n==1'b0)begin
- cnt <= 0;
- end
- else begin
- if( ~pause ) cnt <= cnt + 1'd1;
- else ;
- end
- end
- assign disp_data = cnt;
- endmodule
节下来是testbench
- `timescale 1 ns/1 ns
- module key_hex8_tb();
- //时钟和复位
- reg clk ;
- reg rst_n;
- //uut的输入信号
- reg key_start;
- reg key_pause;
- //uut的输出信号
- wire [7:0] sel;
- wire [6:0] seg;
- //时钟周期,单位为ns,可在此修改时钟周期。
- parameter CYCLE = 20;
- //复位时间,此时表示复位3个时钟周期的时间。
- parameter RST_TIME = 3 ;
- //待测试的模块例化
- key_hex8 my_key_hex8(
- .clk(clk),
- .rst_n(rst_n),
- .key_start(key_start),
- .key_pause(key_pause),
- .sel(sel),
- .seg(seg)
- );
- //生成本地时钟50M
- initial begin
- clk = 0;
- forever
- #(CYCLE/2)
- clk=~clk;
- end
- //产生复位信号
- initial begin
- rst_n = 1;
- #2;
- rst_n = 0;
- #(CYCLE*RST_TIME);
- rst_n = 1;
- end
- reg[9:0] my_rand;
- //输入信号赋值
- initial begin
- #1;
- //赋初值
- key_start = 1;
- key_pause = 1;
- #(10*CYCLE);
- //开始赋值
- repeat(5) begin
- key_start_jetter;
- my_rand = {$random}%1024;
- #(my_rand*CYCLE);
- key_pause_jetter;
- end
- $stop;
- end
- task key_start_jetter;
- begin
- repeat(50) begin
- my_rand = {$random}%1024;
- #(my_rand*CYCLE) key_start = ~key_start;
- end
- key_start = 0;
- #(2_000_000*CYCLE);
- repeat(50) begin
- my_rand = {$random}%1024;
- #(my_rand*CYCLE) key_start = ~key_start;
- end
- key_start = 1;
- #(2_000_000*CYCLE);
- end
- endtask
- task key_pause_jetter;
- begin
- repeat(50) begin
- my_rand = {$random}%1024;
- #(my_rand*CYCLE) key_pause = ~key_pause;
- end
- key_pause = 0;
- #(2_000_000*CYCLE);
- repeat(50) begin
- my_rand = {$random}%1024;
- #(my_rand*CYCLE) key_pause = ~key_pause;
- end
- key_pause = 1;
- #(2_000_000*CYCLE);
- end
- endtask
- endmodule
最后从多个角度看波形结果:
1.总图

2.第一次按下开始计数

3.第一次按下暂停计数

4.第二次按下开始计数

顶,小梅哥,讲的不错,看了你的视频,很感谢
谢谢鼓励和支持
谢谢梅哥{:1:
支持!感觉小梅哥讲的视频把老师一学期讲的课给概括了!点赞!
持续关注小梅哥的视频中。
小梅哥FPGA设计思想与验证方法视频教程
好好好好好好好好好好好好好好好好好好好好
小梅哥FPGA设计思想与验证方法视频教程之高性能计数器IP核使用
好的学习方法,好的视频。
非常感谢!想学习一下
很好 以后就用它来学习了
阿迪王大伟大伟啊我日好噶1
谢谢分享!谢谢分享!谢谢分享!谢谢分享!
棒棒的,大力支持
谢谢分享!十分感谢
好。。
谢谢小编分享,
謝謝分享......
学习
把小梅哥的视频都保存了
谢谢小美哥的东西分享
小梅哥FPGA设计思想与验证方法视频教程
谢谢,学习一下~~~~~~~~~~
支持。。
支持!感觉小梅哥讲的视频把老师一学期讲的课给概括了!点赞!
支持!感觉小梅哥讲的视频把老师一学期讲的课给概括了!点赞!
谢谢分享。
继续学习第十弹
小梅哥讲得不错哦。
顶,小梅哥,讲的不错
挺好的视频,看看啊
謝謝分享......
跟着小梅哥学FPGA
学习ing。
支持支持~~~请继续加油
持续关注小梅哥的视频中。
小编好人,小编真棒 真棒真棒真棒真棒真棒
接下来,大家请看视频教程,由于视
一直在看小梅哥的视频,很详细,从中能学到不少东西
这几天持续学习中
11111111111111111111111111111111111111111111111111111111111111
顶,很感谢,很好的视频
谢谢分享,希望能学到更多知识
,不错期待后续视频
不错期待后续视频;请问小梅哥有没有usb,以太网这样的教程呢
谢谢~~~~~~~~~~~~~~
支持小梅哥的教程
看看了....
bucoo bucuo 学习 虚席
谢谢分享,希望能学到更多知识
谢谢小梅哥的分享,连载视频给了我很大的帮助,我一定会学好FPGA的。
持续关注小梅哥的视频中。
我下了次序有点乱
讲的不错,继续下载
用这个练习不错,尤其是testbench写得佷威武
