1.TLC549簡(jiǎn)介
TLC549是美國(guó)德州儀器公司生產(chǎn)的8位串行A/D轉(zhuǎn)換器芯片娩缰,可與通用微處理器灸撰、控制器通過(guò)CLK、CS拼坎、DATAOUT三條口線(xiàn)進(jìn)行串行接口浮毯。具有4MHz片內(nèi)系統(tǒng)時(shí)鐘和軟、硬件控制電路泰鸡,轉(zhuǎn)換時(shí)間最長(zhǎng)17μs债蓝, TLC549為40000次/s∈⒘洌總失調(diào)誤差最大為±0.5LSB饰迹,典型功耗值為6mW。采用差分參考電壓高阻輸入余舶,抗干擾啊鸭,可按比例量程校準(zhǔn)轉(zhuǎn)換范圍,VREF-接地匿值,VREF+-VREF-≥1V赠制,可用于較小信號(hào)的采樣。
REF+:正基準(zhǔn)信號(hào)輸入端
ANALOG IN:模擬信號(hào)輸入端
REF-:負(fù)基準(zhǔn)電壓輸入端
GND:接地端
#CS:片選信號(hào)挟憔,低電平有效
DATA OUT:轉(zhuǎn)換結(jié)果串行輸出端
I/O CLOCK:外接時(shí)鐘輸入端
VCC:電源輸入端
其他信息可參照TLC549的datasheet钟些。
2.AD通信協(xié)議
TLC549均有片內(nèi)系統(tǒng)時(shí)鐘烟号,該時(shí)鐘與I/O CLOCK是獨(dú)立工作的,無(wú)須特殊的速度或相位匹配政恍。其工作時(shí)序如圖2所示汪拥。當(dāng)CS為高時(shí),數(shù)據(jù)輸出(DATA OUT)端處于高阻狀態(tài)抚垃,此時(shí)I/O CLOCK不起作用喷楣。
當(dāng)CS為低時(shí),AD前一次轉(zhuǎn)換的數(shù)據(jù)A的最高位A7立馬出現(xiàn)在數(shù)據(jù)線(xiàn)DATA OUT上鹤树,其余七位在I/O CLOCK的下降沿依次由時(shí)鐘同步輸出铣焊,,因此可在I/O CLOCK的上升沿讀取數(shù)據(jù),其中值得注意的是:1.圖中他tsu(cs)至少要1.4us罕伯;2.I/O CLOCK不能超過(guò)1.1MHz曲伊。
讀完8位數(shù)據(jù)后,AD開(kāi)始轉(zhuǎn)換這一次轉(zhuǎn)換的采樣數(shù)據(jù)B追他,以便下一次讀取轉(zhuǎn)換時(shí)坟募,片選信號(hào)CS置高,每次轉(zhuǎn)換不超過(guò)17us邑狸,開(kāi)始于CS拉低后的第八個(gè)I/O CLOCK的下降沿懈糯,沒(méi)有轉(zhuǎn)換完成標(biāo)志,沒(méi)有啟動(dòng)控制端单雾,只要讀取前一次數(shù)據(jù)后就馬上可以開(kāi)始新的AD轉(zhuǎn)換赚哗,轉(zhuǎn)換完成進(jìn)入保持狀態(tài)。
3.代碼
*File name:ad.v
*Author: ***
*Description:The AD module
***************************************************************/
`define AD_CLK_TIME 10'd45
`define AD_CLK_TIME_HALF 10'd22
module AD
(
input sys_clk_50m,
input rst_n,
output reg poc_ad_cs, //TLC549的片選
output reg poc_ad_clk, //TLC549的I/O CLOCK
input pid_ad_data, //TLC549的數(shù)據(jù)串行輸出端硅堆,相對(duì)于FPGA為輸入
output reg [3:0] o_vol_int, //轉(zhuǎn)換后輸出電壓的整數(shù)部分
output reg [3:0] o_vol_dec //轉(zhuǎn)換后輸出電壓的小數(shù)部分
);
reg n_ad_cs; //AD_CS的下一個(gè)狀態(tài)
reg n_ad_clk; //AD_CLK的下一個(gè)狀態(tài)
reg [ 2:0] ad_fsm_cs; //狀態(tài)機(jī)的當(dāng)前狀態(tài)
reg [ 2:0] ad_fsm_ns; //狀態(tài)機(jī)的下一個(gè)狀態(tài)
wire [ 3:0] n_o_vol_int; //o_vol_int的下一個(gè)狀態(tài)
wire [ 3:0] n_o_vol_dec; //o_vol_dec的下一個(gè)狀態(tài)
reg [ 5:0] time_cnt; //用于記錄一個(gè)時(shí)鐘所用時(shí)間的定時(shí)器
reg [ 5:0] n_time_cnt; //time_cnt的下一個(gè)狀態(tài)
reg [ 5:0] bit_cnt; //用來(lái)記錄時(shí)鐘周期個(gè)數(shù)的計(jì)數(shù)器
reg [ 5:0] n_bit_cnt; //bit_cnt的下一個(gè)狀態(tài)
reg [ 7:0] data_out; //用來(lái)保存穩(wěn)定的AD數(shù)據(jù)
reg [ 7:0] n_data_out; //data_out的下一個(gè)狀態(tài)
reg [ 7:0] ad_data_reg; //用于保存數(shù)據(jù)的移位寄存器
reg [ 7:0] n_ad_data_reg; //ad_data_reg_n的下一個(gè)狀態(tài)
wire [11:0] mid1; //數(shù)據(jù)轉(zhuǎn)換電壓的整數(shù)部分
wire [11:0] mid2; //數(shù)據(jù)轉(zhuǎn)換電壓的小數(shù)部分
parameter FSM_IDLE = 3'h0; //狀態(tài)機(jī)的初始狀態(tài)屿储;
parameter FSM_READY = 3'h1; //滿(mǎn)足CS有效時(shí)的第一個(gè)1.4us的延時(shí)狀態(tài)
parameter FSM_DATA = 3'h2; //讀取8個(gè)數(shù)據(jù)狀態(tài)
parameter FSM_WAIT_CONV = 3'h3; //等待轉(zhuǎn)換狀態(tài),等待17us;
parameter FSM_END = 3'h4; //結(jié)束的狀態(tài)
/********************************************
狀態(tài)機(jī)轉(zhuǎn)換
********************************************/
always @ (posedge sys_clk_50m or negedge rst_n)
if (!rst_n)
ad_fsm_cs <= FSM_IDLE;
else
ad_fsm_cs <= ad_fsm_ns;
always @ (*)
begin
case(ad_fsm_cs)
FSM_IDLE:
if((bit_cnt == 6'd2 ) && (time_cnt == `AD_CLK_TIME))
ad_fsm_ns = FSM_READY;
else
ad_fsm_ns = ad_fsm_cs;
FSM_READY:
if((bit_cnt == 6'd1 ) && (time_cnt == `AD_CLK_TIME))
ad_fsm_ns = FSM_DATA;
else
ad_fsm_ns = ad_fsm_cs;
FSM_DATA:
if((bit_cnt == 6'd8 ) && (time_cnt == `AD_CLK_TIME))
ad_fsm_ns = FSM_WAIT_CONV;
else
ad_fsm_ns = ad_fsm_cs;
FSM_WAIT_CONV:
if((bit_cnt == 6'd18) && (time_cnt == `AD_CLK_TIME))
ad_fsm_ns = FSM_END;
else
ad_fsm_ns = ad_fsm_cs;
FSM_END:
ad_fsm_ns = FSM_READY;
default:ad_fsm_ns = FSM_IDLE;
endcase
end
/*********************************************************
時(shí)鐘計(jì)數(shù)器,用以產(chǎn)生1.1M的時(shí)鐘
*********************************************************/
always @ (posedge sys_clk_50m or negedge rst_n)
if (!rst_n)
time_cnt <= 6'd0;
else
time_cnt <= n_time_cnt;
always @ (*)
if (time_cnt == `AD_CLK_TIME)
n_time_cnt = 6'd0;
else
n_time_cnt = time_cnt + 6'd1;
/*********************************************
位計(jì)數(shù)器
*********************************************/
always @ (posedge sys_clk_50m or negedge rst_n)
if (!rst_n)
bit_cnt <= 6'd0;
else
bit_cnt <= n_bit_cnt;
always @ (*)
begin
if (ad_fsm_cs != ad_fsm_ns)
n_bit_cnt = 6'h0;
else if ( time_cnt== `AD_CLK_TIME_HALF )
n_bit_cnt = bit_cnt + 6'h1;
else
n_bit_cnt = bit_cnt;
end
/*******************************************************
產(chǎn)生外接時(shí)鐘輸入端的時(shí)鐘信號(hào)渐逃,頻率為1.1M够掠,占空比約為50%
********************************************************/
always @ (posedge sys_clk_50m or negedge rst_n)
if (!rst_n)
poc_ad_clk <= 1'b0;
else
poc_ad_clk <= n_ad_clk;
always @(*)
begin
if (ad_fsm_cs != FSM_DATA)
n_ad_clk = 1'b0;
else if ( time_cnt == `AD_CLK_TIME_HALF )
n_ad_clk = 1'b1;
else if (time_cnt == `AD_CLK_TIME)
n_ad_clk = 1'b0;
else
n_ad_clk = poc_ad_clk;
end
/****************************************************
對(duì)TLC549的片選信號(hào)進(jìn)行控制
*****************************************************/
always @ (posedge sys_clk_50m or negedge rst_n)
if (!rst_n)
poc_ad_cs <= 1'b0;
else
poc_ad_cs <= n_ad_cs;
always @ (*)
if ((ad_fsm_cs == FSM_DATA) || (ad_fsm_cs == FSM_READY))
n_ad_cs = 1'b0;
else
n_ad_cs = 1'b1;
/******************************************************
對(duì)數(shù)據(jù)寄存器賦值
******************************************************/
always @ (posedge sys_clk_50m or negedge rst_n)
if (!rst_n)
ad_data_reg <= 8'd0;
else
ad_data_reg <= n_ad_data_reg;
always @ (*)
begin
if ((ad_fsm_cs == FSM_DATA) && (!poc_ad_clk) && (n_ad_clk))
n_ad_data_reg = {ad_data_reg[6:0],pid_ad_data};
else
n_ad_data_reg = ad_data_reg;
end
/*************************************************************
輸出數(shù)據(jù)處理
*************************************************************/
always @ (posedge sys_clk_50m or negedge rst_n)
if (!rst_n)
data_out <= 8'd0;
else
data_out <= n_data_out;
always @ (*)
begin
if (ad_fsm_cs == FSM_END)
n_data_out = ad_data_reg;
else
n_data_out = data_out;
end
always @ (posedge sys_clk_50m or negedge rst_n)
if (!rst_n)
o_vol_int <= 4'd0;
else
o_vol_int <= n_o_vol_int;
always @ (posedge sys_clk_50m or negedge rst_n)
if (!rst_n)
o_vol_dec <= 4'd0;
else
o_vol_dec <= n_o_vol_dec;
assign mid1 = {2'h0,data_out[7:0],2'h0} + {4'h0,data_out[7:0]};
assign mid2 = {1'h0,mid1[7:0],3'h0} + {3'h0,mid1[7:0],1'h0};
assign n_o_vol_int = mid1[11:8];
assign n_o_vol_dec = mid2[11:8];
endmodule
解釋一下代碼中在的數(shù)據(jù)轉(zhuǎn)換部分,這里我所用的基準(zhǔn)電壓為5V茄菊,TLC549轉(zhuǎn)換所得數(shù)據(jù)為8位疯潭,即0~255,那么電壓計(jì)算公式如下:
V = data*5/256
這里不使用取模和求余運(yùn)算面殖,因?yàn)榇蠹抑廊∧:颓笥噙\(yùn)算會(huì)生成一個(gè)龐大的電路袁勺,運(yùn)行速度慢,還浪費(fèi)資源畜普,F(xiàn)PGA所擅長(zhǎng)的移位運(yùn)算期丰,無(wú)疑是不錯(cuò)的選擇。
整數(shù)部分計(jì)算如下:
o_vol_int = (data*4+data)/255,轉(zhuǎn)換成移位運(yùn)算為((data<<2)+data)>>8
小數(shù)部分計(jì)算如下
o_vol_dec = ((5data&0xff)10)>>8