首页 > 其他分享 >定时器设计与蜂鸣器驱动

定时器设计与蜂鸣器驱动

时间:2023-11-14 21:56:05浏览次数:27  
标签:CNT 定时器 蜂鸣器 clk Cnt period 信号 Go 驱动

本节设计一个定时器,能够支持以下功能:

1、该定时器的定时时间参数可以通过该模块的一个端口输入,通过调节端口上输入数据的值,就能修改其定时时间。

2、设置一个计数模式控制信号,当该信号为1时,设置为循环定时模式,当该信号为0时,设置为单次定时模式。

3、设置一个计数启动信号,在循环定时模式下,该信号为高电平使能计时,为低电平则停止计时。在单次计数模式下,该信号的一个单基准时钟周期的脉冲使能一次定时。

4、输出计数器实时计数值,该值将用于产生特定占空比的方波。

1、创建Quartus II工程

1.1、创建工程文件夹目录

image-20231113104425822

prj为工程文件存放目录

rtl为verilog可综合代码

img为设计相关图片存放目录(主要为了方便后期写文档)

doc为设计相关文档存放目录

testbench为对应的testbench存放目录

prj文件夹下的ip文件夹存放quartus ii中生成的ip核文件

1.2、创建项目

打开Quartus II,点击File,选择New Project Wizard

QQ截图20231113104128

选择之前创建好的prj文件夹,并输入项目名称

QQ截图20231113104548

在Device family选项中选择Cyclone IV E

在Pin count选项中选择256

在Speed grade选项中选择8

最后在Available devices选项中选择EP4CE10F17C8,并点击Next

20231113105037

在Simulation仿真工具中,Tool Name选择:ModelSim-Altera,Format(s)选择:Verilog HDL,并点击Next完成项目创建

QQ截图20231113104753

2、编写计数器HDL描述文件

2.1、新建Verilog HDL文件

点击新建文件按钮,选择Verilog HDL File

20231113110252

2.2、编写verilog代码,并进行分析与综合

2.2.1、设置输入端口,并给端口定义输入输出类型

module beep_test(

	Clk,
	Rst_n,

	CNT_ACC,	//定时预设值
	MODE,	//模式控制信号
    Cnt_go,	//计数启动信号
    
    CNT_NOW,	//输出计数器实时计数值
	Full_Flag	//定时完成标志信号
);
    
    //端口类型定义
	input Clk;
	input Rst_n;
	
    input [31:0]CNT_ACC;	//通用定时器,故设置为32位
	input MODE;
	input Cnt_Go;
	
	output [31:0]CNT_NOW;
	output Full_Flag;

    
endmodule

Clk:时钟信号

Rst_n:复位信号

CNT_ACC:设置定时预设时间(32位)

MODE:模式控制信号。当该信号为1时,设置为循环定时模式,当该信号为0时,设置为单次定时模式

Cnt_go:计数启动信号。在循环定时模式下,该信号为高电平使能计时,为低电平则停止计时。在单次计数模式下,该信号的一个单基准时钟周期的脉冲使能一次定时。

CNT_NOW:输出计数器实时计数值。该值将用于产生特定占空比的方波(32位)

Full_Flag:定时完成标志信号

2.2.2、设置计时器功能

reg [31:0]cnt;	//定义一个32位的寄存器用作计数器
reg oneshot;	//单次定时的内部使能信号
wire Full_Flag_r;
	
assign CNT_NOW = cnt;
assign Full_Flag_r = (cnt == CNT_ACC - 1)?1'b1:1'b0;
	
always@(posedge Clk)
    Full_Flag <= Full_Flag_r;
	
//时序逻辑的标准结构:always块
always@(posedge Clk or negedge Rst_n)	//当Clk上升沿或者Rst_n下降沿时,做以下操作
if(!Rst_n)
//当Rst_n低电平时,计数器清零
    cnt <= 0;
else if(MODE == 1'b1)
begin
    if(Cnt_Go == 1'b1 && (cnt < CNT_ACC))
        cnt <= cnt + 1'b1;
    else
        cnt <= 0;
end
else if(!MODE)
begin
    if(oneshot)
        cnt <= cnt + 1'b1;
    else
        cnt <= 0;
end
   	                                                            
always@(posedge Clk or negedge Rst_n)
if(!Rst_n)
    oneshot <= 1'b0;
else if(!MODE)begin
    if(Cnt_Go == 1'b1)
        oneshot <= 1'b1;
    else if(Full_Flag)
        oneshot <= 1'b0;
    else
        oneshot <= oneshot;
end
else
    oneshot <= 1'b0;

2.2.3、将代码保存至rtl文件夹中,并分析与综合

保存完成后,Ctrl+K进行分析与综合,以确保代码正确性

QQ截图20231113210758

2.2.4、查看RTL视图

QQ截图20231113211440

3、编写计数器测试脚本(testbench)

新建一个Verilog文件,并将该文件保存在testbench目录下,注意将文件名改为beep_test_tb

3.1、编写计数器测试脚本:

`timescale 1ns/1ns	//时间精度
`define clk_period 20	//定义系统的时钟周期:20ns(如果未定义,则系统用默认的时钟周期,不便于后期移植)


module beep_test_tb;	//测试模块名称
	
	//产生激励信号
	//input型全部定义为reg型
	reg Clk;
	reg Rst_n;
	
	reg [31:0]CNT_ACC;
	reg MODE;
	reg Cnt_Go;
	
	//output型全部定义为wire型
	wire [31:0]CNT_NOW;
	wire Full_Flag;
	
	//将激励信号与待测试模块的端口连接起来
	beep_test beep_test0(	//设置待测试端口名称为beep_test0
		//在前面加上'.'显示例化格式
		.Clk(Clk),
		.Rst_n(Rst_n),

		.CNT_ACC(CNT_ACC),	
		.MODE(MODE),	
		.Cnt_Go(Cnt_Go),	
		
		.CNT_NOW(CNT_NOW),	
		.Full_Flag(Full_Flag)	
	);
	
	//产生时钟激励信号
	initial Clk = 1;
	always #(`clk_period/2) Clk = ~Clk;	//每10ns翻转一次,一个时钟周期为20ns

	//控制端口
	initial begin	//凡是语句块后面超过一个语句的都要加begin end
		//复位
		Rst_n = 0;
		CNT_ACC = 0;
		MODE = 0;
		Cnt_Go = 0;
		//延时20个系统时钟周期
		#(`clk_period*20 + 1);	//'+1'操作是为了保证复位信号不与Clk信号边沿直接对其,方便观察异步复位功效
		Rst_n = 1;
		#(`clk_period*20);
		
		//让信号产生激励以观测定时器工作状态
		//设置预设值为1000,模式为循环定时模式
		CNT_ACC = 1000;
		MODE = 1;
		#(`clk_period*20);
		Cnt_Go = 1;
		#(`clk_period*12000);
		Cnt_Go = 0;
		#(`clk_period*20);
		
		//设置预设值为600,模式为循环定时模式
		CNT_ACC = 600;
		MODE = 1;
		#(`clk_period*20);
		Cnt_Go = 1;
		#(`clk_period*8000);
		Cnt_Go = 0;
		#(`clk_period*20);
		
		
		
		//设置预设值为1000,模式为单次定时模式
		CNT_ACC = 1000;
		MODE = 0;
		#(`clk_period*20);
		Cnt_Go = 1;
		#(`clk_period);
		Cnt_Go = 0;
		#(`clk_period*1200);
		
		//设置预设值为600,模式为单次定时模式
		CNT_ACC = 1000;
		MODE = 0;
		#(`clk_period*20);
		Cnt_Go = 1;
		#(`clk_period);
		Cnt_Go = 0;
		#(`clk_period*1200);
		
		// 让仿真停止下来
		$stop;
		
	end
	

endmodule

(补充:可以按Ctrl+H进行查找和替换操作)

3.2、按Ctrl+K进行分析与综合

3.3、设置native link关联脚本:

选择Assignments,点击Settings

微信截图_20231114164444

选中Compile test bench,点击Test Benches

选择testbench文件夹中beep_test_tb.v文件,并在Test bench name中输入beep_test_tb

微信图片编辑_20231114165135

最后点击Apply完成脚本关联

微信截图_20231114165025

(补充:ModelSim中,信号的定义必须在使用之前,不然会报错)

4、对计数器进行功能仿真

选中Tools->Run Simulation Tool->RTL Simulation

微信截图_20231114165550

出现波形图:

微信截图_20231114181128

(补充1:如果想更改HDL文件中代码后再进行仿真,步骤如下:)

微信截图_20231114181826

(补充2:如果想加入beef_test.v文件中的信号,步骤如下:)

微信截图_20231114202953

(补充3:如果想对波形进行自动分组,则先Ctrl+A选中所有信号,再Ctrl+G)

5、在Quartus II中执行布局布线

新建一个beef_top文件,并保存在rtl文件夹下

代码如下:

module beep_top(

	Clk,
	Rst_n,

	Cnt_Go,	//计数启动信号 在循环定时模式下,该信号为高电平使能计时,为低电平则停止计时。在单次计数模式下,该信号的一个单基准时钟周期的脉冲使能一次定时
	beep
);

	input Clk;
	input Rst_n;
	
	input Cnt_Go;
	output beep;
	
	wire [31:0]CNT_NOW;
	
	beep_test beep_test0(	

		.Clk(Clk),
		.Rst_n(Rst_n),

		.CNT_ACC(32'd49999),
		.MODE(1),
		.Cnt_Go(Cnt_Go),	//该信号连接按钮
		
		.CNT_NOW(CNT_NOW),
		.Full_Flag()
	);

	assign beep = (CNT_NOW >= 24999)?1'b1:1'b0;

endmodule

将该文件置于顶层,再进行分析与综合,步骤如下图:

微信截图_20231114201519

6、对计数器进行时序仿真

选择Tools->Run Simulation Tool->Gate Level Simulation...进行时序仿真

微信截图_20231114202444

7、分配引脚并编译得到FPGA配置文件.sof

点击Pin Planner图标进行引脚分配

微信截图_20231114201649

分配表如图所示:

微信截图_20231114202141

点击全编译按钮

微信截图_20231114202604

全编译完成后,连接开发板,点击Programmer按钮

微信截图_20231114203603

点击Add File...,选择prj\output_files文件夹中的beep_test.sof文件,点击Open,最后点击Start烧录程序

微信截图_20231114203817

8、配置FPGA并运行

标签:CNT,定时器,蜂鸣器,clk,Cnt,period,信号,Go,驱动
From: https://www.cnblogs.com/little55/p/17832683.html

相关文章

  • Vue 组件里的定时器要怎么销毁?
    如果页面上有很多定时器,可以在data选项中创建一个对象timer,给每个定时器取个名字一一映射在对象timer中,在beforeDestroy构造函数中清除,beforeDestroy(){ for(letkinthis.timer){ clearInterval(k) }}如果页面只有单个定时器,可以这么做consttimer=setInterv......
  • 多屏 显卡 驱动 安装
    驱动下载-旌宇显卡官网(sparklevga.com.cn)旌(jing)旗AMDVER15.7.1系列适用于HD5450,HD7600,R5220,R7350,R7360等系列芯片机种VER15.7.1Windows764bit&win1064bithttps://jyxk-drive.oss-cn-beijing.aliyuncs.com/15.7.1%E9%A9%B1%E5%8A%A8.zip  erwaerwa......
  • centos8 python3 安装达梦驱动 dmpython
    方案一全新安装:1.https://eco.dameng.com/download/下载dm8_20231011_x86_rh6_64.iso到/aaa目录2.创建用户所在的组groupadddinstall3.创建用户useradd-gdinstall-m-d/home/dmdba-s/bin/bashdmdba4.修改用户密码passwddmdba5.修改文件打开最大数vi/etc/sec......
  • 聊聊定时器 setTimeout 的时延问题
    全局的 setTimeout()  方法设置一个定时器,一旦定时器到期,就会执行一个函数或指定的代码片段,但是需要注意的是,setTimeout 并不是 ECMAScript 标准的一部分,不过几乎每一个JS运行时都支持了这个函数。定时器的使用比较简单,这里不再阐述,我们这篇文章主要聊下关于setTimeout有......
  • 双通道 H 桥电机驱动芯片AT8833,软硬件兼容替代DRV8833
    上期小编给大家分享了单通道H桥电机驱动芯片,现在来讲一讲双通道的驱动芯片。双通道H桥电机驱动芯片能通过控制电机的正反转、速度和停止等功能,实现对电机的精确控制。下面介绍双通道H桥电机驱动芯片的工作原理和特点。一、工作原理双通道H桥电机驱动芯片是由多个晶体管和......
  • 2.3 Windows驱动开发:内核字符串转换方法
    在内核编程中字符串有两种格式ANSI_STRING与UNICODE_STRING,这两种格式是微软推出的安全版本的字符串结构体,也是微软推荐使用的格式,通常情况下ANSI_STRING代表的类型是char*也就是ANSI多字节模式的字符串,而UNICODE_STRING则代表的是wchar*也就是UNCODE类型的字符,如下文章将介绍这......
  • 2.4 Windows驱动开发:内核字符串拷贝与比较
    在上一篇文章《内核字符串转换方法》中简单介绍了内核是如何使用字符串以及字符串之间的转换方法,本章将继续探索字符串的拷贝与比较,与应用层不同内核字符串拷贝与比较也需要使用内核专用的API函数,字符串的拷贝往往伴随有内核内存分配,我们将首先简单介绍内核如何分配堆空间,然后再以......
  • Arduino之TFT_eSPI驱动彩色LCD屏
    原文:https://blog.csdn.net/qq_45355603/article/details/132298259一、TFT_eSPI库简介1.1安装TFT_eSPI库在User_Setup.h中进行个人屏幕参数的配置: User_Setup.h TFT驱动板 备注TFT_MISO 无 TFT_MOSI SDA TFT_SCLK CLK TFT_CS CS 液晶屏片选信号,低电平使能TFT_DC RS ......
  • go使用定时器
    go使用定时器packagemainimport( "fmt" "os" "os/signal" "syscall" "time")funcmain(){ initTask()}funcstop(ticker*time.Ticker){ //创建一个通道来接收信号 sigCh:=make(chanos.Signal,1) //监听指定的信号 si......
  • HDMI 显示器驱动设计
    1.理论HDMI简介   VGA接口体积较大;且传输的模拟信号易受外界干扰。因此在VGA接口之后,首先推出的是DVI接口,DVI是基于TMDS(TransitionMinimizedDifferentialSignaling,最小化传输差分信号)技术来传输数字信号。   DVI接口设计之初考虑的对象是PC,对于平板电......