iT邦幫忙

2021 iThome 鐵人賽

DAY 18
1

既上一篇我們設計了 Uart_TX 的狀態機,我們今天要來引用狀態機模塊來實現這個 Uart_TX 的模塊。

先來看看這個模塊該有哪些輸入輸出腳:

輸入:

  • clk_50M
  • reset_n
  • write(外部給此模組的驅動信號(enable))
  • write_value(外部輸入給此模組要傳輸的 8 bit 資料)

輸出:

  • uart_txd(data 線)
  • busy(讓外部知道資料傳輸未結束,還不能繼續傳下一筆)
module usage_Uart_TX(
  clk_50M, 
  reset_n, 
  write, 
  write_value, 
  uart_txd, 
  busy
);
/*--------ports declarations--------*/
input       clk_50M;
input       write;
input       reset_n;
input [7:0] write_value;
output      uart_txd;
output      busy;
wire        uart_txd;
wire        busy;

宣告變數:
需要用到的變數有:

  • counter(計數 8 bit 用)
  • cnt_9600(計數用,要做 tick_uart)
  • regdata(load 進來的資料先暫存在這裡)
  • 與狀態機模組連接的變數
/*---------variables---------*/
reg  [7:0] regdata;
reg  [2:0] counter;
reg [12:0] cnt_9600;
reg        tick_uart;
wire       TX_D;
wire       LDEN;
wire       SHEN;
wire       rstcount;
wire       countEN;

引用狀態機模組

/*---------Uart_TX instantiation---------*/
Uart_TX U0(
  .clk_50M(clk_50M),
  .rst_n(reset_n),
  .count(counter),
  .rstcount(rstcount),
  .countEN(countEN),
  .tick_uart(tick_uart),
  .TX_D(TX_D),
  .LDEN(LDEN),
  .SHEN(SHEN),
  .en(write),
  .busy(busy)
);

cnt_9600 & tick_uart:
因為我是以鮑率 9600 為主,所以需除出 9600 HZ,首先,輸入頻率為 50MHZ,50M/9600 = 5208.333,取 5208,因此我們要每計數到 5207(因為0 ~ 5207 就會數 5208 次)就產生一個 clk 的 tick

/*---------9600HZ counter---------*/
always@(posedge clk_50M or negedge reset_n)begin
  if(!reset_n)cnt_9600 <= 13'd0;
  else begin
    if(cnt_9600<13'd5207)begin
      cnt_9600  <= cnt_9600 + 13'd1;
      tick_uart <= 1'b0;
    end 
    else begin
      cnt_9600 <= 13'd0;
      tick_uart <= 1'b1;
    end 
  end
end

靠 rstcount&countEN 來控制 counter

/*---------counter---------*/
always@(posedge clk_50M or negedge reset_n)begin
  if(!reset_n)counter <= 3'd0;
  else begin
    if(tick_uart==1'b1)begin
      if(rstcount)    counter <= 3'd0;
      else if(countEN)counter <= counter + 3'd1;
      else            counter <= counter;
    end
    else counter <= counter;
  end
end

if(tick_uart==1'b1) 是因為一個 count 要待滿一個鮑率的時間週期。

靠 LDEN&SHEN 來控制我們的 regdata

/*---------write_value---------*/
always@(posedge clk_50M or negedge reset_n)begin
  if(!reset_n)regdata <= 8'd0;
  else begin
    if(tick_uart==1'b1)begin
      if(LDEN)     regdata <= write_value;
      else if(SHEN)regdata <= regdata>>1;
      else         regdata <= regdata;
    end
    else regdata <= regdata;
  end
end

endmodule

regdata>>1 這邊右移是因 uart 是 LSB 先傳。

最後的最後

要在非 SHIFT 狀態時 tick_uart 切到狀態機的 TX_D,而在 SHIFT 狀態時切回 regdata 的 LSB。

/*---------assign wire---------*/
assign uart_txd = (SHEN)?(regdata[0]):(TX_D);

來看看 quartus 的 State Machine Viewer 有沒有符合自己的預期

大家可以試著自己寫看看 testbench 來測試結果正不正確~~

那麼到這邊我們就完成了 Uart_TX 的實作了唷~


上一篇
【Day17】Uart_TX 狀態機的實現
下一篇
【Day19】SPI 狀態機的實現
系列文
verilog or very lag30
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言