基于FPGA的ASCII码日期转时间戳算法实现

2021-04-14 17:46:47 浏览数 (2)

基于FPGA的ASCII码日期转时间戳算法实现

本篇为学员项目经验分享。

画师,执笔绘画FPGA江湖 持续更新 欢迎关注!

  • 基于FPGA的ASCII码日期转时间戳算法实现
  • 作者:画师
  • 地点:上海
  • 时间:2020.12.14

一、概念

时间戳是使用数字签名技术产生的数据,签名的对象包括了原始文件信息、签名参数、签名时间等信息。时间戳系统用来产生和管理时间戳,对签名对象进行数字签名产生时间戳,以证明原始文件在签名时间之前已经存在。

在一些通信当中,我们可能会使用ASCII码来进行一些字符串的传输,其中就包括日期等时间数据的传输,而我们的FPGA接收到的就是ASCII码相对应的二进制,不经过转换得到的值就不是原来的值了。而转换成我们想要的时间戳,也需要通过相对应的算法来进行转换,如果得到的值不是原来的值,那么得到的时间戳也将会是错误的,传输到另一端就会解析出错误的值,导致整个传输失败。

二、设计原理

查看ASCII码表可知,规定由8位的二进制数来表示相对应的字符串。而对应的0-9的字符所对应的二进制码分别是0011_0000、0011_0001、0011_0010、0011_0011、0011_0100、0011_0101、0011_0110、0011_0111、0011_1000、0011_1001。通过观察可知,当我们去掉相应的高四位,只留下低四位时,低四位二进制的值正好就是对应的十进制的值。这样我们就能通过相应的算法来得到我们想要的值。

我们可以随意设置一个ASCII码所表示的日期如20201212-20:20:52.。这样,我们首先收到的第一个字符是ASCII码所表示的“2”,也就是二进制所表示的0011_0010,我们去掉高四位留下低四位,然后将第四位的值乘1000,然后将后传输过来的值一次乘100、乘10、乘1,然后再将得到的几个数进行相加,就得到了我们想要的十进制所表示的年2020,后面的值以此类推,去掉无关的字符,只保留对应的数值字符,就可以得到相应的十进制所表示的值,这样就和ASCII码所表示的字符的时间就对上了。

然后,我们就可以使用相对应的Unix时间戳的算法来计算出对应日期的时间戳。Unix时间戳是指从1970年01月01日00时00分00秒到现在的秒数。Unix时间戳的算法可以参照下列式子:

Y=(year-1)*365 year/4-year/100 year/400;

M=367*mon/12-30;

D=day-1;

X=Y M D-719162;

T=((X*24 hour)*60) mim)*60 sec;

第一个中,year/4-year/100 year/400表示的是从0001年到当年的闰年的个数,闰年的天数是366天,所以从 0001年到当年的天数为Y=(year-1)365 year/4-year/100 year/400。在Unix时间戳中,计算月份并不是从1月算起,而是从3月份算起,把3月份当成第一个月会好算一点,用一次函数计算可以得到M=367mon/12-30。然后是日期,是从1号开始的,所以得到的式子就是D=day-1。

由于Unix时间戳是从1970年01月01日00时00分00秒开始算起,所以计算现在的时间戳时,需要减去0001年到1970年01月01日00时00分00秒的时间,因为是从3月份算起,所以0001年已经经过了1月和2月,也就是59天,计算得出的结果为719162,这也就得到了第四个式子X=Y M D-719162。最后就可以得出从1970年01月01日00时00分00秒到当前的秒数,也就是最后一个式子。

由以上原理,我们就可以将ASCII码所表示的时间转换为时间戳了。

三、架构设计

将本设计命名为ascii_2_timestamp,clk为输入的时钟,rst_n为复位信号,ascii表示8位的二进制ASCII码,ivalid为输入的数据有效信号,中间输出值均为转换过后的时间值,再加上一个伴随的数据有效信号,最后输出为time_stamp表示时间戳,done信号告诉下一层转换完成。

四、Verilog代码实现

由于代码较多,这里只贴出部分代码,全部代码下载可以点击左下角阅读原文跳转至叁芯智能科技技术论坛下载,或者登录网址:www.sxznfpga.com。

顶层模块 ascii_2_timestamp 代码:

代码语言:javascript复制
1   module ascii_2_timestamp(
2 
3     input      wire                clk,
4     input      wire                rst_n,
5     
6     input      wire                ivalid,
7     input      wire      [7:0]     ascii,
8     
9     output     wire      [63:0]    time_stamp,
10    output     wire                done
11  );
12
13    wire                 [15:0]    year;
14    wire                 [7:0]     mon;
15    wire                 [7:0]     day;
16    wire                 [7:0]     hour;
17    wire                 [7:0]     min;
18    wire                 [7:0]     sec;
19    wire                           ovalid;
20
21    ascii_2_bin ascii_2_bin_inst(
22
23      .clk                   (clk),
24      .rst_n                 (rst_n),
25      
26      .ivalid                (ivalid),
27      .ascii                 (ascii),
28      
29      .year                  (year),
30      .mon                   (mon),
31      .day                   (day),
32      .hour                  (hour),
33      .min                   (min),
34      .sec                   (sec),
35      
36      .ovalid                (ovalid)
37    );
38    
39    timestamp timestamp_inst(
40    
41      .clk                   (clk),
42      .rst_n                 (rst_n),
43
44      .year                  (year),
45      .mon                   (mon),
46      .day                   (day),
47      .hour                  (hour),
48      .min                   (min),
49      .sec                   (sec),
50      .ivalid                (ovalid),
51      
52      .time_stamp            (time_stamp),
53      .done                  (done)
54    );
55
56  endmodule

ASCII码转换模块 ascii_2_bin 代码:

代码语言:javascript复制
1   module ascii_2_bin(
2  
3     input      wire                clk,
4     input      wire                rst_n,
5     
6     input      wire                ivalid,
7     input      wire      [7:0]     ascii,
8     
9     output     reg       [15:0]    year,
10    output     reg       [7:0]     mon,
11    output     reg       [7:0]     day,
12    output     reg       [7:0]     hour,
13    output     reg       [7:0]     min,
14    output     reg       [7:0]     sec,
15    
16    output     reg                 ovalid
17  );
18 
19    reg                  [3:0]     day_r0;
20    reg                  [3:0]     day_r1;
21    reg                  [3:0]     mon_r0;
22    reg                  [3:0]     mon_r1;
23    reg                  [3:0]     year_r0;
24    reg                  [3:0]     year_r1;
25    reg                  [3:0]     year_r2;
26    reg                  [3:0]     year_r3;
27    reg                  [3:0]     sec_r0;
28    reg                  [3:0]     sec_r1;
29    reg                  [3:0]     min_r0;
30    reg                  [3:0]     min_r1;
31    reg                  [3:0]     hour_r0;
32    reg                  [3:0]     hour_r1;
33 
34    always @ (posedge clk,negedge rst_n) begin
35      if (rst_n == 1'b0) begin
36        year_r0 <= 4'd0;
37        year_r1 <= 4'd0;
38        year_r2 <= 4'd0;
39        year_r3 <= 4'd0;
40        mon_r0 <= 4'd0;
41        mon_r1 <= 4'd0;
42        day_r0 <= 4'd0;
43        day_r1 <= 4'd0;
44      end
45      else
46        if (ivalid == 1'b1 && ascii == "-") begin
47          year_r0 <= year_r0;
48          year_r1 <= year_r1;
49          year_r2 <= year_r2;
50          year_r3 <= year_r3;
51          mon_r0 <= mon_r0;
52          mon_r1 <= mon_r1;
53          day_r0 <= day_r0;
54          day_r1 <= day_r1;
55        end
56        else begin
57          day_r0 <= ascii[3:0];
58          day_r1 <= day_r0;
59          mon_r0 <= day_r1;
60          mon_r1 <= mon_r0;
61          year_r0 <= mon_r1;
62          year_r1 <= year_r0;
63          year_r2 <= year_r1;
64          year_r3 <= year_r2;
65        end
66    end
67    
68    always @ (posedge clk,negedge rst_n) begin
69      if (rst_n == 1'b0)
70        year <= 16'd0;
71      else
72        if (ivalid == 1'b1 && ascii == "-")
73          year <= year_r3 * 1000   year_r2 * 100   year_r1 * 10   year_r0;
74        else
75          year <= year;
76    end
77    
78    always @ (posedge clk,negedge rst_n) begin
79      if (rst_n == 1'b0)
80        mon <= 8'd0;
81      else
82        if (ivalid == 1'b1 && ascii == "-")
83          mon <= mon_r1 * 10   mon_r0;
84        else
85          mon <= mon;
86    end
87    
88    always @ (posedge clk,negedge rst_n) begin
89      if (rst_n == 1'b0)
90        day <= 8'd0;
91      else
92        if (ivalid == 1'b1 && ascii == "-")
93          day <= day_r1 * 10   day_r0;
94        else
95          day <= day;
96    end
97    
98    always @ (posedge clk,negedge rst_n) begin
99      if (rst_n == 1'b0) begin
100       hour_r0 <= 4'd0;
101       hour_r1 <= 4'd0;
102     end
103     else
104       if (ivalid == 1'b1 && ascii == ":") begin
105         hour_r0 <= hour_r0;
106         hour_r1 <= hour_r1;
107       end
108       else begin
109         hour_r0 <= ascii[3:0];
110         hour_r1 <= hour_r0;
111       end
112   end
113   
114   always @ (posedge clk,negedge rst_n) begin
115     if (rst_n == 1'b0)
116       hour <= 4'd0;
117     else
118       if (ivalid == 1'b1 && ascii == ":")
119         hour <= hour_r1 * 10   hour_r0;
120       else
121         hour <= hour;
122   end
123   
124   always @ (posedge clk,negedge rst_n) begin
125     if (rst_n == 1'b0) begin
126       min_r0 <= 4'd0;
127       min_r1 <= 4'd0;
128     end
129     else
130       if (ivalid == 1'b1 && ascii == ":") begin
131         min_r0 <= min_r0;
132         min_r1 <= min_r1;
133       end
134       else begin
135         min_r0 <= ascii[3:0];
136         min_r1 <= min_r0;
137       end
138   end
139   
140   always @ (posedge clk,negedge rst_n) begin
141     if (rst_n == 1'b0)
142       min <= 4'd0;
143     else
144       if (ivalid == 1'b1 && ascii == ":")
145         min <= min_r1 * 10   min_r0;
146       else
147         min <= min;
148   end
149   
150   always @ (posedge clk,negedge rst_n) begin
151     if (rst_n == 1'b0) begin
152       sec_r0 <= 4'd0;
153       sec_r1 <= 4'd0;
154     end
155     else
156       if (ivalid == 1'b1 && ascii == ".") begin
157         sec_r0 <= sec_r0;
158         sec_r1 <= sec_r1;
159       end
160       else begin
161         sec_r0 <= ascii[3:0];
162         sec_r1 <= sec_r0;
163       end
164   end
165   
166   always @ (posedge clk,negedge rst_n) begin
167     if (rst_n == 1'b0)
168       sec <= 4'd0;
169     else
170       if (ivalid == 1'b1 && ascii == ".")
171         sec <= sec_r1 * 10   sec_r0;
172       else
173         sec <= sec;
174   end
175   
176   always @ (posedge clk,negedge rst_n) begin
177     if (rst_n == 1'b0)
178       ovalid <= 1'b0;
179     else
180       if (ivalid == 1'b1 && ascii == ".")
181         ovalid <= 1'b1;
182       else
183         ovalid <= 1'b0;
184   end
185
186 endmodule

时间戳转换模块 timestamp 代码:

代码语言:javascript复制
1   module timestamp(
2  
3     input      wire                clk,
4     input      wire                rst_n,
5  
6     input      wire      [15:0]    year,
7     input      wire      [7:0]     mon,
8     input      wire      [7:0]     day,
9     input      wire      [7:0]     hour,
10    input      wire      [7:0]     min,
11    input      wire      [7:0]     sec,
12    input      wire                ivalid,
13    
14    output     reg       [63:0]    time_stamp,
15    output     reg                 done
16  );
17 
18    reg                                       y_req1;
19    reg                                       y_req2;
20    reg                                       x_sum_req;
21    reg                         [63:0]        y;
22    reg                         [63:0]        y_r1;
23    reg                         [63:0]        y_r2;
24 
25    reg                                       m_req;
26    reg                         [63:0]        m;
27    reg                         [63:0]        m_r;
28    
29    reg                         [63:0]        d;
30   
31    reg                                       x_req;
32    reg                         [63:0]        x;
33    reg                         [63:0]        x_r;
34   
35    reg                                       t_req1;
36    reg                                       t_req2;
37    reg                                       t_req3;
38    reg                         [63:0]        t_r1;
39    reg                         [63:0]        t_r2;
40    
41    always @ (posedge clk,negedge rst_n) begin
42      if (rst_n == 1'b0) begin
43        y_r1 <= 64'd0;
44        y_req1 <= 1'b0;
45      end
46      else
47        if (ivalid == 1'b1) begin
48          y_r1 <= (year - 1) * 365;
49          y_req1 <= 1'b1;
50        end
51        else begin
52          y_r1 <= 1'b0;
53          y_req1 <= 1'b0;
54        end
55    end
56    
57    always @ (posedge clk,negedge rst_n) begin
58      if (rst_n == 1'b0) begin
59        y_r2 <= 64'd0;
60        y_req2 <= 1'b0;
61      end
62      else
63        if (y_req1 == 1'b1) begin
64          y_r2 <= y_r1   year/4 - year/100;
65          y_req2 <= 1'b1;
66        end
67        else begin
68          y_r2 <= y_r2;
69          y_req2 <= 1'b0;
70        end
71    end
72    
73    always @ (posedge clk,negedge rst_n) begin
74      if (rst_n == 1'b0) begin
75        y <= 64'd0;
76        x_sum_req <= 1'b0;
77      end
78      else
79        if (y_req2 == 1'b1) begin
80          y <= y_r2   year/400;
81          x_sum_req <= 1'b1;
82        end
83        else begin
84          y <= y;
85          x_sum_req <= 1'b0;
86        end
87    end
88    
89    always @ (posedge clk,negedge rst_n) begin
90      if (rst_n == 1'b0) begin
91        m_r <= 64'd0;
92        m_req <= 1'b0;
93      end
94      else
95        if (ivalid == 1'b1) begin
96          m_r <= 367 * mon;
97          m_req <= 1'b1;
98        end
99        else begin
100         m_r <= m_r;
101         m_req <= 1'b0;
102       end
103   end
104   
105   always @ (posedge clk,negedge rst_n) begin
106     if (rst_n == 1'b0)
107       m <= 64'd0;
108     else
109       if (m_req == 1'b1)
110         m <= m_r/12   29;
111       else
112         m <= m;
113   end
114   
115   always @ (posedge clk,negedge rst_n) begin
116     if (rst_n == 1'b0)
117       d <= 64'd0;
118     else
119       if (ivalid == 1'b1)
120         d <= day - 1'b1;
121       else
122         d <= d;
123   end
124   
125   always @ (posedge clk,negedge rst_n) begin
126     if (rst_n == 1'b0) begin
127       x_r <= 64'd0;
128       x_req <= 1'b0;
129     end
130     else
131       if (x_sum_req == 1'b1) begin
132         x_r <= y   m   d;
133         x_req <= 1'b1;
134       end
135       else begin
136         x_r <= x_r;
137         x_req <= 1'b0;
138       end
139   end
140   
141   always @ (posedge clk,negedge rst_n) begin
142     if (rst_n == 1'b0) begin
143       x <= 64'd0;
144       t_req1 <= 1'b0;
145     end
146     else
147       if (x_req == 1'b1) begin
148         x <= x_r - 719162;
149         t_req1 <= 1'b1;
150       end
151       else begin
152         x <= x;
153         t_req1 <= 1'b0;
154       end
155   end
156   
157   always @ (posedge clk,negedge rst_n) begin
158     if (rst_n == 1'b0) begin
159       t_r1 <= 64'd0;
160       t_req2 <= 1'b0;
161     end
162     else
163       if (t_req1 == 1'b1) begin
164         t_r1 <= x * 24   hour;
165         t_req2 <= 1'b1;
166       end
167       else begin
168         t_r1 <= t_r1;
169         t_req2 <= 1'b0;
170       end
171   end
172   
173   always @ (posedge clk,negedge rst_n) begin
174     if (rst_n == 1'b0) begin
175       t_r2 <= 64'd0;
176       t_req3 <= 1'b0;
177     end
178     else
179       if (t_req2 == 1'b1) begin
180         t_r2 <= t_r1 * 60   min;
181         t_req3 <= 1'b1;
182       end
183       else begin
184         t_r2 <= t_r2;
185         t_req3 <= 1'b0;
186       end
187   end
188   
189   always @ (posedge clk,negedge rst_n) begin
190     if (rst_n == 1'b0)
191       time_stamp <= 64'd0;
192     else
193       if (t_req3 == 1'b1)
194         time_stamp <= t_r2 * 60   sec;
195       else
196         time_stamp <= 64'd0;
197   end
198   
199   always @ (posedge clk,negedge rst_n) begin
200     if (rst_n == 1'b0)
201       done <= 1'b0;
202     else
203       if (t_req3 == 1'b1)
204         done <= 1'b1;
205       else
206         done <= 1'b0;
207   end
208
209 endmodule

五、仿真测试

仿真测试模块 ascii_2_timestamp_tb 代码:

代码语言:javascript复制
1   `timescale 1ns/1ps
2  
3   module ascii_2_timestamp_tb;
4  
5     reg                                clk;
6     reg                                rst_n;
7     reg                                ivalid;
8     reg                   [7:0]        ascii;
9     
10    wire                  [63:0]       time_stamp;
11    wire                               done;
12 
13    ascii_2_timestamp ascii_2_timestamp_inst(
14 
15        .clk                            (clk),
16        .rst_n                          (rst_n),
17        
18        .ivalid                         (ivalid),
19        .ascii                          (ascii),
20        
21        .time_stamp                     (time_stamp),
22        .done                           (done)
23      );
24      
25    initial clk = 1'b0;
26    always # 10 clk = ~clk;
27    
28    initial begin
29      rst_n = 1'b0;
30      ivalid = 1'b0;
31      ascii = 8'd0;
32      # 201;
33      
34      rst_n = 1'b1;
35      # 200;
36      
37      @ (posedge clk);
38      # 2;
39      ivalid = 1'b1;
40      ascii = "2";
41      
42      @ (posedge clk);
43      # 2;
44      ivalid = 1'b1;
45      ascii = "0";
46      
47      @ (posedge clk);
48      # 2;
49      ivalid = 1'b1;
50      ascii = "2";
51      
52      @ (posedge clk);
53      # 2;
54      ivalid = 1'b1;
55      ascii = "0";
56      
57      @ (posedge clk);
58      # 2;
59      ivalid = 1'b1;
60      ascii = "1";
61      
62      @ (posedge clk);
63      # 2;
64      ivalid = 1'b1;
65      ascii = "2";
66      
67      @ (posedge clk);
68      # 2;
69      ivalid = 1'b1;
70      ascii = "1";
71      
72      @ (posedge clk);
73      # 2;
74      ivalid = 1'b1;
75      ascii = "2";
76      
77      @ (posedge clk);
78      # 2;
79      ivalid = 1'b1;
80      ascii = "-";
81      
82      @ (posedge clk);
83      # 2;
84      ivalid = 1'b1;
85      ascii = "2";
86      
87      @ (posedge clk);
88      # 2;
89      ivalid = 1'b1;
90      ascii = "0";
91      
92      @ (posedge clk);
93      # 2;
94      ivalid = 1'b1;
95      ascii = ":";
96      
97      @ (posedge clk);
98      # 2;
99      ivalid = 1'b1;
100     ascii = "2";
101     
102     @ (posedge clk);
103     # 2;
104     ivalid = 1'b1;
105     ascii = "0";
106     
107     @ (posedge clk);
108     # 2;
109     ivalid = 1'b1;
110     ascii = ":";
111     
112     @ (posedge clk);
113     # 2;
114     ivalid = 1'b1;
115     ascii = "5";
116     
117     @ (posedge clk);
118     # 2;
119     ivalid = 1'b1;
120     ascii = "2";
121     
122     @ (posedge clk);
123     # 2;
124     ivalid = 1'b1;
125     ascii = ".";
126     
127     @ (posedge clk);
128     # 2;
129     ivalid = 1'b0;
130     ascii = 8'd0;
131     
132     # 2000;
133     $stop;
134   end
135
136 endmodule

仿真测试结果:

使用20201212-20:20:52最后生成的时间戳为1613161252。

六、总结

在进行一些特殊的转换时,我们可以去研究他的一些规律,实际上将ASCII码转换成十进制也非常简单,只需要把相对应的ASCII码的二进制数转换成十进制即可,但是那样做的话,后面还需要做其他的转换,相对来说就比较麻烦,所以我就选择了这种去掉高四位的方法。

本篇到此结束,后续有时间还会更新,希望各位多多关注,有问题可以交流。

后续会持续更新,带来Vivado、 ISE、Quartus II 、candence等安装相关设计教程,学习资源、项目资源、好文推荐等,希望大侠持续关注。

江湖偌大,继续闯荡,愿大侠一切安好,有缘再见!

0 人点赞