Verilog学习记录(三):相邻点累加与简单状态机

1.相邻点累加

        相邻点累加,顾名思义就是将相邻的点相加求和,本次实验使用的是相邻点十六位累加。其中的data_in为输入信号,也就是要累加的点。sys_in为采样时钟。在输入位考虑到会有正数和负数,所以需要首先转换成补码。然后由于十六位二进制数相加,所以我们需要对其升位,将原来的八位二进制升到十二位防止溢出。相应的波形图如下:

 

 代码编写如下:

//2023.4.14  Bread
//相邻点累加
`timescale 1ns/1ps
module sigma_16P(
				clk,
				rst,
				data_in,
				syn_in,
				data_out,
				syn_out
				);
input			clk;
input			rst;
input[7:0]		data_in;//采样信号
input			syn_in;//采样时钟
output[11:0]	data_out;//累加结果输出
output			syn_out;//累加结果同步脉冲

reg				syn_in_n1;//syn_in反向延时
wire			syn_pulse;//采样时钟上升沿识别脉冲
assign			syn_pulse=syn_in&syn_in_n1;
reg[3:0]		con_syn;//采样时钟循环计数器

wire[7:0]		comp_8;//补码
wire[11:0]		d_12;//升位结果
assign			comp_8=data_in[7]?{data_in[7],~data_in[6:0]+1}:data_in;//补码运算;
assign			d_12={comp_8[7],comp_8[7],comp_8[7],comp_8[7],comp_8};
reg[11:0]		sigma;//累加运算
reg[11:0]		data_out;
reg				syn_out;


always@(posedge clk or negedge rst)
if(~rst)begin
	syn_in_n1<=0;con_syn<=0;sigma<=0;data_out<=0;syn_out<=0;

end 
else begin
	syn_in_n1<=~syn_in;
	if(syn_pulse)begin
	con_syn<=con_syn+1;
	end
	
	if(syn_pulse)begin
		if(con_syn==15)begin
			sigma<=d_12;
			data_out<=sigma;
			syn_out<=1;
		end
		else begin
		sigma<=sigma+d_12; 
		end
		
	end
	else begin
		syn_out<=0;
	end
end


endmodule

值得注意的是,我们在这里因为没有开发板,所以对时钟频率,采样频率包括分频都是使用的人为的值,如果有开发板的话,应按照开发板的时钟频率严格选取采样频率!

在代码中,使用采样时钟进行采样,每当采样时钟上升沿到来时,syn_pulse会产生一个脉冲,同时con_syn会进行计数,算作一个点输入。当计数到15时候(0-15)data_out将结果输出来。同时在采样时钟这边进行一个十六分频,即当输出数据的时候(采样时钟经过十六个周期),由syn_out产生一个脉冲。

testbench如下:

//----testbench----
module	sigma_16P_tb;
reg					clk,rst;
reg[7:0]			data_in;
reg					syn_in;
wire[11:0]			data_out;
wire				syn_out;

sigma_16P sigma_16P(
					.clk(clk),
					.rst(rst),
					.data_in(data_in),
					.syn_in(syn_in),
					.data_out(data_out),
					.syn_out(syn_out)
					);
initial begin
				clk<=0;rst<=0;data_in=1;syn_in<=0;
		#17		rst<=1;
		#25000	$stop;
end

always #5 		clk<=~clk;
always #100		syn_in<=~syn_in;
							
endmodule

最后进行ModelSIM仿真,为了方便观察,我们将输入置为+1。

结果如下:

 这里可以看到,第一次输出的是15而不是16,这是为什么呢?从代码中不难看出,我们设定的是将复位信号在17ns后置为1,所以第一个con_syn开始计数的时候,我们是没有采样脉冲的,没有采样脉冲就意味着第一个点的值是不会加到sigma的,所以第一次实际只累加了15个点的值,在后面就一直是16了。

2.简单状态机

状态机简写为 FSM(Finite State Machine),也称为同步有限状态机,我们一般简称为状态机,之所以说“同步”是因为状态机中所有的状态跳转都是在时钟的作用下进行的,而“有限”则是说状态的个数是有限的。状态机的每一个状态代表一个事件,从执行当前事件到执行另一事件我们称之为状态的跳转或状态的转移,我们需要做的就是执行该事件然后跳转到一下时间,这样我们的系统就“活”了,可以正常的运转起来了。状态机通过控制各个状态的跳转来控制 流程,使得整个代码看上去更加清晰易懂,在控制复杂流程的时候,状态机优势明显。

本文设计的是一个最简单的状态机,他可以实现上升,下降和保持之间状态的跳转。

 

上图所示是最简单的三角波发生器,在此基础上我们可以多加入一个保持态,将其转换为梯形。

代码如下:

//2023.5.2	Bread
//简单状态机:三角波发生器
`timescale 1ns/10ps
module tri_gen(
				clk,
				rst,
				d_out
					);
					
input			clk;
input			rst;
output[8:0]		d_out;

reg[1:0]		state;//主状态机寄存器;
reg[8:0]		d_out;
reg[7:0]		con;//计数器,记录保持周期个数
always@(posedge clk or negedge rst)
if(~rst)begin
	state<=0;d_out<=0;con<=0;
end
else begin
	case(state)
	0://上升
	begin
		d_out<=d_out+1;
		if(d_out==299)begin
			state<=1;
		end
	end
	1://保持
	begin
		
		if(con==200)begin
			state<=2;
			con<=0;
		end 
		else begin
			con<=con+1;
		end
	end
	2://下降
	begin
		d_out<=d_out-1;
		if(d_out==1)begin
			state<=3;
		end
	end
	3://保持
	begin
		if(con==200)begin
			state<=0;
			con<=0;
		end 
		else begin
			con<=con+1;
		end
	end
	endcase

end
endmodule

 从代码中我们可以看出,该状态机有四种状态,严格来说只有三种:上升、下降和保持。在编写代码的过程中我们要注意代码的运行顺序,从而选择正确的参数。好比我在下降的状态中不小心写成d_out==0了,在仿真的时候就发现了一个异常的脉冲。经过检查原来是下降的时候溢出了,值变为-1了,这里是需要特别注意的。

testbench如下:

//-----testbench-----
module tri_gen_tb;
reg				clk;
reg				rst;
wire[8:0]		d_out;

tri_gen U1(
				.clk(clk),
				.rst(rst),
				.d_out(d_out)
					);

initial begin
				clk<=0;rst<=0;
		#17		rst<=1;
		#80000	$stop;
end
always 	#5 clk<=~clk;
endmodule

ModelSIM仿真如下:

在观察波形的时候,因为三角波信号是模拟信号,所以我们需要改变一下显示的格式:

 

然后就可以看见一个个的梯形波了,如果想单纯实现三角波,可以将保持态去掉。但是这里需要注意一个问题:状态机的位数,比如只需要2个状态 简单的就用一位就可以表示了,如果状态多了的话就要留意了! 

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值