硬件语言Verilog HDL牛客刷题day05时序逻辑部分(2)

该文提供了一系列Verilog代码示例,涵盖了数据位宽转换(如8到12位,8到16位),非重叠和重叠序列检测,以及不同类型的时钟分频器(偶数分频,奇数分频,小数分频)。此外,还展示了自动贩售机的设计,处理不同面额货币找零的问题。所有设计都基于状态机和时序逻辑,部分设计需满足特定的占空比或非重叠检测要求。
摘要由CSDN通过智能技术生成

1.VL33 非整数倍数据位宽转换8to12

1.题目:

实现数据位宽转换电路,实现8bit数据输入转换为12bit数据输出。其中,先到的数据应置于输出的高bit位。

电路的接口如下图所示。valid_in用来指示数据输入data_in的有效性,valid_out用来指示数据输出data_out的有效性;clk是时钟信号;rst_n是异步复位信号。

 


2.解题思路

        2.1 生成一个寄存器  存储数据,寄存器的大小应该要 大于 等于12。  

        2.2        8*3 ==  12*2

        2.3        第一个数据取8位 第二个数据取4位, 输出第一个信号, 第二个信号取后4位加上第三个数据,输出第二个信号。


3.解题代码

`timescale 1ns/1ns

module width_8to12(
	input 				   clk 		,   
	input 			      rst_n		,
	input				      valid_in	,
	input	[7:0]			   data_in	,
 
 	output  reg			   valid_out,
	output  reg [11:0]   data_out
);
reg[23:0] data; // data buffer
reg[1:0] cnt; // counter 

//本题时 1个时序题 采用 状态机 或者  提前模式
// 输入为  8为   输出 为12位    3*8 = 2*12; 
//设置三个状态。


//控制数据
always@(posedge clk or negedge rst_n)
	begin
		if(~rst_n)
			begin
				data <=0;
			end
		else
		 	begin
				if(valid_in == 1'b1)
					begin
						data <={data[15:0],data_in} ;
					end 
				else
					begin
						data <=data;
					end
			end
	end

always@(posedge clk or negedge rst_n)
	begin
		if(~rst_n)
			begin
				cnt <= 0;
			end
		else 
			begin
				if(cnt==2'd0 && valid_in==1'b1)
					begin
						cnt <= 2'd1;
					end
				else if(cnt == 2'd1 && valid_in == 1'b1)
					begin
						cnt <= 2'd2;
					end
				else if(cnt == 2'd2 && valid_in == 1'd1)
					begin
						cnt <=2'd0;
					end
			end
			
	end

always@(posedge clk or negedge rst_n)
	begin
		if(~rst_n)
			begin
				data_out <=0;
				valid_out <=0;
			end
		else 
			begin
				if(cnt == 2'd0)
					begin
						data_out <= data_out;
						valid_out <=0;
					end
				else if(cnt == 2'd1 && valid_in == 1'd1) 
					begin
						data_out <= {data[7:0],data_in[7:4]};
						valid_out <=1;
					end
				else if(cnt == 2'd2 && valid_in == 1'd1)
					begin
						data_out <= {data[3:0],data_in[7:0]};
						valid_out <=1;
					end
				else 
					begin
						valid_out <=0;
					end


			end
	end





endmodule


2.VL34 整数倍数据位宽转换8to16

1.题目:

实现数据位宽转换电路,实现8bit数据输入转换为16bit数据输出。其中,先到的8bit数据应置于输出16bit的高8位。

电路的接口如下图所示。valid_in用来指示数据输入data_in的有效性,valid_out用来指示数据输出data_out的有效性;clk是时钟信号;rst_n是异步复位信号。

 

  


2.解题思路

        2.1 和上面那题差不多。

        2.2 首先是 第一个 和第二个数据 合并之后输出 第一个信号。


3.解题代码

`timescale 1ns/1ns

module width_8to16(
	input 				   clk 		,   
	input 				   rst_n		,
	input				      valid_in	,
	input	   [7:0]		   data_in	,
 
 	output	reg			valid_out,
	output   reg [15:0]	data_out
);

reg[23:0] data; // data buffer
reg[1:0] cnt; // counter 

//本题时 1个时序题 采用 状态机 或者  提前模式
// 输入为  8为   输出 为12位    3*8 = 2*12; 
//设置三个状态。


//控制数据
always@(posedge clk or negedge rst_n)
	begin
		if(~rst_n)
			begin
				data <=0;
			end
		else
		 	begin
				if(valid_in == 1'b1)
					begin
						data <={data[15:0],data_in} ;
					end 
				else
					begin
						data <=data;
					end
			end
	end

always@(posedge clk or negedge rst_n)
	begin
		if(~rst_n)
			begin
				cnt <= 0;
			end
		else 
			begin
				if(cnt==2'd0 && valid_in==1'b1)
					begin
						cnt <= 2'd1;
					end
				else if(cnt == 2'd1 && valid_in == 1'b1)
					begin
						cnt <= 2'd0;
					end
			end
			
	end

always@(posedge clk or negedge rst_n)
	begin
		if(~rst_n)
			begin
				data_out <=0;
				valid_out <=0;
			end
		else 
			begin
				if(cnt == 2'd0)
					begin
						data_out <= data_out;
						valid_out <=0;
					end
				else if(cnt == 2'd1 && valid_in == 1'd1) 
					begin
						data_out <= {data[7:0],data_in[7:0]};
						valid_out <=1;
					end
				else 
					begin
						valid_out <=0;
					end


			end
	end

endmodule

 



3.VL35 状态机-非重叠的序列检测

1.题目:

设计一个状态机,用来检测序列 10111,要求:

1、进行非重叠检测   即101110111 只会被检测通过一次

2、寄存器输出且同步输出结果

注意rst为低电平复位

 

 


2.解题思路

         2.1状态机 的解题思路, 时序同步输出。

        2.2 注意 存储空间 清除问题,因为是 非重叠。

         

 


3.解题代码

`timescale 1ns/1ns

module sequence_test1(
	input wire clk  ,
	input wire rst  ,
	input wire data ,
	output reg flag
);
//*************code***********//
reg[4:0] data1; 


always@(posedge clk or negedge rst)
	begin
		if(~rst)
			begin
				flag <=0;
			end
		else
			begin
				if({data1[3:0],data} == 5'b10111)
					begin
						flag <=1;
						data1 <= 5'd0;
					end
				else
				  	begin
						flag <=0;
						data1 <= {data1[3:0],data};
					end
			end
	end




//*************code***********//
endmodule

4.VL36 状态机-重叠序列检测

1.题目:

设计一个状态机,用来检测序列 1011,要求:

1、进行重叠检测   即10110111 会被检测通过2次

2、寄存器输出,在序列检测完成下一拍输出检测有效

注意rst为低电平复位


2.解题思路

        2.1 这里为 重复检测,所以 存储数据的寄存器不需要清零。

        2.1 这个的状态机,周期比同步周期 晚了一个时序


3.解题代码

`timescale 1ns/1ns

module sequence_test2(
	input wire clk  ,
	input wire rst  ,
	input wire data ,
	output reg flag
);
//*************code***********//
reg[4:0] data1;

always@(posedge clk or rst)
	begin
		if(~rst)
			begin
				data1 <=0;
			end
		else 
			begin
				data1 <= {data1[3:0],data};
			end
	end
always@(posedge clk or negedge rst)
	begin
		if(~rst)
			begin
				flag <=0;
			end
		else
			begin
				if(data1[3:0]== 4'b1011)
					begin
						flag <=1;
					end
				else
					begin
						flag <=0;
					end
			end
	end
//*************code***********//
endmodule

 



5.VL37 时钟分频(偶数)

1.题目:

请使用D触发器设计一个同时输出2/4/8分频的50%占空比的时钟分频器

注意rst为低电平复位

 

 


2.解题思路

        2.1 首先是 需要一个 记录时序此时 的 计数器。

        2.2 就是注意时序是 同步的 

        2.3 注意这里的  输出类型是  wire  所以时使用  assign 持续赋值语句。

        2.4 注意这个 的输出 先是 1  , 然后是 0.


3.解题代码

`timescale 1ns/1ns

module even_div
    (
    input     wire rst ,
    input     wire clk_in,
    output    wire clk_out2,
    output    wire clk_out4,
    output    wire clk_out8
    );
//*************code***********//
reg[2:0] cnt ;//计数器
always@(posedge clk_in or negedge rst)
    begin
        if(~rst)
            begin
                cnt <=3'b000;
            end
        else 
            begin
                if(cnt == 3'd000)
                    begin
                        cnt <=3'b111;
                    end
                else
                    begin
                        cnt <= cnt-1'b1;
                    end
            end
    end
assign clk_out2 = (cnt[0]);
assign clk_out4 = (cnt[1]);
assign clk_out8 = (cnt[2]);
//*************code***********//
endmodule

 



6.VL38 自动贩售机1

1.题目:

设计一个自动贩售机,输入货币有三种,为0.5/1/2元,饮料价格是1.5元,要求进行找零,找零只会支付0.5元。

ps:投入的货币会自动经过边沿检测并输出一个在时钟上升沿到1,在下降沿到0的脉冲信号

注意rst为低电平复位


2.解题思路

        2.1 首先是 当零钱的数额大于等于 饮料的价格 时输出 信号。

        2.2 注意找零使用  0.5 元, 所以我们的把价格计录成 0.5 的个数就行了。

        2.3 记得 零钱的数目清零。 因为找零了。

 


3.解题代码

`timescale 1ns/1ns
module seller1(
	input wire clk  ,
	input wire rst  ,
	input wire d1 ,
	input wire d2 ,
	input wire d3 ,
	
	output reg out1,
	output reg [1:0]out2
);
//*************code***********//
reg[3:0] data;//0.5 的个数

always@(posedge clk or negedge rst)
	begin
		if(~rst)
			begin
				data <=0;
			end
		else
		 	begin
				if(d1 == 1'b1)
					begin
						data <= data+1'b1;
					end
				else if(d2 == 1'b1)
					begin
						data <= data + 4'd2; 
					end
				else if(d3 == 1'b1)
					begin
						data <= data + 4'd4;
					end
			end
	end

always@(posedge clk or negedge rst)
	begin
		if(~rst)
			begin
				out1<=0;
				out2<=0;
			end
		else
			begin
				if(data >= 4'd3)
					begin
						out1<=1;
						out2<=data - 4'd3;
						data<=0;
					end
				else
					begin
						out1<=0;
						out2<=0;
					end
			end
	end


//*************code***********//
endmodule


7.VL39 自动贩售机2

1.题目:

 设计一个自动贩售机,输入货币有两种,为0.5/1元,饮料价格是1.5/2.5元,要求进行找零,找零只会支付0.5元。

ps:     1、投入的货币会自动经过边沿检测并输出一个在时钟上升沿到1,在下降沿到0的脉冲信号

           2、此题忽略出饮料后才能切换饮料的问题

注意rst为低电平复位

信号的示意 :

d1 0.5

d2 1

sel  选择饮料

out1 饮料1

out2 饮料2

out3 零钱

 


2.解题思路

        

        2.1 首先是 当零钱的数额大于等于 饮料的价格 时输出 信号。

        2.2 注意找零使用  0.5 元, 所以我们的把价格计录成 0.5 的个数就行了。

        2.3 记得 零钱的数目清零。 因为找零了。

        2.4 注意又两种 饮料,所以要判断当时是  买那种饮料。


3.解题代码

`timescale 1ns/1ns

module seller2(
	input wire clk  ,
	input wire rst  ,
	input wire d1 ,
	input wire d2 ,
	input wire sel ,
	
	output reg out1,
	output reg out2,
	output reg out3
);
//*************code***********//
reg[3:0] data;

always@(posedge clk or negedge rst)
	begin
		if(~rst)
			begin
				data <=0;
			end
		else
			begin
				if(d1 == 1'b1)
					begin
						data <= data + 4'd1;
					end
				else if(d2== 1'd1)
					begin
						data <= data +4'd2;
					end
				else
					begin
						data <=data;
					end
			end
	end


always@(posedge clk or negedge rst)
	begin
		if(~rst)
			begin
				out1<=0;
				out2<=0;
				out3<=0;
			end
		else
			begin
				if(sel == 1'b0)
					begin
						if(data >= 4'd3)
							begin
								out1<=1;
								out2<=0;
								out3<=(data - 4'd3);
								data<=0;
							end
						else
							begin
								out1<=0;
								out2<=0;
								out3<=0;
							end
					end
				else if(sel == 1'b1)
					begin
						if(data >= 4'd5)
							begin
								out1<=0;
								out2<=1;
								out3<=(data - 4'd5);
								data<=0;
							end
						else 
							begin
								out1<=0;
								out2<=0;
								out3<=0;
							end
					end
			end
	end



//*************code***********//
endmodule

 



8.VL40 占空比50%的奇数分频

1.题目:

设计一个同时输出7分频的时钟分频器,占空比要求为50%

注意rst为低电平复位


2.解题思路

        2.1  把他计数成  14   的 ,每 7 个计数, 输出信号变化 。

        2.2 输出信号首先 是0 .

        2.3 注意输出的信号 的类型是 wire  只能使用 assign  持续赋值。

        2.4 同时输出 7个分频哦, 


3.解题代码

`timescale 1ns/1ns

module odo_div_or
   (
    input    wire  rst ,
    input    wire  clk_in,
    output   wire  clk_out7
    );

//*************code***********//
reg[3:0] cnt; //counter

always@(posedge clk_in or negedge rst or negedge clk_in)
    begin
        if(~rst)
            begin
                cnt <=0;
            end
        else 
            begin
                if(cnt == 4'd13)
                    begin
                        cnt <=0 ;
                    end
                else 
                    begin
                        cnt <= cnt + 1;
                    end

            end
    end



assign clk_out7 = (cnt>=7) ? 1 : 0;
//*************code***********//
endmodule

 



9.VL41 任意小数分频

1.题目:

请设计一个可以实现任意小数分频的时钟分频器,比如说8.7分频的时钟信号

注意rst为低电平复位

提示:

其实本质上是一个简单的数学问题,即如何使用最小公倍数得到时钟周期的分别频比。

设小数为nn,此处以8.7倍分频的时钟周期为例。

首先,由于不能在硬件上进行小数的运算(比如2.1个时钟这种是不现实的,也不存在3.3个寄存器),小数分频不能做到分频后每个时钟周期都是源时钟的nn倍,也无法实现占空比为1/2,因此,考虑小数分频,其实现方式应当为53个clkout时钟周期是10个clkin时钟周期的8.7倍。


 

2.解题思路

        2.1  一个分频就是一个周期  所以 这里是 8 个时钟的周期, 或者 9个时钟的周期。

        2.2  给了提示, 前三个是  8分频, 后几个 是 9分频。

        2.3 注意是 输出信号的周期  晚一个时间节点。

        2.4 注意一个 输出信号的类型为  wire .  


3.解题代码

`timescale 1ns/1ns

module div_M_N(
 input  wire clk_in,
 input  wire rst,
 output wire clk_out
);
parameter M_N = 8'd87; 
parameter c89 = 8'd24; // 8/9时钟切换点
parameter div_e = 5'd8; //偶数周期
parameter div_o = 5'd9; //奇数周期
//*************code***********//
reg[7:0] cnt; //counter 
reg clk_out1;
always@(posedge clk_in or negedge rst )
    begin
        if(~rst)
            begin
                cnt <=0;
            end
        else
            begin
                if(cnt == 8'd86)
                    begin
                        cnt <=0;
                    end
                else
                    begin
                        cnt <= cnt +1;
                    end
            end
    end

always@(posedge clk_in or negedge rst)
    begin
        if(~rst)
            begin
                clk_out1 <=0;
            end
        else
            begin
                case(cnt)
                        8'd0 : clk_out1 <= ~clk_out1;
                        8'd4 : clk_out1 <= ~clk_out1;
                        8'd8 : clk_out1 <= ~clk_out1;
                        8'd12: clk_out1 <= ~clk_out1;
                        8'd16: clk_out1 <= ~clk_out1;
                        8'd20: clk_out1 <= ~clk_out1;
                        8'd24: clk_out1 <= ~clk_out1;
                        8'd28: clk_out1 <= ~clk_out1;
                        8'd33: clk_out1 <= ~clk_out1;
                        8'd37: clk_out1 <= ~clk_out1;
                        8'd42: clk_out1 <= ~clk_out1;
                        8'd46: clk_out1 <= ~clk_out1;
                        8'd51: clk_out1 <= ~clk_out1;
                        8'd55: clk_out1 <= ~clk_out1;
                        8'd60: clk_out1 <= ~clk_out1;
                        8'd64: clk_out1 <= ~clk_out1;
                        8'd69: clk_out1 <= ~clk_out1;
                        8'd73: clk_out1 <= ~clk_out1;
                        8'd78: clk_out1 <= ~clk_out1;
                        8'd82: clk_out1 <= ~clk_out1;
                        //'d86: clk_out1 <= ~clk_out1;
                        default : clk_out1 <= clk_out1;
                    endcase
            end
    end

assign clk_out =  clk_out1;  

//*************code***********//
endmodule


10.VL42 无占空比要去的奇数分频

1.0题目:

请设计一个同时输出5分频的时钟分频器,本题对占空比没有要求

注意rst为低电平复位

 


2.解题思路

        2.1 计数 器, 每5 个计数 转换输出信号, 只能计数 上升沿,所以第一个变换的时候是在  cnt =0 的时候,第二个是在 cnt = 2 的时候。


3.解题代码

`timescale 1ns/1ns

module odd_div (    
    input     wire rst ,
    input     wire clk_in,
    output    wire clk_out5
);
//*************code***********//
reg[3:0] cnt ;// counter
reg out;

always@(posedge clk_in or negedge rst)
    begin
        if(~rst)
            begin
                cnt <=0;
            end
        else
            begin
                if(cnt == 3'd4)
                    begin
                        cnt <=0;
                    end
                else
                    begin
                        cnt <= cnt +1;
                    end
            end
    end

always@(posedge clk_in or negedge rst)
    begin
        if(~rst)
            begin
                out <=0;
            end
        else
            begin
                if(cnt == 3'd0)
                    begin
                        out <= ~out;
                    end
                else if(cnt == 3'd2)
                    begin
                        out <= ~out; 
                    end
                else
                    begin
                        out <= out;
                    end
            end
    end
assign clk_out5 = out;
//*************code***********//
endmodule

 



11. VL43 根据状态转移写状态机-三段式

1.题目

如图所示为两种状态机中的一种,请根据状态转移图写出代码,状态转移线上的0/0等表示的意思是过程中data/flag的值。

要求:

1、 必须使用对应类型的状态机

2、 使用三段式描述方法,输出判断要求要用到对现态的判断

 


2.解题思路

        2.1 三段式状态机

  

 

 


3.解题代码

`timescale 1ns/1ns

module fsm1(
	input wire clk  ,
	input wire rst  ,
	input wire data ,
	output reg flag
);
//*************code***********//
parameter s0 = 2'd00,
		  s1 = 2'd01,
		  s2 = 2'd10,
		  s3 = 2'd11;
reg[1:0] nextstate,cstate;


always@(posedge clk or negedge rst)
	begin
		if(~rst)
			begin
				cstate <= s0;
			end
		else
			begin
				cstate <= nextstate;
			end
	end

always@(posedge clk or negedge rst)
	begin
		if(~rst)
			begin
				nextstate <=s1;
			end
		else
			begin
				if(nextstate == s0)
					begin
						nextstate <=data ? s1:s0;
					end
				else if(nextstate ==s1)
					begin
						nextstate <=data ? s2:s1;
					end
				else if(nextstate == s2)
					begin
						nextstate <=data ? s3:s2;
					end
				else if(nextstate == s3)
					begin
						nextstate <=data ? s0:s3;
					end
			end
	end
always@(posedge clk or negedge rst)
	begin
		if(~rst)
			begin
				flag <=0;
			end
		else 
			begin
				if(cstate == s3 && data ==1'd1)
					begin
						flag <=1;
					end
				else
					begin
						flag <=0;
					end
			end
	end


//*************code***********//
endmodule



12.VL44 根据状态转移写状态机-二段式

1.题目:

如图所示为两种状态机中的一种,请根据状态转移图写出代码,状态转移线上的0/0等表示的意思是过程中data/flag的值。

要求:

1、 必须使用对应类型的状态机

2、 使用二段式描述方法

  

   


2.解题思路

             2.1.注意三段机 与 二段机的差别 。

             2.2 三段机的次态 的下一个状态  等于  data  和 上一个次态。

             2.3 二段机的次态 的下一个状态  等于  data 和  上一个现态。



 3.解题代码

`timescale 1ns/1ns

module fsm2(
	input wire clk  ,
	input wire rst  ,
	input wire data ,
	output reg flag
);

//*************code***********//
parameter s0 = 3'd0,
		  s1 = 3'd1,
		  s2 = 3'd2,
		  s3 = 3'd3,
		  s4 = 3'd4;
reg[2:0] nextstate,cstate;


always@(posedge clk or negedge rst)
	begin
		if(~rst)
			begin
				cstate <= s0;
			end
		else
			begin
				cstate <= nextstate;
			end
	end

always@(*)//因为是根据现态来的, 所以是 用的 *  , 上升沿在 cstate变化 的时候可能没有用, 
	begin  //我们这里是要在 cstate 变化之后运行
			case(cstate)
				s0:begin
					nextstate = data ? s1 : s0;
					flag = 1'b0; 
				end
				s1:begin
					nextstate = data ? s2 : s1;
					flag = 1'b0;
				end
				s2:begin
					nextstate = data ? s3 : s2;
					flag = 1'b0;
				end
				s3:begin
					nextstate = data ? s4 : s3;
					flag = 1'b0;
				end
				s4:begin
					nextstate = data ? s1 : s0;
					flag = 1'b1;
				end
				default:begin  
					nextstate = s0;
					flag = 1'b0;             
				end
        	endcase
	end


//*************code***********//
endmodule

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值