verilog語言RS232串列埠接收模組設計——串列埠除錯工具傳送資料在數碼管顯示
阿新 • • 發佈:2019-01-06
RS-232是常用的傳輸介面,是硬體學習的入門級介面。
一、介面特性
DE-9 Male (Pin Side) DE-9 Female (Pin Side) ------------- ------------- \ 1 2 3 4 5 / \ 5 4 3 2 1 / \ 6 7 8 9 / \ 9 8 7 6 / --------- ---------
訊號 | DB-25 | DE-9 | EIA/TIA 561 | Yost |
---|---|---|---|---|
公共接地 | 7 | 5 | 4 | 4,5 |
傳送資料(TD、TXD) | 2 | 3 | 6 | 3 |
接受資料(RD、RXD) | 3 | 2 | 5 | 6 |
資料終端準備(DTR) | 20 | 4 | 3 | 2 |
資料準備好(DSR) | 6 | 6 | 1 | 7 |
請求傳送(RTS) | 4 | 7 | 8 | 1 |
清除傳送(CTS) | 5 | 8 | 7 | 8 |
資料載波檢測(DCD) | 8 | 1 | 2 | 7 |
振鈴指示(RI) | 22 | 9 | 1 | - |
RS-232設計之初是用來連線調變解調器做傳輸之用,也因此它的腳位意義通常也和調變解調器傳輸有關,而我們做硬體與PC介面通常只用到兩個管腳即可:TXD,RXD.
由於發送接收資料分別採用兩條序列匯流排進行傳輸,因此rs232介面是可以全雙工工作的,最大速率可達10KB/s.
根據美國電子工業學會(EIA)的標準。在TxD和RxD上:
邏輯1(MARK) =-3V~-15V 邏輯0(SPACE)=+3~+15V 這與TTL的邏輯電平不相匹配,我們常採用MAX232晶片完成TTL←→EIA雙向電平轉換 二、非同步通訊協議 S-232使用非同步通訊協議。也就是說資料的傳輸沒有時鐘訊號。接收端必須有某種方式,使之與接收資料同步。 對於RS-232來說,是這樣處理的:1、序列線纜的兩端事先約定好序列傳輸的引數(傳輸速度、傳輸格式等)
2、當沒有資料傳輸的時候,傳送端向資料線上傳送"1"
3、每傳輸一個位元組之前,傳送端先發送一個"0"來表示傳輸已經開始。這樣接收端便可以知道有資料到來了。
4、開始傳輸後,資料以約定的速度和格式傳輸,所以接收端可以與之同步
5、每次傳輸完成一個位元組之後,都在其後傳送一個停止位("1")
波特率不是隨意的,必須服從一定的標準,常用的序列傳輸速率值包括以下幾種:
1200 波特.
9600 波特.
38400 波特.
115200 波特 (通常情況下是你可以使用的最高速度) 三、接收模組設計 接收模組設計主要包括了有三個部分: 波特率產生部分:這一部分主要是收到串列埠傳輸有效訊號rs_ena後,每間隔一定時間(波特率時間間隔)就產生一個時鐘週期的(系統時鐘)高電平rs_clk, 使得高電平時刻落在可採用串列埠資料的中間時刻點,以供接收時提供取樣時刻。 資料接收部分:這一部分的主要功能是對接收序列訊號進行處理,提取到序列訊號的下降沿,在下降沿處啟動一個計數器。該計數器範圍為0-11,在計數器有效範圍 內令rs_ena為高電平傳給第一部分,然後利用第一部分輸出的rs_clk,在rs_clk有效位置將接收資料傳給快取區,首先接收的資料放在低儲存位,等計數器計滿後將buff 裡的值傳給輸出暫存器。同時rs_ena,計數器等清零。等待下一次傳輸的到來。
第一部分程式碼:
module rs_clk_gen(
clk,rst,rs_clk,rs_ena
);
input clk;//系統時鐘
input rst;//復位訊號
input rs_ena; //串列埠通訊允許訊號
output rs_clk; //輸出允許的波特率訊號時鐘
parameter N1=5207;//5208,9600bps 50M的系統時鐘;
parameter N2=2603;//2604,這裡是0-2603,共計數2604次
reg rs_clk='b0;
reg [13:0] count='d0;//計數器
always @(posedge clk or negedge rst)
begin
if(!rst)
begin
count<='d0; //復位訊號到來時,count計數器清零
end
else
if(count==N1 || !rs_ena) count<='d0;//當count計滿或者無串列埠通訊使能時count都不計數
else count<=count+'b1;//當且僅當count不為0,通訊使能時count計數。
end
always @(posedge clk or negedge rst)
begin
if (!rst)
rs_clk<='b0;
else
if(count==N2&&rs_ena)//當且僅當count計數到一半且通訊使能時允許時鐘翻轉
rs_clk<='b1; //
else
rs_clk<='b0;//使得rs_clk是一個小波峰的時鐘訊號,在有效訊號的資料位為高電平。
end
endmodule
第一部分的模擬結果:由於分頻係數太大,不容易觀察,這裡採用N1=3,N2=2來模擬。模擬之後要改回不然會出錯。
接收模組程式碼
module rs_receive(
input rx_data,//接收到的串列埠資料
input clk,
input rst,
output [7:0] byte_data_out,//接收完成的一位元組資料輸出
input rs_clk,//輸入的資料有效取樣時刻時鐘
output reg rs_ena='b0//有效資料到來標誌
);
//++++++++++++++++++++++++++++++++++++++++++++++
reg rx_data0='b0;
reg rx_data1='b0;
reg rx_data2='b0;//宣告暫存器用於提取有效資料的下降沿;
wire neg_rx_data=~rx_data1 & rx_data2;//下降沿時該訊號電平為高
always @(posedge clk or negedge rst)
begin
if(!rst)
begin
rx_data0<='b0;
rx_data1<='b0;
rx_data2<='b0;
end
else
begin
rx_data0<=rx_data;
rx_data1<=rx_data0;
rx_data2<=rx_data1;
end
end
//+++++++++++++++++++++++++++++++++++++++++++++
reg rx_int='b0;//接收中斷訊號
//reg rs_ena;
reg [3:0]num='d0;
always @(posedge clk or negedge rst)
begin
if(!rst)
begin
rx_int<='b0;
rs_ena<='bz;
end
else
if(neg_rx_data)
begin
rx_int<='b1;//下降沿到來時,產生接收中斷--此期間即使有下降沿到來也不理會,此時使能模組1,即rs_ena為高電平。
rs_ena<='b1;
end
else
if(num=='d10)
begin
rx_int<='b0;//num==10,即資料接收完成時,中斷結束。
rs_ena<='b0;
end
end
reg [7:0]rx_data_buf='d0;//接收訊號快取區,由於資料一位一位傳輸,不能立刻賦值輸出,用於快取資料,到接收完成再賦值給輸出
reg [7:0]data_byte_r='d0;//暫存器型,用於完成賦值,最後賦給輸出。
assign byte_data_out=data_byte_r;
always @(posedge clk or negedge rst)
begin
if(!rst)
num<='d0;
else
if(rx_int)
begin
if(rs_clk)//在接收中斷的情況下,到來一次取樣時鐘進行一次如下運算,
begin
num<=num+1'b1;
case(num)
'd1:rx_data_buf[0]<=rx_data;
'd2:rx_data_buf[1]<=rx_data;
'd3:rx_data_buf[2]<=rx_data;
'd4:rx_data_buf[3]<=rx_data;//資料依次加入到快取區
'd5:rx_data_buf[4]<=rx_data;
'd6:rx_data_buf[5]<=rx_data;
'd7:rx_data_buf[6]<=rx_data;
'd8:rx_data_buf[7]<=rx_data;
default:;
endcase
end
else
if(num=='d10)
begin//資料接收完成,將快取資料交給暫存器,同時計數器清零
num<='d0;
data_byte_r<=rx_data_buf;
end
end
end
endmodule
頂層模組程式碼:
`timescale 1ns / 1ps
//////////////////////////////////////////////////////////////////////////////////
// Company: bupt abs_lab
// Engineer: mr.bai
//
// Create Date: 18:44:58 03/03/2014
// Design Name: rs232_receive_module
// Module Name: rs232_top
// Project Name:
// Target Devices:
// Tool versions:
// Description:
//
// Dependencies:
//
// Revision:
// Revision 0.01 - File Created
// Additional Comments:
//
//////////////////////////////////////////////////////////////////////////////////
module rs232_top(
input clk,
input rst,
input rs232_rx,
output reg [7:0] sm_seg,
output reg [1:0]sm_bit='b01
);
wire rs_clk,rs_ena;
rs_clk_gen M1(
.clk(clk),.rst(rst),.rs_clk(rs_clk),.rs_ena(rs_ena)
);
wire [7:0] byte_data_out;
rs_receive M2(
.rx_data(rs232_rx),
.clk(clk),
.rst(rst),
.byte_data_out(byte_data_out),
.rs_clk(rs_clk),
.rs_ena(rs_ena)
);
//====================數碼管顯示接收資料部分===================================
parameter N2=50000;
reg clk3=1'b0;
reg [16:0]count3=17'd0;
//assign clk_out=clk3;
always @(posedge clk or negedge rst)
begin
if (!rst)
begin
count3<=17'd0;
clk3<=1'b0;
end
else
if(count3<N2-1)
begin
count3<=count3+1'b1;
if(count3<(N2/2-1))
clk3<=1'b0;
else
clk3<=1'b1;
end
else
begin
count3<=17'd0;
clk3<=1'b0;
end
end
//==================state select================
reg[3:0] Num;
always @(posedge clk3)
begin
case (sm_bit)
'b01: begin
Num<=byte_data_out[7:4];
sm_bit<='b10;
end
'b10: begin
Num<=byte_data_out[3:0];
sm_bit<='b01;
end
default:
Num<='d0;
endcase
end
//=========================================================
always @ (Num)//
begin
case (Num)
4'h0 : sm_seg = 8'h3f; // "0"
4'h1 : sm_seg = 8'h06; // "1"
4'h2 : sm_seg = 8'h5b; // "2"
4'h3 : sm_seg = 8'h4f; // "3"
4'h4 : sm_seg = 8'h66; // "4"
4'h5 : sm_seg = 8'h6d; // "5"//共陰極數碼管表
4'h6 : sm_seg = 8'h7d; // "6"
4'h7 : sm_seg = 8'h07; // "7"
4'h8 : sm_seg = 8'h7f; // "8"
4'h9 : sm_seg = 8'h6f; // "9"
4'ha : sm_seg = 8'h77; // "a"
4'hb : sm_seg = 8'h7c; // "b"
4'hc : sm_seg = 8'h39; // "c"
4'hd : sm_seg = 8'h5e; // "d"
4'he : sm_seg = 8'h79; // "e"
4'hf : sm_seg = 8'h71; // "f"
endcase
end
//==============================================
endmodule
綜合模擬之後效果:在pc端輸入 A, B, C, 1, 2, 3等資料,串列埠偵錯程式傳輸出的是該資料對應的16進位制ASCII碼值;
A對應的16進位制ascii碼為41H,數碼管顯示輸出正確