当前位置:   article > 正文

FPGA-自动售货机verilog

自动售货机verilog

1.项目需求

该项目来自野火的状态机拓展提高训练

image-20220916115843938

2.需求分析

读完这道题,我认为在该项目中我们需要三个模块。分别是,按键消抖模块,可乐状态机模块,LED控制模块。

  • 按键消抖模块:根据按键的输入,在完成消抖判断后输出值。
  • 可乐状态机:根据按键消抖模块的输出,得到每一个状态,将状态作为模块的输出给LED模块
  • LED模块:根据状态机的状态做出对应的操作即可

模块框图如下

image-20220916174605005

3.代码编写

3.1 按键消抖模块

思路:当判断到按键按下,例如低电平触发后,开启一个计数器,计时20ms(可调整)在20ms区间或超过20ms的区间里,如果持续为低电平,那么我们认为按键真的触发了,而不是因为电平抖动。拉高一个变量作为按键的输出即可。

代码如下 较为简单不做详细解释

module key_filter
#(
	parameter CNT_MAX = 20'd999_999 //50Mhz的时钟 计20ms
)
(
	input wire clk , //系统时钟50Mh
	input wire rst , //全局复位
	input wire key_in ,
	output reg key_out
);


reg [20:0] cnt ; 

 //计数器
always@(posedge clk or negedge rst)
	if(!rst)
		cnt <= 20'b0;
	else if(key_in == 1'b1)
		cnt <= 20'b0;
	//如果在该按键触发期间,计数超过了20ms,不清零,保持原状即可
	else if(cnt == CNT_MAX && key_in == 1'b0)
		cnt <= CNT_MAX;
	else
		cnt <= cnt + 1'b1;


always@(posedge clk or negedge rst)
	if(!rst)
		key_out <= 1'b0;
	//在CNT_MAX时拉高标志,需要-1是因为时序电路
	else if(cnt == CNT_MAX-1'b1)
		key_out = 1'b1;
	else 
		key_out = 1'b0;

endmodule

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38

3.2 可乐状态机模块

3.2.1状态机简介

这应该是这题里面最重要的部分。状态机的编程思想具体大家可以查阅相关文章,这里只做大概解释。

所谓状态机,我认为指的是让程序根据输入和输出,在指定的有限个状态之间进行轮转的模式

举个例子

如果是电梯的话,每1秒运行一层楼,都进行一次判断,例如现在在5楼停止,处于关门状态

有人按下了1楼,下一个时刻,状态机检测到了1楼的信号,和进行比对,5>1,于是把状态改为下楼

1S后下到了4楼,此时,有人按下了3楼。又过了1S,电梯运行到了3楼,状态机发现当前楼层是需要停止的楼层于是把状态改为开门,开门一段时间后再把状态改回关门

关门后,发现1楼还没到,那么状态改为下楼,继续走到1楼,到了1楼之后,还是进行开门,关门的状态切换,再次判断发现没有要走的楼层了,状态就停留在了关门。

伪代码例子如图

case(state)
	关门:
		if(目标楼层 > 当前楼层)  			state <= 上升
		if(目标楼层 < 当前楼层)  			state <= 下降
		if(目标楼层 == 当前楼层 && 无人按下) state <= 关门
		if(目标楼层 == 当前楼层 && 有人按下) state <= 开门
	开门:
		if(延时时间到达) 	state <= 关门
		else 			state <= 开门
	上升:
		if(目标楼层 > 当前楼层)  			state <= 上升
		if(目标楼层 == 当前楼层)  			state <= 开门
	下降:
		if(目标楼层 < 当前楼层)  			state <= 下降
		if(目标楼层 == 当前楼层)  			state <= 开门
endcase
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16

3.2.2状态机核心代码

如果能理解这个代码的话,那么本题的可乐状态机其实是更加简单的。

这里我们定义按键0是0.5元,按键1是1元,根据题目要求,核心部分状态机如下。KEY0投币的话 对应状态+0.5元,KEY1加一元,超过10S没投币的话 状态回到空闲态。2.5和3元的状态下,当计数到达10S后回到空闲态

//投币状态机
always@(posedge clk or negedge rst)
	if(!rst)
		state <= IDLE;
	else case(state)
			IDLE: //空闲
				if(key_out[0]) 		state <= HALF;
				else if(key_out[1]) 	state <= ONE;
			HALF: //0.5
				if(key_out[0]) 		state <= ONE;
				else if(key_out[1]) 	state <= ONE_HALF;
        		else if(key_flag) 	state <= IDLE; //这里是10s后没按键按下的标志位
			ONE: //1 
				if(key_out[0]) 		state <= ONE_HALF;
				else if(key_out[1]) 	state <= TWO;
				else if(key_flag) 	state <= IDLE;
			ONE_HALF: //1.5	 
				if(key_out[0]) 		state <= TWO;
				else if(key_out[1]) 	state <= TWO_HALF;
				else if(key_flag) 	state <= IDLE;
			TWO:	 //2 
				if(key_out[0]) 		state <= TWO_HALF;
				else if(key_out[1]) 	state <= THREE;
				else if(key_flag) 	state <= IDLE;
			TWO_HALF:	  //2.5
                if(cnt_10s==CNT_10S) state <= IDLE; //这里是流水的10s的标志位
			THREE:	  //3
                if(cnt_10s==CNT_10S) state <= IDLE;//这里是双向流水的10s的标志位
			default:	 					state <= IDLE;
		endcase
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30

根据题目要求还需要有10s内按键没按下后清零状态的功能,那么这个功能靠一个定时器实现即可,不过这里不推荐直接直接计算10S(一个大佬和我说那样直接算那么长不太好)。

因为我们的时钟是50Mhz,也就是20ns。那么我选择计数500ms,20个500ms就是1S

//计数500ms 除非按键按下或者计满
always@(posedge clk or negedge rst)
	if(!rst)
		key_cnt <= 25'b0;
	else if(key_cnt == CNT_500MS_MAX || key_out[0] || key_out[1]) //按键按下时清空计数
		key_cnt <= 25'b0;
	else
		key_cnt <= key_cnt + 1'b1;	

//按键500ms标志
always@(posedge clk or negedge rst)
	if(!rst)
		key_500ms_flag <= 1'b0;
	else if(key_cnt == CNT_500MS_MAX -1 )
		key_500ms_flag <= 1'b1;
	else
		key_500ms_flag <= 1'b0;	
		
//计数10s 除非按键按下
always@(posedge clk or negedge rst)
	if(!rst)
		key_10s <= 5'b0;
	else if( (key_10s == CNT_10S && key_500ms_flag) || key_out[0] || key_out[1]) //按键按下时清空计数
		key_10s <= 5'b0;
	else if(key_500ms_flag)
		key_10s <= key_10s + 1'b1;	
		
//按键10s标志
always@(posedge clk or negedge rst)
	if(!rst)
		key_flag <= 1'd0;
	else if(key_10s == CNT_10S - 1 && key_500ms_flag) 
		key_flag <= 1'd1;
	else
		key_flag <= 1'd0;
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35

除了按键按下10s内清零外,还有流水灯10s后自动切换会初始状态的代码,那么我们就是在2.5元和3元的状态触发时,使能一个定时器,计到10s后让该状态跳转回IDLE的空闲状态即可。

//10S定时使能信号
always@(posedge clk or negedge rst)
	if(!rst)
		cnt_en <= 1'b0;
	else if(cnt_flag)
		cnt_en <= 1'b0;
	else if(state == TWO_HALF || state == THREE)
		cnt_en <= 1'b1;


//500ms计数器
always@(posedge clk or negedge rst)
	if(!rst)
		cnt <= 25'd0;
	else if(cnt == CNT_500MS_MAX && cnt_en) 	
		cnt <= 25'd0;
	else if(cnt_en)	//使能时才运行定时器
		cnt <= cnt + 1'b1;	

//500ms计数标志位
always@(posedge clk or negedge rst)
	if(!rst)
		cnt_500ms_flag <= 1'b0;
	else if(cnt == CNT_500MS_MAX - 1) 	
		cnt_500ms_flag <= 1'b1;
	else //使能时才运行定时器
		cnt_500ms_flag <=  1'b0;	
		
//计20个500ms		
always@(posedge clk or negedge rst)
	if(!rst)
		cnt_10s <= 5'b0;
	else if(cnt_10s == CNT_10S && cnt_500ms_flag)
		cnt_10s <= 5'b0;
	else if(cnt_500ms_flag)	
		cnt_10s <= cnt_10s + 1'b1;

//流水灯10S标志位
always@(posedge clk or negedge rst)
	if(!rst)
		cnt_flag <= 1'd0;
	else if(cnt_10s == CNT_10S - 1 && cnt_500ms_flag) 
		cnt_flag <= 1'd1;
	else
		cnt_flag <= 1'd0;
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45

3.3.3 状态机模块完整代码

module cola_fsm#(
	parameter CNT_500MS_MAX = 25'd24_999_999,
	parameter CNT_10S = 5'd19,
	
	parameter IDLE = 		7'b000_0001,
	parameter HALF = 		7'b000_0010,
	parameter ONE = 		7'b000_0100,
	parameter ONE_HALF = 7'b000_1000,
	parameter TWO = 		7'b001_0000,
	parameter TWO_HALF = 7'b010_0000,
	parameter THREE = 	7'b100_0000
)(
	input wire clk,
	input wire rst,
	input wire[1:0] key_out,
	output wire[6:0] state_out
);

reg [6:0] state;

reg cnt_en;				//10S计数器使能
reg [24:0] cnt;		//500ms计数器
reg cnt_500ms_flag;
reg [4:0]cnt_10s;		//流水灯的10s计数器
reg cnt_flag;

reg [24:0] key_cnt; //投币的500ms定时器
reg [4:0] key_10s;	//投币的10s定时器
reg key_500ms_flag;
reg key_flag;

assign state_out = state; //这样的话RTL会识别出是一个状态机 但是如果不这样的话也没问题
//投币状态机
always@(posedge clk or negedge rst)
	if(!rst)
		state <= IDLE;
	else case(state)
			IDLE:	 
				if(key_out[0]) 		state <= HALF;
				else if(key_out[1]) 	state <= ONE;
			HALF:
				if(key_out[0]) 		state <= ONE;
				else if(key_out[1]) 	state <= ONE_HALF;
				else if(key_flag) 	state <= IDLE;
			ONE:	 
				if(key_out[0]) 		state <= ONE_HALF;
				else if(key_out[1]) 	state <= TWO;
				else if(key_flag) 	state <= IDLE;
			ONE_HALF:	 
				if(key_out[0]) 		state <= TWO;
				else if(key_out[1]) 	state <= TWO_HALF;
				else if(key_flag) 	state <= IDLE;
			TWO:	 
				if(key_out[0]) 		state <= TWO_HALF;
				else if(key_out[1]) 	state <= THREE;
				else if(key_flag) 	state <= IDLE;
			TWO_HALF:	 
				if(cnt_flag) state <= IDLE;
			THREE:	 
				if(cnt_flag) state <= IDLE;
			default:	 					state <= IDLE;
		endcase

//10S定时使能信号
always@(posedge clk or negedge rst)
	if(!rst)
		cnt_en <= 1'b0;
	else if(cnt_flag)
		cnt_en <= 1'b0;
	else if(state == TWO_HALF || state == THREE)
		cnt_en <= 1'b1;


//500ms计数器
always@(posedge clk or negedge rst)
	if(!rst)
		cnt <= 25'd0;
	else if(cnt == CNT_500MS_MAX && cnt_en) 	
		cnt <= 25'd0;
	else if(cnt_en)	//使能时才运行定时器
		cnt <= cnt + 1'b1;	


//500ms计数器
always@(posedge clk or negedge rst)
	if(!rst)
		cnt_500ms_flag <= 1'b0;
	else if(cnt == CNT_500MS_MAX - 1) 	
		cnt_500ms_flag <= 1'b1;
	else if(cnt_en)	//使能时才运行定时器
		cnt_500ms_flag <=  1'b0;	
		
//计20个500ms		
always@(posedge clk or negedge rst)
	if(!rst)
		cnt_10s <= 5'b0;
	else if(cnt_10s == CNT_10S && cnt_500ms_flag)
		cnt_10s <= 5'b0;
	else if(cnt_500ms_flag)	
		cnt_10s <= cnt_10s + 1'b1;

//流水灯10S标志位
always@(posedge clk or negedge rst)
	if(!rst)
		cnt_flag <= 1'd0;
	else if(cnt_10s == CNT_10S - 1 && cnt_500ms_flag) 
		cnt_flag <= 1'd1;
	else
		cnt_flag <= 1'd0;
		
//计数500ms 除非按键按下或者计满
always@(posedge clk or negedge rst)
	if(!rst)
		key_cnt <= 25'b0;
	else if(key_cnt == CNT_500MS_MAX || key_out[0] || key_out[1]) //按键按下时清空计数
		key_cnt <= 25'b0;
	else
		key_cnt <= key_cnt + 1'b1;	

//按键500ms标志
always@(posedge clk or negedge rst)
	if(!rst)
		key_500ms_flag <= 1'b0;
	else if(key_cnt == CNT_500MS_MAX -1 )
		key_500ms_flag <= 1'b1;
	else
		key_500ms_flag <= 1'b0;	
		
//计数10s 除非按键按下
always@(posedge clk or negedge rst)
	if(!rst)
		key_10s <= 5'b0;
	else if( (key_10s == CNT_10S && key_500ms_flag) || key_out[0] || key_out[1]) //按键按下时清空计数
		key_10s <= 5'b0;
	else if(key_500ms_flag)
		key_10s <= key_10s + 1'b1;	
		
//按键10s标志
always@(posedge clk or negedge rst)
	if(!rst)
		key_flag <= 1'd0;
	else if(key_10s == CNT_10S - 1 && key_500ms_flag) 
		key_flag <= 1'd1;
	else
		key_flag <= 1'd0;
endmodule
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72
  • 73
  • 74
  • 75
  • 76
  • 77
  • 78
  • 79
  • 80
  • 81
  • 82
  • 83
  • 84
  • 85
  • 86
  • 87
  • 88
  • 89
  • 90
  • 91
  • 92
  • 93
  • 94
  • 95
  • 96
  • 97
  • 98
  • 99
  • 100
  • 101
  • 102
  • 103
  • 104
  • 105
  • 106
  • 107
  • 108
  • 109
  • 110
  • 111
  • 112
  • 113
  • 114
  • 115
  • 116
  • 117
  • 118
  • 119
  • 120
  • 121
  • 122
  • 123
  • 124
  • 125
  • 126
  • 127
  • 128
  • 129
  • 130
  • 131
  • 132
  • 133
  • 134
  • 135
  • 136
  • 137
  • 138
  • 139
  • 140
  • 141
  • 142
  • 143
  • 144
  • 145
  • 146

3.3 LED控制模块

这里就比较简单了,只需要根据状态操作LED即可

module led_controller
#(
	parameter CNT_500MS_MAX = 25'd24_999_999
)
(
	input wire clk,
	input wire rst,
	input wire[6:0] state,
	output wire[3:0] led_out
);
reg [24:0] cnt;
reg[1:0] led_state;
reg[3:0] led_out_reg;
reg double_state;
reg cnt_flag	;


//led输出信号
assign led_out = ~led_out_reg;
	
//500ms计数器
always@(posedge clk or negedge rst)
	if(!rst)
		cnt <= 25'b0;
	else if(cnt == CNT_500MS_MAX && (|led_state))	
		cnt <= 25'b0;
	else if((|led_state))
		cnt <= cnt + 1'b1;
	else 
		cnt <= cnt;
//特殊情况
always@(posedge clk or negedge rst)
	if(!rst)
		led_state <= 2'b00;
	else if(state == 7'b0100000) //未找零
		led_state <= 2'b10; 
	else if(state == 7'b1000000) //找零
		led_state <= 2'b01;
	else 
		led_state <= 2'b00;
		
		
//计数器满500ms标志位
always@(posedge clk or negedge rst)
	if(!rst)
		cnt_flag	<= 1'b0;
	else if(cnt == CNT_500MS_MAX - 1 && (|led_state))	
		cnt_flag	<= 1'b1;
	else
		cnt_flag	<= 1'b0;
		
//led寄存器信号
always@(posedge clk or negedge rst)
	if(!rst)
		led_out_reg <= 4'b0000;
	else if(state == 7'b000_0001)
		led_out_reg <= 4'b0000;
	else if(state == 7'b0000010)
		led_out_reg <= 4'b1000;
	else if(state == 7'b0000100)
		led_out_reg <= 4'b1100;
	else if(state == 7'b0001000)
		led_out_reg <= 4'b1110;
	else if(state == 7'b0010000)
		led_out_reg <= 4'b1111; 
	//双向流水
	else if(led_state ==  2'b01)	begin
		if(led_out_reg == 4'b0000 || led_out_reg == 4'b1111 || led_out_reg == 4'b1110)
			led_out_reg <= 4'b0001;
		else if(cnt_flag && double_state)
			led_out_reg <= led_out_reg << 1'b1;
		else if(cnt_flag)
			led_out_reg <= led_out_reg >> 1'b1; 
	end
		
	//单向流水
	else if(led_state ==  2'b10)	begin
		if(led_out_reg == 4'b0000 || led_out_reg == 4'b1111 || led_out_reg == 4'b1110)
			led_out_reg <= 4'b0001;
		else if(cnt_flag && led_out_reg == 4'b1000)
			led_out_reg <= 4'b0001;
		else if(cnt_flag)
			led_out_reg <= led_out_reg << 1'b1; 
	end
	else led_out_reg <= 4'b0000;
		
//double_state信号
always@(posedge clk or negedge rst)
	if(!rst)
		double_state <= 1'b0;
	else if(led_out_reg == 4'b0001 && led_state ==  2'b01)	
		double_state <= 1'b1;
	else if(led_out_reg == 4'b1000 && led_state ==  2'b01)
		double_state <= 1'b0;
	else if(led_state == 2'b10)
		double_state <= 1'b0;
	else 
		double_state <= double_state;
endmodule

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72
  • 73
  • 74
  • 75
  • 76
  • 77
  • 78
  • 79
  • 80
  • 81
  • 82
  • 83
  • 84
  • 85
  • 86
  • 87
  • 88
  • 89
  • 90
  • 91
  • 92
  • 93
  • 94
  • 95
  • 96
  • 97
  • 98
  • 99
  • 100

3.4 顶层模块

没什么好说的 例化各个模块就可以了

module cola_machine(
	input wire [1:0] key_in,
	input wire clk,
	input wire rst,
	output wire[3:0] led_out
);

wire[1:0] key_out;
wire [6:0] state;


//按键消抖模块 //这边其实应该改在test_bench里的 这里懒得弄了
key_filter #(.CNT_MAX(20'd5))key1(
	.clk(clk),
	.rst(rst),
	.key_in(key_in[0]),
	.key_out(key_out[0])
);
key_filter #(.CNT_MAX(20'd5))key2(
	.clk(clk),
	.rst(rst),
	.key_in(key_in[1]),
	.key_out(key_out[1])
);
//led控制模块
led_controller led_ctrl(
	.clk(clk),
	.rst(rst),
	.state(state),
	.led_out(led_out)
);

//状态机 
cola_fsm fsm(
	.clk(clk),
	.rst(rst),
	.key_out(key_out),
	.state_out(state)
);

endmodule
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41

4.仿真

4.1 TestBench

`timescale 1ns/1ns
module tb_cola_machine();
 
//reg define
reg clk;
reg rst;
reg [1:0]key_in;
reg random;
wire [3:0]led_out;

initial begin
	clk = 1'b1;
	rst <= 1'b0;
	#20
	rst <= 1'b1;
end


always #10 clk = ~clk;

always@(posedge clk or negedge rst)
	if(!rst)
		random <= 1'b0;
	else 
		random <= {$random} % 2;

always@(posedge clk or negedge rst)
	if(!rst)
		key_in[0] <= 1'b0;
	else 
		key_in[0] <= random;

always@(posedge clk or negedge rst)
	if(!rst)
		key_in[1] <= 1'b0;
	else 
		key_in[1] <= ~random;

defparam cola_machine_inst.fsm.CNT_500MS_MAX = 25'd24;
defparam cola_machine_inst.led_ctrl.CNT_500MS_MAX = 25'd24;
 cola_machine
 cola_machine_inst(
	.clk (clk ), 
	.rst (rst ), 
	.key_in(key_in),
	.led_out(led_out)
 );

 endmodule
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49

4.2 波形

观察可以发现,在两个1元+一个0.5元按下后,状态来到了0100000也就是2.5元的模式,在此期间定时器使能,底下的led_out也有对应的20格输出,一格500ms,就是10秒了

image-20220917105232822

3元的双向流水则更为明显,因为双向,所以存在左右的切换,四个led灯,所以跳转三次,切换一次左右,这里的double_state一格对应的就是三格led_out,一共有3*6 + 2格,也是20格,10S

image-20220917105518706

声明:本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:【wpsshop博客】
推荐阅读
相关标签
  

闽ICP备14008679号