設計背景
模數轉換器,又稱(chēng)A/D轉換器,簡(jiǎn)稱(chēng)ADC,通常是指一個(gè)將模擬信號轉換為抗干擾性更強的數字信號的電子器件。一般的ADC是將一個(gè)輸入電壓信號轉換為一個(gè)輸出的數字信號。由于數字信號本身不具有實(shí)際意義,僅僅表示一個(gè)相對大小,故任何一個(gè)ADC都需要一個(gè)參考模擬量作為轉換標準。比較常見(jiàn)的參考標準為最大的可轉換信號大小,而輸出的數字量則表示輸入信號相對于參考信號的大小。本設計則通過(guò)對模數轉換芯片(TLC549)的采樣控制,實(shí)現一個(gè)簡(jiǎn)易的數字電壓表。
設計原理
TLC549典型的配置電路如下圖所示:
TLC549的端口描述如下:
TLC549是一個(gè)8位的串行模數轉換器,A/D轉換時(shí)間最大為17us,最大轉換速率為4MHz。下圖為T(mén)LC549的訪(fǎng)問(wèn)時(shí)序,從圖中可以看出,TLC549的使用只需對外接輸入輸出時(shí)鐘(I/O CLK)和芯片選擇(/CS)、輸入的模擬信號(ANALOG IN)的控制。
分析時(shí)序圖可知:當片選信號(/CS)拉低時(shí),ADC前一次的轉換數據(A)的最高位A7立即出現在數據線(xiàn)DATA OUT上,之后的數據在時(shí)鐘I/O CLOCK的下降沿改變,可在I/O CLOCK的上升沿讀取數據。轉換時(shí),/CS要置為高電平。在設計操作時(shí),要注意Tsu(CS)、Tconv、Twh(CS)和I/O CLOCK的頻率這幾個(gè)參數。Tsu(CS)為CS拉低到I/O CLOCK第一個(gè)時(shí)鐘到來(lái)的時(shí)間,至少要1.4us;Twh(CS)為ADC的轉換時(shí)鐘,不超過(guò)17us,Tconv的值也不超過(guò)17us;I/O CLOCK為 1.1MHz。其他參數可參考數據手冊。
由于A(yíng)DC是8位的,所以采樣的電壓值為:
V =(D*Vref)/256
其中V為采樣的電壓值;D為ADC轉換后讀取的8位二進(jìn)制數;Vref為參考電壓值,此處為2.5V。
設計架構
本設計通過(guò)調節電位器RW1改變ADC的模擬輸入值,數據采樣讀取后由數碼管顯示,最后用萬(wàn)用表測量輸入電壓,并與讀取在數碼管上的數據(單位為mV)作比較。設計的架構圖如下:?
設計架構圖對應端口的功能描述表:
tlc549_Driver模塊采用序列機實(shí)現接口訪(fǎng)問(wèn)時(shí)序,并且產(chǎn)生1MHz的ADC_Clk和采集到ADC_data;Control模塊,將采集到的ADC數據(ADC_data)換算成對應的電壓值,并經(jīng)過(guò)二進(jìn)制到BCD轉換以后傳送到數碼管;DIG_LED_DRIVE模塊負責數碼管的驅動(dòng),將傳遞過(guò)來(lái)的數據顯示出來(lái)。
設計代碼
AD_TLC549頂層模塊代碼:
module AD_TLC549(Clk,Rst_n,ADC_Din,ADC_Clk,ADC_Cs_n,Dig_Led_sel,Dig_Led_seg); input Clk; input Rst_n; input ADC_Din; output ADC_Clk; output ADC_Cs_n; output [2:0]Dig_Led_sel; output [7:0]Dig_Led_seg; wire Get_Flag; wire [7:0]ADC_data; wire [23:0]seg_data; tlc549_Driver tlc549_Driver( .Clk(Clk), .Rst_n(Rst_n), .En(1'b1), .ADC_Din(ADC_Din), .ADC_Clk(ADC_Clk), .ADC_Cs_n(ADC_Cs_n), .Data(ADC_data), .Get_Flag(Get_Flag) ); Control Control( .Clk(Clk), .Rst_n(Rst_n), .Get_Flag(Get_Flag), .ADC_data(ADC_data), .seg_data(seg_data) ); DIG_LED_DRIVE DIG_LED_DRIVE( .Clk(Clk), .Rst_n(Rst_n), .Data(seg_data), .Dig_Led_seg(Dig_Led_seg), .Dig_Led_sel(Dig_Led_sel) ); endmodule
tlc549_Driver模塊代碼:
module tlc549_Driver (Clk,Rst_n,En,ADC_Din,ADC_Clk,ADC_Cs_n,Data,Get_Flag); input Clk; //系統50MHz時(shí)鐘輸入 input Rst_n;//全局復位 input En; //ADC轉換使能,高電平有效 input ADC_Din;//ADC串行數據輸入 output reg ADC_Clk; //ADC時(shí)鐘信號輸出 output reg ADC_Cs_n;//ADC片選信號輸出 output reg Get_Flag;//數據轉換完成標志 output reg [7:0] Data;//ADC轉換以后的電壓值 reg [10:0] Cnt1; //系統時(shí)鐘計數器 reg [7:0] data_tmp;//數據寄存器 //系統時(shí)鐘上升沿計數 always@(posedge Clk or negedge Rst_n) begin if(!Rst_n) Cnt1 <= 11'd0; else if(!En) Cnt1 <= 11'd0; else if(Cnt1 == 11'd1310) Cnt1 <= 11'd0; else Cnt1 <= Cnt1 + 1'b1; end always@(posedge Clk or negedge Rst_n) begin if(!Rst_n) begin ADC_Clk <= 1'b0; ADC_Cs_n <= 1'b1; data_tmp <= 8'd0; Data <= 8'd0; end else if(En) begin case(Cnt1) 1 : ADC_Cs_n <= 1'b0; //1~71(Tsu) 71 : begin ADC_Clk <= 1; data_tmp[7] <= ADC_Din;end 96 : ADC_Clk <= 0; 121 : begin ADC_Clk <= 1; data_tmp[6] <= ADC_Din;end 146 : ADC_Clk <= 0; 171 : begin ADC_Clk <= 1; data_tmp[5] <= ADC_Din;end 196 : ADC_Clk <= 0; 221 : begin ADC_Clk <= 1; data_tmp[4] <= ADC_Din;end 246 : ADC_Clk <= 0; 271 : begin ADC_Clk <= 1; data_tmp[3] <= ADC_Din;end 296 : ADC_Clk <= 0; 321 : begin ADC_Clk <= 1; data_tmp[2] <= ADC_Din;end 346 : ADC_Clk <= 0; 371 : begin ADC_Clk <= 1; data_tmp[1] <= ADC_Din;end 396 : ADC_Clk <= 0; 421 : begin ADC_Clk <= 1; data_tmp[0] <= ADC_Din;end 446 : begin ADC_Clk <= 0; ADC_Cs_n <= 1'b1; Get_Flag<=1;end 447 : begin Data <= data_tmp; Get_Flag<=0; end //447~1310(Twh) 1310: ; default:; endcase end else begin ADC_Cs_n <= 1'b1; ADC_Clk <= 1'b0; end end endmodule? Control模塊代碼:
module Control(Clk,Rst_n,Get_Flag,ADC_data,seg_data); input Clk;//系統時(shí)鐘輸入 input Rst_n;//系統復位 input Get_Flag;//ADC采集數據完成標志 input [7:0]ADC_data;//ADC采集數據輸入 output reg [23:0]seg_data;//數碼管待顯示數據 reg [3:0]qianwei; //千位 reg [3:0]baiwei; //百位 reg [3:0]shiwei; //十位 reg [3:0]gewei; //個(gè)位 reg [15:0]tenvalue;//采樣的電壓值 //采集電壓值計算 always@(posedge Clk or negedge Rst_n) begin if(!Rst_n) tenvalue<=0; else if(Get_Flag)//新的數據采集完成,可以進(jìn)行計算 tenvalue<=(ADC_data*100*25)/256; end //二進(jìn)制轉BCD值 always@(posedge Clk or negedge Rst_n) begin if(!Rst_n) begin qianwei<=0; baiwei<=0; shiwei<=0; gewei<=0; end else begin qianwei<=tenvalue/1000; //2 baiwei<=(tenvalue/100)%10; //5 shiwei<=(tenvalue/10)%10; //0 gewei<=tenvalue%10; //0 end end //數碼管顯示數值 always@(posedge Clk or negedge Rst_n) begin if(!Rst_n) seg_data<=0; else seg_data<={ qianwei, //千位 baiwei, //百位 shiwei, //十位 gewei, //個(gè)位 8'hFF //空閑 }; end endmodule? DIG_LED_DRIVE模塊代碼:
/*數碼管掃描模塊,位選為外部74hc138譯碼器進(jìn)行控制*/ /*仿真時(shí)請將本文件設置為頂層,并在代碼中根據相應注釋中的內容選擇cnt1_MAX = 24*/ module DIG_LED_DRIVE(Clk,Rst_n,Data,Dig_Led_seg,Dig_Led_sel); input Clk; //系統時(shí)鐘輸入 input Rst_n; //系統復位 input [23:0]Data;//待顯示數據 output [7:0]Dig_Led_seg;//數碼管段選 output [2:0]Dig_Led_sel;//數碼管位選 parameter system_clk = 50_000_000; localparam cnt1_MAX = 24;/*仿真的時(shí)候使用,板級驗證時(shí)請注釋掉*/ //localparam cnt1_MAX = system_clk/1000/2-1;/*板級驗證的時(shí)候使用,仿真時(shí)請注釋掉*/ reg [14 :0] cnt1; //分頻計數器 reg clk_1K; //掃描時(shí)鐘,1KHz reg [2:0]sel_r; //數碼管位選 reg [7:0]seg_r; //數碼管段選 reg [3:0]disp_data; //單位顯示數據緩存 //1KHz時(shí)鐘分頻計數器 always@(posedge Clk) begin if(!Rst_n)cnt1<=0; else if(cnt1==cnt1_MAX)cnt1<=0; else cnt1<=cnt1+1'b1; end //得到1KHz時(shí)鐘 always@(posedge Clk or negedge Rst_n) begin if(!Rst_n) clk_1K<=0; else if(cnt1==cnt1_MAX) clk_1K<=~clk_1K; end //位選信號控制 always@(posedge clk_1K or negedge Rst_n) begin if(!Rst_n) sel_r<=3'd0; else if(sel_r == 3'd3) sel_r<=3'd0; else sel_r<=sel_r+1'b1; end //根據不同的數碼管位選擇不同的待顯示數據 always@(*) begin if(!Rst_n) disp_data=4'd0; else begin case(sel_r) 3'd0:disp_data=Data[23:20]; 3'd1:disp_data=Data[19:16]; 3'd2:disp_data=Data[15:12]; 3'd3:disp_data=Data[11:8]; 3'd4:disp_data=Data[7:4]; 3'd5:disp_data=Data[3:0]; default :disp_data=4'd0; endcase end end //數據譯碼,將待顯示數據翻譯為符合數碼管顯示的編碼 always@(*) begin if(!Rst_n) seg_r=8'hff; else begin case(disp_data) 4'd0: seg_r=8'hc0; 4'd1: seg_r=8'hf9; 4'd2: seg_r=8'ha4; 4'd3: seg_r=8'hb0; 4'd4: seg_r=8'h99; 4'd5: seg_r=8'h92; 4'd6: seg_r=8'h82; 4'd7: seg_r=8'hf8; 4'd8: seg_r=8'h80; 4'd9: seg_r=8'h90; 4'd10: seg_r=8'h88; 4'd11: seg_r=8'h83; 4'd12: seg_r=8'hc6; 4'd13: seg_r=8'ha1; 4'd14: seg_r=8'h86; 4'd15: seg_r=8'h8e; default : seg_r=8'hff; endcase end end assign Dig_Led_seg = seg_r; assign Dig_Led_sel = sel_r; endmodule? 仿真測試
AD_TLC549_tb頂層測試代碼如下:
?
`timescale 1ns/1ps module AD_TLC549_tb; reg Clk; reg Rst_n; reg ADC_Din; wire ADC_Clk; wire ADC_Cs_n; wire [2:0] Dig_Led_sel; wire [7:0] Dig_Led_seg; initial begin Clk = 1; Rst_n = 0; ADC_Din = 0; #200.1 Rst_n = 1; #1400 ADC_Din=1; //aa #1000 ADC_Din=0; #1000 ADC_Din=1; #1000 ADC_Din=0; #1000 ADC_Din=1; #1000 ADC_Din=0; #1000 ADC_Din=1; #1000 ADC_Din=0; #17000 #1400 ADC_Din=1; //98 #1000 ADC_Din=0; #1000 ADC_Din=0; #1000 ADC_Din=1; #1000 ADC_Din=1; #1000 ADC_Din=0; #1000 ADC_Din=0; #1000 ADC_Din=0; //#20000 $stop; end AD_TLC549 AD_TLC549_dut( .Clk(Clk), .Rst_n(Rst_n), .ADC_Din(ADC_Din), .ADC_Clk(ADC_Clk), .ADC_Cs_n(ADC_Cs_n), .Dig_Led_sel(Dig_Led_sel), .Dig_Led_seg(Dig_Led_seg) ); always #10 Clk = ~Clk; endmodule? 仿真圖如下所示:
審核編輯:黃飛
?
評論