1.簡介
????????ADM3485E 是一款 3.3V 低功耗數據收發器,具有 ±15kV 的 ESD(靜電放電) 保護,專為多點總線傳輸線上的半雙工通信設計。它支持平衡數據傳輸,符合 TIA/EIA 標準 RS-485 和 RS-422 的要求。作為一款半雙工收發器,ADM3485E 采用共享差分線路設計,提供獨立的驅動器和接收器啟用輸入,確保高效的數據傳輸與接收控制。這款收發器在高噪聲環境下具有出色的抗干擾性能,非常適合工業自動化、通信設備及其他需要可靠數據傳輸的應用場景。其框架如下所示:

? ? ? ?根據這個架構,可以推測出 ADM3485E 的工作原理。其由接收器(R)和發射器(D)兩部分組成,A 和 B 是差分信號。在接收信號時,差分信號(A、B)首先進入差分放大器,放大器通過比較 A 和 B 的電壓差,判斷信號是高電平還是低電平。在此過程中,RE_n 是接收端差分放大器的使能信號,用于控制接收功能的啟用與禁用。發射器部分的工作原理類似,數據輸入到差分驅動器后,驅動器根據控制信號生成差分信號 A 和 B,從而實現信號的發送。在此過程中,DE是發送端差分放大器的使能信號,用于控制發送功能的啟用與禁用。常見器件連接方式如下:
? ? ? ? 這里說明一下,FPGA的普通IO引腳可以直接用于UART通信的TX、RX信號。但是RS-485的不行,需要轉換電平,也就是使用類似ADM3485E 這樣的轉換芯片,原因如下:FPGA通常采用單端TTL信號,而RS-485通過差分電壓差值傳遞邏輯信號,因此必須進行信號轉換。可能有人會考慮使用FPGA的LVDS(低電壓差分信號),但實際上并不適用。雖然LVDS和RS-485都屬于差分信號,但它們的電氣特性存在顯著差異:
? ? ? ? (1)電壓差范圍不同:LVDS的典型電壓差為350-1200mV,而RS-485要求200mV-2V。雖然范圍有部分重疊,但LVDS的電壓差偏小,無法完全滿足RS-485標準。
? ? ? ? (2)應用場景差異:LVDS專為短距離高速傳輸設計,具有低電壓差和低功耗特性;而RS-485則針對遠距離通信優化,較大的電壓差使其具備更強的抗干擾能力和更長的傳輸距離。
????????在長距離傳輸時,LVDS較小的電壓差容易導致信號衰減,影響通信可靠性。因此,兩種標準具有不同的應用場景,不能直接替代使用。
2.引腳說明
? ? ? ? ADM3485引腳如圖2所示。

下面是引腳說明:
IO | 類型 | 功能 |
RO | 輸出-數字引腳 | 接收器輸出端,根據差分信號A,B來輸入高低電平 |
RE_n | 輸出-數字引腳 | 接收器輸出使能,低電平有效 |
DE | 輸出-數字引腳 | 發送器輸出使能,高電平有效 |
DI | 輸入-數字引腳 | 發送器的數據輸入端 |
GND | 模擬引腳 | 地 |
A | 模擬引腳 | 差分傳輸線+(正向) |
B | 模擬引腳 | 差分傳輸線-(反向) |
VCC | 模擬引腳 | 供電電源 |
????????在電路設計中,通常會將RE_n,DE這兩個使能信號短接作為一個引腳RT,低電平代表接收使能,高電平是發送使能,如圖3所示。這樣既可以實現控制通信的功能,也可以減少IO引腳的使用。

3.RS485協議
? ? ? 由于RS485協議的時序較為常見,因此ADM3485E器件手冊中并未專門列出時序圖。起初,我以為RS485會有獨特的時序,但在查閱相關資料后,我發現RS485的時序與UART協議的時序實際上是相同的。這是因為UART協議本身并不定義具體的電氣特性,它僅規定了數據傳輸的時序格式(如起始位、數據位、校驗位和停止位)。換句話說,UART負責將并行數據轉換為串行數據,而信號的實際傳輸則是由外部驅動電路來實現。
電信號的傳輸過程遵循不同的電平標準和接口規范。對于異步串行通信,常見的接口標準包括RS232、RS422和RS485等,它們定義了各自的電氣特性。例如,RS232是單端信號傳輸,而RS422/485則采用差分信號傳輸。
總結來說,UART是一種協議標準,主要負責數據的串并轉換;而RS485則是一種物理接口標準,專注于信號的傳輸方式和電氣特性。雖然RS485和UART的時序相同,但它們分別代表了不同層次的協議:UART作為數據格式的定義,RS485作為接口規范。
UART 在發送或接收過程中的一幀數據由 4 部分組成,起始位、數據位、奇偶校驗位和停止位,如圖4所示。

? ? ? ? 各組成成分的詳細信息如下表所示。
字段 | 描述 | 大小 | 備注 |
起始位 (Start Bit) | 用于標識數據幀的開始。 | 1位 | 一般為邏輯低電平 (0),表示數據的開始。因為空閑時是高電平,所以有低電平時可以識別出來。 |
數據位 (Data Bits) | 傳輸的有效數據。 | 5-9位(常見為8位) | 數據位數量可配置,常用的是8位數據。 |
校驗位 (Parity Bit) | 用于錯誤檢測,可以選擇偶校驗、奇校驗或無校驗。 | 1位(可選) | 校驗位幫助檢測數據傳輸中的錯誤。 |
停止位 (Stop Bit) | 標識數據幀的結束。 | 1位、1.5位或2位 | 停止位可選,常見的是1位或2位。 |
空閑位 (Idle Bit) | 在沒有數據傳輸時,線路處于的狀態。 | 無 | 當UART線路空閑時,它處于邏輯高電平 (1)。 |
4.verilog代碼
? ? ? ? 根據ADM3485E工作的原理可知,要想實現對ADM3485E的通信控制,主要是實現UART協議幀的發送和接收。 通過根據UART協議幀的結構,并配合接收和發送使能信號,即可實現對ADM3485E的通信控制。需要發送的時候開啟發送使能,不發送的時候關閉發送使能。所以先實現uart發送和接收,再在外層加個控制邏輯就可以了。
uart_tx的verilog代碼:
/* * file : uart_tx.v* author : yuluo_lhw* date : 2025-09-01* version : v1.0* description : uart tx :8bit data 無校驗位 1位停止位*/
module uart_tx(
input wire clk, //采樣時鐘
input wire rst_n,
input wire [7:0] data,
input wire tx_en, //上升沿有效output reg tx,
output reg tx_done);
parameter CLK_FREQ = 100_000_000; //時鐘頻率
parameter BAUDRATE = 115200 ;
localparam BAUD_CNT = CLK_FREQ/BAUDRATE; //為得到指定波特率,對系統時鐘計數 BPS_CNT 次,也就是BPS_CNT個CLK發送一個bit. 868.0wire tx_en_pos ;
reg tx_en_do ;
reg tx_en_d1 ;
reg [9:0] baud_cnt ;
reg [3:0] bit_cnt ;
reg tx_busy ; //1:進入發送bit階段 0:空閑
//tx_en
assign tx_en_pos = ~tx_en_d1& tx_en_do ;
always@(posedge clk or negedge rst_n)beginif(~rst_n)begintx_en_do <= 0 ;tx_en_d1 <= 0 ;endelse begintx_en_do <= tx_en ;tx_en_d1 <= tx_en_do ;end
end//tx_busy
always@(posedge clk or negedge rst_n)beginif(~rst_n)begintx_busy <= 0 ;endelse beginif(tx_en_pos) begin tx_busy <= 1 ;endelse if(bit_cnt>=9 && (baud_cnt>=BAUD_CNT-1) ) tx_busy <= 0 ; //發送玩停止位結束else tx_busy <= tx_busy ;end
end//baud_cnt
always@(posedge clk or negedge rst_n)beginif(~rst_n)beginbaud_cnt <= 0 ;endelse beginif(tx_busy) begin if(baud_cnt>=BAUD_CNT-1) baud_cnt <= 0 ;else baud_cnt <= baud_cnt + 1 ;endelse baud_cnt <= 0 ;end
end//bit_cnt
always@(posedge clk or negedge rst_n)beginif(~rst_n)beginbit_cnt <= 0 ;endelse beginif(tx_busy) begin if(baud_cnt==BAUD_CNT-1) bit_cnt <= bit_cnt + 1 ;else bit_cnt <= bit_cnt ;endelse bit_cnt <= 0 ;end
end//tx
always@(posedge clk or negedge rst_n)beginif(~rst_n)begintx <= 1 ;endelse beginif(tx_busy) begin case(bit_cnt)4'd0: tx <= 0 ; //停止位4'd1: tx <= data[0] ; //小端傳送4'd2: tx <= data[1] ; 4'd3: tx <= data[2] ; 4'd4: tx <= data[3] ; 4'd5: tx <= data[4] ; 4'd6: tx <= data[5] ; 4'd7: tx <= data[6] ; 4'd8: tx <= data[7] ; 4'd9: tx <= 1 ; //停止位default : tx <= 1 ;endcaseend else tx <= 1 ;end
end
//tx_done
always@(posedge clk or negedge rst_n)beginif(~rst_n)begintx_done <= 1 ;endelse beginif(tx_busy) begin tx_done <= 0 ;endelse tx_done <= 1 ;end
end
endmodule
仿真代碼:
`timescale 1ns / 1psmodule tb_uart_tx;reg clk;
reg rst_n;
reg [7:0] data;
reg tx_en;wire tx;
wire tx_done;uart_tx #(
.CLK_FREQ (100_000_000),
.BAUDRATE (115200 )
) u_uart_tx(.clk(clk),.rst_n(rst_n),.data(data),.tx_en(tx_en),.tx(tx),.tx_done(tx_done)
);always #5 clk = ~clk ;initial beginclk = 0 ;rst_n = 0;tx_en = 0;//data1data = 8'b01010101; #20 rst_n = 1; #10 tx_en = 1;#10 tx_en = 0;@(posedge tx_done); //等待上升沿//wait(tx_done == 1);//data2#10 data = 8'b11000011; #10 tx_en = 1;#10 tx_en = 0;@(posedge tx_done); //等待上升沿#50;$finish;
end// Monitor signals
initial begin$monitor("At time %t, tx = %b, tx_done = %b, data = %b", $time, tx, tx_done, data);
endendmodule
????????從以下兩圖數據可以看出,每個比特的傳輸需要 868 個時鐘周期。因此,在 100MHz 時鐘頻率下,每秒可傳輸的數據量為 100,000,000/868 ≈ 115,200 比特,該結果與預期相符。
? ? ? ? 如下圖所示,數據幀的發送格式符合預期:起始位為0,隨后是8位數據位(采用小端傳輸,先發送低位),接著是1位停止位1,最后恢復為空閑狀態。
? ? ? ? 接收端的代碼也按照UART協議幀來寫就可以了,只要檢測到rx的下降沿就開始接收數據,不過rx最好進行打拍,避免出現亞穩態。這里就不粘貼了。
5.參考資料
????????ADI-ADM3485E.pdf
? ???以上就是本次學習的記錄。歡迎加我為好友(QQ:235840795),一起交流與學習!