【Day18】Uart_TX 的实现

既上一篇我们设计了 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 的实作了唷~


<<:  成员 21 人:

>>:  [番外] 来个音乐拨放器 Play! (续)

DAY9-OH CRUD.

前言: 上一篇的最後我们提到今天要来补完Update和Delete,可是阿森不想让所有人都可以控制...

2.1 Design System - 制作的工具

「有些事现在不做,一辈子都不会做了」~练习曲 求学时,体育老师让我们看这部电影并身体力行的带我们骑...

【从实作学习ASP.NET Core】Day05 | Model 模型

今天我们要让程序加上 Model 来串接资料库,让 Controller 向 Model 取得商品...

Day 0x11 UVa100 The 3n + 1 problem

Virtual Judge ZeroJudge 题意 输入两整数,根据演算法输出最大的 cycle...

Day36 - 「登愣登愣,登愣登登登」~ 隐挑战 Day12 ─ 果然我的青春写扣喜剧搞错了。完

重复是学习之母。继续写是完赛之母。 继续写是完赛之母XDDDDDDDDDDD 这会不会太符合我现况...