基于温度检测练习: 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
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
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
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
仿真测试代码:
发送的数据是
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
仿真波形:
收到固定包头就启动计数器
仿真波形结果是对的,能真确解析出包头、命令 、数据值