• FPGA解析B码----连载3


    前言

        这两天没有更新,主要是在调试B码的时间计算程序,今天刚刚将B码的时间解析出来。本来计划先输出1PPS信号,结果发现之前的B码解析遗漏了很多判断,所以只能先解析出各个信号,才能正确输出1PPS。现在将解析B码时间的程序的过程一一介绍。

    第一章:时间顺序

        由于FPGA都是并行计算,所以对于搞习惯while(1)的小伙伴并不那么友好,所以自己总结了一个顺序执行的方法,并且B码的接收也是顺序接收的,所以必须加入顺序执行程序。

        方案两种:

        (1)接收到两个P帧之后启动定时器,然后根据定时器判断每个帧的状态,这种比较依赖于定时器的启动和B码的正确性,所以摒弃了这种结构;

        (2)利用下降沿关系,顺延下降沿。

        接收B码中我采用了第2种方法。先看顺延结构:

    1. reg resettime_en_d0;
    2. reg resettime_en_d1;
    3. wire resettime_falling_flag;(第一个下降沿)
    4. wire resettime_rasing_flag;
    5. assign resettime_falling_flag = (~resettime_en_d0) & resettime_en_d1;
    6. assign resettime_rasing_flag = (~resettime_en_d1) & resettime_en_d0;
    7. always @(posedge clk or negedge rst_n) begin
    8. if (!rst_n) begin
    9. resettime_en_d0 <= 1'b0;
    10. resettime_en_d1 <= 1'b0;
    11. end
    12. else begin
    13. resettime_en_d0 <= timebeginflag;(源下降沿)
    14. resettime_en_d1 <= resettime_en_d0;
    15. end
    16. end

        中间有第一个下降沿,当然随便你用哪个下降沿,B码的每个下降沿都可以,你自己定义的下降沿也可以。

    1. reg resettime1_en_d0;
    2. reg resettime1_en_d1;
    3. wire resettime1_falling_flag;(第二个下降沿)
    4. wire resettime1_rasing_flag;
    5. assign resettime1_falling_flag = (~resettime1_en_d0) & resettime1_en_d1;
    6. assign resettime1_rasing_flag = (~resettime1_en_d1) & resettime1_en_d0;
    7. always @(posedge clk or negedge rst_n) begin
    8. if (!rst_n) begin
    9. resettime1_en_d0 <= 1'b0;
    10. resettime1_en_d1 <= 1'b0;
    11. end
    12. else begin
    13. resettime1_en_d0 <= resettime_falling_flag;
    14. resettime1_en_d1 <= resettime1_en_d0;
    15. end
    16. end

        这样就在下降沿之后又创造出一个下降沿,如果不保证不出错的话就只能这样做。当然大神估计不屑于这种方式,但是这种是最快出程序并且最不容易出错的方式。

        优点:不容易出错,不需要太多考虑到FPGA的并行执行规则。

    第二章:锁存B码,判断起始P帧

    1. (*noprune*)reg [3:0] bcodelevellatch1;
    2. (*noprune*)reg [3:0] bcodelevellatch2;
    3. always@(posedge clk or negedge rst_n)
    4. begin
    5. if (rst_n == 1'b0)begin
    6. bcodelevellatch1 <= 1'd0;
    7. bcodelevellatch2 <= 1'd0;
    8. end
    9. else if (resettime_falling_flag == 1'b1)begin
    10. bcodelevellatch1 <= bcodelevel;
    11. bcodelevellatch2 <= bcodelevellatch1;
    12. end
    13. end

        首先是上篇文章中判断出来一个脉宽是0 ,1 ,还是P码之后,造出延后的一个下降沿resettime_falling_flag,将得到的数据锁存到latch中。

    1. (*noprune*)reg bcodereadyflag;
    2. always@(posedge clk or negedge rst_n)
    3. begin
    4. if (rst_n == 1'b0)
    5. bcodereadyflag <= 1'd0;
    6. else if (resettime1_falling_flag == 1'b1)begin
    7. if((bcodelevellatch1 >= 4'd3)&&(bcodelevellatch2 >= 4'd3))
    8. bcodereadyflag <= 1'd1;
    9. else bcodereadyflag <= 1'd0;
    10. end
    11. end

        锁存后,根据上文中制造的延后的第二个下降沿,判断两个锁存值是否都是P帧。如果是,将标志位置1,如果不是继续为0。当然这个标志只出现一个周期。

        至此,B码的起始帧已经判断完毕。

    第三章:锁存B码各个信息码

        首先在采集到一个B码之后,必须加入一个计数变量,因为B码1s一共100个,所以需要将100个B码信息全部锁存。

    1. (*noprune*)reg [7:0] bcodebitcnt; /*synthesis noprune*/
    2. (*noprune*)reg bcodeflag;
    3. always@(posedge clk or negedge rst_n)
    4. begin
    5. if (rst_n == 1'b0)begin
    6. bcodebitcnt <= 8'd0;
    7. bcodeflag <= 1'd0;
    8. end
    9. else if (bpluse_falling_flag == 1)begin
    10. bcodebitcnt <= bcodebitcnt + 1'b1;
    11. bcodeflag <= 1'd0;
    12. end
    13. else if (bcodereadyflag == 1)
    14. bcodebitcnt <= 8'd3;
    15. else if (bcodebitcnt == 8'd101)begin
    16. bcodebitcnt <= 0;
    17. bcodeflag <= 1'd1;
    18. end
    19. else begin
    20. bcodebitcnt <= bcodebitcnt;
    21. bcodeflag <= 1'd0;
    22. end
    23. end

        分开说明:B码的下降沿时,bcodebitcnt加1,在没有锁存到两个P帧时,此变量一直加,到101时变为0,也就是没有检测到2个P帧时随意存储。当检测到bcodereadyflag变为1时,即锁存在两个P帧时,将cnt变为3,重新进行存储。因为1和2两个位存储两个P帧,所以这个地方变为3。

        B码的下降沿时,bcodeflag变为0,当存储到101个时,变为1,即100个码元存储完毕,可以进行下一步运算,当然此处也为一个周期的高电平。

        分析:为啥是101?为啥不是100?当变为101时,下一个周期状态立马变为100了,所以下次B码下降沿来的时候,不会存储到101的单元里面。

    1. reg resettime2_en_d0;
    2. reg resettime2_en_d1;
    3. wire resettime2_falling_flag;
    4. wire resettime2_rasing_flag;
    5. assign resettime2_falling_flag = (~resettime2_en_d0) & resettime2_en_d1;
    6. assign resettime2_rasing_flag = (~resettime2_en_d1) & resettime2_en_d0;
    7. always @(posedge clk or negedge rst_n) begin
    8. if (!rst_n) begin
    9. resettime2_en_d0 <= 1'b0;
    10. resettime2_en_d1 <= 1'b0;
    11. end
    12. else begin
    13. resettime2_en_d0 <= resettime1_falling_flag;
    14. resettime2_en_d1 <= resettime2_en_d0;
    15. end
    16. end

        再顺延一个下降沿。现在说明5个下降沿的作用。

        第1个下降沿:bcodein。

        第2个下降沿:bpluse_falling_flag,这个下降沿延后了B码下降沿一个周期。B码的下降沿。B码的上升沿启动time定时器,B码的下降沿停止time定时器。此时判断B码的时间,看看是2ms,5ms,还是8ms。当然这个时候判断时间不是很准确,但是每个硬件电路都会有延迟,这个地方将time的判断时间范围扩大点,这样就可以判断出来大致的B码的值。

        同时将锁存计数器bcodebitcnt加1,并且判断是否存储到100个码元,如果是第100个码元,置位接收完毕标志位:bcodeflag。

        第3个下降沿:resettime_falling_flag,锁存B码的两个值。

        第4个下降沿:resettime1_falling_flag,锁存B码的两个值后,判断两个B码是否为两个P标志位。此时如果两个B码为P标志位,将bcodebitcnt置为3,那么下次B码采集后才放入bcodebitcnt=3的寄存器中(此处涉及到下降沿的并行问题,逻辑分析之后能明白就行,编写的时候自己想放那哪个寄存器都行,只要能接收对就好)。

        第5个下降沿:resettime2_falling_flag,将B码的值存入到bcodebitcnt对应的寄存器中。对应程序如下:

    1. (*noprune*)reg [3:0] b_data_rec1;
    2. (*noprune*)reg [3:0] b_data_rec2;
    3. (*noprune*)reg [3:0] b_data_rec3;
    4. (*noprune*)reg [3:0] b_data_rec4;
    5. (*noprune*)reg [3:0] b_data_rec5;
    6. (*noprune*)reg [3:0] b_data_rec6;
    7. ......
    8. (*noprune*)reg [3:0] b_data_rec100;
    9. always@(posedge clk or negedge rst_n)
    10. begin
    11. if (rst_n == 1'b0)begin
    12. b_data_rec1 <= 4'd0;
    13. b_data_rec2 <= 4'd0;
    14. b_data_rec3 <= 4'd0;
    15. b_data_rec4 <= 4'd0;
    16. b_data_rec5 <= 4'd0;
    17. b_data_rec6 <= 4'd0;
    18. ......
    19. b_data_rec100 <= 4'd0;
    20. end
    21. else if (resettime2_falling_flag == 1'b1)begin
    22. if (bcodereadyflag == 1)begin
    23. b_data_rec1 <= 4'd3;
    24. b_data_rec2 <= 4'd3;
    25. end
    26. if(bcodebitcnt == 8'd3) b_data_rec3 <= bcodelevel;
    27. if(bcodebitcnt == 8'd4) b_data_rec4 <= bcodelevel;
    28. if(bcodebitcnt == 8'd5) b_data_rec5 <= bcodelevel;
    29. if(bcodebitcnt == 8'd6) b_data_rec6 <= bcodelevel;
    30. ......
    31. if(bcodebitcnt == 8'd100)b_data_rec50 <= bcodelevel;
    32. end
    33. end

       第四章:BUG

        编写程序的时候有很多不在控制之内得效果,其他只要这些bug能完整完成你需要的逻辑就行。就比如上面写的为什么置位成3,其实是有问题的,本来下面应该放入3的寄存器例,但是由于FPGA的执行逻辑问题,下次的下降沿才放入3的寄存器,所以不管怎么说,只要每个状态都能完成你需要的东西,就可以了。

        但是如果时间充足的话,还是最好没有bug。

        程序中还有一个bug,我现在还不知道在哪里,但是结果出来的不太对,所以明天得继续搞定这个东西,只有慢慢得来了,急不得!!!

    最后:

        今天先写到锁存B码的值,其实下面就直接根据逻辑将锁存的100个值在bcodeflag变为1的那个周期内计算对应的utc时间即可。这段程序已经编写完毕,并且能够正确解析出B码的utc时间了。剩下的部分和验证部分明天再写!

  • 相关阅读:
    【进化计算】遗传算法求解gr48数据集
    Scrapy 爬虫教程:从原理到实战
    看微功耗遥测终端机如何轻松应对野外环境挑战?
    【知识积累】利用BeanDefinitionRegistryPostProcessor修改Mybatis的mapper代理对象
    手动撸代码实现Vue管道符过滤器filter功能
    VHDL基础知识笔记(1)
    使用frp+nginx内网穿透并配置https
    Cookie加密6
    python关键字保留字
    【数学建模】MATLAB应用实战系列(八十八)-组合权重法应用案例(附MATLAB和Python代码)
  • 原文地址:https://blog.csdn.net/weixin_45426095/article/details/126143135