一直想从一段式状态机切换到三段式状态机,从书上和网上不断搜寻三段式案例及方法,感觉很简单,就想拿之前做过的实验把一段式改成三段式,可是写起来并非那么简单,很棘手,改完后也没有成功,尤其状态机里面的计数器,查了一些资料,就一句话带过,把计数器提出来,但怎么提、怎么来保证同步、怎么不让生成latch,并没有仔细的讲清楚。也许自己比较笨吧,一时半会改不出来,当时就想,是不是起步太高了,应该在找一个简单的例程改写,循序渐进。这时就重新阅读黑金的"Verilog那些事儿"教程,看里面哪个例程比较简单,容易改的,结果找到建模篇的实验五例程进行改写,改完后发现三段式写还是比较简单的,思路也比较清晰。当然我跟书上的思路有点不一样,我是这样做的:
产生SOS信号,就是短音(100ms)、间隔(50ms)、长音(300ms),三种音之间的一个组合,可以得到下面波形,这是SOS信号吗?好吧,就是利用三段式产生如下一个波形。
由于不像占空比为50%波形那么有简单,中间要产生不同的占空比高低电平,那么就把它定义成18个状态,加上空闲状态,共19个状态,每个状态,输出高或低就行。
代码实现:
sos.v
1 module sos( 2 //input 3 sys_clk, 4 rst_n, 5 start_cnt, 6 7 //output 8 sig_out 9 ); 10 /*************************************************************/ 11 input sys_clk; 12 input rst_n; 13 input start_cnt; 14 15 output sig_out; 16 /*************************************************************/ 17 parameter T1MS = 16'd49_999; 18 /*************************************************************/ 19 reg [15 : 0] cnt; 20 always @(posedge sys_clk or negedge rst_n) 21 if(!rst_n) 22 cnt <= 16'd0; 23 else if(!start_cnt || cnt == T1MS) 24 cnt <= 16'd0; 25 else if(start_cnt) 26 cnt <= cnt + 1'b1; 27 else 28 cnt <= 16'd0; 29 /*************************************************************/ 30 reg [15 : 0] cnt_ms; 31 always @(posedge sys_clk or negedge rst_n) 32 if(!rst_n) 33 cnt_ms <= 16'd0; 34 else if(start_cnt && cnt == T1MS) 35 cnt_ms <= cnt_ms + 1'b1; 36 else if(!start_cnt || cnt_ms == 11'd1950) 37 cnt_ms <= 16'd0; 38 /*************************************************************/ 39 parameter IDLE = 5'd0 ; 40 parameter SHORT_1 = 5'd1 ; 41 parameter DLY_1 = 5'd2 ; 42 parameter SHORT_2 = 5'd3 ; 43 parameter DLY_2 = 5'd4 ; 44 parameter SHORT_3 = 5'd5 ; 45 parameter DLY_3 = 5'd6 ; 46 parameter LONG_1 = 5'd7 ; 47 parameter DLY_4 = 5'd8 ; 48 parameter LONG_2 = 5'd9 ; 49 parameter DLY_5 = 5'd10 ; 50 parameter LONG_3 = 5'd11 ; 51 parameter DLY_6 = 5'd12 ; 52 parameter SHORT_4 = 5'd13 ; 53 parameter DLY_7 = 5'd14 ; 54 parameter SHORT_5 = 5'd15 ; 55 parameter DLY_8 = 5'd16 ; 56 parameter SHORT_6 = 5'd17 ; 57 parameter DLY_9 = 5'd18 ; 58 /*************************************************************/ 59 reg [4 : 0] state_crt,state_nxt; 60 always @(posedge sys_clk or negedge rst_n) 61 if(!rst_n) 62 state_crt <= IDLE; 63 else 64 state_crt <= state_nxt; 65 /*************************************************************/ 66 always @( * ) 67 case(state_crt) 68 IDLE : state_nxt = SHORT_1; 69 SHORT_1 : if(cnt_ms == 11'd100 ) state_nxt = DLY_1; 70 else state_nxt = SHORT_1; 71 DLY_1 : if(cnt_ms == 11'd150 ) state_nxt = SHORT_2; 72 else state_nxt = DLY_1; 73 SHORT_2 : if(cnt_ms == 11'd250 ) state_nxt = DLY_2; 74 else state_nxt = SHORT_2; 75 DLY_2 : if(cnt_ms == 11'd300 ) state_nxt = SHORT_3; 76 else state_nxt = DLY_2; 77 SHORT_3 : if(cnt_ms == 11'd400 ) state_nxt = DLY_3; 78 else state_nxt = SHORT_3; 79 DLY_3 : if(cnt_ms == 11'd450 ) state_nxt = LONG_1; 80 else state_nxt = DLY_3; 81 LONG_1 : if(cnt_ms == 11'd750 ) state_nxt = DLY_4; 82 else state_nxt = LONG_1; 83 DLY_4 : if(cnt_ms == 11'd800 ) state_nxt = LONG_2; 84 else state_nxt = DLY_4; 85 LONG_2 : if(cnt_ms == 11'd1100) state_nxt = DLY_5; 86 else state_nxt = LONG_2; 87 DLY_5 : if(cnt_ms == 11'd1150) state_nxt = LONG_3; 88 else state_nxt = DLY_5; 89 LONG_3 : if(cnt_ms == 11'd1450) state_nxt = DLY_6; 90 else state_nxt = LONG_3; 91 DLY_6 : if(cnt_ms == 11'd1500) state_nxt = SHORT_4; 92 else state_nxt = DLY_6; 93 SHORT_4 : if(cnt_ms == 11'd1600) state_nxt = DLY_7; 94 else state_nxt = SHORT_4; 95 DLY_7 : if(cnt_ms == 11'd1650) state_nxt = SHORT_5; 96 else state_nxt = DLY_7; 97 SHORT_5 : if(cnt_ms == 11'd1750) state_nxt = DLY_8; 98 else state_nxt = SHORT_5; 99 DLY_8 : if(cnt_ms == 11'd1800) state_nxt = SHORT_6; 100 else state_nxt = DLY_8; 101 SHORT_6 : if(cnt_ms == 11'd1900) state_nxt = DLY_9; 102 else state_nxt = SHORT_6; 103 DLY_9 : if(cnt_ms == 11'd1950) state_nxt = IDLE; 104 else state_nxt = DLY_9; 105 default : state_nxt = IDLE; 106 endcase 107 /*************************************************************/ 108 reg sig_out_temp; 109 always @(posedge sys_clk or negedge rst_n) 110 if(!rst_n) 111 sig_out_temp <= 1'b0; 112 else begin 113 case(state_nxt) 114 IDLE : sig_out_temp <= 1'b0; 115 SHORT_1 : sig_out_temp <= 1'b1; 116 DLY_1 : sig_out_temp <= 1'b0; 117 SHORT_2 : sig_out_temp <= 1'b1; 118 DLY_2 : sig_out_temp <= 1'b0; 119 SHORT_3 : sig_out_temp <= 1'b1; 120 DLY_3 : sig_out_temp <= 1'b0; 121 LONG_1 : sig_out_temp <= 1'b1; 122 DLY_4 : sig_out_temp <= 1'b0; 123 LONG_2 : sig_out_temp <= 1'b1; 124 DLY_5 : sig_out_temp <= 1'b0; 125 LONG_3 : sig_out_temp <= 1'b1; 126 DLY_6 : sig_out_temp <= 1'b0; 127 SHORT_4 : sig_out_temp <= 1'b1; 128 DLY_7 : sig_out_temp <= 1'b0; 129 SHORT_5 : sig_out_temp <= 1'b1; 130 DLY_8 : sig_out_temp <= 1'b0; 131 SHORT_6 : sig_out_temp <= 1'b1; 132 DLY_9 : sig_out_temp <= 1'b0; 133 default : sig_out_temp <= 1'b0; 134 endcase 135 end 136 /*************************************************************/ 137 assign sig_out = start_cnt ? (~sig_out_temp) : 1'b0; 138 /*************************************************************/ 139 endmodule 140 141 142
sos_top.v
1 `timescale 1ns/10ps 2 module sos_top; 3 /*************************************************************/ 4 reg sys_clk; 5 reg rst_n; 6 wire start_cnt; 7 /*************************************************************/ 8 initial begin 9 sys_clk = 1'b0; 10 rst_n = 1'b0; 11 #100; 12 rst_n = 1'b1; 13 end 14 /*************************************************************/ 15 always #10 sys_clk = ~sys_clk; 16 /*************************************************************/ 17 reg [27:0] cnt; 18 always @(posedge sys_clk or negedge rst_n) 19 if(!rst_n) 20 cnt <= 28'd0; 21 else 22 cnt <= cnt + 1'b1; 23 24 assign start_cnt = 1'b1;//~cnt[27]; 25 /*************************************************************/ 26 sos u1_sos( 27 //input 28 .sys_clk(sys_clk), 29 .rst_n(rst_n), 30 .start_cnt(start_cnt), 31 32 //output 33 .sig_out(sig_out) 34 ); 35 /*************************************************************/ 36 endmodule
仿真波形:
最后输出进行反向,那是因为书上是驱动蜂鸣器的,而蜂鸣器工作是低电平有效,故输出取反。此实验没有下载到板子上验证,就是做了一个仿真,从仿真波形来看,与设计思想是对的。从上面的波形来看,感觉state_crt和state_nxt貌似基本上在同一时刻变换,其实不是的,state_nxt会比state_crt早一拍,把波形状态切换时刻放大就可以明显看到,如下波形: