三段式状态机要注意的几点:
1. 三段always模块中,第二个always模块是组合逻辑always模块,用阻塞赋值(“ = ”)。
第一个和第三个always模块是同步时序always模块,用非阻塞赋值(“ <= ”);
2. 第二部分为组合逻辑always模块,对于always的敏感列表建议采用always@(*)的方式。
同时,注意判断时条件完备,防止产生锁存器。
3. 第二部分case中的条件应该为当前态(current_state)。
4. 第三部分case中的条件应该为次态(next_state)。
三段式状态转移表
一段式状态转移表
注意他俩的区别,判别对象不一样。在发送计数的地方有区别。
三段式第三段描述的下一状态next_state要执行的动作,如果执行1次,计数值+1.在第2段状态转移判别sendcount的时候,计数值代表已经发送的次数。所以当sendcount为1时,已经执行了第一次发送。
一段式描述的是当前状态应该执行的动作,对计数值sendcount判断时,当前动作尚未执行。所以当sendcount为0时,会执行第一次发送。
一个是+1动作后判断,一个是+1动作前判断。
//三段式状态机写法,UART发送状态机,无校验
module uart_tx_fsm(clk_baud,reset_n,start_n,data,tx,busy);
input clk_baud,reset_n,start_n;
input [7:0] data;
output tx;
output busy;
reg tx,busy;
parameter IDLE = 4'b0001;
parameter START = 4'b0010;
parameter SEND = 4'b0100;
parameter STOP = 4'b1000;
reg [3:0]state;
reg [3:0]next_state;
reg [3:0]sendcount;
reg [7:0]buffer;
always @(posedge clk_baud or negedge reset_n)begin
if(reset_n == 0) state <= IDLE;
else state <= next_state ;
end
always @(*) begin // 或者用always @(state,start_n,sendcount)
case (state)
IDLE: if(start_n==0) next_state = START;
else next_state = IDLE;
START:next_state = SEND;
SEND: if(sendcount==4'd8) next_state = STOP;
else next_state = SEND;
STOP: next_state = IDLE;
default:next_state = IDLE;
endcase
end
always @(posedge clk_baud) begin
case (next_state) //用
IDLE:begin
tx<=1;busy<=0;sendcount<=0;buffer<=0;
end
START:begin
tx<=0;busy<=1;sendcount<=0;buffer<=data;
end
SEND:begin
tx<=buffer[0];busy<=1;sendcount<=sendcount+1;buffer<=buffer>>1;
end
STOP:begin
tx<=1;busy<=1;sendcount<=0;buffer<=0;
end
default:begin
tx<=1;busy<=0;sendcount<=0;buffer<=0;
end
endcase
end
endmodule
//一段式UART发送状态机,无校验
module uart_tx_fsm(clk_baud,reset_n,start_n,data,tx,busy);
input clk_baud,reset_n,start_n;
input [7:0] data;
output tx;
output busy;
reg tx,busy;
parameter IDLE = 4'b0001;
parameter START = 4'b0010;
parameter SEND = 4'b0100;
parameter STOP = 4'b1000;
reg [3:0]state;
reg [3:0]sendcount;
reg [7:0]buffer;
always @(posedge clk_baud or negedge reset_n)begin
if(reset_n == 0) state <= IDLE;
else
case (state)
IDLE: begin
tx<=1;busy<=0;sendcount<=0;buffer<=0;
if(start_n==0) state = START;
else state = IDLE;
end
START:begin
tx<=0;busy<=1;sendcount<=0;buffer<=data;
state = SEND;
end
SEND: begin
tx<=buffer[0];busy<=1;sendcount<=sendcount+1;buffer<=buffer>>1;
if(sendcount==4'd7) state = STOP;
else state = SEND;
end
STOP: begin
tx<=1;busy<=1;sendcount<=0;buffer<=0;
state = IDLE;
end
default:begin
tx<=1;busy<=0;sendcount<=0;buffer<=0;
state = IDLE;
end
endcase
end
endmodule
网友评论