|
![](static/image/common/ico_lz.png)
楼主 |
发表于 2013-11-16 15:44:54
|
显示全部楼层
下面是代码,仅仅供学习使用,请勿商用- ////////////////////////////////////////////////////////////////////////////////
- // Company:
- // Engineer:
- // Create Date: 2013/11/16
- // Design Name:
- // Module Name: uart_rx
- // Project Name:
- // Target Device:
- // Tool versions:
- // Description:
- //
- // Dependencies:
- //
- // Revision:
- // Revision 0.01 - File Created
- // Additional Comments:
- //
- ////////////////////////////////////////////////////////////////////////////////
- `timescale 1ns / 1ps
- module uart_rx
- (
- input clk ,
- input rst_n ,
- input [15 :0] uart_rx , //16个通道的串口数据,这个是可以扩展的
- output reg [16*8-1:0] uart_dat, // 接收到的串口并行数据 n通道数据 [8*n+7:8*n];
- output reg [16 -1:0] uart_en // 接收到的串口并行数据使能n通道使能 [n]
- );
- parameter DELAY =1 ;
- parameter IDLE = 2'b01; // 状态机IDLE状态
- parameter REC = 2'b10; // 状态机正在接收数据状态
- parameter S_POINT = 4'd7 ; // 采样点
- parameter [63:0] BAUD_RATE = 115200;//波特率设置
- parameter [63:0] CLK_FRE = (10**8);//时钟频率设置,单位赫兹
- parameter [63:0] CLK_DIV_RATE = ((2**16)*(16)*BAUD_RATE)/CLK_FRE; //小数分频系数
- reg [15:0] uart_rx_ff1 ;
- reg [15:0] uart_rx_ff2 ;
- reg uart_rx_ff3 ;
- reg [16:0] div_cnt ;
- reg [15:0] clk_en ;
- reg [3 :0] ch_cnt ;
- reg clk_en_ff1 ;
- reg clk_en_ff2 ;
- reg [3:0] ch_cnt_ff1 ;
- reg [3:0] ch_cnt_ff2 ;
- wire rx_dat_next ;
- wire rx_dat_curr ;
- wire rx_dat_curr_ff1;
- wire rx_dat_curr_ff2;
- reg [1:0] sta_next ;
- reg [3:0] bit_cnt_next ;
- reg [3:0] byte_cnt_next ;
- wire [1:0] sta_curr ;
- wire [3:0] bit_cnt_curr ;
- wire [3:0] byte_cnt_curr ;
- reg [8:0] shift_next ;
- wire [8:0] shift_curr ;
- reg sample_dat ;
- reg [8:0] rx_dat ;
- wire get_dat ;
- wire sample_point ;
- wire dat_sta ;
- wire stop_sta ;
- wire start_sta ;
- ram_infer
- #(
- .DATA_WIDTH(22 ),
- .ADDR_WIDTH(4 )
- )
- u_ram_state
- (
- .data ({shift_next,sta_next,bit_cnt_next,byte_cnt_next,rx_dat_next,rx_dat_curr,rx_dat_curr_ff1} ),
- .raddr (ch_cnt ),
- .waddr (ch_cnt_ff2 ),
- .wren (clk_en_ff2 ),
- .clk (clk ),
- .q ({shift_curr,sta_curr,bit_cnt_curr,byte_cnt_curr,rx_dat_curr,rx_dat_curr_ff1,rx_dat_curr_ff2})
- );
- assign rx_dat_next = uart_rx_ff3;
- assign start_sig = ~rx_dat_curr&rx_dat_curr_ff1; //下降沿确定起始
- assign sample_point = (bit_cnt_curr == S_POINT)?1'b1:1'b0; //采样点
- assign start_sta = (byte_cnt_curr == 4'd0)?1'b1:1'b0; //起始状态
- assign stop_sta = (byte_cnt_curr == 4'd10)?1'b1:1'b0; //结束状态
- assign dat_sta = (byte_cnt_curr >= 4'd1 &&byte_cnt_curr <= 4'd9)?1'b1:1'b0;
- always @(*)
- begin
- case(sta_curr)
- IDLE:
- begin
- bit_cnt_next = 4'd0;
- byte_cnt_next = 4'd0;
- if(start_sig == 1'b1)
- sta_next = REC; //接收到下降沿,跳转到接收状态
- else
- sta_next = IDLE;
- end
- REC:
- begin
- if(sample_point == 1'b1) //在采样点处看状态
- begin
- if(start_sta == 1'b1) //如果是起始状态
- begin
- if(sample_dat == 1'b0) //看采样数据是否为0,为0认为为真,否则假
- begin
- sta_next = REC;
- bit_cnt_next = bit_cnt_curr + 4'd1;
- byte_cnt_next = byte_cnt_curr +4'd1;
- end
- else
- begin
- sta_next = IDLE;
- bit_cnt_next = 4'd0;
- byte_cnt_next = 4'd0;
- end
- end
- else if(stop_sta == 1'b1) //停止位进入IDLE
- begin
- sta_next = IDLE;
- bit_cnt_next = bit_cnt_curr + 4'd1;
- byte_cnt_next = 4'd0;
- end
- else
- begin
- sta_next = REC;
- bit_cnt_next = bit_cnt_curr + 4'd1;
- byte_cnt_next = byte_cnt_curr +4'd1;
- end
- end
- else
- begin
- sta_next = REC;
- bit_cnt_next = bit_cnt_curr + 4'd1;
- byte_cnt_next = byte_cnt_curr ;
- end
- end
- default:
- begin
- sta_next = IDLE;
- bit_cnt_next = 4'd0;
- byte_cnt_next = 4'd0;
- end
- endcase
- end
- always @(*) //多数判决,当采样点的前一个点和后一个点以及采样点有两个相同则去这个值
- begin
- if(rx_dat_curr == rx_dat_curr_ff1)
- sample_dat = rx_dat_curr;
- else if(rx_dat_curr == rx_dat_curr_ff2)
- sample_dat = rx_dat_curr;
- else
- sample_dat = rx_dat_curr_ff1;
- end
- always @(*)
- begin
- if(sta_curr == REC &&sample_point == 1'b1 && dat_sta == 1'b1) //数据接收移位
- shift_next = {shift_curr[7:0],sample_dat}; //这里把校验位也移入
- else
- shift_next = shift_curr;
- end
- assign get_dat = (sta_curr == REC &&sample_point ==1'b1 &&stop_sta == 1'b1)?1'b1:1'b0;
- always @(*)
- begin
- if(get_dat == 1'b1)
- rx_dat = {sample_dat&(~(^shift_curr)),shift_curr[8:1]}; //如果校验错误数据丢弃
- else
- rx_dat = 2'd0;
- end
- generate
- genvar i;
- for (i=0;i<16;i=i+1)
- begin:TX_DAT
- always @(posedge clk or negedge rst_n)
- begin
- if(rst_n==1'b0)
- begin
- uart_dat <= 'd0;
- uart_en <= 'd0;
- end
- else if(clk_en_ff2 == 1'b1&&(ch_cnt_ff2 == i)&&get_dat == 1'b1)
- begin
- uart_dat[8*i+:8] <= #DELAY rx_dat[7:0];
- uart_en [i] <= #DELAY rx_dat[8];
- end
- else
- begin
- uart_dat[8*i+:8] <= #DELAY 8'd0;
- uart_en [i] <= #DELAY 1'd0;
- end
- end
- end
- endgenerate
- always @(posedge clk or negedge rst_n)
- begin
- if(rst_n==1'b0)
- div_cnt <= #DELAY 17'd0;
- else
- div_cnt <= #DELAY {1'b0,div_cnt[15:0]} + CLK_DIV_RATE[16:0];
- end
- always@(posedge clk or negedge rst_n)
- begin
- if(rst_n ==1'b0)
- clk_en <= 16'd0;
- else
- clk_en <= #DELAY {clk_en[14:0],div_cnt[16]};
- end
- always @(posedge clk or negedge rst_n)
- begin
- if(rst_n == 1'b0)
- ch_cnt <= 4'd0;
- else if((|clk_en) == 1'b1)
- ch_cnt <= #DELAY ch_cnt + 4'd1;
- else
- ch_cnt <= #DELAY 4'd0;
- end
- always @(posedge clk or negedge rst_n)
- begin
- if(rst_n == 1'b0)
- begin
- clk_en_ff1 <= 1'b0;
- clk_en_ff2 <= 1'b0;
- ch_cnt_ff1 <= 4'd0;
- ch_cnt_ff2 <= 4'd0;
- end
- else
- begin
- clk_en_ff1 <= #DELAY |clk_en;
- clk_en_ff2 <= #DELAY clk_en_ff1;
- ch_cnt_ff1 <= #DELAY ch_cnt;
- ch_cnt_ff2 <= #DELAY ch_cnt_ff1;
- end
- end
- always @(posedge clk or negedge rst_n)
- begin
- if(rst_n == 1'b0)
- begin
- uart_rx_ff1 <= 16'd0;
- uart_rx_ff2 <= 16'd0;
- end
- else
- begin
- uart_rx_ff1 <= #DELAY uart_rx ;
- uart_rx_ff2 <= #DELAY uart_rx_ff1 ;
- end
- end
- always @(posedge clk or negedge rst_n)
- begin
- if(rst_n == 1'b0)
- uart_rx_ff3 <= 1'b0 ;
- else if(clk_en_ff1 == 1'b1)
- uart_rx_ff3 <= #DELAY uart_rx_ff2[ch_cnt_ff1] ;
- else
- uart_rx_ff3 <= #DELAY 1'b0;
- end
- endmodule
复制代码 |
|