半双工是用一根信号线双向传输,不可同时发送接收。
主要代码:
状态机定义
localparam IDLE = 3
RECEIVE = 3
SEND = 3
状态机
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
assign rxd = state_now == SEND ? 1
内部指令系统,随便写的
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
module uart
(
inout xd,
input clk,
input [55:0] data_in,
input send_start,
output reg send_flag,
output [55:0] data_out,
output reg data_out_en
);
省略
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
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
仿真结果: