基于FPGA的简易数字频率计+上板测试(小梅哥AC620FPGA开发板)
基于FPGA的简易数字频率计+上板测试(小梅哥AC620FPGA开发板
- 目录
- 主要架构
- 1.计数模块
- 2.数码显示模块
- 3.控制信号模块
- 4.分频模块
- 例化模块
- 上板测试图
- 附:74HC595移位寄存器解析(图片)
目录
主要架构
数字频率计的原理很简单,就是计算每秒钟内待测信号的脉冲个数,按照分模块设计的思想,分为:1.计数模块,2.数码管显示模块,3.控制信号模块,4.分频模块。
1.计数模块
计数器用BCD计数器,根据测量频率最大为50M,设计出计数器电路由8个4位BCD计数器级联实现。
2.数码显示模块
BCD计数器的输出值为4位BCD码,经过显示译码电路送至数码管,显示译码电路通过查找表LUT设计方法实现;8位数码管同时显示8个不同的值需要通过16个IO(8位位选,8位段选)动态扫描显示,扫描间隔为1ms,AC620实验板上为了节省IO,通过两片74HC595(串行移位寄存器,可上网查看数据手册)实现串并转换,将16位串行数据转换为16位并行数据,所以采用三个IO口(工作频率SCK,存储频率RCK,数据线DIO)就可以实现数码管动态扫描显示,查阅74HC595数据手册可知,3.3V电压时工作频率SCK为1.25M。
BCD计数器代码:
module BCDcounter(clk,rst_n,en,cin,cout,q);input clk; //待测信号input rst_n; //复位信号input en; //使能信号input cin; //进位输入output reg cout; //进位输出output [3:0]q; //BCD码输出reg [3:0]cnt; //四位计数器//计数器模块(对cin计数,计到9的时候清零)always@(posedge clk,negedge rst_n)if(!rst_n)cnt <= 4'd0;else if(en)beginif(cin == 1'b1)beginif(cnt == 4'd9)cnt <= 4'd0;elsecnt <= cnt + 1'b1;endelsecnt <= cnt;end//产生进位信号always@(posedge clk,negedge rst_n)if(!rst_n)cout <= 1'b0;else if(en)beginif(cin == 1'b1 && cnt == 4'd8)cout <= 1'b1;elsecout <= 1'b0;end//BCD计数器输出assign q = cnt;
endmodule
74HC595驱动代码:
module HC595driver(clk,rst_n,en,seg,sel,sck,rck,si);input clk; //系统时钟信号input rst_n; //复位信号input en; //使能信号input [7:0]seg; //数据输入input [7:0]sel; //数据输入output reg sck; //移位寄存器控制脉冲output reg rck; //输出寄存器控制脉冲output reg si; //串行数据输出parameter CNT_MAX = 4; //HC595工作频率,50M时钟分频数reg [15:0] divider_cnt; //分频计数器reg [4:0]SCK_edge_cnt; //四位计数器//分频计数器模块always@(posedge clk,negedge rst_n)if(!rst_n)divider_cnt <= 16'd0;else if(divider_cnt == CNT_MAX)divider_cnt <= 16'd0;elsedivider_cnt <= divider_cnt + 1'b1;//对clk进行4分频,输出为sck_plusewire sck_pluse;assign sck_pluse = (divider_cnt == CNT_MAX);//对sck_pluse进行计数,用于查找表实现数据的串行输入以及移位时钟sck与存储时钟rck的产生always@(posedge clk,negedge rst_n)if(!rst_n)SCK_edge_cnt <= 5'd0;else if(sck_pluse)beginif(SCK_edge_cnt == 5'd31)SCK_edge_cnt <= 5'd0;elseSCK_edge_cnt <= SCK_edge_cnt + 1'b1;endelseSCK_edge_cnt <= SCK_edge_cnt;//利用查找表产生sck,rck,si脉冲,将16位数据从最高位至最低位送入并输出always@(posedge clk,negedge rst_n)if(!rst_n)beginsck <= 1'b0;rck <= 1'b0;si <= 1'b0;endelse begincase(SCK_edge_cnt)5'd0:begin sck <= 1'b0;rck <= 1'b1;si <= seg[7]; end5'd1:begin sck <= 1'b1;rck <= 1'b0; end5'd2:begin sck <= 1'b0;si <= seg[6]; end5'd3:begin sck <= 1'b1; end5'd4:begin sck <= 1'b0;si <= seg[5]; end5'd5:begin sck <= 1'b1; end5'd6:begin sck <= 1'b0;si <= seg[4]; end5'd7:begin sck <= 1'b1; end5'd8:begin sck <= 1'b0;si <= seg[3]; end5'd9:begin sck <= 1'b1; end5'd10:begin sck <= 1'b0;si <= seg[2]; end5'd11:begin sck <= 1'b1; end5'd12:begin sck <= 1'b0;si <= seg[1]; end5'd13:begin sck <= 1'b1; end5'd14:begin sck <= 1'b0;si <= seg[0]; end5'd15:begin sck <= 1'b1; end5'd16:begin sck <= 1'b0;si <= sel[7]; end5'd17:begin sck <= 1'b1; end5'd18:begin sck <= 1'b0;si <= sel[6]; end5'd19:begin sck <= 1'b1; end5'd20:begin sck <= 1'b0;si <= sel[5]; end5'd21:begin sck <= 1'b1; //送入数据end5'd22:begin sck <= 1'b0;si <= sel[4]; end5'd23:begin sck <= 1'b1; end5'd24:begin sck <= 1'b0;si <= sel[3]; end5'd25:begin sck <= 1'b1; end5'd26:begin sck <= 1'b0;si <= sel[2]; end5'd27:begin sck <= 1'b1; end5'd28:begin sck <= 1'b0;si <= sel[1]; end5'd29:begin sck <= 1'b1; end5'd30:begin sck <= 1'b0;si <= sel[0]; end5'd31:beginsck <= 1'b1; endendcaseend
endmodule
8位数码管显示代码:
module HEX8(clk,rst_n,en,disp_data,sel,seg);input clk; //系统时钟信号50Minput rst_n; //复位信号input en; //数码管显示使能信号 1使能,0关闭input [31:0]disp_data; //8位数码管待显示的数据output [7:0]sel; //位选输出output reg[7:0]seg; //段选输出reg [15:0]divider_cnt;reg clk_1k;reg [7:0]sel_r;reg [3:0]data_tmp;//分频器计数器模块always@(posedge clk,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;elsedivider_cnt <= divider_cnt + 1'b1;//利用分频器产生1khz时钟 always@(posedge clk,negedge rst_n)if(!rst_n)clk_1k <= 1'b0;else if(!en)clk_1k <= 1'b0;else if(divider_cnt == 24999)clk_1k <= ~clk_1k;else clk_1k <= clk_1k;//8位循环移位寄存器模块always@(posedge clk_1k,negedge rst_n)if(!rst_n)sel_r <= 8'b0000_0001;else if(sel_r == 8'b1000_0000)sel_r <= 8'b0000_0001;elsesel_r <= sel_r << 1;//8路数据选择器模块,选择数码管段选数据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//数码管显示译码器模块(LUT查找表)always@(*)case(data_tmp)4'h0: seg = 8'b1100_0000;4'h1: seg = 8'b1111_1001;4'h2: seg = 8'b1010_0100;4'h3: seg = 8'b1011_0000;4'h4: seg = 8'b1001_1001;4'h5: seg = 8'b1001_0010;4'h6: seg = 8'b1000_0010;4'h7: seg = 8'b1111_1000;4'h8: seg = 8'b1000_0000;4'h9: seg = 8'b1001_0000;4'ha: seg = 8'b1000_1000;4'hb: seg = 8'b1000_0011;4'hc: seg = 8'b1100_0110;4'hd: seg = 8'b1010_0001;4'he: seg = 8'b1000_0110;4'hf: seg = 8'b1000_1110;endcase//二选一数据选择器,位选输出assign sel = en?sel_r:8'b0000_0000;endmodule
3.控制信号模块
(1)待测信号控制脉冲 —— 产生高电平时长为1s的门控信号,和待测信号经过与门;起到控制待测脉冲到达计数器的作用
(2)锁存信号控制脉冲 —— 计数器在门控信号为低电平时需要清零,以便下次计数,数码管上显示的数据需要保持,通过设计一个32位锁存器实现;在门控信号高脉冲结束时将数据送至锁存器供数码管显示
(3)计数器复位脉冲 —— 将计数结果送至锁存器后,需要将计数器清零
信号产生代码:
module signal(clk,rst_n,signal_10hz,signal_25khz,signal_50mhz,led_test);input clk; //系统时钟input rst_n; //系统复位信号output reg signal_10hz; //10hz测试信号output reg signal_25khz; //25khz测试信号output reg signal_50mhz; //50M测试信号output reg led_test; //信号输出指示灯reg [21:0]cnt;reg [9:0]cnt2;//计数器模块always@(posedge clk,negedge rst_n)if(!rst_n)cnt <= 22'd0;else if(cnt == 22'd2499999)cnt <= 22'd0;elsecnt <= cnt + 1'b1;//利用计数器模块产生10hz脉冲always@(posedge clk,negedge rst_n)if(!rst_n)signal_10hz <= 1'b0;else if(cnt == 22'd2499999)signal_10hz <= ~signal_10hz;else signal_10hz <= signal_10hz;always@(*)led_test <= signal_10hz; //信号输出指示灯//计数器模块always@(posedge clk,negedge rst_n)if(!rst_n)cnt2 <= 10'd0;else if(cnt2 == 10'd999) cnt2 <= 10'd0;elsecnt2 <= cnt2 + 1'b1;//利用计数器模块产生25khz脉冲always@(posedge clk,negedge rst_n)if(!rst_n)signal_25khz <= 1'b0;else if(cnt2 == 10'd999)signal_25khz <= ~signal_25khz;else signal_25khz <= signal_25khz;always@(*) signal_50mhz <= clk;
endmodule
4.分频模块
系统需要0.5hz的门控信号,1hz的脉冲信号,利用分频器将50M系统时钟分频得到
module console(clk,rst_n,clk_1hz,en_cnt,load,rst_cnt);input clk; //系统时钟50Minput rst_n; //系统复位信号output reg clk_1hz; //输出到clk_1hz引脚output reg en_cnt; //输出到en_cnt引脚output reg load; //输出到load引脚output rst_cnt; //输出到rst_cnt引脚
//clk_1hz以1hz的频率闪烁,也就是每500ms翻转一次;时钟周期是20ns,所以应该计数25_000_000次;需要一个25位的寄存器reg [24:0]cnt;//计数器模块always@(posedge clk,negedge rst_n)if(!rst_n)cnt <= 25'd0;else if(cnt == 25'd24_999_999) //进行仿真的时候可以用24_999;只是功能仿真cnt <= 25'd0;elsecnt <= cnt + 1'b1;
//利用计数器模块产生1hz脉冲always@(posedge clk,negedge rst_n)if(!rst_n)clk_1hz <= 1'b0;else if(cnt == 25'd24_999_999)clk_1hz <= ~clk_1hz;else clk_1hz <= clk_1hz;//产生en_cnt信号always@(posedge clk_1hz,negedge rst_n)if(!rst_n)en_cnt <= 1'b0;else en_cnt <= ~en_cnt;//产生load信号always@(*)load <= ~en_cnt;//产生rst_load信号assign rst_cnt = (clk_1hz || en_cnt);
endmodule
例化模块
module digital_frequency_meter(clk,rst_n,fin,sck,rck,si,led1,led2,signal_10hz,signal_25khz,signal_50mhz);
wire en_cnt; //计数器使能信号(0.5hz 高电平时长为1s)wire load; //锁存信号(控制计数器数据输出到数码管)wire rst_cnt; //BCD计数器清零信号wire [31:0]data_temp; //计数器与数码管待显示数据的中间变量reg [31:0]data_lock; //32位锁存寄存器(锁存数码管待显示数据)//例化信号产生模块signal signal(.clk(clk),.rst_n(rst_n),.signal_10hz(signal_10hz),.signal_25khz(signal_25khz),.signal_50mhz(signal_50mhz),.led_test(led2));/例化频率计信号控制模块console console(.clk(clk),.rst_n(rst_n),.clk_1hz(led1),.en_cnt(en_cnt),.load(load),.rst_cnt(rst_cnt));//例化BCD计数器模块(8个)(计数器输出数据是data_temp)BCDcounter_top BCDcounter_top_test(.clk(fin),.rst_n(rst_cnt),.en(en_cnt),.cin(1'b1),.cout(),.q(data_temp));//32位输出数据锁存器(在load的上升沿将输出数据更新,否则锁存,数据不变)always@(posedge load,negedge rst_n)if(!rst_n)data_lock <= 32'd0;elsedata_lock <= data_temp;//例化数码管显示模块(数码管显示的是data_lock中的数据)HEX8_top HEX8_top(.clk(clk),.rst_n(rst_n),.en(1'b1),.disp_data(data_lock),.sck(sck),.rck(rck),.si(si));
endmodule
RTL:
上板测试图
附:74HC595移位寄存器解析(图片)
AC620 的8位数码管连接方式:
基于FPGA的简易数字频率计+上板测试(小梅哥AC620FPGA开发板)相关推荐
- 基于小梅哥AC620开发板的NIOS II LWIP百兆以太网例程移植到自己做的板子上
原程序是运行在小梅哥AC620开发板上的:基于小梅哥AC620开发板的NIOS II LWIP百兆以太网例程_ZLK1214的专栏-CSDN博客_小梅哥ac620[开发板]开发板型号:小梅哥AC620 ...
- 单片机c语言数字频率计的课程设计,基于单片机的简易数字频率计设计报告(最终版)最新版...
<基于单片机的简易数字频率计设计报告.doc>由会员分享,可免费在线阅读全文,更多与<基于单片机的简易数字频率计设计报告(最终版)>相关文档资源请在帮帮文库(www.woc88 ...
- 基于FPGA的简易DDS信号发生器的设计与验证
基于FPGA的简易DDS信号发生器的设计与验证 一,理论介绍 补充:举例理解 二,代码实现 1,实验目标 2,MATLAB代码 3,verilog代码及实现思路 一,理论介绍 DDS 是直接数字式频率 ...
- 基于FPGA的简易DDS信号发生器的设计(一)
写这篇文章的本意不是为了探讨AD9767怎么使用,因为9767的控制实在是太简单了,准备好数据直接输出即可,和网上大多数的并行DA输出基本上一模一样,更麻烦的反而是硬件方面.发文的原因是最近一位很细心 ...
- 频谱仪设计基于FPGA的频谱仪设计,可以测试分析多种频率的频谱,分辨率100HZ
频谱仪设计基于FPGA的频谱仪设计,可以测试分析多种频率的频谱,分辨率100HZ,配套资料多达100M,东西复杂 ID:982500594354361311卡哇伊2号小宝贝
- arduinopn532模块_NFC开发板/nfc芯片标签/PN532开发板/RFID读卡器/NFC模块/Arduino
带40 kB ROM和1 kB RAM的80C51微控制器内核 高度集成的模拟电路,解调和译码响应 输出缓冲驱动器通过非常少量的外部无源器件连接天线 集成了RF场检测器 集成了数据模式检测器 支持IS ...
- 选择的串口 _ 不存在或开发板没有连接_PC 和开发板之间传输文件
8.1 传输文件的多种方法 在嵌入式开发中,涉及交叉编译:在 PC 上编译,在开发板上运行.所以就涉及 PC 和开发板之间的文件 传输,方法有多种:网络传输.串口传输.USB 传输,当然,还有最笨的方 ...
- micropython开发板性能_MicroPython支持的开发板:高性能、低成本创客首选
原标题:MicroPython支持的开发板:高性能.低成本创客首选 Python的开放.简洁.黏合正符合了现发展阶段对大数据分析.可视化.各种平台程序协作产生了快速的促进作用.自Python3的发布到 ...
- 玩转开发板--Linux系统移植至开发板fl2440实践过程
一.开发板介绍 CPU:S3C2440(SAMSUNG).ARM920T.400MHz Pone/mic:耳机和话筒 JTAG:可以通过外部插入直接控制CPU,因此在初始化内存时,起到 ...
最新文章
- 查询数据(使用聚合函数,还是单表)
- Windows 技术篇-设置dns提升网速,刷新dns缓存
- 卡夫卡编年史队列基准
- [JavaScript]return false;和e.preventDefault();的区别
- hadoop为什么出现
- Remote branch Develop not found in upstream origin
- 根据一个id查找出数组里面的数据并改掉_Excel最强大的VLOOKUP以及INDEXamp;MATCH查找函数...
- 关于[知识竞赛现场管理系统-双屏PPT版]内置的第三方答题平台以及[评委计分系统-双屏专业版]的特殊疑难问题 汇编
- 基于JQUERY的WEB在线流程图设计器GOOFLOW 0.5版 数据值解析
- 环保线绕电阻器的主要特性和应用分析
- Fiddler https最新抓包方法(Android 9.0)
- c语言中if函数作用,c语言函数if的用法怎么用
- cogs426 血帆海盗 最小割定理
- ios 图片合成幻灯片_为iPad构建iOS幻灯片应用程序
- stm32h7 串口idle_【STM32H7教程】第30章 STM32H7的USART应用之八个串口FIFO实现
- (Tekla Structures二次开发)创建多边形板
- Qpython SL4A服务调用GPS定位获取获取位置信息
- 普通pc机的轻连接到底能建多少?
- 撒旦撒旦阿三的撒的撒
- 巴西支付Boleto对巴西外贸有多重要!?