FPGA开发

led_run

module led_run(clk,rst_n,led);
	input clk,rst_n;
	output reg[3:0] led;
	reg [1:0] state;
	reg [25:0] cnt;
	parameter T=5000_0000;//常量
	always @ (posedge clk,negedge rst_n)//时钟上升沿 复位下降沿(复位低电平有效 那就是下降沿触发)
		begin
			if(!rst_n)
				begin 
					state<=0;//<=非阻塞赋值用在时序逻辑电路里  //=阻塞赋值在组合逻辑电路中使用
					cnt<=0;
					led<=4'b1111;
				end
			else
				case(state)
					0	:	begin
								if(cnt<T-1)
									begin
									cnt<=cnt+1;
									state<=0;
									led<=4'b0111;
									end
								else
									begin
									cnt<=0;
									state<=1;
									led<=4'b1011;
									end
							end
							
					1	:	begin
								if(cnt<T-1)
									begin
									cnt<=cnt+1;
									state<=1;
									led<=4'b1011;
									end
								else
									begin
									cnt<=0;
									state<=2;
									led<=4'b1101;
									end
							end
					
					2	:	begin
								if(cnt<T-1)
									begin
									cnt<=cnt+1;
									state<=2;
									led<=4'b1101;
									end
								else
									begin
									cnt<=0;
									state<=3;
									led<=4'b1110;
									end
							end
							
					3	:	begin
								if(cnt<T-1)
									begin
									cnt<=cnt+1;
									state<=3;
									led<=4'b1110;
									end
								else
									begin
									cnt<=0;
									state<=0;
									led<=4'b0111;
									end
							end
					default : state<=0;
				endcase
		end
endmodule 

led_run_state

Verilog HDL(硬件描述语言) 编写的 三段式状态机,用于控制 4 个 LED 灯 按照特定的顺序循环点亮(类似跑马灯效果)。


代码功能分析

1. 模块定义

module led_run_state3(clk, rst_n, led);
  • clk:时钟信号输入(用于同步状态切换)。
  • rst_n:复位信号(低电平有效,0 时复位)。
  • led:输出 4 位寄存器,控制 4 个 LED 灯的亮灭(1 灭,0 亮)。

2. 状态机设计(三段式)

(1) 状态定义
reg [1:0] c_state, n_state; // 当前状态(c_state)和下一状态(n_state)
parameter T = 5000_0000;    // 计时周期(控制LED切换速度)
  • c_state:当前状态(2 位,可表示 4 种状态 0~3)。
  • n_state:下一状态(由组合逻辑计算)。
  • T:计数器阈值(5000_0000 个时钟周期后切换状态)。
(2) 组合逻辑计算下一状态(第一段)
always @ (*) begin
    if (!rst_n) n_state = 0; // 复位时回到状态0
    else
        case (c_state)
            0: if (cnt == T-1) n_state = 1; else n_state = 0;
            1: if (cnt == T-1) n_state = 2; else n_state = 1;
            2: if (cnt == T-1) n_state = 3; else n_state = 2;
            3: if (cnt == T-1) n_state = 0; else n_state = 3;
            default: n_state = 0;
        endcase
end
  • 根据 c_state 和计数器 cnt 决定 n_state
    • 如果 cnt 计满 T-1,则切换到下一状态(0→1→2→3→0 循环)。
    • 否则保持当前状态。
(3) 时序逻辑更新当前状态(第二段)
always @ (posedge clk, negedge rst_n) begin
    if (!rst_n) c_state <= 0; // 复位时状态归零
    else c_state <= n_state;  // 否则更新状态
end
  • 在时钟上升沿或复位时更新 c_state

3. 计数器(第三段)

always @ (posedge clk, negedge rst_n) begin
    if (!rst_n) cnt <= 0;
    else if (cnt < T-1) cnt <= cnt + 1;
    else cnt <= 0;
end
  • 每个时钟周期 cnt 自增 1,直到 T-1 后归零,用于控制状态切换的时间间隔。

4. LED 输出逻辑

always @ (*) begin
    if (!rst_n) led = 4'b1111; // 复位时全灭
    else
        case (c_state)
            0: led = 4'b0111; // 第1个LED亮(低电平有效)
            1: led = 4'b1011; // 第2个LED亮
            2: led = 4'b1101; // 第3个LED亮
            3: led = 4'b1110; // 第4个LED亮
            default: led = 4'b1111;
        endcase
end
  • 根据 c_state 控制 LED 的亮灭:
    • 00111(第1个亮)
    • 11011(第2个亮)
    • 21101(第3个亮)
    • 31110(第4个亮)
    • 复位时 1111(全灭)。

硬件行为

  1. 复位时(rst_n=0

    • led = 4'b1111(所有 LED 熄灭)。
    • c_state = 0cnt = 0
  2. 正常运行(rst_n=1

    • 5000_0000 个时钟周期,状态切换一次(0→1→2→3→0)。
    • LED 依次点亮,形成 “流水灯” 效果。

改进建议

  1. n_state 逻辑优化
    • 可以用 n_state = (cnt == T-1) ? (c_state + 1) % 4 : c_state; 简化代码。
  2. led 输出时序
    • 建议用 always @ (posedge clk) 避免组合逻辑的竞争冒险。
  3. 参数化 T
    • 可通过模块参数传递 T,方便调整 LED 切换速度。

总结

这是一个典型的 “三段式状态机” 实现,通过 状态切换 + 计时器 控制 LED 循环点亮,适用于 FPGA 或 ASIC 设计中的硬件控制场景。

完整代码

module led_run_state3(clk,rst_n,led);//三段式状态机
	input clk,rst_n;
	output reg[3:0] led;
	reg [25:0] cnt;
	parameter T=5000_0000;//常量
	reg [1:0] c_state,n_state;//三段式状态机
	//用组合逻辑写
	always @ (*)
		begin
			if(!rst_n)
				n_state=0;
			else
				case(c_state)
					0	:	begin
								if(cnt==T-1)
									n_state=1;//记够跳
								else
									n_state=0;//否则不跳
							end
				
					1	:	begin
								if(cnt==T-1)
									n_state=2;//记够跳
								else
									n_state=1;//否则不跳
							end
						
					2	:	begin
								if(cnt==T-1)
									n_state=3;//记够跳
								else
									n_state=2;//否则不跳
							end
						
					3	:	begin
								if(cnt==T-1)
									n_state=4;//记够跳
								else
									n_state=3;//否则不跳
							end
				
					default:n_state=0;
				endcase
		end
	
	always @ (posedge clk,negedge rst_n)
		begin
			if(!rst_n)
				c_state<=0;
			else
				c_state<=n_state;
		end
	
	//计数器
	always @ (posedge clk, negedge rst_n)
		begin
			if(!rst_n)
				cnt<=0;
			else
				if(cnt<T-1)
					cnt<=cnt+1;
				else
					cnt<=0;
		end
		
	always @ (*)
		begin
			if(!rst_n)
				led=4'b1111;
			else
				case(c_state)
					0	:	led=4'b0111;
					1	:	led=4'b1011;
					2	:	led=4'b1101;
					3	:	led=4'b1110;
					default	:	led=4'b1111;
				endcase
		end
endmodule 

测试代码

`timescale 1ns/1ps
module led_run_tb;
	reg clk,rst_n;
	wire [3:0] led;
	
	defparam dut.T=50;
	
	led_run_state3 dut(
						.clk(clk),
						.rst_n(rst_n),
						.led(led)
					);
					
	//写激励
	initial begin
		clk=0; rst_n=0;
		#200.1 rst_n=1;
		#20000 $stop;
	end
	
	always #10 clk=~clk;
endmodule 

按键抖动

完整代码

module key_filter(clk,rst_n,key_in,key_out);
	input clk,rst_n;
	input key_in;
	output reg key_out;
	
	reg [18:0] cnt;
	parameter T = 50_0000;
	
	reg state;
	
	always @ (posedge clk,negedge rst_n)
		begin
			if(!rst_n)//复位
				begin
					state<=0;
					cnt<=0;
					key_out<=1;//没按下
				end
			else
				case(state)
					0	:	begin
								if(key_in==0)
									if(cnt<T-1)
										begin
											cnt<=cnt+1;
											key_out<=1;
											state<=0;
										end
									else
										begin
											cnt<=0;
											key_out<=0;
											state<=1;
										end
								else
									begin
										cnt<=0;
										key_out<=1;
										state<=0;
									end
							end
							
					1	:	begin
								if(key_in==1)
									if(cnt<T-1)
										begin
											cnt<=cnt+1;
											key_out<=0;
											state<=1;
										end
									else
										begin
											cnt<=0;
											key_out<=1;
											state<=0;
										end
								else
									begin
										cnt<=0;
										key_out<=0;
										state<=1;
									end
							end
					default:state<=0;
				endcase
		end
endmodule 

测试代码

`timescale 1ns/1ps
module key_filter_tb;
	reg clk,rst_n;
	reg key_in;
	wire key_out;
	
	defparam dut.T=50;
	
	key_filter dut(
							.clk(clk),
							.rst_n(rst_n),
							.key_in(key_in),
							.key_out(key_out)
						);
						
	initial begin
		clk=0; rst_n=0;
		key_in=1;
		
		#200.1 rst_n=1;
		
		#678 key_in=0;
		#488 key_in=1;
		#678 key_in=0;
		#488 key_in=1;
		#678 key_in=0;
		#488 key_in=1;
		#678 key_in=0;
		#488 key_in=1;
		#678 key_in=0;
		#488 key_in=1;
		#678 key_in=0;
		#488 key_in=1;
		#678 key_in=0;
		
		#2000 key_in=1;
		
		#678 key_in=0;
		#488 key_in=1;
		#678 key_in=0;
		#488 key_in=1;
		#678 key_in=0;
		#488 key_in=1;
		#678 key_in=0;
		#488 key_in=1;
		
		#2000 $stop;
		
	end
	
	always #10 clk =~clk;
	
endmodule 

按键抖动(下午)

完整代码

module key_filter(clk,rst_n,key_in,nege_flag,pose_flag);
	input clk,rst_n;
	input key_in;
	output nege_flag,pose_flag;
	
	reg [18:0] cnt;
	parameter T = 50_0000;
	
	reg state;
	reg key_out;
	
	always @ (posedge clk,negedge rst_n)
		begin
			if(!rst_n)//复位
				begin
					state<=0;
					cnt<=0;
					key_out<=1;//没按下
				end
			else
				case(state)
					0	:	begin
								if(key_in==0)
									if(cnt<T-1)
										begin
											cnt<=cnt+1;
											key_out<=1;
											state<=0;
										end
									else
										begin
											cnt<=0;
											key_out<=0;
											state<=1;
										end
								else
									begin
										cnt<=0;
										key_out<=1;
										state<=0;
									end
							end
							
					1	:	begin
								if(key_in==1)
									if(cnt<T-1)
										begin
											cnt<=cnt+1;
											key_out<=0;
											state<=1;
										end
									else
										begin
											cnt<=0;
											key_out<=1;
											state<=0;
										end
								else
									begin
										cnt<=0;
										key_out<=0;
										state<=1;
									end
							end
					default:state<=0;
				endcase
		end
		
	reg key_buff1,key_buff2;
	
	always @ (posedge clk,negedge rst_n)
		begin
			if(!rst_n)
				begin
					key_buff1<=0;
					key_buff2<=0;
				end
			else
				begin
					key_buff1<=key_out;
					key_buff2<=key_buff1;
				end
		end
	
	assign nege_flag=(~key_buff1)&&(key_buff2);
	assign pose_flag=(~key_buff2)&&key_buff1;
	
endmodule 

测试代码

`timescale 1ns/1ps
module key_filter_tb;
	reg clk,rst_n;
	reg key_in;
	wire pose_flag,nege_flag;
	
	defparam dut.T=50;
	
	key_filter dut(
							.clk(clk),
							.rst_n(rst_n),
							.key_in(key_in),
							.pose_flag(pose_flag),
							.nege_flag(nege_flag)
						);
						
	initial begin
		clk=0; rst_n=0;
		key_in=1;
		
		#200.1 rst_n=1;
		
		#678 key_in=0;
		#488 key_in=1;
		#678 key_in=0;
		#488 key_in=1;
		#678 key_in=0;
		#488 key_in=1;
		#678 key_in=0;
		#488 key_in=1;
		#678 key_in=0;
		#488 key_in=1;
		#678 key_in=0;
		#488 key_in=1;
		#678 key_in=0;
		
		#2000 key_in=1;
		
		#678 key_in=0;
		#488 key_in=1;
		#678 key_in=0;
		#488 key_in=1;
		#678 key_in=0;
		#488 key_in=1;
		#678 key_in=0;
		#488 key_in=1;
		
		#2000 $stop;
		
	end
	
	always #10 clk =~clk;
	
endmodule 

实现

第一步:按键消抖(防抖)

  • 问题:按键按下时会有抖动(比如10ms内0-1-0-1乱跳),直接读会误判多次按下。
  • 解决
    • 检测到按键状态变化(比如1→0)时,先不立刻响应,而是:
      1. 开始数数(计数器cnt从0加到T-1,比如数满10ms)。
      2. 如果这期间按键状态一直稳定,才确认“真的按下了”。
    • 代码里用 state=0state=1 区分“等待按下”和“等待松开”两种状态。

第二步:边沿检测(抓瞬间)

  • 问题:消抖后的信号key_out只告诉你当前是按下还是松开,但我们需要 按下/松开的瞬间
  • 解决
    • 用两个寄存器 key_buff1key_buff2key_out的历史值:
      • key_buff1 = 当前值
      • key_buff2 = 上一次的值
    • 按下瞬间1→0):
      nege_flag = (~key_buff1) && key_buff2 (当前是0,上次是1)。
    • 松开瞬间0→1):
      pose_flag = key_buff1 && (~key_buff2) (当前是1,上次是0)。

7段数码管

完整代码

module seg7(clk,rst_n,/*data_in*/,sel,seg);
	input clk,rst_n;
	//input [23:0] data_in;
	output reg[2:0] sel;
	output reg[7:0] seg;
	
	parameter data_in = 24'h789abc;

	//分频器
	reg [14:0] cnt;
	reg clk_1ms;
	parameter T=25000;//1毫秒/2微秒=50000 占空比50%
	
	always @ (posedge clk,negedge rst_n)
		begin
			if(!rst_n)
				begin
					cnt<=0;
					clk_1ms<=0;
				end
			else
				if(cnt<T-1)
					cnt<=cnt+1;
				else
					begin
						cnt<=0;
						clk_1ms<=~clk_1ms;
					end
		end
	
	reg [3:0] temp;
	reg [2:0] state;
	
	always @ (posedge clk_1ms,negedge rst_n)
		begin
			if(!rst_n)
				begin
					sel<=3'b000;
					state<=0;
					temp<=0;
				end
			else
				case(state)
					0	:	begin
								sel<=3'b000;
								temp<=data_in[23:20];
								state<=1;
							end
					1	:	begin
								sel<=3'b001;
								temp<=data_in[19:16];
								state<=2;
							end
					2	:	begin
								sel<=3'b010;
								temp<=data_in[15:12];
								state<=3;
							end
					3	:	begin
								sel<=3'b011;
								temp<=data_in[11:8];
								state<=4;
							end
					4	:	begin
								sel<=3'b100;
								temp<=data_in[7:4];
								state<=5;
							end
					5	:	begin
								sel<=3'b101;
								temp<=data_in[3:0];
								state<=0;
							end
					default	:	state<=0;
				endcase
		end

	always @ (*)
		begin
			if(!rst_n)
				seg=8'b1111_1111;
			else
				case(temp)
					0 : seg = 8'b1100_0000;  // 显示数字 0
					1 : seg = 8'b1111_1001;  // 显示数字 1
					2 : seg = 8'b1010_0100;  // 显示数字 2
					3 : seg = 8'b1011_0000;  // 显示数字 3
					4 : seg = 8'b1001_1001;  // 显示数字 4
					5 : seg = 8'b1001_0010;  // 显示数字 5
					6 : seg = 8'b1000_0010;  // 显示数字 6
					7 : seg = 8'b1111_1000;  // 显示数字 7
					8 : seg = 8'b1000_0000;  // 显示数字 8
					9 : seg = 8'b1001_0000;  // 显示数字 9
					// 字母 A-F
					10 : seg = 8'b1000_1000;  // A
					11 : seg = 8'b1000_0011;  // b
					12 : seg = 8'b1100_0110;  // C
					13 : seg = 8'b1010_0001;  // d
					14 : seg = 8'b1000_0110;  // E
					15 : seg = 8'b1000_1110;  // F
					default : seg = 8'b1111_1111;  // 全灭
				endcase
		end
	
endmodule 

测试代码

计数器

完整代码

module seg7(clk,rst_n,data_in,sel,seg);
	input clk,rst_n;
	input [23:0] data_in;
	output reg[2:0] sel;
	output reg[7:0] seg;

	//分频器
	reg [14:0] cnt;
	reg clk_1ms;
	parameter T=25000;//1毫秒/2微秒=50000 占空比50%
	
	always @ (posedge clk,negedge rst_n)
		begin
			if(!rst_n)
				begin
					cnt<=0;
					clk_1ms<=0;
				end
			else
				if(cnt<T-1)
					cnt<=cnt+1;
				else
					begin
						cnt<=0;
						clk_1ms<=~clk_1ms;
					end
		end
	
	reg [3:0] temp;
	reg [2:0] state;
	
	always @ (posedge clk_1ms,negedge rst_n)
		begin
			if(!rst_n)
				begin
					sel<=3'b000;
					state<=0;
					temp<=0;
				end
			else
				case(state)
					0	:	begin
								sel<=3'b000;
								temp<=data_in[23:20];
								state<=1;
							end
					1	:	begin
								sel<=3'b001;
								temp<=data_in[19:16];
								state<=2;
							end
					2	:	begin
								sel<=3'b010;
								temp<=data_in[15:12];
								state<=3;
							end
					3	:	begin
								sel<=3'b011;
								temp<=data_in[11:8];
								state<=4;
							end
					4	:	begin
								sel<=3'b100;
								temp<=data_in[7:4];
								state<=5;
							end
					5	:	begin
								sel<=3'b101;
								temp<=data_in[3:0];
								state<=0;
							end
					default	:	state<=0;
				endcase
		end

	always @ (*)
		begin
			if(!rst_n)
				seg=8'b1111_1111;
			else
				case(temp)
					0 : seg = 8'b1100_0000;  // 显示数字 0
					1 : seg = 8'b1111_1001;  // 显示数字 1
					2 : seg = 8'b1010_0100;  // 显示数字 2
					3 : seg = 8'b1011_0000;  // 显示数字 3
					4 : seg = 8'b1001_1001;  // 显示数字 4
					5 : seg = 8'b1001_0010;  // 显示数字 5
					6 : seg = 8'b1000_0010;  // 显示数字 6
					7 : seg = 8'b1111_1000;  // 显示数字 7
					8 : seg = 8'b1000_0000;  // 显示数字 8
					9 : seg = 8'b1001_0000;  // 显示数字 9
					// 字母 A-F
					10 : seg = 8'b1000_1000;  // A
					11 : seg = 8'b1000_0011;  // b
					12 : seg = 8'b1100_0110;  // C
					13 : seg = 8'b1010_0001;  // d
					14 : seg = 8'b1000_0110;  // E
					15 : seg = 8'b1000_1110;  // F
					default : seg = 8'b1111_1111;  // 全灭
				endcase
		end
	
endmodule 
module key_filter(clk,rst_n,key_in,nege_flag,pose_flag);
	input clk,rst_n;
	input key_in;
	output nege_flag,pose_flag;
	
	reg [18:0] cnt;
	parameter T = 50_0000;
	
	reg state;
	reg key_out;
	
	always @ (posedge clk,negedge rst_n)
		begin
			if(!rst_n)//复位
				begin
					state<=0;
					cnt<=0;
					key_out<=1;//没按下
				end
			else
				case(state)
					0	:	begin
								if(key_in==0)
									if(cnt<T-1)
										begin
											cnt<=cnt+1;
											key_out<=1;
											state<=0;
										end
									else
										begin
											cnt<=0;
											key_out<=0;
											state<=1;
										end
								else
									begin
										cnt<=0;
										key_out<=1;
										state<=0;
									end
							end
							
					1	:	begin
								if(key_in==1)
									if(cnt<T-1)
										begin
											cnt<=cnt+1;
											key_out<=0;
											state<=1;
										end
									else
										begin
											cnt<=0;
											key_out<=1;
											state<=0;
										end
								else
									begin
										cnt<=0;
										key_out<=0;
										state<=1;
									end
							end
					default:state<=0;
				endcase
		end
		
	reg key_buff1,key_buff2;
	
	always @ (posedge clk,negedge rst_n)
		begin
			if(!rst_n)
				begin
					key_buff1<=0;
					key_buff2<=0;
				end
			else
				begin
					key_buff1<=key_out;
					key_buff2<=key_buff1;
				end
		end
	
	assign nege_flag=(~key_buff1)&&(key_buff2);
	assign pose_flag=(~key_buff2)&&key_buff1;
	
endmodule 
module key_num(clk,rst_n,add_flag,sub_flag,data);
	input clk,rst_n;
	input add_flag,sub_flag;
	output reg[3:0] data;
	always @ (posedge clk,negedge rst_n)
		begin
			if(!rst_n)
				data <=0;
			else
				if(add_flag)
					if(data<15)
						data<=data+1;
					else
						data<=data;
				else
					if(sub_flag)
						if(data>0)
							data<=data-1;
						else
							data<=data;
					else
						data<=data;
		end 
endmodule 
module key_num_top(clk,rst_n,key_add,key_sub,sel,seg);
	input clk,rst_n;
	input key_add,key_sub;
	output [2:0] sel;
	output [7:0] seg;
	
	key_filter k1(
						.clk(clk),
						.rst_n(rst_n),
						.key_in(key_add),
						.nege_flag(add_flag),
						.pose_flag()
					);
					
	key_filter k2(
						.clk(clk),
						.rst_n(rst_n),
						.key_in(key_sub),
						.nege_flag(sub_flag),
						.pose_flag()
					);
					
	wire [3:0] data;
	
	key_num k3(
						.clk(clk),
						.rst_n(rst_n),
						.add_flag(add_flag),
						.sub_flag(sub_flag),
						.data(data)
				);
	
	seg7 s1(
					.clk(clk),
					.rst_n(rst_n),
					.data_in({20'd0,data}),
					.sel(sel),
					.seg(seg)
				);
	
endmodule 

BCD码

完整代码

//module move(data_in,data_out);
//	input [19:0] data_in;
//	output [19:0] data_out;
//	wire [19:0] d_reg;
//	
//	adjust a1(
//					.d_in(data_in[19:16]),
//					.d_out(d_reg[19:16])
//				);
//	
//	adjust a2(
//					.d_in(data_in[15:12]),
//					.d_out(d_reg[15:12])
//				);
//				
//	adjust a3(
//					.d_in(data_in[11:8]),
//					.d_out(d_reg[11:8])
//				);
//	
//	assign d_reg[7:0]=data_in[7:0];
//	
//	assign data_out=d_reg<<1;
//				
//endmodule 



module move #(parameter BIN_WIDTH=10,
							parameter BCD_WIDTH=16)(data_in,data_out);
	input [BIN_WIDTH+BCD_WIDTH-1:0] data_in;
	output [BIN_WIDTH+BCD_WIDTH-1:0] data_out;
	
	wire [BIN_WIDTH+BCD_WIDTH-1:0] d_reg;
	
	genvar i;
	
	generate
		for(i=0;i<BCD_WIDTH/4;i=i+1)
			begin : adjust_inst
				adjust a1(.d_in(data_in[BIN_WIDTH+BCD_WIDTH-1-i*4:BIN_WIDTH+BCD_WIDTH-4-i*4]),
							.d_out(d_reg[BIN_WIDTH+BCD_WIDTH-1-i*4:BIN_WIDTH+BCD_WIDTH-4-i*4]));
			end
	endgenerate
	
	assign d_reg[BIN_WIDTH-1:0]=data_in[BIN_WIDTH-1:0];
	assign data_out =d_reg<<1;

endmodule 
//module bin_bcd_v2 (bin,bcd);
//	input [7:0] bin;
//	output [11:0] bcd;
//	
//	wire [19:0] temp[8:0];
//	
//	assign temp[0]={12'd0,bin};
//
//	move m1(.data_in(temp[0]),.data_out(temp[1]));
//	move m2(.data_in(temp[1]),.data_out(temp[2]));
//	move m3(.data_in(temp[2]),.data_out(temp[3]));
//	move m4(.data_in(temp[3]),.data_out(temp[4]));
//	move m5(.data_in(temp[4]),.data_out(temp[5]));
//	move m6(.data_in(temp[5]),.data_out(temp[6]));
//	move m7(.data_in(temp[6]),.data_out(temp[7]));
//	move m8(.data_in(temp[7]),.data_out(temp[8]));
//	
//	assign bcd=temp[8][19:8];
//
//endmodule 

//顶层

module bin_bcd_v2 # (parameter BIN_WIDTH=10,
							parameter BCD_WIDTH=16)(bin,bcd);
	input [BIN_WIDTH-1:0] bin;
	output [BCD_WIDTH-1:0] bcd;
	
	wire [BIN_WIDTH+BCD_WIDTH-1:0] temp [BIN_WIDTH:0];
	
	assign temp[0]={{BCD_WIDTH{1'b0}},bin};	

	genvar i;
	generate
		for(i=0;i<BIN_WIDTH;i=i+1)
			begin:move_inst
				move #(.BIN_WIDTH(BIN_WIDTH),
					.BCD_WIDTH(BCD_WIDTH)) m1(.data_in(temp[i]),.data_out(temp[i+1]));
			end
	endgenerate
	
	assign bcd=temp[BIN_WIDTH][BIN_WIDTH+BCD_WIDTH-1:BIN_WIDTH];
endmodule 
module adjust (d_in,d_out);
	input [3:0] d_in;
	output [3:0] d_out;
	assign d_out=(d_in>4)?d_in+3:d_in;
endmodule 
//bcd版本一
module bin_bcd(bin,bcd);
	input [7:0] bin;
	output [11:0] bcd;
	
	assign bcd[11:8]=bin/100;
	assign bcd[7:4]=(bin/10)%10;
	assign bcd[3:0]=bin%10;
endmodule 

测试代码

`timescale 1ns/1ps

module bin_bcd_tb;
	reg [9:0] bin;
	wire [15:0] bcd;
	
	bin_bcd_v2 dut(
						.bin(bin),
						.bcd(bcd)
					);
					
	initial begin
		bin=0;
		
		#20
		repeat(10)
			begin
				bin=($random)%1024;
				#20;
			end
		#20;
	end

endmodule 

BCD码的Keynum计数+第四个小数点点亮

完整代码

//module move(data_in,data_out);
//	input [19:0] data_in;
//	output [19:0] data_out;
//	wire [19:0] d_reg;
//	
//	adjust a1(
//					.d_in(data_in[19:16]),
//					.d_out(d_reg[19:16])
//				);
//	
//	adjust a2(
//					.d_in(data_in[15:12]),
//					.d_out(d_reg[15:12])
//				);
//				
//	adjust a3(
//					.d_in(data_in[11:8]),
//					.d_out(d_reg[11:8])
//				);
//	
//	assign d_reg[7:0]=data_in[7:0];
//	
//	assign data_out=d_reg<<1;
//				
//endmodule 



module move #(parameter BIN_WIDTH=10,
							parameter BCD_WIDTH=16)(data_in,data_out);
	input [BIN_WIDTH+BCD_WIDTH-1:0] data_in;
	output [BIN_WIDTH+BCD_WIDTH-1:0] data_out;
	
	wire [BIN_WIDTH+BCD_WIDTH-1:0] d_reg;
	
	genvar i;
	
	generate
		for(i=0;i<BCD_WIDTH/4;i=i+1)
			begin : adjust_inst
				adjust a1(.d_in(data_in[BIN_WIDTH+BCD_WIDTH-1-i*4:BIN_WIDTH+BCD_WIDTH-4-i*4]),
							.d_out(d_reg[BIN_WIDTH+BCD_WIDTH-1-i*4:BIN_WIDTH+BCD_WIDTH-4-i*4]));
			end
	endgenerate
	
	assign d_reg[BIN_WIDTH-1:0]=data_in[BIN_WIDTH-1:0];
	assign data_out =d_reg<<1;

endmodule 
//module bin_bcd_v2 (bin,bcd);
//	input [7:0] bin;
//	output [11:0] bcd;
//	
//	wire [19:0] temp[8:0];
//	
//	assign temp[0]={12'd0,bin};
//
//	move m1(.data_in(temp[0]),.data_out(temp[1]));
//	move m2(.data_in(temp[1]),.data_out(temp[2]));
//	move m3(.data_in(temp[2]),.data_out(temp[3]));
//	move m4(.data_in(temp[3]),.data_out(temp[4]));
//	move m5(.data_in(temp[4]),.data_out(temp[5]));
//	move m6(.data_in(temp[5]),.data_out(temp[6]));
//	move m7(.data_in(temp[6]),.data_out(temp[7]));
//	move m8(.data_in(temp[7]),.data_out(temp[8]));
//	
//	assign bcd=temp[8][19:8];
//
//endmodule 

module bin_bcd_v2 # (parameter BIN_WIDTH=10,
							parameter BCD_WIDTH=16)(bin,bcd);
	input [BIN_WIDTH-1:0] bin;
	output [BCD_WIDTH-1:0] bcd;
	
	wire [BIN_WIDTH+BCD_WIDTH-1:0] temp [BIN_WIDTH:0];
	
	assign temp[0]={{BCD_WIDTH{1'b0}},bin};	

	genvar i;
	generate
		for(i=0;i<BIN_WIDTH;i=i+1)
			begin:move_inst
				move #(.BIN_WIDTH(BIN_WIDTH),
					.BCD_WIDTH(BCD_WIDTH)) m1(.data_in(temp[i]),.data_out(temp[i+1]));
			end
	endgenerate
	
	assign bcd=temp[BIN_WIDTH][BIN_WIDTH+BCD_WIDTH-1:BIN_WIDTH];
endmodule 
module adjust (d_in,d_out);
	input [3:0] d_in;
	output [3:0] d_out;
	assign d_out=(d_in>4)?d_in+3:d_in;
endmodule 
module seg7(clk,rst_n,data_in,sel,seg,dp);
	input clk,rst_n;
	input [23:0] data_in;
	input [5:0] dp;
	output reg[2:0] sel;
	output reg[7:0] seg;

	//分频器
	reg [14:0] cnt;
	reg clk_1ms;
	parameter T=25000;//1毫秒/2微秒=50000 占空比50%
	
	always @ (posedge clk,negedge rst_n)
		begin
			if(!rst_n)
				begin
					cnt<=0;
					clk_1ms<=0;
				end
			else
				if(cnt<T-1)
					cnt<=cnt+1;
				else
					begin
						cnt<=0;
						clk_1ms<=~clk_1ms;
					end
		end
	
	reg [3:0] temp;
	reg [2:0] state;
	
	always @ (posedge clk_1ms,negedge rst_n)
		begin
			if(!rst_n)
				begin
					sel<=3'b000;
					state<=0;
					temp<=0;
				end
			else
				case(state)
					0	:	begin
								sel<=3'b000;
								temp<=data_in[23:20];
								state<=1;
							end
					1	:	begin
								sel<=3'b001;
								temp<=data_in[19:16];
								state<=2;
							end
					2	:	begin
								sel<=3'b010;
								temp<=data_in[15:12];
								state<=3;
							end
					3	:	begin
								sel<=3'b011;
								temp<=data_in[11:8];
								state<=4;
							end
					4	:	begin
								sel<=3'b100;
								temp<=data_in[7:4];
								state<=5;
							end
					5	:	begin
								sel<=3'b101;
								temp<=data_in[3:0];
								state<=0;
							end
					default	:	state<=0;
				endcase
		end

	always @ (*)
		begin
			if(!rst_n)
				seg[6:0]=7'b111_1111;
			else
				case(temp)
					0 : seg[6:0] = 7'b100_0000;  // 显示数字 0
					1 : seg[6:0] = 7'b111_1001;  // 显示数字 1
					2 : seg[6:0] = 7'b010_0100;  // 显示数字 2
					3 : seg[6:0] = 7'b011_0000;  // 显示数字 3
					4 : seg[6:0] = 7'b001_1001;  // 显示数字 4
					5 : seg[6:0] = 7'b001_0010;  // 显示数字 5
					6 : seg[6:0] = 7'b000_0010;  // 显示数字 6
					7 : seg[6:0] = 7'b111_1000;  // 显示数字 7
					8 : seg[6:0] = 7'b000_0000;  // 显示数字 8
					9 : seg[6:0] = 7'b001_0000;  // 显示数字 9
					// 字母 A-F
					10 : seg[6:0] = 7'b000_1000;  // A
					11 : seg[6:0] = 7'b000_0011;  // b
					12 : seg[6:0] = 7'b100_0110;  // C
					13 : seg[6:0] = 7'b010_0001;  // d
					14 : seg[6:0] = 7'b000_0110;  // E
					15 : seg[6:0] = 7'b000_1110;  // F
					default : seg[6:0] = 7'b111_1111;  // 全灭
				endcase
		end
		
	always @ (*)
		begin
			if(!rst_n)
				seg[7]=1'b1;
			else
				case(sel)
					0	:	seg[7]=dp[5];
					1	:	seg[7]=dp[4];
					2	:	seg[7]=dp[3];
					3	:	seg[7]=dp[2];
					4	:	seg[7]=dp[1];
					6	:	seg[7]=dp[0];
					default	:	seg[7]=1'b1;
				endcase
		end 
	
endmodule 
module key_filter(clk,rst_n,key_in,nege_flag,pose_flag);
	input clk,rst_n;
	input key_in;
	output nege_flag,pose_flag;
	
	reg [18:0] cnt;
	parameter T = 50_0000;
	
	reg state;
	reg key_out;
	
	always @ (posedge clk,negedge rst_n)
		begin
			if(!rst_n)//复位
				begin
					state<=0;
					cnt<=0;
					key_out<=1;//没按下
				end
			else
				case(state)
					0	:	begin
								if(key_in==0)
									if(cnt<T-1)
										begin
											cnt<=cnt+1;
											key_out<=1;
											state<=0;
										end
									else
										begin
											cnt<=0;
											key_out<=0;
											state<=1;
										end
								else
									begin
										cnt<=0;
										key_out<=1;
										state<=0;
									end
							end
							
					1	:	begin
								if(key_in==1)
									if(cnt<T-1)
										begin
											cnt<=cnt+1;
											key_out<=0;
											state<=1;
										end
									else
										begin
											cnt<=0;
											key_out<=1;
											state<=0;
										end
								else
									begin
										cnt<=0;
										key_out<=0;
										state<=1;
									end
							end
					default:state<=0;
				endcase
		end
		
	reg key_buff1,key_buff2;
	
	always @ (posedge clk,negedge rst_n)
		begin
			if(!rst_n)
				begin
					key_buff1<=0;
					key_buff2<=0;
				end
			else
				begin
					key_buff1<=key_out;
					key_buff2<=key_buff1;
				end
		end
	
	assign nege_flag=(~key_buff1)&&(key_buff2);
	assign pose_flag=(~key_buff2)&&key_buff1;
	
endmodule 
module key_num(clk,rst_n,add_flag,sub_flag,data);
	input clk,rst_n;
	input add_flag,sub_flag;
	output reg[3:0] data;
	always @ (posedge clk,negedge rst_n)
		begin
			if(!rst_n)
				data <=0;
			else
				if(add_flag)
					if(data<15)
						data<=data+1;
					else
						data<=data;
				else
					if(sub_flag)
						if(data>0)
							data<=data-1;
						else
							data<=data;
					else
						data<=data;
		end 
endmodule 
module key_num_top(clk,rst_n,key_add,key_sub,sel,seg);
	input clk,rst_n;
	input key_add,key_sub;
	output [2:0] sel;
	output [7:0] seg;
	
	key_filter k1(
						.clk(clk),
						.rst_n(rst_n),
						.key_in(key_add),
						.nege_flag(add_flag),
						.pose_flag()
					);
					
	key_filter k2(
						.clk(clk),
						.rst_n(rst_n),
						.key_in(key_sub),
						.nege_flag(sub_flag),
						.pose_flag()
					);
					
	wire [3:0] data;
	wire [7:0] data_bcd;
	
	key_num k3(
						.clk(clk),
						.rst_n(rst_n),
						.add_flag(add_flag),
						.sub_flag(sub_flag),
						.data(data)
				);
	
	seg7 s1(
					.clk(clk),
					.rst_n(rst_n),
					.data_in({16'd0,data_bcd}),
					.sel(sel),
					.seg(seg),
					.dp(6'b111011)
				);
				
	bin_bcd_v2 # (.BIN_WIDTH(4),
						.BCD_WIDTH(8)) b1(.bin(data),.bcd(data_bcd));
	
endmodule 

呼吸灯

原理:逐渐点亮2s,逐渐熄灭2s。使用PWM脉冲宽度调制:将两秒时间分为1000份,每份2毫秒,两毫米再分成一千份,2微秒,两微秒直接使用系统时钟进行计数,最终将两毫秒的计数与两秒的计数进行判断,如果两豪秒计数器小于两秒计数器,就让led点亮。

一个灯的电亮和熄灭

module led_breath (clk,rst_n,led);
	input clk,rst_n;
	output led;
	
	reg [6:0] cnt_2us;
	reg [9:0] cnt_2ms,cnt_2s;
	
	parameter T2us=100;
	parameter T2ms=1000;
	parameter T2s=1000;
	always @ (posedge clk,negedge rst_n)
		begin
			if(!rst_n)
				cnt_2us<=0;
			else
				if(cnt_2us<T2us-1)
					cnt_2us<=cnt_2us+1;
				else
					cnt_2us<=0;
		end
		
		wire flag_2us;
		
		assign flag_2us=(cnt_2us==T2us-1)?1'b1:1'b0;
		
		//2ms计数器
		always @ (posedge clk,negedge rst_n)
			begin
				if(!rst_n)
					cnt_2ms<=0;
				else
					if(flag_2us)
						if(cnt_2ms<T2ms-1)
							cnt_2ms<=cnt_2ms+1;
						else
							cnt_2ms<=0;
					else
						cnt_2ms<=cnt_2ms;
			end
			
		wire flag_2ms;
		
		assign flag_2ms=(cnt_2ms==T2ms-1&&flag_2us)?1'b1:1'b0;
		
		//2s计数器
		always @ (posedge clk,negedge rst_n)
			begin
				if(!rst_n)
					cnt_2s<=0;
				else
					if(flag_2ms)
						if(cnt_2s<T2s-1)
							cnt_2s<=cnt_2s+1;
						else
							cnt_2s<=0;
					else
						cnt_2s<=cnt_2s;
			end
		
		wire flag_2s;
		assign flag_2s=(cnt_2s==T2s-1&&flag_2ms)?1'b1:1'b0;
		reg led_change;
		always @ (posedge clk,negedge rst_n)
			begin
				if(!rst_n)
					led_change<=0;
				else
					if(flag_2s)
						led_change<=~led_change;
					else
						led_change<=led_change;
			end
		wire led_signal;
		assign led_signal = (cnt_2ms<cnt_2s)?1'b0:1'b1;
		assign led=(led_change==0)?led_signal:(~led_signal);
		
		
	
endmodule 

四个灯循环点亮

module led_breath_top(clk,rst_n,led);
	input clk,rst_n;
	output [3:0] led;
	wire [3:0] en;
	
	led_ctrl l1(
						.clk(clk),
						.rst_n(rst_n),
						.en(en)
					);
					
	led_breath l2(
						.clk(clk),
						.rst_n(en[3]),
						.led(led[3])
					);
					
					
	led_breath l3(
						.clk(clk),
						.rst_n(en[2]),
						.led(led[2])
					);
	
	led_breath l4(
						.clk(clk),
						.rst_n(en[1]),
						.led(led[1])
					);
					
	led_breath l5(
						.clk(clk),
						.rst_n(en[0]),
						.led(led[0])
					);
	
	
endmodule 
module led_ctrl(clk,rst_n,en);
	input clk,rst_n;
	output reg[3:0] en;
	reg[28:0] cnt;
	parameter T1=5000_0000;
	parameter T2=10000_0000;
	parameter T3=15000_0000;
	
	always @ (posedge clk,negedge rst_n)
		begin
			if(!rst_n)
				cnt<=0;
			else
				if(cnt<T3-1)
					cnt<=cnt+1;
				else
					cnt<=cnt;
		end
		
	always @ (*)
		begin
			if(!rst_n)
				en<=4'b0000;
			else
				if(cnt>=T3-1)
					en<=4'b1111;
				else
					if(cnt>=T2-1)
						en<=4'b1110;
					else
						if(cnt>=T1-1)
							en<=4'b1100;
						else
							en<=4'b1000;
		end
	
endmodule 
module led_breath (clk,rst_n,led);
	input clk,rst_n;
	output led;
	
	reg [6:0] cnt_2us;
	reg [9:0] cnt_2ms,cnt_2s;
	
	parameter T2us=100;
	parameter T2ms=1000;
	parameter T2s=1000;
	always @ (posedge clk,negedge rst_n)
		begin
			if(!rst_n)
				cnt_2us<=0;
			else
				if(cnt_2us<T2us-1)
					cnt_2us<=cnt_2us+1;
				else
					cnt_2us<=0;
		end
		
		wire flag_2us;
		
		assign flag_2us=(cnt_2us==T2us-1)?1'b1:1'b0;
		
		//2ms计数器
		always @ (posedge clk,negedge rst_n)
			begin
				if(!rst_n)
					cnt_2ms<=0;
				else
					if(flag_2us)
						if(cnt_2ms<T2ms-1)
							cnt_2ms<=cnt_2ms+1;
						else
							cnt_2ms<=0;
					else
						cnt_2ms<=cnt_2ms;
			end
			
		wire flag_2ms;
		
		assign flag_2ms=(cnt_2ms==T2ms-1&&flag_2us)?1'b1:1'b0;
		
		//2s计数器
		always @ (posedge clk,negedge rst_n)
			begin
				if(!rst_n)
					cnt_2s<=0;
				else
					if(flag_2ms)
						if(cnt_2s<T2s-1)
							cnt_2s<=cnt_2s+1;
						else
							cnt_2s<=0;
					else
						cnt_2s<=cnt_2s;
			end
		
		wire flag_2s;
		assign flag_2s=(cnt_2s==T2s-1&&flag_2ms)?1'b1:1'b0;
		reg led_change;
		always @ (posedge clk,negedge rst_n)
			begin
				if(!rst_n)
					led_change<=0;
				else
					if(flag_2s)
						led_change<=~led_change;
					else
						led_change<=led_change;
			end
		wire led_signal;
		assign led_signal = (cnt_2ms<cnt_2s)?1'b0:1'b1;
		assign led=(led_change==0)?led_signal:(~led_signal);
		
		
	
endmodule 

自动售货机

模块功能

输入信号

  • clk:时钟信号(同步状态转换)
  • rst_n:低电平复位信号(复位状态机和输出)
  • half:投入0.5元(脉冲信号)
  • one:投入1元(脉冲信号)

输出信号

  • goods:出货信号(高电平有效)
  • change:找零信号(高电平有效)

核心逻辑

  • 通过 6个状态 跟踪累计金额,假设商品价格为 2.5元(从状态转移推断)。
  • 达到目标金额后:
    • 状态5:出货不找零(累计刚好2.5元)。
    • 状态6:出货并找零(累计超过2.5元)。

状态机详解

状态 累计金额 可能的下一状态转移 行为
0 0元 投0.5元→1;投1元→2 初始化
1 0.5元 投0.5元→2;投1元→3 累计中
2 1元 投0.5元→3;投1元→4 累计中
3 1.5元 投0.5元→4;投1元→6 累计中
4 2元 投0.5元→5;投1元→6 接近目标金额
5 2.5元 返回状态0,goods=1 出货不找零
6 3元 返回状态0,goods=1change=1 出货并找零0.5元

完整代码

module auto_sell (clk,rst_n,half,one,change,goods);
	input clk,rst_n;
	input half,one;
	output reg change;
	output reg goods;
	reg[3:0] state;
	always @(posedge clk,negedge rst_n)
		begin
			if(!rst_n)
				begin
					state<=0;
					change<=0;
					goods<=0;
				end
			else
				case(state)
					0: begin
						if(half)
							begin
								state<=1;
								goods<=0;
								change<=0;
							end
						else
							if(one)
								begin
									state<=2;
									goods<=0;
									change<=0;
								end
							else
								begin
									state<=0;
									goods<=0;
									change<=0;
								end
						end
					
					1: begin
						if(half)
							begin
								state<=2;
							end
						else
							if(one)
								begin
									state<=3;
								end
							else
								begin
									state<=1;
								end
						end
					
					2: begin
						if(half)
							begin
								state<=3;
							end
						else
							if(one)
								begin
									state<=4;
								end
							else
								begin
									state<=2;
								end
						end
					
					3: begin
						if(half)
							begin
								state<=4;
							end
						else
							if(one)
								begin
									state<=6;
								end
							else
								begin
									state<=3;
								end
						end
						
					4: begin
						if(half)
							begin
								state<=5;
							end
						else
							if(one)
								begin
									state<=6;
								end
							else
								begin
									state<=4;
								end
						end
					
					5: begin
							state<=0;
							goods<=1;
							change<=0;
						end
						
					6: begin
							state<=0;
							goods<=1;
							change<=1;
						end
					default :state<=0;
				endcase
		end
endmodule 

测试代码

`timescale 1ns/1ps

module auto_sell_tb;

 reg clk, rst_n;
 reg half, one;
 
 wire change;
 wire goods;
 
 auto_sell dut(
      .clk(clk),
      .rst_n(rst_n),
      .half(half),
      .one(one), 
      .change(change), 
      .goods(goods)
     );
     
 initial begin
  clk = 0; rst_n = 0;
  one = 0; half = 0;
  
  #200.1 rst_n = 1;
  
  #200 half = 1;
  #20 half = 0;
  
  #50 one = 1;
  #20 one = 0;
  
  #100 half = 1;
  #20 half = 0;
  
  #100 one = 1;
  #20 one = 0;
  
  #5000 $stop;
 end
 
 always #10 clk = ~clk;
     
endmodule
posted @ 2025-07-06 10:41  快乐星猫i  阅读(8)  评论(0)    收藏  举报