这两天没有更新,主要是在调试B码的时间计算程序,今天刚刚将B码的时间解析出来。本来计划先输出1PPS信号,结果发现之前的B码解析遗漏了很多判断,所以只能先解析出各个信号,才能正确输出1PPS。现在将解析B码时间的程序的过程一一介绍。
由于FPGA都是并行计算,所以对于搞习惯while(1)的小伙伴并不那么友好,所以自己总结了一个顺序执行的方法,并且B码的接收也是顺序接收的,所以必须加入顺序执行程序。
方案两种:
(1)接收到两个P帧之后启动定时器,然后根据定时器判断每个帧的状态,这种比较依赖于定时器的启动和B码的正确性,所以摒弃了这种结构;
(2)利用下降沿关系,顺延下降沿。
接收B码中我采用了第2种方法。先看顺延结构:
- reg resettime_en_d0;
- reg resettime_en_d1;
- wire resettime_falling_flag;(第一个下降沿)
- wire resettime_rasing_flag;
- assign resettime_falling_flag = (~resettime_en_d0) & resettime_en_d1;
- assign resettime_rasing_flag = (~resettime_en_d1) & resettime_en_d0;
- always @(posedge clk or negedge rst_n) begin
- if (!rst_n) begin
- resettime_en_d0 <= 1'b0;
- resettime_en_d1 <= 1'b0;
- end
- else begin
- resettime_en_d0 <= timebeginflag;(源下降沿)
- resettime_en_d1 <= resettime_en_d0;
-
- end
- end
中间有第一个下降沿,当然随便你用哪个下降沿,B码的每个下降沿都可以,你自己定义的下降沿也可以。
- reg resettime1_en_d0;
- reg resettime1_en_d1;
- wire resettime1_falling_flag;(第二个下降沿)
- wire resettime1_rasing_flag;
- assign resettime1_falling_flag = (~resettime1_en_d0) & resettime1_en_d1;
- assign resettime1_rasing_flag = (~resettime1_en_d1) & resettime1_en_d0;
- always @(posedge clk or negedge rst_n) begin
- if (!rst_n) begin
- resettime1_en_d0 <= 1'b0;
- resettime1_en_d1 <= 1'b0;
- end
- else begin
- resettime1_en_d0 <= resettime_falling_flag;
- resettime1_en_d1 <= resettime1_en_d0;
-
- end
- end
这样就在下降沿之后又创造出一个下降沿,如果不保证不出错的话就只能这样做。当然大神估计不屑于这种方式,但是这种是最快出程序并且最不容易出错的方式。
优点:不容易出错,不需要太多考虑到FPGA的并行执行规则。
- (*noprune*)reg [3:0] bcodelevellatch1;
- (*noprune*)reg [3:0] bcodelevellatch2;
-
- always@(posedge clk or negedge rst_n)
- begin
- if (rst_n == 1'b0)begin
- bcodelevellatch1 <= 1'd0;
- bcodelevellatch2 <= 1'd0;
- end
- else if (resettime_falling_flag == 1'b1)begin
- bcodelevellatch1 <= bcodelevel;
- bcodelevellatch2 <= bcodelevellatch1;
- end
- end
首先是上篇文章中判断出来一个脉宽是0 ,1 ,还是P码之后,造出延后的一个下降沿resettime_falling_flag,将得到的数据锁存到latch中。
- (*noprune*)reg bcodereadyflag;
- always@(posedge clk or negedge rst_n)
- begin
- if (rst_n == 1'b0)
- bcodereadyflag <= 1'd0;
- else if (resettime1_falling_flag == 1'b1)begin
- if((bcodelevellatch1 >= 4'd3)&&(bcodelevellatch2 >= 4'd3))
- bcodereadyflag <= 1'd1;
- else bcodereadyflag <= 1'd0;
- end
- end
锁存后,根据上文中制造的延后的第二个下降沿,判断两个锁存值是否都是P帧。如果是,将标志位置1,如果不是继续为0。当然这个标志只出现一个周期。
至此,B码的起始帧已经判断完毕。
首先在采集到一个B码之后,必须加入一个计数变量,因为B码1s一共100个,所以需要将100个B码信息全部锁存。
- (*noprune*)reg [7:0] bcodebitcnt; /*synthesis noprune*/
- (*noprune*)reg bcodeflag;
- always@(posedge clk or negedge rst_n)
- begin
- if (rst_n == 1'b0)begin
- bcodebitcnt <= 8'd0;
- bcodeflag <= 1'd0;
- end
- else if (bpluse_falling_flag == 1)begin
- bcodebitcnt <= bcodebitcnt + 1'b1;
- bcodeflag <= 1'd0;
- end
- else if (bcodereadyflag == 1)
- bcodebitcnt <= 8'd3;
- else if (bcodebitcnt == 8'd101)begin
- bcodebitcnt <= 0;
- bcodeflag <= 1'd1;
- end
- else begin
- bcodebitcnt <= bcodebitcnt;
- bcodeflag <= 1'd0;
- end
- 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的单元里面。
- reg resettime2_en_d0;
- reg resettime2_en_d1;
- wire resettime2_falling_flag;
- wire resettime2_rasing_flag;
- assign resettime2_falling_flag = (~resettime2_en_d0) & resettime2_en_d1;
- assign resettime2_rasing_flag = (~resettime2_en_d1) & resettime2_en_d0;
- always @(posedge clk or negedge rst_n) begin
- if (!rst_n) begin
- resettime2_en_d0 <= 1'b0;
- resettime2_en_d1 <= 1'b0;
- end
- else begin
- resettime2_en_d0 <= resettime1_falling_flag;
- resettime2_en_d1 <= resettime2_en_d0;
-
- end
- 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对应的寄存器中。对应程序如下:
- (*noprune*)reg [3:0] b_data_rec1;
- (*noprune*)reg [3:0] b_data_rec2;
- (*noprune*)reg [3:0] b_data_rec3;
- (*noprune*)reg [3:0] b_data_rec4;
- (*noprune*)reg [3:0] b_data_rec5;
- (*noprune*)reg [3:0] b_data_rec6;
- ......
- (*noprune*)reg [3:0] b_data_rec100;
-
- always@(posedge clk or negedge rst_n)
- begin
- if (rst_n == 1'b0)begin
- b_data_rec1 <= 4'd0;
- b_data_rec2 <= 4'd0;
- b_data_rec3 <= 4'd0;
- b_data_rec4 <= 4'd0;
- b_data_rec5 <= 4'd0;
- b_data_rec6 <= 4'd0;
- ......
- b_data_rec100 <= 4'd0;
- end
- else if (resettime2_falling_flag == 1'b1)begin
- if (bcodereadyflag == 1)begin
- b_data_rec1 <= 4'd3;
- b_data_rec2 <= 4'd3;
- end
- if(bcodebitcnt == 8'd3) b_data_rec3 <= bcodelevel;
- if(bcodebitcnt == 8'd4) b_data_rec4 <= bcodelevel;
- if(bcodebitcnt == 8'd5) b_data_rec5 <= bcodelevel;
- if(bcodebitcnt == 8'd6) b_data_rec6 <= bcodelevel;
- ......
- if(bcodebitcnt == 8'd100)b_data_rec50 <= bcodelevel;
- end
- end
编写程序的时候有很多不在控制之内得效果,其他只要这些bug能完整完成你需要的逻辑就行。就比如上面写的为什么置位成3,其实是有问题的,本来下面应该放入3的寄存器例,但是由于FPGA的执行逻辑问题,下次的下降沿才放入3的寄存器,所以不管怎么说,只要每个状态都能完成你需要的东西,就可以了。
但是如果时间充足的话,还是最好没有bug。
程序中还有一个bug,我现在还不知道在哪里,但是结果出来的不太对,所以明天得继续搞定这个东西,只有慢慢得来了,急不得!!!
今天先写到锁存B码的值,其实下面就直接根据逻辑将锁存的100个值在bcodeflag变为1的那个周期内计算对应的utc时间即可。这段程序已经编写完毕,并且能够正确解析出B码的utc时间了。剩下的部分和验证部分明天再写!