• 基于FPGA自适应串口通信(Auto Baud Rate)


    做的课设,相当于复习了一遍verilog。


    实现了

    1.接收端固定模式:8N1 BAUD:921600。

    2.发送端8N1,任意波特率(不取极端值)。

    3.数码管显示波特率(16进制)。

     

    用了

    1.两天一夜。

    2.ego1平台+usb2uart。


    整体框图

    输入tx信号经过频率捕获层获得100Mhz下的计数值,送给波特率产生层得到接收层波特率。

    接收层接收数据送给串口FIFO层,串口FIFO层根据发送层的反馈将数据送出FIFO。

    发送层将数据按固定921600波特率发给PC机。从而实现波特率交换。


    频率捕获层算法

    1.uart协议

    这里只考虑最常用的8N1,即8位数据,无校验,1位停止位。

    在时钟线上升沿,tx线下降沿并维持到下一个上升沿即为一个开始位。然后8位数据(低位在前)。然后到第10位停止位高电平。

    值得一提的是,tx线不会在某个电平完后恢复初始电平,比如说上一个数据位是低,当前位还是低,这个数据位结束后不会变回高再变低。

    有什么影响?倘若tx发送0xff,那么其实只有一个低电平脉宽!即起始位那个脉宽。

    2.算法

     先打两拍,同步时钟以及滤除尖峰脉冲。考虑到输入的数据信号大多为ascii码。

    我们从里面找一个最特殊的,U,这个字符二进制为10101010,再加上开始结束位的tx线电平变化为:

    0101010101,这里有4个或者说5个低电平脉宽,这是最理想的情况。这样测出来的脉宽都是波特率。

    但是如果是一般的字符,发送一个字节可能获得多个低电平脉宽,从里面找最小的有极大可能就是波特率(极小可能最小的低电平脉宽是波特率的倍数)。

    所以我们的算法就是多次测频率,从里面找一个最小的,即认为是波特率。注意这里的频率,波特率都是相对于ego1的100Mhz时钟,并不需要化为实际波特率。

    程序

     1 `timescale 1ns / 1ps
     2 
     3 
     4 module cap_freqence(
     5             input        clk,
     6             input        rst_n,
     7             input         freq_in,
     8             input         cap_en,
     9             output     freq_cap//27bit 0-134,217,727 对输入信号波特率测得的频率            
    10     );
    11 reg[26:0]  freq_cap = 14'd10416;    //rst ??????
    12 reg[26:0] tmp_cap,sequence_cap[2:0];    //cap 5 times and Use the smallest one as baud
    13 reg [2:0] cap_cnt;
    14 // reg cap_finish;
    15 reg s0_RS_232_RX,s1_RS_232_RX;        //同步寄存器,消除亚稳态
    16 reg tmp0_RS_232_RX,tmp1_RS_232_RX;    //数据寄存器,移位寄存器
    17 reg cap_state;                        //0:idle 1:work
    18 wire neg_RX;//下降沿
    19 always@(posedge clk or negedge rst_n)//同步寄存器,消除亚稳态
    20     if(!rst_n)
    21         begin
    22             s0_RS_232_RX <= 1'b0;
    23             s1_RS_232_RX <= 1'b0;    
    24         end
    25     else 
    26         begin
    27             s0_RS_232_RX <= freq_in;   //次态
    28             s1_RS_232_RX <= s0_RS_232_RX;//现态
    29         end
    30 always@(posedge clk or negedge rst_n)//数据寄存器
    31     if(!rst_n)
    32         begin
    33             tmp0_RS_232_RX <= 1'b0;
    34             tmp1_RS_232_RX <= 1'b0;    
    35         end
    36     else 
    37         begin
    38             tmp0_RS_232_RX <= s1_RS_232_RX;
    39             tmp1_RS_232_RX <= tmp0_RS_232_RX;    
    40         end
    41 //共打两拍再检测输入脚
    42 assign neg_RX = (!tmp0_RS_232_RX) & tmp1_RS_232_RX;//下降沿检测
    43 
    44 always@(posedge clk or negedge rst_n)//cap工作状态
    45     if(!rst_n)begin
    46         cap_state <= 0;
    47         end
    48     else if(neg_RX)                    //下降沿开始测频
    49         cap_state <= 1; 
    50     else if (tmp0_RS_232_RX)        //高电平退出测频
    51         cap_state <= 0; 
    52 
    53 always@(posedge clk or negedge rst_n)//以100Mhz时钟测输入引脚低电平脉宽
    54     if(!rst_n)
    55         begin
    56             tmp_cap <= 27'd0;
    57             
    58         end
    59     else if(cap_state)                //串口工作状态(接受)时计数
    60         begin
    61             if(tmp0_RS_232_RX)        //计完一次频率
    62                 begin
    63                    sequence_cap[cap_cnt] <= tmp_cap;
    64                    tmp_cap <= 27'd0;
    65                    cap_cnt <= cap_cnt + 1;//0 1 2 3,4测完4次后为4
    66                 end
    67             else
    68                tmp_cap <= tmp_cap + 1'b1; 
    69         end
    70         
    71 integer i;
    72 reg[26:0] min_cap;
    73 
    74 always@(cap_cnt)                    //测完一个序列便从测频序列里找出最小脉宽即为bps
    75     begin
    76         if (cap_cnt == 2'd5)
    77             begin
    78                 min_cap=sequence_cap[0];//1st one as minimal cap
    79                 for (i=1;i<5;i=i+1)
    80                     if (sequence_cap[i] < min_cap)
    81                         if (sequence_cap[i] > 10)
    82                             min_cap = sequence_cap[i];
    83                 if (cap_en)            //手动控制更新baud
    84                     freq_cap = min_cap;
    85             end
    86     end
    87     
    88 endmodule

    这个程序有瑕疵,用了初始化。不懂

    freq_cap
    这个变量放在rst里面复位后,之后都不能被下面
    freq_cap = min_cap;
    这句更新,暂时这么写吧!


    效果

  • 相关阅读:
    Druid 介绍及配置
    LoadRunner性能测试入门教程
    Java 程序员必须收藏的资源大全
    JProfiler 入门教程
    Web网站的性能测试工具
    职场中必须知道的8条规则
    作为测试人员需要的技能和工作要求
    web性能监控与分析
    Java应用常用性能分析工具
    mockito简单教程
  • 原文地址:https://www.cnblogs.com/katachi/p/10962505.html
Copyright © 2020-2023  润新知