15、TLC549AD转换时序详解(源代码注释)
了解一个芯片的功能应该看它的参数,应用一个芯片你就得认真的去读懂它的时序图。
改进了上次的实验,加入了256的8位的缓存,并求平均。
由图1、图2可知道 :
1、f(ioclk)max=1.1MHz。
2、t(su)min=1.4us。
3、t(wh)min=17us。
4、CS为低电平的时候读取数据;高电平的时候AD转换。
5、数据的读取需要8个ioclk,在ioclk上升沿的时候读取数据位。
6、数据必须在CS置零1.4us后才能读取。

图1: TLC549的信号时序图

图2: TLC549相关参数
在本次实验中参数如下选取
1、f(ioclk)=1MHz。
2、t(su)=1.5us。
3、t(wh)=17us。
因为FPGA的主时钟是50Mhz (t(sys)=0.02us)
所以t(ioclk)=50*t(sys);
t(su)=1.5us=75*t(sys);
t(wh)=17us=850*t(sys);
那么一次AD转换读取需要的时间为:
t(su)+8*t(ioclk)+t(wh)=(75+8*50+850)*t(sys)=1325*t(sys)
module TLC549ADC
(
input rst,
input clk,
input adc_data,
output reg cs,
output reg ioclk,
output reg [7:0] led_out,
output reg [3:0] V_H,
output reg [3:0] V_L,
output reg [3:0] Va_100,
output reg [3:0] Va_10,
output reg [3:0] Va_1
);
integer k;
reg signed [7:0] data_r [255:0]; //256个8位的数据缓存
//clk计数器
reg [11:0] clk_cnt;
wire cs_n_read;
wire cs_high;
wire conover;
//时钟计数器
always @(posedge clk or negedge rst) begin
if(!rst)
clk_cnt <= 11'd0;
else if(clk_cnt >=11'd1325)
clk_cnt <= 11'b0;
else
clk_cnt <= clk_cnt + 1'b1;
end
// t(su)+8*t(ioclk)+t(wh)=(75+8*50+850)*t(sys)=1325*t(sys)
assign cs_n_read = (clk_cnt > 11'd74)&&(clk_cnt <= 11'd475); //400个t(sys)
assign cs_high = (clk_cnt > 11'd475)&&(clk_cnt <= 11'd1325);//850个t(sys)
assign conover = (clk_cnt == 11'd425) ? 1'b1 : 1'b0; //数据读取完后conover有一个上升沿
//CS的时序;在AD转换的过程中CS为高电平,在数据读取的过程中CS为低电平。
always @(posedge clk or negedge rst) begin
if(!rst)
cs <= 1'b1;
else if(cs_high)
cs <= 1'b1;
else
cs <= 1'b0;
end
//50分频;提供IOClk信号
reg [5:0] div_cnt;
always @(posedge clk or negedge rst) begin
if(!rst) begin
div_cnt <= 6'd0;
ioclk <= 1'b0;
end
else if(cs_n_read) begin //从第75t(sys)到第475t(sys),这400个时钟里才有IOCLK信号,
//才能读取数据,这样保证在0到第74t(sys)CS是低电平的。
div_cnt <= div_cnt + 1'b1;
if(div_cnt < 6'd25)
ioclk <= 1'b1;
else if((div_cnt >= 6'd25)&&(div_cnt < 6'd50))
ioclk <= 1'b0;
else
div_cnt <= 6'b0;
end
end
//读取数据
reg[7:0] radc_data;
always @(posedge clk or negedge rst) begin
if(!rst)
radc_data <= 8'b0;
else
begin
case(clk_cnt) //没50个t(sys)读取一个数据位
11'd75: radc_data[7] <= adc_data;
11'd125: radc_data[6] <= adc_data;
11'd175: radc_data[5] <= adc_data;
11'd225: radc_data[4] <= adc_data;
11'd275: radc_data[3] <= adc_data;
11'd325: radc_data[2] <= adc_data;
11'd375: radc_data[1] <= adc_data;
11'd425: radc_data[0] <= adc_data;
default: radc_data[0] <= 1'b0;
endcase
end
end
//数据处理,conover
reg [7:0] data_cnt;
reg [15:0] Sum;
always @(posedge conover or negedge rst) begin
if(!rst)
begin
for(k=0;k<=255;k=k+1)
data_r [k] = 8'b0;
led_out <= 8'hx;
end
else
begin
data_r[data_cnt] <= radc_data;
data_cnt <= data_cnt + 1'b1; //单个数据放入缓存
if(data_cnt == 8'd255)
begin //写满256个缓存数据
for(k=0;k<=255;k=k+1)
Sum = Sum + data_r[k];
Sum = Sum/255; //求平均
V_H = Sum[7:4];
V_L = Sum[3:0];
Sum = Sum*245/255; //换算成电压值
led_out <= ~Sum[7:0];
Va_100 <= Sum[7:0]/100;
Va_10 <= Sum[7:0]/10%10;
Va_1 <= Sum[7:0]%10;
end
end
end
endmodule
改进后效果明显比上次好一些

sof、pof下载:
时钟为Y1:——回复可见内容——
时钟为Y2:——回复可见内容——