半双工串口

半双工是用一根信号线双向传输,不可同时发送接收。

主要代码:

状态机定义

    localparam  IDLE    =   3'b001,
                RECEIVE =   3'b010,
                SEND    =   3'b100;

状态机

always @ ( * )  begin
        case ( state_now )
            IDLE:   begin
                if( IDLE2RECEIVE )  begin
                    state_next = RECEIVE;
                end
                else    if ( IDLE2SEND )    begin
                    state_next = SEND;
                end
                else    begin
                    state_next = IDLE;
                end

            end
            RECEIVE:    begin
                if( RECEIVE2IDLE )  begin
                    state_next = IDLE;
                end
                else begin
                    state_next = RECEIVE;
                end
            end
            SEND:   begin
                if( SEND2IDLE ) begin
                    state_next = IDLE;
                end
                else begin
                    state_next = SEND;
                end
            end
            default:    begin
                state_next = IDLE;
            end
        endcase

    end


    always @ ( posedge clk_uart )   begin
        state_now <= state_next;    
    end

    always @ ( posedge clk_uart )   begin
        case ( state_now )  
        IDLE:   begin
            txd  <= 1;
            if( IDLE2SEND ) begin
                data_send   <=  { 1'b1,data_send_reg_1[counter_send_1],1'b0 };
                counter_send_1  <=  counter_send_1 + 1 ;
                counter_send    <=  0;
            end
            else    if ( bh_flag == 3'b101 )    begin
                counter_send_1  <=  0;
                data_send   <= 0;               
                counter_send    <=  0;
            end
            else    begin
                data_send   <= 0;               
                counter_send    <=  0;          
            end

            if( data_receive[0] == 0 && data_receive[9] == 1 )  begin
                {  data_receive_reg [6] , data_receive_reg [5] , data_receive_reg [4] , data_receive_reg [3] , data_receive_reg [2] , data_receive_reg [1] , data_receive_reg [0]  }    
                <= { data_receive_reg [5] , data_receive_reg [4] , data_receive_reg [3] , data_receive_reg [2] , data_receive_reg [1] , data_receive_reg [0] , data_receive [8:1] };
                data_receive        <= 0;
                counter_receive     <= 0;
            end
            else    begin
                data_receive        <= 0;
                counter_receive     <= 0;
            end
        end
        RECEIVE:    begin
            rxd_1   <= rxd;
            rxd_2   <= rxd_1;
            rxd_3   <= rxd_2;
            rxd_4   <= rxd_3;
            rxd_5   <= rxd_4;
            rxd_6   <= rxd_5;
            rxd_7   <= rxd_6;
            rxd_8   <= rxd_7;
            counter_receive <=  counter_receive + 1 ;
            data_receive[counter_receive[7:4]]  <=  rxd_8 ;
        end
        SEND:   begin
            counter_send    <=  counter_send + 1 ;
            txd     <= data_send [ counter_send [7:4] ] ;
        end
        default:    begin
            data_send   <= 0;
            counter_send    <=  0;
            data_receive        <= 0;
            counter_receive     <= 0;
            txd      <= 1;
        end
        endcase
    end

状态转换条件

assign  IDLE2RECEIVE    = state_now == IDLE  &&  rxd == 0;
assign  IDLE2SEND       = state_now == IDLE  &&  counter_send_1 <= 8'd6  ;
assign  RECEIVE2IDLE    = state_now == RECEIVE  &&  counter_receive >= 8'd155;
assign  SEND2IDLE       = state_now == SEND  &&  counter_send >= 8'd159;

输出

assign  xd = state_now == SEND ? txd : 1'bz;
assign  rxd = state_now == SEND ? 1'bz : xd;

内部指令系统,随便写的

    always @ ( posedge clk_uart )  begin
        if ( data_receive_reg[0] == 8'h7f ) begin
            data_send_reg[0]   <=   8'h0f;
            data_send_reg[1]   <=   8'h0e;
            data_send_reg[2]   <=   8'h0d;
            data_send_reg[3]   <=   8'h0c;
            data_send_reg[4]   <=   8'h0b;
            data_send_reg[5]   <=   8'h0a;
            data_send_reg[6]   <=   8'h09;
        end
        else ;

    end

意思是收到一个 7f 字节时就返回7个字节 0f 0e 0d 0c 0b 0a 09 仿真正常 如下
这里写图片描述

增加2017.7.24:

应同事要求做了相应更改,隐藏部分代码:

`timescale 1ns / 1ps
//-------------------------------------------------------------------
//      一次发送一个字节,从低字节开始发送
//      如果发送的数据为 56'h 07060504030201
//          另一端就收的数据为 56'h 01020304050607
//-------------------------------------------------------------------
module uart
    (
    inout            xd,         //数据线
    input            clk,        //20m时钟    
    input  [55:0]    data_in,    //上层模块发送数据,比发送开始信号提前一个周期就绪 
    input            send_start, //发送开始信号,send_flag = 1 时才能发送
    output  reg      send_flag,  //发送就绪状态   
    output [55:0]    data_out,   //收到的数据,data_out_en = 1 时有效    
    output  reg      data_out_en //输出数据有效位
    );
//--------------变量定义------------------------------------------------------    
       省略
//---------------------clk_uart=波特率*16------------------------  
//---------------------默认115200--------------------------------
//------------------  UART_B = 20M / 115200 * 16 / 2 = 1389 -----     
    localparam UART_B = 16'd1389;

    reg clk_uart = 0;
    reg [15:0]  clk_counter = 0 ;
    wire clk_end;
    assign clk_end = clk_counter >= UART_B;
    always @ ( posedge clk )    begin
        if ( clk_end )  begin
            clk_uart <= ~clk_uart;
            clk_counter <= 0 ;
        end
        else    begin
            clk_counter <= clk_counter + 1 ;
        end
    end
//-----------------------inout口xd配置---------------------------------
    assign    xd  = state_now == SEND ? txd : 1'bz;
    assign    rxd = state_now == SEND ? 1'bz : xd;
//-----------------------状态跳转标志位--------------------------------
    隐藏   
//---------------未用----------------输入变化触发输出--------------    
    ...
//-----------------------数据输出------------------------------------   
    省略
//----------------------数据输入转存--------------------------------  
    省略
//------------------------状态机下一状态-------------------------- 
    always @ ( * )  begin
        case ( state_now )
            IDLE:   begin
                if( IDLE2RECEIVE )  begin
                    state_next = RECEIVE;
                end
                else    if ( IDLE2SEND )    begin
                    state_next = SEND;
                end
                else    begin
                    state_next = IDLE;
                end             
            end
            RECEIVE:    begin
                if( RECEIVE2IDLE )  begin
                    state_next = IDLE;
                end
                else begin
                    state_next = RECEIVE;
                end
            end
            SEND:   begin
                if( SEND2IDLE ) begin
                    state_next = IDLE;
                end
                else begin
                    state_next = SEND;
                end
            end
            default:    begin
                state_next = IDLE;
            end
        endcase 
    end 
//--------------------状态机转换-------------------------------  
    always @ ( posedge clk_uart )   begin
        state_now <= state_next;    
    end
//---------------------状态机输出部分-------------------------------   
    always @ ( posedge clk_uart )   begin
        case ( state_now )  
        IDLE:   begin
            txd  <= 1;
            send_flag <= counter_send_1 >= 8'd7 && counter_receive_1 == 0 && counter_receive == 0;
            if( IDLE2SEND ) begin
                data_send   <=  { 1'b1,data_send_reg_1[counter_send_1],1'b0 };
                counter_send_1  <=  counter_send_1 + 1 ;
                counter_send    <=  0;
            end
            else    if ( send_start )   begin
                counter_send_1  <=  0;
                data_send   <= 0;               
                counter_send    <=  0;
            end
            else    begin
                data_send   <= 0;               
                counter_send    <=  0;          
            end         
            if( data_receive[0] == 0 && data_receive[9] == 1 )  begin
                {  data_receive_reg [6] , data_receive_reg [5] , data_receive_reg [4] , data_receive_reg [3] , data_receive_reg [2] , data_receive_reg [1] , data_receive_reg [0]  }    
                <= { data_receive_reg [5] , data_receive_reg [4] , data_receive_reg [3] , data_receive_reg [2] , data_receive_reg [1] , data_receive_reg [0] , data_receive [8:1] };
                data_receive        <= 0;
                counter_receive     <= 0;
                if ( counter_receive_1 >= 4'd6 ) begin
                    counter_receive_1 <= 0;
                    data_out_en         <= 1'b1;
                end
                else begin
                    counter_receive_1 <= counter_receive_1 + 1'b1;
                end                             
            end
            else    begin
                data_receive        <= 0;
                counter_receive     <= 0;
            end
        end
        RECEIVE:    begin
            rxd_1   <= rxd;
            rxd_2   <= rxd_1;
            rxd_3   <= rxd_2;
            rxd_4   <= rxd_3;
            rxd_5   <= rxd_4;
            rxd_6   <= rxd_5;
            rxd_7   <= rxd_6;
            rxd_8   <= rxd_7;
            data_out_en         <= 0;
            send_flag <= 0;
            counter_receive <=  counter_receive + 1 ;
            data_receive[counter_receive[7:4]]  <=  rxd_8 ;
        end
        SEND:   begin
            counter_send    <=  counter_send + 1 ;
            txd     <= data_send [ counter_send [7:4] ] ;
            send_flag <= 0;         
        end
        default:    begin
            data_send   <= 0;
            send_flag <= 0;
            counter_send    <=  0;
            data_receive        <= 0;
            counter_receive     <= 0;
            txd      <= 1;
            data_out_en         <= 0;
        end
        endcase
    end     
endmodule

仿真结果:
这里写图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值