1. 程式人生 > >verilog語言RS232串列埠接收模組設計——串列埠除錯工具傳送資料在數碼管顯示

verilog語言RS232串列埠接收模組設計——串列埠除錯工具傳送資料在數碼管顯示

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")
與我前一篇部落格中的ps2介面類似的是,資料都是通過一條匯流排傳輸,傳輸有效資料之前會先發送一個"0“,然後是一個或多個位元組的有效資料(低位在前,高位在後), 接著傳送的是校驗位,與ps2介面不同的是該校驗位可以是奇校驗也可以是偶校驗也可以無校驗位。最後傳送的值是高電平。 不同之處是,ps2介面有傳送時鐘,裝置傳送的資料在下降沿有效,而串列埠是沒有傳送時鐘的。不過我們可以通過提取資料下降沿的方式構造出有效取樣時鐘。 資料的傳輸速度是用波特來描述的,亦即每秒鐘傳輸的資料位,例如1000波特表示每秒鐘傳輸1000位元的資料, 或者說每個資料位持續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,數碼管顯示輸出正確