FPGA串口接收学习

1.接收原理和思路

初步思路:除发送位和停止位外,在数据位的每一位数据的中间时刻进行采样,读取到高电平或者低电平,如图所示:图中读取到的数据位为0110(左至右)

 但是,倘若有外界干扰,忽然将某数据位的电平拉低了一瞬间,如图:此时再在各个数据位的中间时刻检测会检测到:0010(从左至右)很显然是错误的。

解决办法:在每一位的数据位上进行多次采样,然后比较0和1的概率。1的概率大就为高电平,0的概率大就为低电平。

然后还需要检测起始位,怎么检测起始位呢?边缘检测电路!边缘检测电路原理如下:

当波形2的第一个上升沿检测到波形 1的的值为1,第二个上升沿检测到波形1的值为0时,就说明其产生了下降沿。边缘检测电路由两个触发器构成,如图所示:

 接下来就可以开始代码编写啦!

源文件代码:

module uart_tx(
    input clk,
    input uart_rx, //从外部接收到的数据
    input rst,//复位
    input [2:0] Baud_set,//选择接收数据的波特率,要和发送数据的波特率一致
    output reg [7:0] Rx_Data, //最后我们看到的数据
    output reg Rx_Done
    );
    
reg Rx_En;//开始接收数据 
    
//设置波特率
reg [17:0] Baud;
always@(Baud_set)
case(Baud_set)
    3'd0:Baud=18'd166666;//波特率为300
    3'd1:Baud=18'd41666;//波特率为1200
    3'd2:Baud=18'd20833;//波特率为2400
    3'd3:Baud=18'd5208;//波特率为9600
    3'd4:Baud=18'd2604;//波特率为19200
    3'd5:Baud=18'd1302;//波特率为38400
    3'd6:Baud=18'd868;//波特率为57600
    3'd7:Baud=18'd434;//波特率为115200
endcase 

//波特率分频
reg [17:0] counter_Baud;
always@(posedge clk or negedge rst)
    if(!rst) counter_Baud<=0;
    else if(Rx_En)
        begin
            if(counter_Baud==Baud-1) counter_Baud<=0;
            else counter_Baud<=counter_Baud+1;
        end
    else counter_Baud<=0;

//检测起始位
reg [1:0] Detect;   
always@(posedge clk or negedge rst)
 if(!rst) Detect<=2'b00;
 else if(!Rx_En)
          begin
              Detect[0] <= uart_rx;
              Detect[1] <= Detect[0];
          end
 else Detect<=2'b00;
    
//控制En
always@(posedge clk or negedge rst) 
    if(!rst)  Rx_En<=0;
    else if(Detect==2'b10) Rx_En<=1;
    else if(Rx_Done) Rx_En<=0;
    else Rx_En<=Rx_En;    

//设置采样时钟
//每位数据为分成16段,舍弃前5段后4段,取中间7段进行采样
reg [7:0] counter_1;   //对采样次数进行计数
reg [4:0] counter_time; //counter_time计时到24时(1s/115200/16/20=24),为一个时间间隔
wire [14:0] caiyang;  // 每位数据为分成16段,每一小段的时间为1s/115200/16,故每一小段的计数值为1s/115200/20/16=Baud/16;
assign caiyang = Baud/16;
always@(posedge clk or negedge rst) 
    if(!rst) counter_time<=0;
    else if(Rx_En==1 )
           begin
            if(counter_time==caiyang-1)  counter_time<=0;
            else counter_time<=counter_time+1;
           end
    else if(Rx_Done)  counter_time<=0;
    else counter_time<=0;
always@(posedge clk or negedge rst) 
    if(!rst) counter_1<=0;
    else if(Rx_En==1)
            begin
                if(counter_1==160 && counter_time==18)  counter_1<=0;
                else if(counter_time==caiyang-1) counter_1<=counter_1+1;
                else counter_1<=counter_1;
            end
    else if(Rx_Done)  counter_1<=0;   
    else counter_1<=0;  
 wire clk_16_caiyang;
 assign clk_16_caiyang = (counter_time==caiyang/2);
 
 //开始采样
 reg [3:0] x_bit [7:0]; //定义一个二维数组,该二维数组里面有7个元素,分别表示8个数据位,每个元素位宽三位 
 reg [3:0] start;//起始位
 reg [3:0] stop;//停止位
 always@(posedge clk or negedge rst)
    if(!rst) begin
                  start<=0;
                  stop<=0;
                  x_bit[0]<=0;
                  x_bit[1]<=0;
                  x_bit[2]<=0;
                  x_bit[3]<=0;
                  x_bit[4]<=0;
                  x_bit[5]<=0;
                  x_bit[6]<=0;
                  x_bit[7]<=0;
            end
    else if(clk_16_caiyang)
            begin
                case(counter_1)
                    0: begin
                        start<=0;
                        stop<=0;
                        x_bit[0]<=0;
                        x_bit[1]<=0;
                        x_bit[2]<=0;
                        x_bit[3]<=0;
                        x_bit[4]<=0;
                        x_bit[5]<=0;
                        x_bit[6]<=0;
                        x_bit[7]<=0;
                       end
                    5,6,7,8,9,10,11:start<=start+uart_rx;
                    21,22,23,24,25,26,27:x_bit[0]<=x_bit[0]+uart_rx;
                    37,38,39,40,41,42,43:x_bit[1]<=x_bit[1]+uart_rx;
                    53,54,55,56,57,58,59:x_bit[2]<=x_bit[2]+uart_rx;
                    69,70,71,72,73,74,75:x_bit[3]<=x_bit[3]+uart_rx;
                    85,86,87,88,89,90,91:x_bit[4]<=x_bit[4]+uart_rx;
                    101,102,103,104,105,106,107:x_bit[5]<=x_bit[5]+uart_rx;
                    117,118,119,120,121,122,123:x_bit[6]<=x_bit[6]+uart_rx;
                    133,134,135,136,137,138,139:x_bit[7]<=x_bit[7]+uart_rx;
                    149,150,151,152,153,154,155:stop<=stop+uart_rx;
                    default: begin
                              start<=start;
                              x_bit[0]<=x_bit[0];
                              x_bit[1]<=x_bit[1];
                              x_bit[2]<=x_bit[2];
                              x_bit[3]<=x_bit[3];
                              x_bit[4]<=x_bit[4];
                              x_bit[5]<=x_bit[5];
                              x_bit[6]<=x_bit[6];
                              x_bit[7]<=x_bit[7]; 
                              stop<=stop;
                             end
                endcase
            end
 else begin
             start<=start;
             x_bit[0]<=x_bit[0];
             x_bit[1]<=x_bit[1];
             x_bit[2]<=x_bit[2];
             x_bit[3]<=x_bit[3];
             x_bit[4]<=x_bit[4];
             x_bit[5]<=x_bit[5];
             x_bit[6]<=x_bit[6];
             x_bit[7]<=x_bit[7]; 
             stop<=stop;
      end
  //控制Rx_Done
 always@(posedge clk or negedge rst)  
    if(!rst) Rx_Done<=0;
    else if(counter_1==160&&counter_time==18) Rx_Done<=1;
    else Rx_Done<=0; 
 //判断采样得到的数据并且进行赋值
 reg Data_start;
 reg Data_stop;
  always@(posedge clk or negedge rst)
    if(!rst) Rx_Data<=0;
    else if(counter_1==159)
        begin
           Data_start<=(start>=3'd4)?1'b1:1'd0;
           Data_stop<=(stop>=3'd4)?1'b1:1'd0;
           Rx_Data[0]<=(x_bit[0]>=3'd4)?1'b1:1'd0;
           Rx_Data[1]<=(x_bit[1]>=3'd4)?1'b1:1'd0;
           Rx_Data[2]<=(x_bit[2]>=3'd4)?1'b1:1'd0;
           Rx_Data[3]<=(x_bit[3]>=3'd4)?1'b1:1'd0;
           Rx_Data[4]<=(x_bit[4]>=3'd4)?1'b1:1'd0;
           Rx_Data[5]<=(x_bit[5]>=3'd4)?1'b1:1'd0;
           Rx_Data[6]<=(x_bit[6]>=3'd4)?1'b1:1'd0; 
           Rx_Data[7]<=(x_bit[7]>=3'd4)?1'b1:1'd0;           
        end
    else Rx_Data<=Rx_Data;
endmodule

激励文件代码:

module uart_rx_tb();

    reg clk;
    reg uart_rx; //从外部接收到的数据
    reg rst;//复位
    reg [2:0] Baud_set;//选择接收数据的波特率,要和发送数据的波特率一致
    wire [7:0] Rx_Data; //最后我们看到的数据
    wire Rx_Done;

uart_tx uart_tx_Inst(
    .clk(clk),
    .uart_rx(uart_rx),
    .rst(rst),
    .Baud_set(Baud_set),
    .Rx_Data(Rx_Data),
    .Rx_Done(Rx_Done)
);
initial clk=1;
initial Baud_set=3'd7;
always #10 clk=~clk;
initial
    begin
        rst=0;
        uart_rx=1;
        #200;
        rst=1;
        uart_tx_byte(8'b11011011);
        @(posedge Rx_Done) 
        #5000;
        uart_tx_byte(8'b10011010);
        @(posedge Rx_Done) 
        #6000;
        uart_tx_byte(8'b10011110);    
    end

task uart_tx_byte;  //发送一个字节
    input [7:0] tx_data;
    begin
        uart_rx=1;
        #200;
        uart_rx=0;
        #8680;
        uart_rx=tx_data[0];
        #8680;
        uart_rx=tx_data[1];
        #8680;
        uart_rx=tx_data[2];
        #8680;
        uart_rx=tx_data[3];
        #8680;
        uart_rx=tx_data[4];
        #8680;
        uart_rx=tx_data[5];
        #8680;
        uart_rx=tx_data[6];
        #8680;
        uart_rx=tx_data[7];
        #8680;
        uart_rx=1;
        #8680;
    end
endtask
endmodule

代码已测试可以使用!

  • 1
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值