DSP

半双工串口

2019-07-13 20:24发布

半双工是用一根信号线双向传输,不可同时发送接收。 主要代码: 状态机定义 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 仿真结果:
这里写图片描述