FPGA——串口接收的使用(連續接收5字節並進行處理)


一、設計思路

  • led模塊的功能是指定時間,控制八個時間段的亮滅,兩個輸入信號,8位的ctr信號,32位的time信號
    time信號的計算公式:時間(clk),例如,系統時鍾為50MHz,想要一段時間為1秒,則有time = 150*10^6;
  • 串口接收后如何對數據進程處理,將40bit的數據,輸入到led模塊?
    • 引入校驗位,例如:只有輸入的前兩個字節為,0x20,0x21,輸入的后一個字節為0xCE,才為正確的數據

二、串口接收以及仿真代碼

[https://www.cnblogs.com/cnlntr/p/12483495.html]

三、串口接收的數據處理模塊(定義與下一個模塊的通信協議)

module uart_tx_cmd(
   clk      ,
   rst_n    ,
   rx_done  ,
   data     ,
   ctr      ,
   tim
);
parameter   DATA_W   =  8;
parameter   CTR_W    =  8;
parameter   TIM_W    =  32;
parameter   CNTD_N   =  8; //一串完整數據所包含字節的個數,兩個起始校驗字節+5個數據字節+1個終值校驗字節
parameter   CNTD_W   =  3; //字節計數器位寬

input                   clk;
input                   rst_n;
input                   rx_done;
input    [DATA_W-1:0]   data;

output   [CTR_W-1:0]    ctr;
output   [TIM_W-1:0]    tim;

reg      [CTR_W-1:0]    ctr;
reg      [TIM_W-1:0]    tim;

reg      [CNTD_W-1:0]   cnt_data;
wire                    add_cnt_data;
wire                    end_cnt_data;

//8個8位的寄存器,用來存放串口發送的完整數據
reg      [7:0]          data_save[7:0];
reg                     data_done;

//串口發送字節計數器
always @(posedge clk or negedge rst_n)begin
   if(!rst_n)
      cnt_data <= 0;
   else if(add_cnt_data)begin
      if(end_cnt_data)
         cnt_data <= 0;
      else
         cnt_data <= cnt_data + 1'b1;
   end
end
assign add_cnt_data = rx_done;
assign end_cnt_data = add_cnt_data && cnt_data == CNTD_N - 1;

always @(posedge clk or negedge rst_n)begin
   if(!rst_n)begin 
      data_save[0] <= 0;
      data_save[1] <= 0;
      data_save[2] <= 0;
      data_save[3] <= 0;
      data_save[4] <= 0;
      data_save[5] <= 0;
      data_save[6] <= 0;
      data_save[7] <= 0;
   end
   else if(rx_done)
      data_save[cnt_data] <= data;
end

always @(posedge clk or negedge rst_n)begin
   if(!rst_n)
      {ctr,tim} <= 40'b0;
   else if(data_done && (data_save[0]== 8'h20 && data_save[1] == 8'h21 && data_save[7] == 8'hCE))begin
      ctr <= data_save[2];
      tim[7:0]    <= data_save[6];
      tim[15:8]   <= data_save[5];
      tim[23:16]  <= data_save[4];
      tim[31:24]  <= data_save[3];
   end
end

always @(posedge clk or negedge rst_n)begin
   if(!rst_n)
      data_done <= 0;
   else if(end_cnt_data)
      data_done <= 1;
   else
      data_done <= 0;
end

endmodule

四、led控制模塊

module led_beta4(
   clk   ,
   rst_n ,
   ctr   ,
   tim   ,
   led   
);
parameter   CNT_W    =  27;            //計數器位寬
parameter   CTR_W    =  8;             //輸入控制信號位寬
parameter   CNT1_W   =  3;             //控制信號計數器位寬
parameter   TIM_W    =  32;            //時間位寬


input                clk;
input                rst_n;
input    [CTR_W-1:0] ctr;
input    [TIM_W-1:0] tim;
output               led;

reg                  led;

reg   [CNT_W-1:0]    cnt;
wire                 add_cnt;
wire                 end_cnt;

reg   [CNT1_W-1:0]   cnt_ctr;
wire                 add_cnt_ctr;
wire                 end_cnt_ctr;
wire                 led_tmp;

//0.25s計數器
always @(posedge clk or negedge rst_n)begin
   if(!rst_n)
      cnt <= 0;
   else if(add_cnt)begin
      if(end_cnt)
         cnt <= 0;
      else
         cnt <= cnt + 1'b1;
   end
end
assign add_cnt = (tim >= 1);
assign end_cnt = add_cnt && cnt == tim - 1;

//8位控制信號計數器
always @(posedge clk or negedge rst_n)begin
   if(!rst_n)
      cnt_ctr <= 0;
   else if(add_cnt_ctr)begin
      if(end_cnt_ctr)
         cnt_ctr <= 0;
      else
         cnt_ctr <= cnt_ctr + 1'b1;
   end
end
assign add_cnt_ctr = end_cnt;
assign end_cnt_ctr = add_cnt_ctr && cnt_ctr == CTR_W - 1;

always @(posedge clk or negedge rst_n)begin
   if(!rst_n)
      led <= 1;
   else
      led <= led_tmp;
end

assign led_tmp = ctr[cnt_ctr];

endmodule

五、頂層模塊

module uart_rx_ctrl_led(
   clk      ,
   rst_n    ,
   led      ,
   uart_rx  
);

input    clk;
input    rst_n;
input    uart_rx;
output   led;

wire     led;

wire  [31:0]   tim;
wire  [7:0]    ctr;
wire  [7:0]    data;
wire           rx_done;

led_beta4 led_beta4(
   .clk     (clk),
   .rst_n   (rst_n),
   .ctr     (ctr),
   .tim     (tim),
   .led     (led)
);

my_uart_rx my_uart_rx(
   .rst_n      (rst_n),
   .clk        (clk),
   .uart_rx    (uart_rx),
   .baud_set   (4'd4),
   .data       (data),
   .rx_done    (rx_done) 
);

uart_tx_cmd uart_tx_cmd(
   .clk     (clk),
   .rst_n   (rst_n),
   .rx_done (rx_done),
   .data    (data),
   .ctr     (ctr),
   .tim     (tim)
);

endmodule

六、仿真代碼

`timescale 1ns / 1ns

module uart_rx_ctrl_led_tb();

parameter CYCLE   =  20;

reg   clk ;
reg   rst_n;
wire  led;
reg   uart_rx;

uart_rx_ctrl_led uart_rx_ctrl_led(
   clk      ,
   rst_n    ,
   led      ,
   uart_rx  
);

initial begin
   clk = 1;
   forever 
   #(CYCLE/2)
   clk = ~clk;
end

initial begin
   rst_n = 1;
   #3
   rst_n = 0;
   #(10*CYCLE)
   rst_n = 1;
end

initial begin
   uart_rx = 1'b1;
   @(posedge rst_n);
   #(8*CYCLE);
   uart_tx(8'h20);
   @(posedge uart_rx_ctrl_led.rx_done);
   uart_tx(8'h21);
   @(posedge uart_rx_ctrl_led.rx_done);
   uart_tx(8'hE8);
   @(posedge uart_rx_ctrl_led.rx_done);
   uart_tx(8'h03);
   @(posedge uart_rx_ctrl_led.rx_done);
   uart_tx(8'h00);
   @(posedge uart_rx_ctrl_led.rx_done);
   uart_tx(8'h00);
   @(posedge uart_rx_ctrl_led.rx_done);
   uart_tx(8'h00);
   @(posedge uart_rx_ctrl_led.rx_done);
   uart_tx(8'hCE);
   @(posedge uart_rx_ctrl_led.rx_done);
   #2000000;
   $stop;
end

task uart_tx;
   input [7:0] data_in;
   begin
      uart_rx = 1'b0;
      #(5208*CYCLE);
      uart_rx = data_in[0];
      #(5208*CYCLE);
      uart_rx = data_in[1];
      #(5208*CYCLE);
      uart_rx = data_in[2];
      #(5208*CYCLE);
      uart_rx = data_in[3];
      #(5208*CYCLE);
      uart_rx = data_in[4];
      #(5208*CYCLE);
      uart_rx = data_in[5];
      #(5208*CYCLE);
      uart_rx = data_in[6];
      #(5208*CYCLE);
      uart_rx = data_in[7];
      #(5208*CYCLE);
      uart_rx = 1'b1;
   end
endtask

endmodule

七、小結

計數器問題
第一個代碼:加一條件為1,結束條件是由變量控制的,當變量tim輸入為0的時候就變成了,0-1 = FFFF FFFF FFFF FFFF
因此要改動為第二個代碼

always @(posedge clk or negedge rst_n)begin
   if(!rst_n)
      cnt <= 0;
   else if(add_cnt)begin
      if(end_cnt)
         cnt <= 0;
      else
         cnt <= cnt + 1'b1;
   end
end
assign add_cnt = 1;
assign end_cnt = add_cnt && cnt == tim - 1;
always @(posedge clk or negedge rst_n)begin
   if(!rst_n)
      cnt <= 0;
   else if(add_cnt)begin
      if(end_cnt)
         cnt <= 0;
      else
         cnt <= cnt + 1'b1;
   end
end
assign add_cnt = (tim >= 1);
assign end_cnt = add_cnt && cnt == tim - 1;


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM