## 7-Seg Display Controlled by UART實驗報告
### B1095165 黃瑄凱 指導教授:林宏益
## 一、實驗目的
>使用者輸入0~9, A~F, 七段顯示器顯示該數字/文字。
>
>使用者輸入其他數字/文字,七段顯示器顯示E。
## 二、實驗原理
### 原理:
(參考文獻1中有更詳細的說明)
#### UART重點
起始位(Start Bit):在每個數據帧開始時,UART發送一個邏輯“0”的信號,表示傳輸字符開始。
數據位(Data Bits):緊隨在起始位後面,數據位的個數可以是4、5、6、7、8等,構成一個字符。
奇偶校驗位(Parity Bit):用於校驗數據傳輸的正確性,使得數據位中“1”的位數為偶數或奇數,以校驗數據的準確性。
停止位(Stop Bit):標識一個字符數據的結束,可以是1位、1.5位或2位的高電平。同時也提供計算機校正時鐘同步的機會。
#### 工作原理
發送數據過程:在空閒狀態下(線路處於高電平),發送端拉低線路一個數據位的時間,按照約定的波特率從低位到高位依次發送數據,發送完畢後,發送校驗位和停止位,一幀數據發送完成。
接收數據過程:在檢測到線路下降沿(高電平變為低電平)時,開始接收數據。從低位到高位接收數據,並進行校驗,確認正確性後通知接收設備或存入緩衝。
工作圖

[圖片來源](https://www.ebyte.com/new-view-info.aspx?id=1390)
## 三、實驗材料:
* Verilog HDL程式碼
* Testbench
* 電路示意圖
* VCS編譯器
## 四、實驗步驟:
1.編寫Verilog HDL程式碼,包括數字轉換和重置功能。
2.創建相應的Testbench來驗證設計的正確性。
3.使用VCS編譯器進行合成。
## 五、實驗結果:
* Verilog HDL程式碼-Top.module
```
`timescale 1ns / 1ps
module UART_Data_Processor(
input clk,
input rst,
input rx_pin_in,
output [7:0] seg7
);
wire rx_pin_H2L;
Edge_Detector rx_in_detect(
.clk( clk ),
.rst( rst ),
.pin_in( rx_pin_in ),
.sig_H2L( rx_pin_H2L )
);
wire rx_band_sig;
wire clk_bps;
Baud_Rate_Generator rx_baud_gen(
.clk( clk ),
.rst( rst ),
.band_sig( rx_band_sig ),
.clk_bps( clk_bps )
);
wire [7:0] rx_data;
UART_Control_Unit rx_control(
.clk( clk ),
.rst( rst ),
.rx_pin_in( rx_pin_in ),
.rx_pin_H2L( rx_pin_H2L ),
.rx_band_sig( rx_band_sig ),
.rx_clk_bps( clk_bps ),
.rx_data( rx_data ),
.rx_done_sig( rx_done_sig )
);
ASCII_to_7seg u_ASCII2seg7(
.rst( rx_done_sig ),
.ASCII( rx_data ),
.seg7_out(seg7)
);
endmodule
```
* Verilog HDL程式碼-H2L Signal detect
```
`timescale 1ns / 1ps
module Edge_Detector(
input clk,
input rst,
input pin_in,
output sig_H2L
);
reg pin_pre;
assign sig_H2L = !pin_in & pin_pre;
always @( posedge clk or posedge rst )
if( rst )
pin_pre <= 1'b0;
else
pin_pre <= pin_in;
endmodule
```
* Verilog HDL程式碼-generator
```
`timescale 1ns / 1ps
module Baud_Rate_Generator(
input clk,
input rst,
input band_sig,
output reg clk_bps
);
parameter SYS_RATE = 125000000;
parameter BAND_RATE = 9600; //此處使用9600
parameter CNT_BAND = SYS_RATE / BAND_RATE;
parameter HALF_CNT_BAND = CNT_BAND / 2;
reg [13:0] cnt_bps;
always @( posedge clk or posedge rst )
if( rst )
begin
cnt_bps <= HALF_CNT_BAND;
clk_bps <= 1'b0;
end
else if( !band_sig )
begin
cnt_bps <= HALF_CNT_BAND;
clk_bps <= 1'b0;
end
else if( cnt_bps == CNT_BAND )
begin
cnt_bps <= 14'd0;
clk_bps <= 1'b1;
end
else
begin
cnt_bps <= cnt_bps + 1'b1;
clk_bps <= 1'b0;
end
endmodule
```
* Verilog HDL程式碼-Control
```
`timescale 1ns / 1ps
module UART_Control_Unit (
input clk,
input rst,
input rx_pin_in,
input rx_pin_H2L,
output reg rx_band_sig,
input rx_clk_bps,
output reg [7:0] rx_data,
output reg rx_done_sig
);
localparam [3:0] IDLE = 4'd0, BEGIN = 4'd1, DATA0 = 4'd2,
DATA1 = 4'd3, DATA2 = 4'd4, DATA3 = 4'd5,
DATA4 = 4'd6, DATA5 = 4'd7, DATA6 = 4'd8,
DATA7 = 4'd9, END = 4'd10, BFREE = 4'd11;
reg [3:0] pos;
always @(posedge clk or posedge rst)
if (rst) begin
rx_band_sig <= 1'b0;
rx_data <= 8'd0;
pos <= IDLE;
rx_done_sig <= 1'b0;
end else begin
case (pos)
IDLE:
if (rx_pin_H2L) begin
rx_band_sig <= 1'b1;
pos <= pos + 1'b1;
rx_data <= 8'd0;
end
BEGIN:
if (rx_clk_bps) begin
if (rx_pin_in == 1'b0) begin
pos <= pos + 1'b1;
end else begin
rx_band_sig <= 1'b0;
pos <= IDLE;
end
end
DATA0, DATA1, DATA2, DATA3, DATA4, DATA5, DATA6, DATA7:
if (rx_clk_bps) begin
rx_data[pos - DATA0] <= rx_pin_in;
pos <= pos + 1'b1;
end
END:
if (rx_clk_bps) begin
rx_done_sig <= 1'b1;
pos <= pos + 1'b1;
rx_band_sig <= 1'b0;
end
BFREE:
begin
rx_done_sig <= 1'b0;
pos <= IDLE;
end
endcase
end
endmodule
```
* Verilog HDL程式碼-ASCII 7-seg signal
```
module ASCII_to_7seg (
input rst,
input [7:0] ASCII,
output reg [7:0] seg7_out
);
always @* begin
case (ASCII)
8'b0011_0000: seg7_out <= 8'b00000011;
8'b0011_0001: seg7_out <= 8'b10011111;
8'b0011_0010: seg7_out <= 8'b00100101;
8'b0011_0011: seg7_out <= 8'b00001101;
8'b0011_0100: seg7_out <= 8'b10011001;
8'b0011_0101: seg7_out <= 8'b01001001;
8'b0011_0110: seg7_out <= 8'b01000001;
8'b0011_0111: seg7_out <= 8'b00011111;
8'b0011_1000: seg7_out <= 8'b00000001;
8'b0011_1001: seg7_out <= 8'b00001001;
8'b0100_0001: seg7_out <= 8'b00010001;
8'b0100_0010: seg7_out <= 8'b11000001;
8'b0100_0011: seg7_out <= 8'b11100101;
8'b0100_0100: seg7_out <= 8'b10000101;
8'b0100_0101: seg7_out <= 8'b01100001;
8'b0100_0110: seg7_out <= 8'b01110001;
default: seg7_out <= 8'b01100001;
endcase
end
endmodule
```
* Verilog HDL程式碼-Testbench
```
`timescale 1ns / 1ps
module rx_top_tb();
reg clk;
reg rst;
reg uart_rx;
wire [7:0] seg7;
integer i;
reg [7:0] data_test = 8'h41;
UART_Data_Processor u_rx_top(
.clk(clk),
.rst(rst),
.rx_pin_in(uart_rx),
.seg7(seg7)
);
initial begin
$dumpfile("rx_top.vcd");
$dumpvars;
end
initial begin
clk = 0;
for (i = 0; i < 256; i = i + 1) begin
rst = 1;
#15 rst = 0;
uart_rx = 1;
// 起始位
#104167 uart_rx = 0;
// 數據
#104167 uart_rx = data_test[0];
#104167 uart_rx = data_test[1];
#104167 uart_rx = data_test[2];
#104167 uart_rx = data_test[3];
#104167 uart_rx = data_test[4];
#104167 uart_rx = data_test[5];
#104167 uart_rx = data_test[6];
#104167 uart_rx = data_test[7];
// 停止
#104167 uart_rx = 1;
#104167 uart_rx = 1;
#104167 uart_rx = 1;
#104167 uart_rx = 1;
#104167 uart_rx = 1;
#104167 uart_rx = 1;
#104167 uart_rx = 1;
data_test = data_test + 1;
end
#50 $finish;
end
always #4 clk = ~clk; //此處一定要用4,不能用10
endmodule
```
* Testbench模擬結果

* 電路圖

* Coverage
* Lint

* 實驗影片
[7-seg Display controlled bu UART](https://youtu.be/rr6zHzBjJdw)
## 六、實驗討論:
這次實驗中遇到最大的問題莫過於是wave圖沒有輸入訊號,後來和同學討論才知道Testbench中有著許多問題,uart. Baud rate我設定的值為9600,起初#的數值快到30000後來改成104167還是有許多問題。最後發現我設定125000000如果delay用10ns切一次會產生問題,後來改成4ns就把問題解決掉了。
## 七、實驗心得:
這次實驗相比前幾次十分的困難,我們需要撰寫的.v檔已經不是一個就能解決,要透過一個top包許多檔案才能完成我們的code,而這次我也遇到了許多bug,一開始simulation看到20幾個error,到最後能產生結果的成就感是相當巨大的。也非常慶幸網路上有許多資料能夠參考,才讓我得以順利完成這份作業。
## 八、參考文獻:
1.[徐晓康. (2022, December 1). Verilog功能模块——Uart收发. CSDN博客.](https://blog.csdn.net/weixin_42837669/article/details/127772676)
2.[YodaLee. (2021, September 5). Open FPGA 系列 - UART.](https://yodalee.me/2021/09/openfpga_uart/)
3.課堂講義
## 九、實驗成果:
[7-seg Display controlled bu UART](https://youtu.be/rr6zHzBjJdw)