串口用状态机发送多字节

这种写法错哪里了呢,为什么这个Data会只维持一个时钟周期后又变了

img

img


状态机代码:
`timescale 1ns / 1ps

module uart_tx_data(
Clk,
Reset_n,
DATA40,
trans_go,
uart_tx,
trans_done
);

input Clk;
input Reset_n;
input trans_go;
input [39:0]DATA40;
output uart_tx;
output trans_done;

reg [7:0]Data;
reg Send_Go;
wire Tx_done;

uart_byte_tx uart_byte_tx(
    .Clk(Clk),    
    .Reset_n(Reset_n),
    .Data(Data),   
    .Send_Go(Send_Go),
    .Baud_set(3'd4),
    .uart_tx(uart_tx),
    .Tx_done(Tx_done) 
    );

reg [2:0]state, next_state;
parameter IDLE = 0, send1 = 1, send2 = 2, send3 = 3, send4 = 4, send5 = 5;


always @(posedge Clk or negedge Reset_n)
begin 
if (!Reset_n)
Send_Go <= 0;
else if (Tx_done)
Send_Go <= 1;
else if (trans_go)
Send_Go <= 1;
else
Send_Go <= 0;
end

always @(*)
begin    
    case (state)
    0: begin
        if (trans_go) begin
        Data = DATA40[7:0];
        next_state = 1;
        end
        else begin
        Data = Data;
        next_state = 0;
        end
    end
    1: begin
        if (Tx_done) begin
        Data = DATA40[15:8];
        next_state = 2;
        end
        else
        begin
        Data = Data;
        next_state = 1;
        end
    end
    2: begin
        if (Tx_done) begin
        Data = DATA40[23:16];
        next_state = 3;
        end
        else
        begin
        Data = Data;
        next_state = 2;
        end
    end
    3: begin
        if (Tx_done) begin
        Data = DATA40[31:24];
        next_state = 4;
        end
        else
        begin
        Data = Data;
        next_state = 3;
        end
    end
    4: begin
        if (Tx_done) begin
        Data = DATA40[39:32];
        next_state = 5;
        end
        else
        begin
        Data = Data;
        next_state = 4;
        end
    end
    5: begin
        if (Tx_done)
        next_state = 0;
        else begin
            next_state = 5;
            end
        end
    default:begin
            next_state = 0;
            Data = 0;
            end
    endcase
end

always @(posedge Clk or negedge Reset_n)
begin
    if (!Reset_n)
    state = 0;
    else
    state = next_state;
end

assign trans_done = (state == 5 && Tx_done == 1);

endmodule

你这写法就有问题,不是三段式状态机。最后一个always块里的这一句state = next_state就错了,导致根本就不能是一个三段式状态机,然后你在第2个always块判断状态的跳转可以用阻塞赋值,但是data输出不能用阻塞赋值,因为这样会有一个小毛刺,当你的状态从1跳转的2的时候,Tx_done仍然是高电平,所以Data = DATA40[23:16]这一句被执行了。
解决方法是:把Data 的赋值再用一个always块 + 非阻塞赋值的时序逻辑单独描述就可以了。也就是第一个 always 语句实现同步状态跳转;第二个 always 语句采用组合逻辑判断状态转移条件;第三个 always 语句采用时序逻辑描述状态输出。
详细可参考:

FPGA状态机(一段式、二段式、三段式)、摩尔型(Moore)和米勒型(Mealy)_孤独的单刀的博客-CSDN博客_摩尔型状态机 1、状态机1.1、理论FPGA不同于CPU的一点特点就是CPU是顺序执行的,而FPGA是同步执行(并行)的。那么FPGA如何处理明显具有时间上先后顺序的事件呢?这个时候我们就需要使用到状态机了。状态机简写为 FSM(Finite State Machine),也称为同步有限状态机,我们一般简称为状态机,之所以说“同步”是因为状态机中所有的状态跳转都是在时钟的作用下进行的,而“有限”则是说状态的个数是有限的。状态机的每一个状态代表一个事件,从执行当前事件到执行另一事件我们称之为状态 的跳转或状态的 https://blog.csdn.net/wuzhikaidetb/article/details/119421783?ops_request_misc=%257B%2522request%255Fid%2522%253A%2522165519997216782391839741%2522%252C%2522scm%2522%253A%252220140713.130102334.pc%255Fblog.%2522%257D&request_id=165519997216782391839741&biz_id=0&utm_medium=distribute.pc_search_result.none-task-blog-2~blog~first_rank_ecpm_v1~rank_v31_ecpm-3-119421783-null-null.nonecase&utm_term=%E7%8A%B6%E6%80%81%E6%9C%BA&spm=1018.2226.3001.4450

时序电路不要使用非阻塞赋值,否则没等判断出结果就赋值了。=改为"<="

把波形放大看看,Tx_done可能和state没对齐。使data在Tx_done为1的毛刺时再次赋值。