UART发送状态机三段式与一段式对比
文章图片
三段式串口发送仿真输出
三段式状态机要注意的几点:
1. 三段always模块中,第二个always模块是组合逻辑always模块,用阻塞赋值(“ = ”)。
第一个和第三个always模块是同步时序always模块,用非阻塞赋值(“ <= ”);
2. 第二部分为组合逻辑always模块,对于always的敏感列表建议采用always@(*)的方式。
同时,注意判断时条件完备,防止产生锁存器。
3. 第二部分case中的条件应该为当前态(current_state)。
4. 第三部分case中的条件应该为次态(next_state)。
文章图片
三段式状态转移表
文章图片
一段式状态转移表
【UART发送状态机三段式与一段式对比】注意他俩的区别,判别对象不一样。在发送计数的地方有区别。
三段式第三段描述的下一状态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 ;
endalways @(*) 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
endalways @(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
endendmodule
//一段式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;
endSTART:begin
tx<=0;
busy<=1;
sendcount<=0;
buffer<=data;
state = SEND;
endSEND: 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
endendmodule
推荐阅读
- python学习之|python学习之 实现QQ自动发送消息
- Java基础-高级特性-枚举实现状态机
- Quartz|Quartz 源码解析(四) —— QuartzScheduler和Listener事件监听
- UI(三十)发送请求NSURLSession
- Fescar|Fescar example解析 - TM发送逻辑
- Android-发送通知/含Android8.0+耐心照着官方教程实现,不是很难
- 借助android|借助android uiautomator+情迁工具箱自动朗读实现语音红包自动发送语音,自动领取
- python获取linux系统信息,并发送邮件
- RocketMQ学习六-消息发送错误与解决方案
- RocketMQ学习四-消息发送高可用设计