串口接收多个字节(串口多字节数据的接收)
导读:这次设计一个可以接收多字节(通过修改例化时的位宽实现)的串口接收模块。...
这次设计一个可以接收多字节(通过修改例化时的位宽实现)的串口接收模块 。
当接收到9个字节的数据 ,但是我们只需要8个字节的数据时候 ,我们需要的是前八位的数据还是后八位的数据我们无法确定 。
所以我们需要设定一种传输协议 ,这种协议我们可以自定义规则 。我们就设定前缀为8h55+8hA5 ,后缀为8hF0的一串数据即为我们需要的数据 。
1 、状态机的设定
2 、需要的模块
(1) 8位串口接收模块
`timescale 1ns / 1ps ////////////////////////////////////////////////////////////////////////////////// // Company: // Engineer: Lclone // // Create Date: 2022/12/16 15:37:44 // Design Name: uart_byte_rx // Module Name: uart_byte_rx // Project Name: uart_byte_rx // Target Devices: // Tool Versions: // Description: 8位串口接收模块 // // Dependencies: // // Revision: // Revision 0.01 - File Created // Additional Comments: // ////////////////////////////////////////////////////////////////////////////////// module uart_byte_rx # ( parameter RX_BAUD = 9600, //波特率 parameter CLK_FQC = 50_000_000, //模块时钟频率 parameter BAUD_CNT = CLK_FQC/RX_BAUD) //模块每波特需要计数的次数(设置此端口方便仿真用) ( input Clk, //时钟频率接口 input Rst_n, //复位接口 input Uart_rx, //串口接收接口 output reg [7:0] Data, //接收到的数据接口 output reg Rx_done //接收完成信号 ); reg uart_rx_r; //延一拍 reg uart_rx_rr; //延两拍 reg receiv_begin; //接收开始信号 reg receiv_flag; //接收状态信号 reg [ 3:0] state; //状态机寄存器 reg [15:0] baud_cnt; //波及计数器 reg [ 3:0] sampel_cnt; //采样计数器 reg sampel_en; //采样使能 reg sampel_ref; //样本寄存器 reg [ 3:0] acc; //累加寄存器 reg [ 3:0] bit_cnt; //数据位寄存器 always @(posedge Clk) begin //延两拍为下降沿捕获 uart_rx_r <= Uart_rx; uart_rx_rr <= uart_rx_r; end always @(posedge Clk or negedge Rst_n) begin //接收信号发生 if(Rst_n == 0) receiv_begin <= 0; else if(state == 0 & uart_rx_rr & ~uart_rx_r) receiv_begin <= 1b1; else receiv_begin <= 0; end always @(posedge Clk or negedge Rst_n) begin //状态机 if(Rst_n == 0) begin state <= 0; sampel_ref <= 8b0; acc <= 8b0; Data <= 8b0; end else case(state) 0: //空闲状态 if(receiv_begin == 1) state <= 3d1; else state <= 0; 1: begin //抽样状态 if(sampel_en == 1) begin sampel_ref <= Uart_rx; state <= 3d2; end else state <= 3b1; end 2: begin //数据判断状态 acc <= acc + sampel_ref; if(sampel_cnt == 7) begin if(acc >= 4) begin Data[7] <= 1b1; state <= 3d3;acc <= 8b0; end else begin Data[7] <= 0; state <= 3d3;acc <= 8b0; end end else state <= 3d1; end 3: begin //数据移位状态 if(bit_cnt < 8) begin Data <= Data >> 1; state <= 3d1; end else state <= 0; end default:; endcase end always @(posedge Clk or negedge Rst_n) begin //接收进行标志 if(Rst_n == 0) receiv_flag <= 0; else if(receiv_begin == 1) receiv_flag <= 1b1; else if(bit_cnt == 9 & baud_cnt == BAUD_CNT/9*8) //这里设置为记到BAUD_CNT/9*8是为了让Rx_done信号提前一点产生 ,避免因为Rx_done出现过晚 ,导致错过下一个起始位的下降沿 。后面和其相同的条件判断 ,也是因为相同原因设置的 。 receiv_flag <= 1b0; end always @(posedge Clk or negedge Rst_n) begin //波特计数 if(Rst_n == 0) baud_cnt <= 0; else if(receiv_flag == 1) begin if(baud_cnt == BAUD_CNT - 1) baud_cnt <= 0; else baud_cnt <= baud_cnt + 1b1; end else baud_cnt <= 0; end always @(posedge Clk or negedge Rst_n) begin //采样计数 if(Rst_n == 0) begin sampel_cnt <= 0; sampel_en <= 0; end else if(receiv_flag == 1) begin case(baud_cnt) BAUD_CNT/9*1-1 : begin sampel_cnt <= 0; sampel_en <=1; end BAUD_CNT/9*2-1 : begin sampel_cnt <= 1; sampel_en <=1; end BAUD_CNT/9*3-1 : begin sampel_cnt <= 2; sampel_en <=1; end BAUD_CNT/9*4-1 : begin sampel_cnt <= 3; sampel_en <=1; end BAUD_CNT/9*5-1 : begin sampel_cnt <= 4; sampel_en <=1; end BAUD_CNT/9*6-1 : begin sampel_cnt <= 5; sampel_en <=1; end BAUD_CNT/9*7-1 : begin sampel_cnt <= 6; sampel_en <=1; end BAUD_CNT/9*8-1 : begin sampel_cnt <= 7; sampel_en <=1; end BAUD_CNT/9*9-1 : sampel_cnt <= 0; default:sampel_en <=0; endcase end end always @(posedge Clk or negedge Rst_n) begin //数据位计数 if(Rst_n == 0) bit_cnt <= 0; else if(bit_cnt == 9 & baud_cnt == BAUD_CNT/9*8) bit_cnt <= 0; else if(baud_cnt == BAUD_CNT - 1) bit_cnt <= bit_cnt + 1b1; end always @(posedge Clk or negedge Rst_n) begin //接收完成信号产生 if(Rst_n == 0) Rx_done <= 0; else if(bit_cnt == 9 & baud_cnt == BAUD_CNT/9*8) Rx_done <= 1b1; else Rx_done <= 0; end endmodule3 、设计的模块代码
`timescale 1ns / 1ps ////////////////////////////////////////////////////////////////////////////////// // Company: // Engineer: // // Create Date: 2022/12/25 00:26:10 // Design Name: // Module Name: uart_bytes_rx // Project Name: // Target Devices: // Tool Versions: // Description: // // Dependencies: // // Revision: // Revision 0.01 - File Created // Additional Comments: // ////////////////////////////////////////////////////////////////////////////////// module uart_bytes_rx #( parameter DATA_WIDTH = 64,//数据位宽 parameter PREFIX1 = 8h55,//前缀1 parameter PREFIX2 = 8hA5,//前缀2 parameter ENDINGS = 8hF0)//后缀 ( input Clk, //时钟信号 input Rst_n, //复位信号 input Uart_rx, //串口接收端口 output reg[DATA_WIDTH-1-8*3:0] Bytes_data, //多字节数据端口 output reg Bytes_Rx_done //多字节接收完成 ); reg [2:0] state; //状态机寄存器 reg [DATA_WIDTH-1:0] bytes_data_reg; //多字节数据接收寄存器 wire [7:0] rx_data_reg; //8位数据接收寄存器 wire Rx_done; //8位数据接收完成信号 uart_byte_rx # ( .RX_BAUD (115200), //波特率 .CLK_FQC (50_000_000)) //时钟频率 uart_byte_rx_inst ( .Clk (Clk), //时钟 .Rst_n (Rst_n), //复位 .Uart_rx (Uart_rx), //串口接收端口 .Data (rx_data_reg), //8位数据端口 .Rx_done (Rx_done) //8位数据接收完成 ); always @(posedge Clk or negedge Rst_n) begin//状态机 if(Rst_n == 0) begin state <= 0; bytes_data_reg <= 0; Bytes_Rx_done <= 0; Bytes_data <= 0; end else case(state) 0:begin if(Rx_done) begin bytes_data_reg[DATA_WIDTH-1:DATA_WIDTH-1-7] <= rx_data_reg;//数据装载 state <= 3d1; end else begin state <= 0; Bytes_Rx_done <= 0; end end 1:begin if(bytes_data_reg[DATA_WIDTH-1:DATA_WIDTH-1-7] == ENDINGS && bytes_data_reg[15:8] ==PREFIX2 && bytes_data_reg[7:0] ==PREFIX1)//数据协议判断 begin Bytes_data <= bytes_data_reg[DATA_WIDTH-1-8:16]; state <= 1b0; Bytes_Rx_done <= 1b1; bytes_data_reg <= 0; end else state <= 3d2; end 2:begin bytes_data_reg <= bytes_data_reg >> 8;//数据移位 state <= 0; end endcase end endmodule4 、仿真验证
(1)仿真激励文件
`timescale 1ns / 1ps ////////////////////////////////////////////////////////////////////////////////// // Company: // Engineer: // // Create Date: 2022/12/26 16:14:35 // Design Name: // Module Name: uart_bytes_rx_tb // Project Name: // Target Devices: // Tool Versions: // Description: // // Dependencies: // // Revision: // Revision 0.01 - File Created // Additional Comments: // ////////////////////////////////////////////////////////////////////////////////// module uart_bytes_rx_tb(); reg CLK_50M; reg RST_N; wire [39:0] Bytes_data; reg Uart_rx; wire Bytes_Rx_done; uart_bytes_rx # ( .DATA_WIDTH (64)) uart_bytes_rx_inst ( .Clk (CLK_50M), .Rst_n (RST_N), .Uart_rx (Uart_rx), .Bytes_data (Bytes_data), .Bytes_Rx_done (Bytes_Rx_done) ); defparam uart_bytes_rx_inst.uart_byte_rx_inst.BAUD_CNT = 50; always #10 CLK_50M <= ~CLK_50M; initial begin CLK_50M <= 1b0; RST_N <= 1b0; Uart_rx <= 1b1; #100 RST_N <= 1b1; #20 data_deliver(8h55); #100 data_deliver(8hA5); #100 data_deliver(8h01); #100 data_deliver(8h23); #100 data_deliver(8h45); #100 data_deliver(8h67); #100 data_deliver(8h89); #100 data_deliver(8hf0); #100 $stop; end task data_deliver; input [7:0] test_data; begin Uart_rx <= 1b0; #1000 Uart_rx <= test_data[0]; #1000 Uart_rx <= test_data[1]; #1000 Uart_rx <= test_data[2]; #1000 Uart_rx <= test_data[3]; #1000 Uart_rx <= test_data[4]; #1000 Uart_rx <= test_data[5]; #1000 Uart_rx <= test_data[6]; #1000 Uart_rx <= test_data[7]; #1000 Uart_rx <= 1b1; #1000; end endtask endmodule(2)仿真结果
5 、应用实例
我们把它应用为一个通过接收电脑串口发送的数据从而改变8位LED每位是否闪烁和闪烁的周期的程序 。
top.v
`timescale 1ns / 1ps module Top( input Sclk, input Rst_n, input Uart_rx, output [7:0] LED ); wire [23:0] Bytes_data; wire Bytes_Rx_done; uart_bytes_rx # ( .DATA_WIDTH (48), .PREFIX1 (8h55), .PREFIX2 (8hA5), .ENDINGS (8hF0)) uart_bytes_rx_inst ( .Clk (Sclk), .Rst_n (Rst_n), .Uart_rx (Uart_rx), .Bytes_data (Bytes_data), .Bytes_Rx_done (Bytes_Rx_done) ); LED_6 LED_6_inst( .SCLK (Sclk), .RST_N (Rst_n), .CTRL_IN (Bytes_data[7:0]), .Time (Bytes_data[23:8]), .LED (LED) ); endmodule uart_bytes_rx.v `timescale 1ns / 1ps module uart_bytes_rx #( parameter DATA_WIDTH = 64,//数据位宽 parameter PREFIX1 = 8h55,//前缀1 parameter PREFIX2 = 8hA5,//前缀2 parameter ENDINGS = 8hF0)//后缀 ( input Clk, //时钟信号 input Rst_n, //复位信号 input Uart_rx, //串口接收端口 output reg[DATA_WIDTH-1-8*3:0] Bytes_data, //多字节数据端口 output reg Bytes_Rx_done //多字节接收完成 ); reg [2:0] state; //状态机寄存器 reg [DATA_WIDTH-1:0] bytes_data_reg; //多字节数据接收寄存器 wire [7:0] rx_data_reg; //8位数据接收寄存器 wire Rx_done; //8位数据接收完成信号 uart_byte_rx # ( .RX_BAUD (115200), //波特率 .CLK_FQC (50_000_000)) //时钟频率 uart_byte_rx_inst ( .Clk (Clk), //时钟 .Rst_n (Rst_n), //复位 .Uart_rx (Uart_rx), //串口接收端口 .Data (rx_data_reg), //8位数据端口 .Rx_done (Rx_done) //8位数据接收完成 ); always @(posedge Clk or negedge Rst_n) begin//状态机 if(Rst_n == 0) begin state <= 0; bytes_data_reg <= 0; Bytes_Rx_done <= 0; Bytes_data <= 0; end else case(state) 0:begin if(Rx_done) begin bytes_data_reg[DATA_WIDTH-1:DATA_WIDTH-1-7] <= rx_data_reg;//数据装载 state <= 3d1; end else begin state <= 0; Bytes_Rx_done <= 0; end end 1:begin if(bytes_data_reg[DATA_WIDTH-1:DATA_WIDTH-1-7] == ENDINGS && bytes_data_reg[15:8] ==PREFIX2 && bytes_data_reg[7:0] ==PREFIX1)//数据协议判断 begin Bytes_data <= bytes_data_reg[DATA_WIDTH-1-8:16]; state <= 1b0; Bytes_Rx_done <= 1b1; bytes_data_reg <= 0; end else state <= 3d2; end 2:begin bytes_data_reg <= bytes_data_reg >> 8;//数据移位 state <= 0; end endcase end endmodule uart_byte_rx.v `timescale 1ns / 1ps module uart_byte_rx # ( parameter RX_BAUD = 9600, parameter CLK_FQC = 50_000_000, parameter BAUD_CNT = CLK_FQC/RX_BAUD) ( input Clk, input Rst_n, input Uart_rx, output reg [7:0] Data, output reg Rx_done ); reg uart_rx_r; reg uart_rx_rr; reg receiv_begin; reg receiv_flag; reg [ 3:0] state; reg [15:0] baud_cnt; reg [ 3:0] sampel_cnt; reg sampel_en; reg sampel_ref; reg [ 3:0] acc; reg [ 3:0] bit_cnt; always @(posedge Clk) begin uart_rx_r <= Uart_rx; uart_rx_rr <= uart_rx_r; end always @(posedge Clk or negedge Rst_n) begin if(Rst_n == 0) receiv_begin <= 0; else if(state == 0 & uart_rx_rr & ~uart_rx_r) receiv_begin <= 1b1; else receiv_begin <= 0; end always @(posedge Clk or negedge Rst_n) begin if(Rst_n == 0) begin state <= 0; sampel_ref <= 8b0; acc <= 8b0; Data <= 8b0; end else case(state) 0: if(receiv_begin == 1) state <= 3d1; else state <= 0; 1: begin if(sampel_en == 1) begin sampel_ref <= Uart_rx; state <= 3d2; end else state <= 3b1; end 2: begin acc <= acc + sampel_ref; if(sampel_cnt == 7) begin if(acc >= 4) begin Data[7] <= 1b1; state <= 3d3;acc <= 8b0; end else begin Data[7] <= 0; state <= 3d3;acc <= 8b0; end end else state <= 3d1; end 3: begin if(bit_cnt < 8) begin Data <= Data >> 1; state <= 3d1; end else state <= 0; end default:; endcase end always @(posedge Clk or negedge Rst_n) begin if(Rst_n == 0) receiv_flag <= 0; else if(receiv_begin == 1) receiv_flag <= 1b1; else if(bit_cnt == 9 & baud_cnt == BAUD_CNT/9*8) receiv_flag <= 1b0; end always @(posedge Clk or negedge Rst_n) begin if(Rst_n == 0) baud_cnt <= 0; else if(receiv_flag == 1) begin if(baud_cnt == BAUD_CNT - 1) baud_cnt <= 0; else baud_cnt <= baud_cnt + 1b1; end else baud_cnt <= 0; end always @(posedge Clk or negedge Rst_n) begin if(Rst_n == 0) begin sampel_cnt <= 0; sampel_en <= 0; end else if(receiv_flag == 1) begin case(baud_cnt) BAUD_CNT/9*1-1 : begin sampel_cnt <= 0; sampel_en <=1; end BAUD_CNT/9*2-1 : begin sampel_cnt <= 1; sampel_en <=1; end BAUD_CNT/9*3-1 : begin sampel_cnt <= 2; sampel_en <=1; end BAUD_CNT/9*4-1 : begin sampel_cnt <= 3; sampel_en <=1; end BAUD_CNT/9*5-1 : begin sampel_cnt <= 4; sampel_en <=1; end BAUD_CNT/9*6-1 : begin sampel_cnt <= 5; sampel_en <=1; end BAUD_CNT/9*7-1 : begin sampel_cnt <= 6; sampel_en <=1; end BAUD_CNT/9*8-1 : begin sampel_cnt <= 7; sampel_en <=1; end BAUD_CNT/9*9-1 : sampel_cnt <= 0; default:sampel_en <=0; endcase end end always @(posedge Clk or negedge Rst_n) begin if(Rst_n == 0) bit_cnt <= 0; else if(bit_cnt == 9 & baud_cnt == BAUD_CNT/9*8) bit_cnt <= 0; else if(baud_cnt == BAUD_CNT - 1) bit_cnt <= bit_cnt + 1b1; end always @(posedge Clk or negedge Rst_n) begin if(Rst_n == 0) Rx_done <= 0; else if(bit_cnt == 9 & baud_cnt == BAUD_CNT/9*8) Rx_done <= 1b1; else Rx_done <= 0; end endmodule LED_6.v `timescale 1ns / 1ps module LED_6( input SCLK, input RST_N, input [ 7:0] CTRL_IN, input [15:0] Time, output reg [ 7:0] LED ); parameter DELAY_10US = 500; parameter COUNT_10MS = 1000; reg [8:0] count_10us; reg [15:0] count_time; reg led_flag; always @(posedge SCLK or negedge RST_N) begin if(RST_N == 0) count_10us <= 0; else if(count_10us == DELAY_10US - 1) count_10us <= 0; else count_10us <= count_10us + 1b1; end always @(posedge SCLK or negedge RST_N) begin if(RST_N == 0) count_time <= 0; else if(count_time == Time - 1) count_time <= 0; else if(count_10us == DELAY_10US - 1) count_time <= count_time + 1b1; end always @(posedge SCLK or negedge RST_N) begin if(RST_N == 0) led_flag <= 0; else if(count_time == COUNT_10MS - 1) led_flag <= ~led_flag; end always @(posedge SCLK or negedge RST_N) begin if(RST_N == 0) LED <= 0; else if(count_time == COUNT_10MS - 1 & led_flag == 1) LED <= CTRL_IN; else if(count_time == COUNT_10MS - 1 & led_flag == 0) LED <= 0; end endmodule创心域SEO版权声明:以上内容作者已申请原创保护,未经允许不得转载,侵权必究!授权事宜、对本内容有异议或投诉,敬请联系网站管理员,我们将尽快回复您,谢谢合作!