在发送数据时将并行数据转换成串行数据来传输,在接收数据时将接收到的串行数据转换成并行数据
采集每一位中间时刻的数据作为这一位的数据 ( 也可以每一位多采几个时刻的数据,取众数 )
`timescale 1ns / 1ps
//
// Engineer: wkk
// Create Date: 2022/11/22 16:35:19
// Module Name: uart_rx
// Description: uart rx function
//
module uart_rx(input sys_clk,input sys_rst_n,input uart_rx,output uart_rx_valid,output [7:0] uart_rx_data
);parameter SYS_CLK = 100_000_000;
// 115200
parameter BAUD_COUNT = 868;
parameter BAUD_HALF_COUNT = 434;
parameter TIME_COUNT_LEN = 12;localparam IDLE_STATE = 4'd0;
localparam START_STATE = 4'd1;
localparam RECV_STATE = 4'd2;
localparam RECV_D0_STATE = 4'd3;
localparam RECV_D1_STATE = 4'd4;
localparam RECV_D2_STATE = 4'd5;
localparam RECV_D3_STATE = 4'd6;
localparam RECV_D4_STATE = 4'd7;
localparam RECV_D5_STATE = 4'd8;
localparam RECV_D6_STATE = 4'd9;
localparam RECV_D7_STATE = 4'd10;
localparam END_STATE = 4'd11; reg [3:0] curr_state;
reg [3:0] next_state;reg uart_rx_d0;
reg uart_rx_d1;
wire uart_rx_en;// 开始计时
reg time_en;
// 计时模式 0: 计数一个波特率周期 1: 计数半个波特率周期
reg half_en;
reg count_en;
reg [TIME_COUNT_LEN-1:0] time_count;reg [7:0] rx_data;
reg [3:0] rx_data_index;// 计时模块
always @(posedge sys_clk or negedge sys_rst_n) beginif(!sys_rst_n || !time_en) begin time_count <= 0;count_en <= 0;end else if(half_en)if(time_count == BAUD_HALF_COUNT -1 )begintime_count <=0;count_en <= 1;endelse begintime_count <= time_count + 1'b1;count_en <= 0;end else if(time_count == BAUD_COUNT -1 )begincount_en <= 1;time_count <= 0;endelse begintime_count <= time_count + 1'b1;count_en <= 0;end
end// 产生下一状态
always @(*) begincase( curr_state )IDLE_STATE: beginif( uart_rx_en )next_state = START_STATE;else next_state = IDLE_STATE;endSTART_STATE:if( count_en)next_state = RECV_STATE;elsenext_state = START_STATE;RECV_STATE:if( count_en )next_state = RECV_D0_STATE;elsenext_state = RECV_STATE;RECV_D0_STATE:if( count_en )next_state = RECV_D1_STATE;elsenext_state = RECV_D0_STATE;RECV_D1_STATE:if( count_en )next_state = RECV_D2_STATE;elsenext_state = RECV_D1_STATE;RECV_D2_STATE:if( count_en )next_state = RECV_D3_STATE;elsenext_state = RECV_D2_STATE;RECV_D3_STATE:if( count_en )next_state = RECV_D4_STATE;elsenext_state = RECV_D3_STATE;RECV_D4_STATE:if( count_en )next_state = RECV_D5_STATE;elsenext_state = RECV_D4_STATE;RECV_D5_STATE:if( count_en )next_state = RECV_D6_STATE;elsenext_state = RECV_D5_STATE;RECV_D6_STATE:if( count_en )next_state = RECV_D7_STATE;elsenext_state = RECV_D6_STATE;RECV_D7_STATE:if( count_en )next_state = END_STATE;elsenext_state = RECV_D7_STATE;END_STATE:next_state = IDLE_STATE;default: ;endcase
endassign uart_rx_data = rx_data;
assign uart_rx_valid = (curr_state == END_STATE)?1'b1:1'b0;// 状态输出
always @(posedge sys_clk or negedge sys_rst_n) beginif(!sys_rst_n) beginrx_data <= 7'b0;time_en <= 1'b0;half_en <= 1'b0;rx_data_index <= 3'b0;end elsecase(curr_state)IDLE_STATE: begintime_en <= 1'b0;half_en <= 1'b0;rx_data_index <= 3'b0;endSTART_STATE: begintime_en <= 1'b1;half_en <= 1'b1;endRECV_STATE:begintime_en <= 1'b1;half_en <= 1'b0;end RECV_D0_STATE:if(rx_data_index == 3'd0)beginrx_data[0] <= uart_rx;rx_data_index <= rx_data_index + 1'b1;end elserx_data[0] <= rx_data[0]; RECV_D1_STATE:if(rx_data_index == 3'd1)beginrx_data[1] <= uart_rx;rx_data_index <= rx_data_index + 1'b1;end elserx_data[1] <= rx_data[1];RECV_D2_STATE:if(rx_data_index == 3'd2)beginrx_data[2] <= uart_rx;rx_data_index <= rx_data_index + 1'b1;end elserx_data[2] <= rx_data[2];RECV_D3_STATE:if(rx_data_index == 3'd3)beginrx_data[3] <= uart_rx;rx_data_index <= rx_data_index + 1'b1;end elserx_data[3] <= rx_data[3];RECV_D4_STATE:if(rx_data_index == 3'd4)beginrx_data[4] <= uart_rx;rx_data_index <= rx_data_index + 1'b1;end elserx_data[4] <= rx_data[4];RECV_D5_STATE:if(rx_data_index == 3'd5)beginrx_data[5] <= uart_rx;rx_data_index <= rx_data_index + 1'b1;end elserx_data[5] <= rx_data[5];RECV_D6_STATE:if(rx_data_index == 3'd6)beginrx_data[6] <= uart_rx;rx_data_index <= rx_data_index + 1'b1;end elserx_data[6] <= rx_data[6];RECV_D7_STATE:if(rx_data_index == 3'd7)beginrx_data[7] <= uart_rx;rx_data_index <= rx_data_index + 1'b1;end elserx_data[7] <= rx_data[7];END_STATE:begintime_en <= 1'b0;half_en <= 1'b0;rx_data_index <= 3'b0;enddefault: ;endcase
end// catch rising edge
assign uart_rx_en = (uart_rx_d0 & !uart_rx_d1) ? 1'b1:1'b0;always @(posedge sys_clk or negedge sys_rst_n) beginif(!sys_rst_n) beginuart_rx_d0 <= 1'b0;uart_rx_d1 <= 1'b0;end else beginuart_rx_d1 <= uart_rx;uart_rx_d0 <= uart_rx_d1;end
end// update curr_state
always @(posedge sys_clk or negedge sys_rst_n) beginif(!sys_rst_n) curr_state <= IDLE_STATE;elsecurr_state <= next_state;
endendmodule
`timescale 1ns / 1ns
//
// Engineer: wkk
// Module Name: uart_rx_tb
//module uart_rx_tb;
reg sys_clk;
reg sys_rst_n;
reg uart_rx;
wire uart_rx_valid;
wire [7:0] uart_rx_data;parameter BAUD_COUNT = 20;
parameter BAUD_HALF_COUNT = 10;
parameter TIME_COUNT_LEN = 5;
uart_rx #(.BAUD_COUNT (BAUD_COUNT),.BAUD_HALF_COUNT(BAUD_HALF_COUNT),.TIME_COUNT_LEN (TIME_COUNT_LEN)
)u_uart_rx(.sys_clk (sys_clk),.sys_rst_n (sys_rst_n),.uart_rx (uart_rx),.uart_rx_valid (uart_rx_valid),.uart_rx_data (uart_rx_data)
);initial begin sys_clk = 0;sys_rst_n = 0;uart_rx = 1;endalways #5 sys_clk = !sys_clk;initial begin#10 sys_rst_n = 1;#30 uart_rx = 0; // 起始位#200 uart_rx = 0; #200 uart_rx = 1;#200 uart_rx = 1;#200 uart_rx = 1;#200 uart_rx = 0;#200 uart_rx = 1;#200 uart_rx = 1;#200 uart_rx = 0;#200 uart_rx = 1; // 停止位#450$stop;endendmodule
使用三个always 模块
第一段
always @(posedge sys_clk or negedge sys_rst_n) beginif(!sys_rst_n) curr_state <= IDLE_STATE;elsecurr_state <= next_state;
end
第二段
always @(*) begincase( curr_state )// ....endcase
end
第三段
always @(posedge sys_clk or negedge sys_rst_n) beginif(!sys_rst_n) begin//...end else begin//...end
end
always 的执行是并行的
倘若使用同步时序逻辑,则:
第一段的内容: curr_state <-- next_state
将下一状态变为当前状态,状态更新
第二段的内容:需要根据curr_state的值结合其他条件,得出下一状态
第一段改变curr_state的值,第二段需要使用curr_state的值,并且两者是并行执行的,会形成冲突,可能使得第二段使用的curr_state是未更新前的,导致状态转移的错误。
上一篇: 国家励志奖学金申请书