03_シリアルポートRS232
1. 理論的研究
1.1 シリアルポート用語の概要
1.1.1 非同期通信
UART と SPI および IIC の違いは、非同期通信インターフェイスであることです。非同期通信では、受信側はデータがいつ
到着するかわからないため、双方が独自のクロックを持っている必要があります。データ送信プロセス中にクロックは必要ありません。送信側の送信時間間隔は不均一であり、受信側はデータのスタート ビットとストップ ビットを利用して情報の同期を実現します。
1.1.2 同期通信
SPI と IIC は同期通信インターフェイスです (詳細は後の章で説明します)。
同期通信では、双方が同じ周波数のクロックを使用します。データ送信中に、クロックもデータと一緒に送信されます。送信側と受信側で使用されるクロックはホストによって提供されます。
1.1.3 全二重
全二重、つまりデータを同時に送信および受信できます。
1.1.4 半二重
データ送信とデータ受信はどちらか一方のみを同時に実行できます。
1.1.5 UART通信
UART通信には信号線が2本しかなく、1つはtxという送信データポート線、もう1つはrxという受信データポート線です。PCの場合、そのtxをFPGAのrxに接続する必要があります。同様に、PCのrxもFPGAのtxに接続する必要があります。txが2つまたはrxが2つ接続されている場合、データは正常に送受信できませんので、rxとtxは本体に対する相対的なものであることを覚えておいてください。UART は全二重を実現できます。つまり、データの送信と受信を同時に行うことができます。
1.2 RS-232信号線
RS-232 信号線ポート規格は、コンピュータ、ルータ、モデム (MODEN、通称
「キャット」) 間の通信によく使用され、この通信システムでは、機器はデータ端末装置 DTE (コンピュータ、ルータ) とデータ通信装置 DCE (モデム) に分けられます。この通信モデルを使用して、信号線の接続と各信号線の役割を説明します。古いデスクトップ コンピュータには通常、RS-232 標準 COM ポート (DB9 インターフェイスとも呼ばれます) があり、
DB9 インターフェイスの信号線は
「ストレート」シリアル ポート接続を示します。
1.3 RS232 通信プロトコルの概要
1) RS232 は UART の一種で、クロック ラインはなく、データ ラインは 2 本 (rx と tx) のみで、どちらも 1 ビット幅です。ここで、rx はデータを受信するための回線、tx はデータを送信するための回線です。
2) rx ビット幅は 1 ビットで、PC がシリアル ポート デバッグ アシスタントを通じて 8 ビット データを FPGA に送信すると、FPGA はシリアル ポート rx を通じて最下位ビットから最上位ビットまでビットごとに受信し、最終的にビットは FPGA 内で 8 ビット データに結合されます。(受信したデータは最終的に 8 ビット データ、1 ビット データ
に結合されます) 3) tx ビット幅は 1 ビットで、FPGA がシリアル ポートを介して 8 ビット データを PC に送信する場合、FPGA は 8 ビット データを 1 つずつ tx ラインを介して PC に送信し、最下位ビットから最上位ビットに順番に送信します。 RS232 プロトコルに従ってシリアル ポート アシスタントを介して。
4) シリアル ポート データの送受信はフレーム構造に基づいており、フレームごとにデータを送受信します。中央に 8 ビットの有効なデータが含まれることに加えて、各フレームには、各フレームの先頭に 0 に固定されたスタート ビットがなければならず、各フレームの終わりには 1 に固定されたストップ ビットもなければなりません。つまり、最も基本的なフレーム構造 (パリティなどを除く) は 10 ビットです。データの送受信がない場合、rx と tx はアイドル状態になります。このとき、rx ラインと tx ラインは
ハイ レベルに維持されます。データ フレームの送信がある場合は、最初にスタート ビット、次に 8 ビットのデータ ビット、次に 1 ビットのストップ ビットがあります。その後、rx と tx は引き続きアイドル状態になり、次のデータ送信を待ちます。図に示すのは、基本的な RS232 フレーム構造です。
5) ボーレート: 情報伝送チャネルでは、データ情報を運ぶ信号単位をシンボルと呼びます (シリアルポートの送信は 1 ビットであるため、シンボルは 2 進数を表します)。1 秒あたりに信号を通じて送信されるシンボルの数はシンボルの伝送速度と呼ばれ、ボーレートと呼ばれ、一般的に使用される記号「ボー」、その単位は「ボー/秒 (Bps)」です。シリアル ポートの一般的なボー レートは 4800、9600、115200 などです。シリアル ポートの章を説明するために 9600 のボー レートを選択します。
6) ビットレート: 1 秒あたりに通信チャネルによって送信される情報の量はビット送信レートと呼ばれ、ビットレートと呼ばれ、その単位は「ビット/秒 (bps)」です。ビット レートはボー レートから計算できます。式は次のとおりです。ビット レート = ボー レート * 単一の変調状態に対応する 2 進数。ボーレートが 9600 の場合、シリアル ポートのビット レートは 9600Bps 1 ビット = 9600bps となります。
7) ボーレートとビットレートの違い
ビットレートとボーレートの関係を議論するには、デコード要素とビットの関係を理解する必要があります。先ほどの例で挙げたバス、地下鉄、タクシーが乗車人数に応じて異なるのと同様に、異なるコード要素を異なる桁のビットで表すこともできます。シンボルに必要なビット数は、シンボルがサポートする状態の数によって決まります。
8) 計算: ボーレートが 9600 の場合、シリアル ポートが 1 ビット データを送受信するのにかかる時間は 1 ボー、つまり 1/9600 秒です。50MHz (周期 20ns) のシステム クロックを使用してカウントすると、カウント数は cnt = (1s * 10^9)ns / 9600bit)ns / 20ns ≈ 5208 システム クロック サイクルとなります。つまり、データの各ビット間の間隔は、50MHz のクロック周波数で 5208 回ダウンカウントする必要があります。
9) ホスト コンピュータがシリアル ポート経由で 8 ビット データを送信する場合、8 ビット有効データを送信する前にボー タイムのスタート ビットが自動的に送信され、8 ビット有効データを送信した後はストップ ビットが自動的に送信されます。同様に、シリアル ポート アシスタントは、ホスト コンピュータから送信されたデータを受信する前に、ボー タイムのスタート ビットを検出してデータの受信を開始する必要があり、8 ビット データを受信した後、ボー タイムのストップ ビットを受信します。
2. 準安定状態
2.1 最初のビートを取る
1) なぜ最初のビートを取るのかというと、受信 rx 信号とクロック信号が同期しておらず、rx 信号がクロック信号と同期している必要があるためです。
2) PC のボーレートと rx 信号は同期しており、rx 信号と FPGA のシステム クロック sys_clk は非同期であるため、この時点で行う必要があるのは、低速クロック ドメイン (PC のボー レート) システムの rx 信号を高速クロック ドメイン (FPGA の sys_clk) システムに同期させることです。
2.2 連続ビート
1) メタステーブル状態とは何ですか?
なぜなら、シリアルポートでデータを送信するときに、オシロスコープを使用して方形パルスの立ち上がりエッジまたは立ち下がりエッジを増幅すると、その立ち上がりエッジと立ち下がりエッジが瞬時にプルアップまたはプルダウンされるのではなく、オペアンプの「スルーレート」と呼ばれる傾き変化プロセスがあることがわかります。このとき、FPGA の第 1 レベル レジスタの出力端子は、クロック エッジが到着してから長期間不定な状態にあり、シリアル ポート入力の決定された rx 値に等しくなるのではなく、0 と 1 の間で発振状態になります。
2) 準安定状態はどのようにして生成されるのでしょうか?
セットアップ時間Tus、ホールド時間Th、RSセットアップ時間、セーブ時間は条件を満たしておらず、レジスタ遅延Tco、判定時間Tmetは条件を満たしておらず、信号入力レジスタはセットアップ時間、ホールド時間を保証するものではありません。
3) 準安定状態を解決するにはどうすればよいですか?
マルチレベルレジスタを使用して、システムに対する準安定性の害を軽減します。基本的には2拍子になります
。
3. 実験の目的
シリアル ポート RS232 に基づいてデータ受信および送信モジュールを設計および実現し、受信および送信モジュールを使用してシリアル ポート データ ループバック実験を完了します。
4. ハードウェアリソース
MAX3232はRS232トランシーバチップです。RS-232レベル規格の信号はコントローラが直接認識できないため、「レベル変換チップ」を介してコントローラが認識できる「TTL」レベルの信号に変換して通信を実現します。
5. モジュール設計
5.1 最上位モジュールのブロック図
5.2 シリアルポートデータ受信モジュール
なぜパラレルデータに付随してバリッドフラグ信号を出力する必要があるかというと、パラレルデータを使用する場合、後段のモジュールやシステムではその時点でサンプリングされたデータが安定して有効であるかどうかが分からない可能性があり、データバリッドフラグ信号の到着はその時点でデータが安定して有効であることを示す指標となるためです。データ有効フラグ信号が High の場合、パラレル データは後続のモジュールまたはシステムで使用できます。
87654321 を送信 —> 87654321
5.3 シリアルデータ送信モジュール
6. 波形図
6.1 シリアルデータ受信モジュール
start_nedge: 立ち下がりエッジ、スタート フラグ信号、場合によっては rex_reg 信号にも 0、1 ジャンプがあり、データ ビットの立ち下がり遅延が発生します。この状況を回避するには、イネーブル信号 work_en を設定すると、work_en 信号は、この時点で表示される start_nedge フラグ信号が必要なシリアル ポート フレームの最初の立ち下がりエッジではないと判断できるため、フィルターで除外できます。
baud_cnt:
データ フレーム内の 10 ビットと 10 ビット データ bit_flag を区別してデータを抽出し、最も安定した状態を見つけます。
8 ビットデータ (有効データ 1 ~ 8) を抽出します。
有効信号が終了した後、work_en が Low になり、カウンタも 0 にクリアされ、
その後データの結合操作が実行され、最後にデータが出力され、信号 po_flag が High になります。
6.2 シリアルデータ送信モジュール
7.RTL
7.1 uart_rx
`timescale 1ns/1ns
module uart_rx
#(
parameter UART_BPS = 'd9600, //串口波特率
parameter CLK_FREQ = 'd50_000_000 //时钟频率
)
(
input wire sys_clk , //系统时钟50MHz
input wire sys_rst_n , //全局复位
input wire rx , //串口接收数据
output reg [7:0] po_data , //串转并后的8bit数据
output reg po_flag //串转并后的数据有效标志信号
);
//********************************************************************//
//****************** Parameter and Internal Signal *******************//
//********************************************************************//
//localparam define
localparam BAUD_CNT_MAX = CLK_FREQ/UART_BPS ;
//reg define
reg rx_reg1 ;
reg rx_reg2 ;
reg rx_reg3 ;
reg start_nedge ;
reg work_en ;
reg [12:0] baud_cnt ;
reg bit_flag ;
reg [3:0] bit_cnt ;
reg [7:0] rx_data ;
reg rx_flag ;
//********************************************************************//
//***************************** Main Code ****************************//
//********************************************************************//
//插入两级寄存器进行数据同步,用来消除亚稳态
//rx_reg1:第一级寄存器,寄存器空闲状态复位为1
always@(posedge sys_clk or negedge sys_rst_n)
if(sys_rst_n == 1'b0)
rx_reg1 <= 1'b1;
else
rx_reg1 <= rx;
//rx_reg2:第二级寄存器,寄存器空闲状态复位为1
always@(posedge sys_clk or negedge sys_rst_n)
if(sys_rst_n == 1'b0)
rx_reg2 <= 1'b1;
else
rx_reg2 <= rx_reg1;
//rx_reg3:第三级寄存器和第二级寄存器共同构成下降沿检测
always@(posedge sys_clk or negedge sys_rst_n)
if(sys_rst_n == 1'b0)
rx_reg3 <= 1'b1;
else
rx_reg3 <= rx_reg2;
//start_nedge:检测到下降沿时start_nedge产生一个时钟的高电平
always@(posedge sys_clk or negedge sys_rst_n)
if(sys_rst_n == 1'b0)
start_nedge <= 1'b0;
else if((~rx_reg2) && (rx_reg3))
start_nedge <= 1'b1;
else
start_nedge <= 1'b0;
//work_en:接收数据工作使能信号
always@(posedge sys_clk or negedge sys_rst_n)
if(sys_rst_n == 1'b0)
work_en <= 1'b0;
else if(start_nedge == 1'b1)
work_en <= 1'b1;
else if((bit_cnt == 4'd8) && (bit_flag == 1'b1))
work_en <= 1'b0;
//baud_cnt:波特率计数器计数,从0计数到BAUD_CNT_MAX - 1
always@(posedge sys_clk or negedge sys_rst_n)
if(sys_rst_n == 1'b0)
baud_cnt <= 13'b0;
else if((baud_cnt == BAUD_CNT_MAX - 1) || (work_en == 1'b0))
baud_cnt <= 13'b0;
else if(work_en == 1'b1)
baud_cnt <= baud_cnt + 1'b1;
//bit_flag:当baud_cnt计数器计数到中间数时采样的数据最稳定,
//此时拉高一个标志信号表示数据可以被取走
always@(posedge sys_clk or negedge sys_rst_n)
if(sys_rst_n == 1'b0)
bit_flag <= 1'b0;
else if(baud_cnt == BAUD_CNT_MAX/2 - 1)
bit_flag <= 1'b1;
else
bit_flag <= 1'b0;
//bit_cnt:有效数据个数计数器,当8个有效数据(不含起始位和停止位)
//都接收完成后计数器清零
always@(posedge sys_clk or negedge sys_rst_n)
if(sys_rst_n == 1'b0)
bit_cnt <= 4'b0;
else if((bit_cnt == 4'd8) && (bit_flag == 1'b1))
bit_cnt <= 4'b0;
else if(bit_flag ==1'b1)
bit_cnt <= bit_cnt + 1'b1;
//rx_data:输入数据进行移位
always@(posedge sys_clk or negedge sys_rst_n)
if(sys_rst_n == 1'b0)
rx_data <= 8'b0;
else if((bit_cnt >= 4'd1)&&(bit_cnt <= 4'd8)&&(bit_flag == 1'b1))
rx_data <= {
rx_reg3, rx_data[7:1]};
//rx_flag:输入数据移位完成时rx_flag拉高一个时钟的高电平
always@(posedge sys_clk or negedge sys_rst_n)
if(sys_rst_n == 1'b0)
rx_flag <= 1'b0;
else if((bit_cnt == 4'd8) && (bit_flag == 1'b1))
rx_flag <= 1'b1;
else
rx_flag <= 1'b0;
//po_data:输出完整的8位有效数据
always@(posedge sys_clk or negedge sys_rst_n)
if(sys_rst_n == 1'b0)
po_data <= 8'b0;
else if(rx_flag == 1'b1)
po_data <= rx_data;
//po_flag:输出数据有效标志(比rx_flag延后一个时钟周期,为了和po_data同步)
always@(posedge sys_clk or negedge sys_rst_n)
if(sys_rst_n == 1'b0)
po_flag <= 1'b0;
else
po_flag <= rx_flag;
endmodule
7.2 uart_tx
`timescale 1ns/1ns
module uart_tx
#(
parameter UART_BPS = 'd9600, //串口波特率
parameter CLK_FREQ = 'd50_000_000 //时钟频率
)
(
input wire sys_clk , //系统时钟50MHz
input wire sys_rst_n , //全局复位
input wire [7:0] pi_data , //模块输入的8bit数据
input wire pi_flag , //并行数据有效标志信号
output reg tx //串转并后的1bit数据
);
//********************************************************************//
//****************** Parameter and Internal Signal *******************//
//********************************************************************//
//localparam define
localparam BAUD_CNT_MAX = CLK_FREQ/UART_BPS ;
//reg define
reg [12:0] baud_cnt;
reg bit_flag;
reg [3:0] bit_cnt ;
reg work_en ;
//********************************************************************//
//***************************** Main Code ****************************//
//********************************************************************//
//work_en:接收数据工作使能信号
always@(posedge sys_clk or negedge sys_rst_n)
if(sys_rst_n == 1'b0)
work_en <= 1'b0;
else if(pi_flag == 1'b1)
work_en <= 1'b1;
else if((bit_flag == 1'b1) && (bit_cnt == 4'd9))
work_en <= 1'b0;
//baud_cnt:波特率计数器计数,从0计数到BAUD_CNT_MAX - 1
always@(posedge sys_clk or negedge sys_rst_n)
if(sys_rst_n == 1'b0)
baud_cnt <= 13'b0;
else if((baud_cnt == BAUD_CNT_MAX - 1) || (work_en == 1'b0))
baud_cnt <= 13'b0;
else if(work_en == 1'b1)
baud_cnt <= baud_cnt + 1'b1;
//bit_flag:当baud_cnt计数器计数到1时让bit_flag拉高一个时钟的高电平
always@(posedge sys_clk or negedge sys_rst_n)
if(sys_rst_n == 1'b0)
bit_flag <= 1'b0;
else if(baud_cnt == 13'd1)
bit_flag <= 1'b1;
else
bit_flag <= 1'b0;
//bit_cnt:数据位数个数计数,10个有效数据(含起始位和停止位)到来后计数器清零
always@(posedge sys_clk or negedge sys_rst_n)
if(sys_rst_n == 1'b0)
bit_cnt <= 4'b0;
else if((bit_flag == 1'b1) && (bit_cnt == 4'd9))
bit_cnt <= 4'b0;
else if((bit_flag == 1'b1) && (work_en == 1'b1))
bit_cnt <= bit_cnt + 1'b1;
//tx:输出数据在满足rs232协议(起始位为0,停止位为1)的情况下一位一位输出
always@(posedge sys_clk or negedge sys_rst_n)
if(sys_rst_n == 1'b0)
tx <= 1'b1; //空闲状态时为高电平
else if(bit_flag == 1'b1)
case(bit_cnt)
0 : tx <= 1'b0;
1 : tx <= pi_data[0];
2 : tx <= pi_data[1];
3 : tx <= pi_data[2];
4 : tx <= pi_data[3];
5 : tx <= pi_data[4];
6 : tx <= pi_data[5];
7 : tx <= pi_data[6];
8 : tx <= pi_data[7];
9 : tx <= 1'b1;
default : tx <= 1'b1;
endcase
endmodule
7.3 RS232
`timescale 1ns/1ns
module rs232
(
input wire sys_clk , //系统时钟50MHz
input wire sys_rst_n , //全局复位
input wire rx , //串口接收数据
output wire tx //串口发送数据
);
//********************************************************************//
//****************** Parameter and Internal Signal *******************//
//********************************************************************//
//parameter define
parameter UART_BPS = 14'd9600 , //比特率
CLK_FREQ = 26'd50_000_000 ; //时钟频率
//wire define
wire [7:0] po_data;
wire po_flag;
//********************************************************************//
//*************************** Instantiation **************************//
//********************************************************************//
//------------------------ uart_rx_inst ------------------------
uart_rx
#(
.UART_BPS (UART_BPS ), //串口波特率
.CLK_FREQ (CLK_FREQ ) //时钟频率
)
uart_rx_inst
(
.sys_clk (sys_clk ), //input sys_clk
.sys_rst_n (sys_rst_n ), //input sys_rst_n
.rx (rx ), //input rx
.po_data (po_data ), //output [7:0] po_data
.po_flag (po_flag ) //output po_flag
);
//------------------------ uart_tx_inst ------------------------
uart_tx
#(
.UART_BPS (UART_BPS ), //串口波特率
.CLK_FREQ (CLK_FREQ ) //时钟频率
)
uart_tx_inst
(
.sys_clk (sys_clk ), //input sys_clk
.sys_rst_n (sys_rst_n ), //input sys_rst_n
.pi_data (po_data ), //input [7:0] pi_data
.pi_flag (po_flag ), //input pi_flag
.tx (tx ) //output tx
);
endmodule
8. テストベンチ
8.1 tb_uart_rx
`timescale 1ns/1ns
module tb_uart_rx();
//********************************************************************//
//****************** Parameter and Internal Signal *******************//
//********************************************************************//
//reg define
reg sys_clk;
reg sys_rst_n;
reg rx;
//wire define
wire [7:0] po_data;
wire po_flag;
//********************************************************************//
//***************************** Main Code ****************************//
//********************************************************************//
//初始化系统时钟、全局复位和输入信号
initial begin
sys_clk = 1'b1;
sys_rst_n <= 1'b0;
rx <= 1'b1;
#20;
sys_rst_n <= 1'b1;
end
//模拟发送8次数据,分别为0~7
initial begin
#200
rx_bit(8'd0); //任务的调用,任务名+括号中要传递进任务的参数
rx_bit(8'd1);
rx_bit(8'd2);
rx_bit(8'd3);
rx_bit(8'd4);
rx_bit(8'd5);
rx_bit(8'd6);
rx_bit(8'd7);
end
//sys_clk:每10ns电平翻转一次,产生一个50MHz的时钟信号
always #10 sys_clk = ~sys_clk;
//定义一个名为rx_bit的任务,每次发送的数据有10位
//data的值分别为0~7由j的值传递进来
//任务以task开头,后面紧跟着的是任务名,调用时使用
task rx_bit(
//传递到任务中的参数,调用任务的时候从外部传进来一个8位的值
input [7:0] data
);
integer i; //定义一个常量
//用for循环产生一帧数据,for括号中最后执行的内容只能写i=i+1
//不可以写成C语言i=i++的形式
for(i=0; i<10; i=i+1) begin
case(i)
0: rx <= 1'b0;
1: rx <= data[0];
2: rx <= data[1];
3: rx <= data[2];
4: rx <= data[3];
5: rx <= data[4];
6: rx <= data[5];
7: rx <= data[6];
8: rx <= data[7];
9: rx <= 1'b1;
endcase
#(5208*20); //每发送1位数据延时5208个时钟周期
end
endtask //任务以endtask结束
//********************************************************************//
//*************************** Instantiation **************************//
//********************************************************************//
//------------------------uart_rx_inst------------------------
uart_rx uart_rx_inst(
.sys_clk (sys_clk ), //input sys_clk
.sys_rst_n (sys_rst_n ), //input sys_rst_n
.rx (rx ), //input rx
.po_data (po_data ), //output [7:0] po_data
.po_flag (po_flag ) //output po_flag
);
endmodule
8.2 tb_uart_tx
`timescale 1ns/1ns
/
module tb_uart_tx();
//********************************************************************//
//****************** Parameter and Internal Signal *******************//
//********************************************************************//
//reg define
reg sys_clk;
reg sys_rst_n;
reg [7:0] pi_data;
reg pi_flag;
//wire define
wire tx;
//********************************************************************//
//***************************** Main Code ****************************//
//********************************************************************//
//初始化系统时钟、全局复位
initial begin
sys_clk = 1'b1;
sys_rst_n <= 1'b0;
#20;
sys_rst_n <= 1'b1;
end
//模拟发送7次数据,分别为0~7
initial begin
pi_data <= 8'b0;
pi_flag <= 1'b0;
#200
//发送数据0
pi_data <= 8'd0;
pi_flag <= 1'b1;
#20
pi_flag <= 1'b0;
//每发送1bit数据需要5208个时钟周期,一帧数据为10bit
//所以需要数据延时(5208*20*10)后再产生下一个数据
#(5208*20*10);
//发送数据1
pi_data <= 8'd1;
pi_flag <= 1'b1;
#20
pi_flag <= 1'b0;
#(5208*20*10);
//发送数据2
pi_data <= 8'd2;
pi_flag <= 1'b1;
#20
pi_flag <= 1'b0;
#(5208*20*10);
//发送数据3
pi_data <= 8'd3;
pi_flag <= 1'b1;
#20
pi_flag <= 1'b0;
#(5208*20*10);
//发送数据4
pi_data <= 8'd4;
pi_flag <= 1'b1;
#20
pi_flag <= 1'b0;
#(5208*20*10);
//发送数据5
pi_data <= 8'd5;
pi_flag <= 1'b1;
#20
pi_flag <= 1'b0;
#(5208*20*10);
//发送数据6
pi_data <= 8'd6;
pi_flag <= 1'b1;
#20
pi_flag <= 1'b0;
#(5208*20*10);
//发送数据7
pi_data <= 8'd7;
pi_flag <= 1'b1;
#20
pi_flag <= 1'b0;
end
//sys_clk:每10ns电平翻转一次,产生一个50MHz的时钟信号
always #10 sys_clk = ~sys_clk;
//********************************************************************//
//*************************** Instantiation **************************//
//********************************************************************//
//------------------------uart_rx_inst------------------------
uart_tx uart_tx_inst(
.sys_clk (sys_clk ), //input sys_clk
.sys_rst_n (sys_rst_n ), //input sys_rst_n
.pi_data (pi_data ), //output [7:0] pi_data
.pi_flag (pi_flag ), //output pi_flag
.tx (tx ) //input tx
);
endmodule
8.3 tb_rs232
`timescale 1ns/1ns
module tb_rs232();
//********************************************************************//
//****************** Parameter and Internal Signal *******************//
//********************************************************************//
//wire define
wire tx ;
//reg define
reg sys_clk ;
reg sys_rst_n ;
reg rx ;
//********************************************************************//
//***************************** Main Code ****************************//
//********************************************************************//
//初始化系统时钟、全局复位和输入信号
initial begin
sys_clk = 1'b1;
sys_rst_n <= 1'b0;
rx <= 1'b1;
#20;
sys_rst_n <= 1'b1;
end
//调用任务rx_byte
initial begin
#200
rx_byte();
end
//sys_clk:每10ns电平翻转一次,产生一个50MHz的时钟信号
always #10 sys_clk = ~sys_clk;
//创建任务rx_byte,本次任务调用rx_bit任务,发送8次数据,分别为0~7
task rx_byte(); //因为不需要外部传递参数,所以括号中没有输入
integer j;
for(j=0; j<8; j=j+1) //调用8次rx_bit任务,每次发送的值从0变化7
rx_bit(j);
endtask
//创建任务rx_bit,每次发送的数据有10位,data的值分别为0到7由j的值传递进来
task rx_bit(
input [7:0] data
);
integer i;
for(i=0; i<10; i=i+1) begin
case(i)
0: rx <= 1'b0;
1: rx <= data[0];
2: rx <= data[1];
3: rx <= data[2];
4: rx <= data[3];
5: rx <= data[4];
6: rx <= data[5];
7: rx <= data[6];
8: rx <= data[7];
9: rx <= 1'b1;
endcase
#(5208*20); //每发送1位数据延时5208个时钟周期
end
endtask
//********************************************************************//
//*************************** Instantiation **************************//
//********************************************************************//
//------------------------ rs232_inst ------------------------
rs232 rs232_inst
(
.sys_clk (sys_clk ), //input sys_clk
.sys_rst_n (sys_rst_n ), //input sys_rst_n
.rx (rx ), //input rx
.tx (tx ) //output tx
);
endmodule