一个简单的基于状态机的串口使用协议

由于最近我亲爱的朋友鸽鸽的课程设计要求,需要使用串口去控制DDS产生波的类型(正弦波、方波、三角波),频率(最大2M),相位。由于要使用串口,那么问题来了,怎样使用?众所周知,串口一次只能传8位数据,换算成10进制也就是255,这是完全满足不了题目要求的,而且还有一个问题,直接使用串口传的数据,你如何知道哪些数据是选择波形的?哪些是控制频率的?。所以,这就涉及到串口的使用协议了,我们需要一个简单的协议来区分波形类型,频率,相位这三个控制数据。

首先有关于串口协议的实现,笔者在这里不做过多赘述,相关资源很多,例程很多。接下来是他的使用协议。这里笔者采用三段式状态机来实现。

说到状态机,就得先确定他的状态。首先是你需要等待获得数据,然后就是接收数据状态,接受数据之后,要按照指定的协议去读数据吧,这就是处理数据状态。到此,结构就很明了了。

这里先说明一下这个简单的协议:一共9位,第0位、第1位、第8位为校验位,由自己设定。第2位为波形选择,第3到5位是频率控制数据,第6到7是相位控制数据。

空闲态(等待数据来临):哎,这里有童鞋要问了,我怎么知道啥时候来数据呢?别急,串口接收协议本身有一个rx_done信号,代表一组8位数据发送完成。这不是刚好使用的标志吗。

数据接收态:需要接收一组数据,根据协议,需要接受的是9个数据,每个数据8位。

数据处理态:对接收的一组数据进行判断,3个校验位是否满足要求,满足就使用,不满足就立即推:放弃这组数据。最后回到空闲态,等待下一组数据。

以下是代码和仿真:

//顶层模块
`timescale 1ns / 1ps

module U1(
       Clk,
       Reset_n,
       uart_rx,
       frec_set,
       phase_set,
       ctrl_model
    );
    
    input Clk;
    input Reset_n;
    input uart_rx;
    output wire[23:0]frec_set;//最大50M
    output wire[15:0]phase_set;//最大360
    output wire [7:0]ctrl_model;
    
   
    wire [7:0]rx_data;
    wire rx_done;
    
    
    parameter Baud_Set = 3'd4;
    
    
    uart_cmd_fsm uart_cmd_fsm(
        .Clk(Clk),
        .Reset_n(Reset_n),
        .rx_data(rx_data),
        .rx_done(rx_done),
        .ctrl_model(ctrl_model),
        .frec_set(frec_set),
        .phase_set(phase_set)
    );

    uart_byte_rx uart_byte_rx(
        .Clk(Clk),
        .Reset_n(Reset_n),
        .Baud_Set(Baud_Set),
        .uart_rx(uart_rx),
        .Data(rx_data),
        .Rx_Done(rx_done)
    );
endmodule
//串口使用协议
`timescale 1ns / 1ps

module uart_cmd_fsm(
    input Clk,
    input Reset_n,
    input [7:0] rx_data,
    input rx_done,
    output reg [7:0] ctrl_model,
    output reg [23:0] frec_set,
    output reg [15:0] phase_set
    );
    
    reg [2:0] state, next_state;

    parameter IDLE = 3'b000;
    parameter RECEIVING = 3'b001;
    parameter PROCESSING = 3'b010;
    
    reg r_rx_done;
    reg [7:0] data_str [8:0];
    reg [3:0]data_count;
    
    always@(posedge Clk or negedge Reset_n)
    if(!Reset_n) begin
        state <= IDLE;
        r_rx_done <= 0; 
        data_count <= 0;
        ctrl_model <= 0;
        frec_set <= 0;
        phase_set <= 0;
    end
    else begin
        state <= next_state;
        r_rx_done <= rx_done;
    end
    
    always@(posedge Clk)
    case(state)
        IDLE:begin
            if(r_rx_done)begin
                next_state <= RECEIVING;
                data_count <= 4'b0001;
                data_str[9] <= rx_data;
            end
            else begin
                next_state <= IDLE;
            end
        end
        
        RECEIVING:begin
            if(data_count <= 9)begin
               next_state <= RECEIVING;
               data_str[data_count-1] <= rx_data;
               data_str[data_count-2] <= data_str[data_count-1]; // 逐个存储接收到的数据
               data_count <= data_count + 1;   
            end
            else
                next_state <= PROCESSING;
        end
        
        PROCESSING: begin
                if ((data_str[0] == 8'h55) && (data_str[1] == 8'hA5) && (data_str[8] == 8'hF0)) begin
                    ctrl_model <= data_str[2];
                    frec_set <= {data_str[3], data_str[4], data_str[5]};
                    phase_set <= {data_str[6], data_str[7]};
                end
                next_state <= IDLE;
            end
            
            default: next_state <= IDLE;
    endcase

endmodule
//串口接收协议
module uart_byte_rx(
    Clk,
    Reset_n,
    Baud_Set,
    uart_rx,
    Data,
    Rx_Done
);

   input Clk;
   input Reset_n;
   input [2:0]Baud_Set;
   input uart_rx;
   output reg[7:0]Data; 
   output reg Rx_Done;
   
   reg [1:0]uart_rx_r;
   always@(posedge Clk)begin
        uart_rx_r[0] <= uart_rx;
        uart_rx_r[1] <= uart_rx_r[0] ;
   end

    wire pedge_uart_rx;
//    assign pedge_uart_rx = ((uart_rx_r[1] == 0) && (uart_rx_r[0] == 1));
    assign pedge_uart_rx = (uart_rx_r == 2'b01);
    wire nedge_uart_rx;
//    assign nedge_uart_rx = ((uart_rx_r[1] == 1) && (uart_rx_r[0] == 0));  
    assign nedge_uart_rx = (uart_rx_r == 2'b10);  
 
    reg [8:0]  Bps_DR;
    always@(*)
        case(Baud_Set)
            0:Bps_DR = 1000000000/9600/16/20 - 1;
            1:Bps_DR = 1000000000/19200/16/20 - 1;
            2:Bps_DR = 1000000000/38400/16/20 - 1;
            3:Bps_DR = 1000000000/57600/16/20 - 1;
            4:Bps_DR = 1000000000/115200/16/20 - 1;
            default:Bps_DR = 1000000000/9600/16/20 - 1;
        endcase
        
    wire bps_clk_16x;
    assign bps_clk_16x = (div_cnt == Bps_DR / 2);

    reg RX_EN;
    always@(posedge Clk or negedge Reset_n)
    if(!Reset_n) 
        RX_EN <= 0;
    else if(nedge_uart_rx)
        RX_EN <= 1;
    else if(Rx_Done || (sta_bit >= 4))
        RX_EN <= 0;
        
    reg [8:0]div_cnt;
    always@(posedge Clk or negedge Reset_n)
    if(!Reset_n)    
        div_cnt <= 0;
    else if(RX_EN)begin
        if(div_cnt == Bps_DR)
            div_cnt <= 0;
        else
            div_cnt <= div_cnt + 1'b1;
    end
    else
        div_cnt <= 0;

    reg [7:0]bps_cnt;
    always@(posedge Clk or negedge Reset_n)
    if(!Reset_n) 
        bps_cnt <= 0;
    else if(RX_EN)begin
        if(bps_clk_16x)begin
            if(bps_cnt == 160)
                bps_cnt <= 0;
            else
                bps_cnt <= bps_cnt + 1'b1;
        end
        else
            bps_cnt <= bps_cnt;
     end
     else
        bps_cnt <= 0;
       
    //reg width name number/depth
    reg[2:0]r_data[7:0];
    reg [2:0]sta_bit;
    reg [2:0]sto_bit;
    
    always@(posedge Clk or negedge Reset_n)
    if(!Reset_n) begin
        sta_bit <= 0;
        sto_bit <= 0;
        r_data[0] <= 0;
        r_data[1] <= 0;
        r_data[2] <= 0;
        r_data[3] <= 0;
        r_data[4] <= 0;
        r_data[5] <= 0;
        r_data[6] <= 0;
        r_data[7] <= 0;
    end
    else if(bps_clk_16x)begin
        case(bps_cnt)
            0:begin
                sta_bit <= 0;
                sto_bit <= 0;
                r_data[0] <= 0;
                r_data[1] <= 0;
                r_data[2] <= 0;
                r_data[3] <= 0;
                r_data[4] <= 0;
                r_data[5] <= 0;
                r_data[6] <= 0;
                r_data[7] <= 0;
            end
            5,6,7,8,9,10,11:sta_bit <= sta_bit + uart_rx;
            21,22,23,24,25,26,27: r_data[0] <= r_data[0] + uart_rx;
            37,38,39,40,41,42,43: r_data[1] <= r_data[1] + uart_rx;
            53,54,55,56,57,58,59: r_data[2] <= r_data[2] + uart_rx;
            69,70,71,72,73,74,75: r_data[3] <= r_data[3] + uart_rx;
            85,86,87,88,89,90,91: r_data[4] <= r_data[4] + uart_rx;
            101,102,103,104,105,106,107: r_data[5] <= r_data[5] + uart_rx;
            117,118,119,120,121,122,123: r_data[6] <= r_data[6] + uart_rx;
            133,134,135,136,137,138,139: r_data[7] <= r_data[7] + uart_rx;
            149,150,151,152,153,154,155: sto_bit <= sto_bit + uart_rx;
            default:;
        endcase
    end
        
    always@(posedge Clk or negedge Reset_n)
    if(!Reset_n) 
        Data <= 0;        
    else if(bps_clk_16x && (bps_cnt == 159))begin
        Data[0] <= (r_data[0] >= 4)?1'b1:1'b0;
        Data[1] <= (r_data[1] >= 4)?1'b1:1'b0;
        Data[2] <= (r_data[2] >= 4)?1'b1:1'b0;
        Data[3] <= (r_data[3] >= 4)?1'b1:1'b0;
        Data[4] <= (r_data[4] >= 4)?1'b1:1'b0;
        Data[5] <= (r_data[5] >= 4)?1'b1:1'b0;
        Data[6] <= (r_data[6] >= 4)?1'b1:1'b0;
        Data[7] <= (r_data[7] >= 4)?1'b1:1'b0;
    end 
    
//    always@(posedge Clk or negedge Reset_n)
//    if(!Reset_n) 
//        Data <= 0;        
//    else if(bps_clk_16x && (bps_cnt == 159))begin
//        Data[0] <= r_data[0][2];
//        Data[1] <= r_data[1][2];
//        Data[2] <= r_data[2][2];
//        Data[3] <= r_data[3][2];
//        Data[4] <= r_data[4][2];
//        Data[5] <= r_data[5][2];
//        Data[6] <= r_data[6][2];
//        Data[7] <= r_data[7][2];
//    end 

    always@(posedge Clk or negedge Reset_n)
    if(!Reset_n) 
        Rx_Done <= 0;
    else if((div_cnt == Bps_DR/2) && (bps_cnt == 160))
        Rx_Done <= 1;
    else
        Rx_Done <= 0; 
        
     
        
endmodule
//test_bench
`timescale 1ns / 1ps
module U1_tb();
 
    reg Clk;
    reg Reset_n;
    reg uart_rx;
    wire [23:0]frec_set;//最大50M
    wire [15:0]phase_set;//最大360
    wire [7:0]ctrl_model;
    
   U1 U1(
       Clk,
       Reset_n,
       uart_rx,
       frec_set,
       phase_set,
       ctrl_model
    );
    
    initial Clk = 1;
    always#10 Clk = ~Clk;
    
    initial begin
       Reset_n = 0;
       uart_rx = 1;
       #201;
       Reset_n = 1;
       #200; 
       uart_tx_byte(8'h55);
       #90000;
       uart_tx_byte(8'hA5);
       #90000;
       uart_tx_byte(8'hFF);
       #90000;
       uart_tx_byte(8'hF1);
       #90000;
       uart_tx_byte(8'hA2);
       #90000;
       uart_tx_byte(8'hC3);
       #90000;
       uart_tx_byte(8'h55);
       #90000;
       uart_tx_byte(8'hA5);
       #90000;
       uart_tx_byte(8'hF0);
       #90000;
       $stop;
    end
    
    task uart_tx_byte;
        input [7:0]tx_data;
        begin
            uart_rx = 1;
            #20;
            uart_rx = 0;
            #8680;
            uart_rx = tx_data[0];
            #8680;
            uart_rx = tx_data[1];
            #8680;
            uart_rx = tx_data[2];
            #8680;
            uart_rx = tx_data[3];
            #8680;
            uart_rx = tx_data[4];
            #8680;
            uart_rx = tx_data[5];
            #8680;
            uart_rx = tx_data[6];
            #8680;
            uart_rx = tx_data[7];
            #8680;
            uart_rx = 1;
            #8680;         
        end
    endtask

    
endmodule

仿真波形图:

  • 2
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值