因考慮到工業環境外界因素干擾,故將每位接收數據分為16等份,僅接收中間最穩定的6份相加最後再判斷是1或0
- module uart_rx(
- clk,
- rst,
- baud_set, //波特率設置
- rx, //接收數據
- data,
- done //接收結束時done為1
- );
- input clk;
- input rst;
- input [2:0] baud_set;
- input rx;
- output [7:0] data;
- output done;
- reg reg0_rx;
- reg reg1_rx;
- reg tmp0_rx;
- reg tmp1_rx;
- wire nedge;
- wire error;
- reg done;
- reg en;
- reg [8:0] div_cnt;
- reg [7:0] bps_cnt;
- reg [2:0] reg_data [9:0];
- wire [9:0] tmp_data;
- reg [7:0] data;
- reg [8:0] bps_DR;
- //===========================================
- // 狀態機
- //===========================================
- parameter idle = 1'b0, //空閒
- trans = 1'b1; //接收數據
- reg present_state, next_state;
- always@(posedge clk or negedge rst)
- begin
- if(!rst) present_state <= idle;
- else present_state <= next_state;
- end
- always@(*)
- begin
- case(present_state)
- idle : if(nedge)
- next_state = trans;
- else
- next_state = idle;
- trans : if(div_cnt == 9'd324 && bps_cnt == 8'd159)
- next_state = idle;
- else
- next_state = trans;
- endcase
- end
- always@(posedge clk or negedge rst)
- begin
- if(!rst) en <= 1'b0;
- else
- begin
- case(present_state)
- idle : en <= 1'b0;
- trans : en <= 1'b1;
- endcase
- end
- end
- //===========================================
- // 波特率設置
- //===========================================
- always@(posedge clk or negedge rst)
- begin
- if(!rst)
- bps_DR <= 9'd324;
- else
- begin
- case(baud_set)
- 0 : bps_DR <= 9'd324; //9600 bps
- 1 : bps_DR <= 9'd162; //19200 bps
- 2 : bps_DR <= 9'd80; //38400 bps
- 3 : bps_DR <= 9'd53; //57600 bps
- 4 : bps_DR <= 9'd26; //115200 bps
- default : bps_DR <= 9'd324;
- endcase
- end
- end
- //===========================================
- // 分頻計數器
- //===========================================
- always@(posedge clk or negedge rst)
- begin
- if(!rst) div_cnt <= 9'd0;
- else if(en & (~error))
- begin
- if(div_cnt == bps_DR) div_cnt <= 9'd0;
- else div_cnt <= div_cnt + 9'd1;
- end
- else div_cnt <= div_cnt;
- end
- always@(posedge clk or negedge rst)
- begin
- if(!rst) bps_cnt <= 8'd0;
- else if(div_cnt == bps_DR)
- begin
- if(bps_cnt == 8'd159) bps_cnt <= 8'd0;
- else bps_cnt <= bps_cnt + 8'd1;
- end
- else bps_cnt <= bps_cnt;
- end
- //===========================================
- // 除亞穩態
- //===========================================
- always @(posedge clk)
- begin
- reg0_rx <= rx;
- reg1_rx <= reg0_rx;
- end
- //===========================================
- // 邊沿檢測
- //===========================================
- always @(posedge clk)
- begin
- tmp0_rx <= reg1_rx;
- tmp1_rx <= tmp0_rx;
- end
- assign nedge = !tmp0_rx & tmp1_rx; //下降沿檢測
- //===========================================
- // 採樣中間段6位數據
- //===========================================
- always@(posedge clk or negedge rst)
- begin
- if(!rst)
- begin
- reg_data[0] <= 3'd0;
- reg_data[1] <= 3'd0;
- reg_data[2] <= 3'd0;
- reg_data[3] <= 3'd0;
- reg_data[4] <= 3'd0;
- reg_data[5] <= 3'd0;
- reg_data[6] <= 3'd0;
- reg_data[7] <= 3'd0;
- reg_data[8] <= 3'd0;
- reg_data[9] <= 3'd0;
- end
- else
- begin
- case(bps_cnt)
- 8'd6,8'd7,8'd8,8'd9,8'd10,8'd11 : reg_data[0] <= reg_data[0] + tmp1_rx;
- 8'd22,8'd23,8'd24,8'd25,8'd26,8'd27 : reg_data[1] <= reg_data[1] + tmp1_rx;
- 8'd38,8'd39,8'd40,8'd41,8'd42,8'd43 : reg_data[2] <= reg_data[2] + tmp1_rx;
- 8'd54,8'd55,8'd56,8'd57,8'd58,8'd59 : reg_data[3] <= reg_data[3] + tmp1_rx;
- 8'd70,8'd71,8'd72,8'd73,8'd74,8'd75 : reg_data[4] <= reg_data[4] + tmp1_rx;
- 8'd86,8'd87,8'd88,8'd89,8'd90,8'd91 : reg_data[5] <= reg_data[5] + tmp1_rx;
- 8'd102,8'd103,8'd104,8'd105,8'd106,8'd107 : reg_data[6] <= reg_data[6] + tmp1_rx;
- 8'd118,8'd119,8'd120,8'd121,8'd122,8'd123 : reg_data[7] <= reg_data[7] + tmp1_rx;
- 8'd134,8'd135,8'd136,8'd137,8'd138,8'd139 : reg_data[8] <= reg_data[8] + tmp1_rx;
- 8'd150,8'd151,8'd152,8'd153,8'd154,8'd155 : reg_data[9] <= reg_data[9] + tmp1_rx;
- default:;
- endcase
- end
- end
- //===========================================
- // 若採樣的6位數據相加結果大於等於4則判斷為1,否則為0
- //===========================================
- assign tmp_data[0] = (reg_data[0] >= 3'd4) ? 1'b1 : 1'b0; //start bit起始位
- assign tmp_data[1] = (reg_data[1] >= 3'd4) ? 1'b1 : 1'b0;
- assign tmp_data[2] = (reg_data[2] >= 3'd4) ? 1'b1 : 1'b0;
- assign tmp_data[3] = (reg_data[3] >= 3'd4) ? 1'b1 : 1'b0;
- assign tmp_data[4] = (reg_data[4] >= 3'd4) ? 1'b1 : 1'b0;
- assign tmp_data[5] = (reg_data[5] >= 3'd4) ? 1'b1 : 1'b0;
- assign tmp_data[6] = (reg_data[6] >= 3'd4) ? 1'b1 : 1'b0;
- assign tmp_data[7] = (reg_data[7] >= 3'd4) ? 1'b1 : 1'b0;
- assign tmp_data[8] = (reg_data[8] >= 3'd4) ? 1'b1 : 1'b0;
- assign tmp_data[9] = (reg_data[9] >= 3'd4) ? 1'b1 : 1'b0; //stop bit停止位
- //===========================================
- //若起始位為1時表示接收錯誤立即停止接收數據
- //===========================================
- assign error = (tmp_data[0] == 1'b1) ? 1'b1 : 1'b0;
- //===========================================
- // 數據接收結束done信號
- //===========================================
- always@(posedge clk or negedge rst)
- begin
- if(!rst)
- done <= 1'b0;
- else if(bps_cnt == 8'd159)
- done <= 1'b1;
- else
- done <= 1'b0;
- end
- //==========================================
- // 將數據寄存起來最後輸出
- //==========================================
- always@(posedge clk or negedge rst)
- begin
- if(!rst)
- data <= 8'b0;
- else if(div_cnt == bps_DR && bps_cnt == 8'd159)
- data <= tmp_data[8:1];
- else
- data <= data;
- end
- //===========================================
- endmodule
- //===========================================
- // 將發送模組與接收模組連接,測試是否能正確接收數據
- //===========================================
- module uart_top(
- clk,
- rst,
- baud_set,
- in_data,
- out_data,
- tx_done,
- rx_done
- );
- input clk;
- input rst;
- input [2:0] baud_set; //波特率設置
- input [7:0] in_data; //輸入數據
- output [7:0] out_data; //輸出數據
- output tx_done; //發送結束
- output rx_done; //接收結束
- wire w;
- uart_tx uart_tx(
- .rst(rst),
- .clk(clk),
- .baud_set(baud_set),
- .din(in_data),
- .tx(w),
- .done(tx_done)
- );
- uart_rx uart_rx(
- .clk(clk),
- .rst(rst),
- .baud_set(baud_set),
- .rx(w),
- .data(out_data),
- .done(rx_done)
- );
- endmodule
- // 仿真檔testbench
- `timescale 1ns/100ps
- module uart_top_test1;
- reg clk;
- reg rst;
- reg [2:0] baud_set;
- reg [7:0] in_data;
- wire [7:0] out_data;
- wire tx_done;
- wire rx_done;
- uart_top uart_top(
- .clk(clk),
- .rst(rst),
- .baud_set(baud_set),
- .in_data(in_data),
- .out_data(out_data),
- .tx_done(tx_done),
- .rx_done(rx_done)
- );
- initial
- begin
- clk = 1'b1;
- forever #10 clk = ~clk; //clk頻率為50M Hz
- end
- initial
- begin
- #0
- rst = 1'b0;
- baud_set = 3'd0; //設置為9600 bps
- in_data = 8'b10101010;
- #1
- rst = 1'b1;
- #2000000
- $stop;
- #10
- $finish;
- end
- endmodule
在此特別將發送結束信號tx_done與接收結束信號rx_done採取不同寬度以方便區分,
發送數據為10101010,接收數據為10101010,故接收正確!