基于温度检测练习: uart_rx + ascii_2_hex + opcode_dect 仿真

top code:  对所有模块进行例化

 1 module temp_top(
 2                     clk             ,
 3                     rst_n           ,
 4                     rxd_din         
 5 );
 6 
 7 input               clk             ;
 8 input               rst_n           ;
 9 input               rxd_din         ;
10 
11 wire                rxd_din         ;
12 wire[8-1:0]         u1_dout         ;
13 wire                u1_dout_vld     ;
14 
15 wire[4-1:0]         u2_dout         ;
16 wire                u2_dout_vld     ;
17 
18 wire[8-1:0]         u3_dout_cmd     ;
19 wire[8-1:0]         u3_dout_data    ;
20 wire                u3_dout_vld     ;
21 
22 uart_rx         uart_rx_u1(
23                                     .clk         (clk           )    ,
24                                     .rst_n       (rst_n         )    ,
25                                     .rxd         (rxd_din       )    ,
26                                     .dout        (u1_dout       )    ,
27                                     .dout_vld    (u1_dout_vld   )    
28 ); 
29 
30 
31 ascii_2_hex     ascii_2_hex_u2(
32                                     .clk         (clk           )    ,
33                                     .rst_n       (rst_n         )    ,
34                                     .din         (u1_dout       )    ,
35                                     .din_vld     (u1_dout_vld   )    ,
36                                     .dout        (u2_dout       )    ,
37                                     .dout_vld    (u2_dout_vld   )         
38 );
39 
40 opcode_dect     opcode_dect_u3(
41                                     .clk         (clk           )    ,
42                                     .rst_n       (rst_n         )    ,
43                                     .din         (u2_dout       )    ,
44                                     .din_vld     (u2_dout_vld   )    ,
45 
46                                     .dout_cmd    (u3_dout_cmd   )    ,
47                                     .dout_data   (u3_dout_data  )    ,
48                                     .dout_vld    (u3_dout_vld   )                              
49 );
50 
51 endmodule
View Code

uart_rx:  接收串口8bit数据,并产生有效标志信号

  1 module uart_rx(
  2                     clk                     ,
  3                     rst_n                   ,
  4                     rxd                     ,
  5                     dout                    ,
  6                     dout_vld        
  7 );  
  8     
  9 localparam   BAUD_RATE_115200    = 9'd434   ;
 10 localparam   BAUD_RATE_921600    = 8'd54    ;
 11 localparam   D_W                 = 4'd8     ;
 12     
 13 input               clk                     ;
 14 input               rst_n                   ;
 15 input               rxd                     ;
 16             
 17 output[D_W-1:0]     dout                    ;
 18 output              dout_vld                ;
 19     
 20 
 21 reg[9-1:0]          baud_rate               ;
 22 reg[9-1:0]          cnt0                    ;  //产生波特率
 23 reg[4-1:0]          cnt1                    ;  //接受字节个数
 24 
 25 
 26 reg                 rxd_0                   ;
 27 reg                 rxd_1                   ;
 28 reg                 rxd_2                   ;
 29 reg                 cnt0_flag               ;
 30 reg[D_W-1:0]        dout                    ;
 31 reg                 dout_vld                ;
 32 
 33 wire                rxd_h_2_l               ;
 34 wire                add_cnt0                ;
 35 wire                end_cnt0                ;
 36 wire                add_cnt1                ;
 37 wire                end_cnt1                ;
 38 wire                baud_rate_flag          ;
 39 
 40 assign              baud_rate_flag  = 1'b0  ;   //0 : 115200;   1:921600
 41 
 42 always @(*)begin
 43     if(!baud_rate_flag)begin
 44         baud_rate = BAUD_RATE_115200;
 45     end
 46     else begin
 47         baud_rate = BAUD_RATE_921600;
 48     end
 49 end
 50 
 51 //打三拍,让rxd信号进行同步化
 52 always @(posedge clk or negedge  rst_n)begin
 53     if(!rst_n)begin
 54         rxd_0   <= 0;
 55         rxd_1   <= 0;
 56         rxd_2   <= 0;
 57     end
 58     else begin
 59         rxd_0   <= rxd;
 60         rxd_1   <= rxd_0;
 61         rxd_2   <= rxd_1;
 62     end
 63 end
 64 
 65 assign  rxd_h_2_l   = rxd_2 & (~rxd_1);    //检测rxd的下降沿
 66 
 67 
 68 always @(posedge clk or negedge  rst_n)begin
 69     if(!rst_n)begin
 70         cnt0_flag <= 0;
 71     end
 72     else if(rxd_h_2_l)begin //检测到有下降沿,启动计数器
 73         cnt0_flag <= 1;
 74     end
 75     else if(end_cnt1)begin  //待接收字节数收完,就停止计数
 76         cnt0_flag <= 0;
 77     end
 78 end
 79 
 80 
 81 always @(posedge clk or negedge  rst_n)begin
 82     if(!rst_n)begin
 83         cnt0 <= 0;
 84     end
 85     else if(add_cnt0)begin
 86         if(end_cnt0)begin
 87             cnt0 <= 0;
 88         end
 89         else begin
 90             cnt0 <= cnt0 + 1;
 91         end
 92     end
 93 end
 94 
 95 assign add_cnt0 = cnt0_flag;
 96 assign end_cnt0 = add_cnt0 && cnt0 == baud_rate - 1;
 97 
 98 always @(posedge clk or negedge  rst_n)begin
 99     if(!rst_n)begin
100         cnt1 <= 0;
101     end
102     else if(add_cnt1)begin
103         if(end_cnt1)begin
104             cnt1 <= 0;
105         end
106         else begin
107             cnt1 <= cnt1 + 1;
108         end
109     end
110 end
111 
112 assign add_cnt1 = end_cnt0;
113 assign end_cnt1 = add_cnt1 && cnt1 == (1 + D_W ) - 1;   //数9个字节 :起始位+ 8bit数据
114 //(停止位不数,当在数停止位时,很有可能下一个字节发过来了, 这时就有可能会出现检测不到起始位)
115 
116 always @(posedge clk or negedge  rst_n)begin
117     if(!rst_n)begin
118         dout <= 0;
119     end
120     else if(add_cnt0 && (cnt0 == (baud_rate>>1)-1) && (cnt1 != 0))begin   //在计数器有效期间,且在中间取值
121         dout[cnt1-1] <= rxd_2;
122     end
123 end
124 
125 
126 always @(posedge clk or negedge  rst_n)begin
127     if(!rst_n)begin
128         dout_vld <= 0;
129     end
130     else begin
131         dout_vld <= end_cnt1;
132     end
133 end
134 
135 endmodule
View Code

ascii_2_hex: 将串口接收的数据进行转换,因为用串口助手发送数据时,选的是ASCII格式,所以内部需要对这个数据进行一个转换,并产生有效标志信号,(注意输出的位宽是4bit,因为只解析出0~9、A~F、 a~f,也就是0~15)

 1 module ascii_2_hex(
 2                     clk         ,
 3                     rst_n       ,
 4                     din         ,
 5                     din_vld     ,
 6                     dout        ,
 7                     dout_vld    
 8 );
 9 parameter       D_W =   4'd8    ;
10 
11 input           clk             ;
12 input           rst_n           ;
13 input[D_W-1:0]  din             ;
14 input           din_vld         ;
15 
16 output[4-1:0]   dout            ;
17 output          dout_vld        ;
18 
19 wire            num_0_to_9      ;
20 wire            num_A_to_F      ;
21 wire            num_a_to_f      ;
22 
23 reg[4-1:0]      dout            ;
24 reg             dout_vld        ;
25 
26 assign          num_0_to_9 = (din >= 8'd48) && (din < 8'd58 );  //字符0~9
27 assign          num_A_to_F = (din >= 8'd65) && (din < 8'd71 );  //字符A~F
28 assign          num_a_to_f = (din >= 8'd97) && (din < 8'd103);  //字符a~f
29 
30 always @(posedge clk or negedge rst_n)begin
31     if(!rst_n)begin
32         dout <= 0;
33     end
34     else if(num_0_to_9)begin
35         dout <= din - 8'd48;
36     end
37     else if(num_A_to_F)begin
38         dout <= din - 8'd55;
39     end
40     else if(num_a_to_f)begin
41         dout <= din - 8'd87;
42     end
43     else begin
44         dout <= 0;
45     end
46 end
47 
48 always @(posedge clk or negedge rst_n)begin
49     if(!rst_n)begin
50         dout_vld <= 0;
51     end
52     else if(din_vld && (num_0_to_9 || num_A_to_F || num_a_to_f))begin
53         dout_vld <= 1;
54     end
55     else begin
56         dout_vld <= 0;
57     end
58 end
59 
60 endmodule
View Code

opcode_dect: 对转换的数据进行解析,用串口助手工具发送过来的一组数据,数据里包含了固定格式“” 包头 + 命令 + 数据值 ”,所以需要对包头进行检测,然后在将命令和数据值进行解析出来,单独存放

  1 module opcode_dect(
  2                     clk         ,
  3                     rst_n       ,
  4                     din         ,
  5                     din_vld     ,
  6                     
  7                     dout_cmd    ,
  8                     dout_data   ,
  9                     dout_vld        
 10 );
 11 
 12 
 13 input               clk         ;
 14 input               rst_n       ;
 15 input   [ 4-1:0]    din         ;   //输入的数据是4位宽
 16 input               din_vld     ;
 17           
 18 output  [ 8-1:0]    dout_cmd    ;   //命令
 19 output  [ 8-1:0]    dout_data   ;   //数据
 20 output              dout_vld    ;
 21           
 22 reg     [ 4-1:0]    din_0       ;
 23 reg     [ 4-1:0]    din_1       ;
 24 reg     [ 4-1:0]    din_2       ;
 25 wire    [16-1:0]    din_temp    ;
 26 reg     [ 3-1:0]    cnt0        ;
 27 reg                 add_flag    ; 
 28 
 29 wire                add_cnt0    ;
 30 wire                end_cnt0    ;
 31                                                      
 32 reg     [ 8-1:0]    dout_cmd    ;
 33 reg     [ 8-1:0]    dout_data   ;
 34 reg                 dout_vld    ;
 35 
 36 
 37 always @(posedge clk or negedge rst_n)begin
 38     if(!rst_n)begin
 39         din_0 <= 0;
 40         din_1 <= 0;
 41         din_2 <= 0;
 42     end
 43     else if(din_vld)begin
 44         din_0 <= din;
 45         din_1 <= din_0;
 46         din_2 <= din_1;
 47     end
 48 end
 49 
 50 assign din_temp = {din_2, din_1, din_0, din};   //将连续进来的四个数据,拼接在一起
 51 
 52 always @(posedge clk or negedge rst_n)begin
 53     if(!rst_n)begin
 54         add_flag <= 0;
 55     end
 56     else if(din_vld && din_temp == 16'h55d5)begin   //收到固定包头格式,就启动计数器
 57         add_flag <= 1;
 58     end
 59     else if(end_cnt0)begin
 60         add_flag <= 0;
 61     end
 62 end
 63 
 64 always @(posedge clk or negedge rst_n)begin
 65     if(!rst_n)begin
 66         cnt0 <= 0;
 67     end
 68     else if(add_cnt0)begin
 69         if(end_cnt0)begin
 70             cnt0 <= 0;
 71         end
 72         else begin
 73             cnt0 <= cnt0 + 1;
 74         end
 75     end
 76 end
 77 
 78 assign add_cnt0 = add_flag && din_vld;  //启动计数器条件注意加上 数据有效时
 79 assign end_cnt0 = add_cnt0 && cnt0 == 4-1;
 80 
 81 //把命令解析输出来
 82 always @(posedge clk or negedge rst_n)begin
 83     if(!rst_n)begin
 84         dout_cmd <= 0;
 85     end
 86     else if(add_cnt0 && cnt0 == 1-1 && din_vld)begin    
 87         dout_cmd[8-1:4] <= din;
 88     end
 89     else if(add_cnt0 && cnt0 == 2-1 && din_vld)begin
 90         dout_cmd[4-1:0] <= din;
 91     end
 92 end
 93 
 94 //把数据解析输出来
 95 always @(posedge clk or negedge rst_n)begin
 96     if(!rst_n)begin
 97         dout_data <= 0;
 98     end
 99     else if(add_cnt0 && cnt0 == 3-1 && din_vld)begin
100         dout_data[8-1:4] <= din;
101     end
102     else if(add_cnt0 && cnt0 == 4-1 && din_vld)begin
103         dout_data[4-1:0] <= din;
104     end
105 end
106 
107 always @(posedge clk or negedge rst_n)begin
108     if(!rst_n)begin
109         dout_vld <= 0;
110     end
111     else begin
112         dout_vld <= end_cnt0;
113     end
114 end
115 
116 endmodule
View Code

仿真测试代码:

发送的数据是 

55d5 80 01 

55d5 82 02

55d5 84 04

55d5 88 08

55d5 80 00

注意,上面的数值是ASCII码值,不是十六进制,所以先提前用工具转换下,比如串口助手工具

 

 

  1 `timescale 1ns/100ps
  2 
  3 module top_sim;
  4 
  5 parameter   CLK_CYCLE           = 20        ;
  6 parameter   BAUD_RATE           = 9'd434    ;
  7 
  8 reg         clk         ;
  9 reg         rst_n       ;
 10 reg         rxd_din     ;
 11 
 12 initial begin
 13     clk = 1;
 14     forever begin
 15         #(CLK_CYCLE/2);
 16         clk = ~clk;
 17     end
 18 end
 19 
 20 initial begin
 21     rst_n = 1;
 22     #1;
 23     rst_n = 0;
 24     #(CLK_CYCLE*2);
 25     rst_n = 1;
 26 end
 27 
 28 integer i;
 29 
 30 initial begin
 31     #1;
 32     rxd_din = 1;
 33     #(CLK_CYCLE*4);
 34     for(i=0; i<8; i=i+1)begin
 35         begin   //8'h35
 36             rxd_din = 0;    //起始位
 37             #(CLK_CYCLE*BAUD_RATE);  //保持位宽时间
 38             
 39             rxd_din = 1;
 40             #(CLK_CYCLE*BAUD_RATE);
 41             
 42             rxd_din = 0;
 43             #(CLK_CYCLE*BAUD_RATE);
 44             
 45             rxd_din = 1;
 46              #(CLK_CYCLE*BAUD_RATE);
 47              
 48             rxd_din = 0;
 49             #(CLK_CYCLE*BAUD_RATE);
 50             
 51             rxd_din = 1;
 52             #(CLK_CYCLE*BAUD_RATE);
 53             
 54             rxd_din = 1;
 55             #(CLK_CYCLE*BAUD_RATE);
 56             
 57             rxd_din = 0;
 58             #(CLK_CYCLE*BAUD_RATE);
 59             
 60             rxd_din = 0;
 61             #(CLK_CYCLE*BAUD_RATE);
 62             
 63             rxd_din = 1;    //停止位
 64             #(CLK_CYCLE*BAUD_RATE);
 65 
 66             #(CLK_CYCLE*2);
 67         end
 68         
 69         begin   //8'h35
 70             rxd_din = 0;    //起始位
 71             #(CLK_CYCLE*BAUD_RATE);  //保持位宽时间
 72             
 73             rxd_din = 1;
 74             #(CLK_CYCLE*BAUD_RATE);
 75             
 76             rxd_din = 0;
 77             #(CLK_CYCLE*BAUD_RATE);
 78             
 79             rxd_din = 1;
 80              #(CLK_CYCLE*BAUD_RATE);
 81              
 82             rxd_din = 0;
 83             #(CLK_CYCLE*BAUD_RATE);
 84             
 85             rxd_din = 1;
 86             #(CLK_CYCLE*BAUD_RATE);
 87             
 88             rxd_din = 1;
 89             #(CLK_CYCLE*BAUD_RATE);
 90             
 91             rxd_din = 0;
 92             #(CLK_CYCLE*BAUD_RATE);
 93             
 94             rxd_din = 0;
 95             #(CLK_CYCLE*BAUD_RATE);
 96             
 97             rxd_din = 1;    //停止位
 98             #(CLK_CYCLE*BAUD_RATE);
 99 
100             #(CLK_CYCLE*2);
101         end
102          
103         begin   //8'h64
104             rxd_din = 0;    //起始位
105             #(CLK_CYCLE*BAUD_RATE);  //保持位宽时间
106             
107             rxd_din = 0;
108             #(CLK_CYCLE*BAUD_RATE);
109             
110             rxd_din = 0;
111             #(CLK_CYCLE*BAUD_RATE);
112             
113             rxd_din = 1;
114              #(CLK_CYCLE*BAUD_RATE);
115              
116             rxd_din = 0;
117             #(CLK_CYCLE*BAUD_RATE);
118             
119             rxd_din = 0;
120             #(CLK_CYCLE*BAUD_RATE);
121             
122             rxd_din = 1;
123             #(CLK_CYCLE*BAUD_RATE);
124             
125             rxd_din = 1;
126             #(CLK_CYCLE*BAUD_RATE);
127             
128             rxd_din = 0;
129             #(CLK_CYCLE*BAUD_RATE);
130             
131             rxd_din = 1;    //停止位
132             #(CLK_CYCLE*BAUD_RATE);
133 
134             #(CLK_CYCLE*2);
135         end
136         
137         begin   //8'h35
138             rxd_din = 0;    //起始位
139             #(CLK_CYCLE*BAUD_RATE);  //保持位宽时间
140             
141             rxd_din = 1;
142             #(CLK_CYCLE*BAUD_RATE);
143             
144             rxd_din = 0;
145             #(CLK_CYCLE*BAUD_RATE);
146             
147             rxd_din = 1;
148              #(CLK_CYCLE*BAUD_RATE);
149              
150             rxd_din = 0;
151             #(CLK_CYCLE*BAUD_RATE);
152             
153             rxd_din = 1;
154             #(CLK_CYCLE*BAUD_RATE);
155             
156             rxd_din = 1;
157             #(CLK_CYCLE*BAUD_RATE);
158             
159             rxd_din = 0;
160             #(CLK_CYCLE*BAUD_RATE);
161             
162             rxd_din = 0;
163             #(CLK_CYCLE*BAUD_RATE);
164             
165             rxd_din = 1;    //停止位
166             #(CLK_CYCLE*BAUD_RATE);
167 
168             #(CLK_CYCLE*2);
169         end
170         
171   /***************************8x***************************************/       
172         begin   //8'h38
173             rxd_din = 0;    //起始位
174             #(CLK_CYCLE*BAUD_RATE);  //保持位宽时间
175             
176             rxd_din = 0;
177             #(CLK_CYCLE*BAUD_RATE);
178             
179             rxd_din = 0;
180             #(CLK_CYCLE*BAUD_RATE);
181             
182             rxd_din = 0;
183              #(CLK_CYCLE*BAUD_RATE);
184              
185             rxd_din = 1;
186             #(CLK_CYCLE*BAUD_RATE);
187             
188             rxd_din = 1;
189             #(CLK_CYCLE*BAUD_RATE);
190             
191             rxd_din = 1;
192             #(CLK_CYCLE*BAUD_RATE);
193             
194             rxd_din = 0;
195             #(CLK_CYCLE*BAUD_RATE);
196             
197             rxd_din = 0;
198             #(CLK_CYCLE*BAUD_RATE);
199             
200             rxd_din = 1;    //停止位
201             #(CLK_CYCLE*BAUD_RATE);
202 
203             #(CLK_CYCLE*2);
204         end
205         
206         begin   //8'h30
207             rxd_din = 0;    //起始位
208             #(CLK_CYCLE*BAUD_RATE);  //保持位宽时间
209             
210             rxd_din = 0;
211             #(CLK_CYCLE*BAUD_RATE);
212             
213             rxd_din = (i==1);
214             #(CLK_CYCLE*BAUD_RATE);
215             
216             rxd_din = (i==2);
217              #(CLK_CYCLE*BAUD_RATE);
218              
219             rxd_din = (i==3);
220             #(CLK_CYCLE*BAUD_RATE);
221             
222             rxd_din = 1;
223             #(CLK_CYCLE*BAUD_RATE);
224             
225             rxd_din = 1;
226             #(CLK_CYCLE*BAUD_RATE);
227             
228             rxd_din = 0;
229             #(CLK_CYCLE*BAUD_RATE);
230             
231             rxd_din = 0;
232             #(CLK_CYCLE*BAUD_RATE);
233             
234             rxd_din = 1;    //停止位
235             #(CLK_CYCLE*BAUD_RATE);
236 
237             #(CLK_CYCLE*2);
238         end
239  /*******************************************************************/
240  
241 /***************************0x***************************************/ 
242         begin   //8'h30
243             rxd_din = 0;    //起始位
244             #(CLK_CYCLE*BAUD_RATE);  //保持位宽时间
245             
246             rxd_din = 0;
247             #(CLK_CYCLE*BAUD_RATE);
248             
249             rxd_din = 0;
250             #(CLK_CYCLE*BAUD_RATE);
251             
252             rxd_din = 0;
253              #(CLK_CYCLE*BAUD_RATE);
254              
255             rxd_din = 0;
256             #(CLK_CYCLE*BAUD_RATE);
257             
258             rxd_din = 1;
259             #(CLK_CYCLE*BAUD_RATE);
260             
261             rxd_din = 1;
262             #(CLK_CYCLE*BAUD_RATE);
263             
264             rxd_din = 0;
265             #(CLK_CYCLE*BAUD_RATE);
266             
267             rxd_din = 0;
268             #(CLK_CYCLE*BAUD_RATE);
269             
270             rxd_din = 1;    //停止位
271             #(CLK_CYCLE*BAUD_RATE);
272 
273             #(CLK_CYCLE*2);
274         end
275         
276         begin   //8'h31
277             rxd_din = 0;    //起始位
278             #(CLK_CYCLE*BAUD_RATE);  //保持位宽时间
279             
280             rxd_din = (i==0);
281             #(CLK_CYCLE*BAUD_RATE);
282             
283             rxd_din = (i==1);
284             #(CLK_CYCLE*BAUD_RATE);
285             
286             rxd_din = (i==2);
287              #(CLK_CYCLE*BAUD_RATE);
288               
289             rxd_din = (i==3);
290             #(CLK_CYCLE*BAUD_RATE);
291             
292             rxd_din = 1;
293             #(CLK_CYCLE*BAUD_RATE);
294             
295             rxd_din = 1;
296             #(CLK_CYCLE*BAUD_RATE);
297             
298             rxd_din = 0;
299             #(CLK_CYCLE*BAUD_RATE);
300             
301             rxd_din = 0;
302             #(CLK_CYCLE*BAUD_RATE);
303             
304             rxd_din = 1;    //停止位
305             #(CLK_CYCLE*BAUD_RATE);
306 
307             #(CLK_CYCLE*2);
308         end
309  /*******************************************************************/
310     end
311 end
312 
313 
314 temp_top    temp_top_u0(
315                             .clk      (clk      )     ,
316                             .rst_n    (rst_n    )     ,
317                             .rxd_din  (rxd_din  )       
318 );
319 
320 
321 
322 endmodule
View Code

仿真波形:

收到固定包头就启动计数器

 

 

仿真波形结果是对的,能真确解析出包头、命令 、数据值

 

posted @ 2022-08-25 11:22  MyBooks  阅读(50)  评论(0编辑  收藏  举报