2009082329阮丽华 - TLC5620实验报告(2013模版) - 图文

更新时间:2024-05-11 08:46:01 阅读量: 综合文库 文档下载

说明:文章内容仅供预览,部分内容可能不全。下载后的文档,内容与下面显示的完全一致。下载之前请确认下面内容是否您想要的,是否完整无缺。

实 验 报 告

实验名称:姓 名:学 号:指导教师:实验时间:

[TLC5620 串行D/A实验] [XXX] [201008 22XX] [解武] [2013年 X月XX日] 信息与通信工程学院

TLC5620串行D/A实验

1 实验要求

TLC5620是4通道8位的串行D/A转换器。

任务1: 观察已给程序的实验现象,并结合实验结果理解原程序语句的含义,体会基本句话,模块的用

法。在掌握整个程序工作的原理后,修改程序,使其实现单通道的DA转换:

在按下通道的按键之后,用数码管显示输入的数字量;停止按键,数码管计数停止,继续按键则继续计数。按下复位键,则系统清零,数码管显示0值。将转换后的模拟电压加到LED两端,观察LED亮度变化是否符合理论规律。

任务2: 在任务1的基础上,进一步体会程序的编写思想,将顶层图形文件修改成一个用语言描述的模

块,实现原程序所要求的各项功能:

通过4个按键选择不同通道,每个通道的数字量输入都可以在数码管上进行显示。松开按键,则计数显示保持前一状态,按下按键继续计数。设置复位键,按下复位键,系统清零。每个通道对应的模拟电压通过LED的亮度显示。通过硬件实现,观察实验结果。

2 实验原理

2.1 TLC5620基本原理

TLC5620封装如实验图1所示,是一个4通道8位的串行数模(D/A)转换器,其最大转换速度可达1MBps。其管脚REFA~REFD为四个通道的参考电压,实验平台的参考电压均为2.5V;DACA~DACD为4路四个模拟信号输出通道;DATA为串行数据输入;CLK为DAC串行数据输入时钟,其下降沿锁存输入数据DATA;LOAD为串行数据锁存信号,低电平锁存。LDAC为DAC输出更新控制信号,当LDAC为低电平时,则把锁存在锁存器的数据送到DAC并转换为模拟信号,在相应的通道进行输出,故可以始终把LDAC信号置为低电平,也就是说加载信号一旦产生,数据立刻转换输出。

表1为TLC5620各引脚功能介绍。

图1 XXXX封装示意图

表1 XXXX引脚功能

引脚 名称 GND DACA DACB DACC DACD DATA CLK LDAC LOAD REFA REFB REFC REFD VDD

序号 1 12 11 10 9 6 7 13 8 2 3 4 5 14

I O O O O I I I I I I I I I 输入/输出

地回路及参考终端 DAC A模拟信号输出 DAC B模拟信号输出 DAC C模拟信号输出 DAC D模拟信号输出

串行数字数据输入接口,在CLK下降沿时将输入的数字量转发到串行接口寄存器里 串行接口时钟,用于控制串行数据的输入

加载DAC。当引脚出现高电平时,即使有数字量被读入串行口也不会对DAC的输出进行更新。只有当引脚从高电平变为低电平时,DAC输出才更新。

串口加载控制。当LDAC是低电平,并且LOAD引脚出现下降沿时数字量被保存到锁存器,随后输出端产生模拟电压。

输入到DAC A的参考电压。这个电压定义了输出模拟量的范围。 输入到DAC B的参考电压。这个电压定义了输出模拟量的范围。 输入到DAC C的参考电压。这个电压定义了输出模拟量的范围。 输入到DAC D的参考电压。这个电压定义了输出模拟量的范围。 输入电源正极

功能描述

因为TLC5620为四通道的数模转换器,只有一个DATA数据输入端,所以传送的数据中要包含通道的信息,以便DAC能识别出该数据属于哪个通道,转换完成后的模拟信号输出到相应的通道中。TLC5620传输的一帧数据位11位,先传送高位,最后传送低位,帧格式如表2所示。

表2 XXXX的数据结构

D10 D9 D8 输出模式RNG D7 D6 D5 D4 D3 D2 D1 D0 通道选择 8位数据D7~D0 D10、D9为通道选择位,00~11分别选择DACA~DACD通道。RNG的数值为0或者1,为输出倍数。TLC5620的输出电压为:

Vo(DACA/B/C/D)?VREFA/B/C/D?CODE(1?RNG) 256DAC内部有移位寄存器和锁存器,要在工程中实现在LOAD高电平时把11位数据在CLK的下降沿逐位(由高位到低位)发送到DATA端,发送完毕后,LOAD置为低电平,指示DAC进行模数转换。

TLC5620的访问时序图如图2所示。

图2 XXXX访问时序图

2.2 TLC5620与FPGA连接电路图

VCC2.5VGNDREF_AREF_BREF_CREF_DDATACLKTLC5620VDDLDAC654321dac_ldac2350MHzDAC_ADAC_BDAC_CDAC_DLOADEP2C8Q208C8dac_data162dac_loaddac_clk164168170643Key[3..0]

图3 XXXX与FPGA连接示意图(注: 可以在文件“FPGA实验板电路图.pdf”中截取)

LOAD的低电平的最小保持时间tw(LOAD)为250ns,各个tsu和tv的最小保持时间为50ns。为了尽可能最大利用DAC的转换速度,为此状态机选用5000Hz(200ns)左右的输入时钟,在LOAD低电平时要等待 12个状态机时钟CLK0.5M。为此采用计数器判断等待时间是否满足条件,该计数器使用LOAD的高电平为异步复位信号,低电平时,对CLK0.5M进行计数,当计数器计数值大于12 时,说明LOAD为低电平的时间tw(LOAD)已满足,状态机可跳转到下一态。

在LOAD高电平时,需要产生11个DAC的CLK,同样采用计数器计数值判断,该计数器中,LOAD的低电平为异步复位信号,LOAD为高电平时对DA_CLK计数,满足计数器的值>11时,说明已经送入了11bit的串行数据,可以进行置LOAD为低电平,对11bit数据锁存进行数模转换。

2.3 任务原理

2.3.1任务原理1

将给定程序的4通道转换改成单通道的DA转换:修改程序,将四个通道的按键修改成一个按键,用一个5HZ的时钟信号进行采样,并将采样的数字信号传输给TLC5620,按照其时序要求,对5620初始化,使其将采样的按键的数字信号按照上述提供的公式转化为模拟信号,并输出给LED灯,并且随着

按键时间延长,数字输入的增大,转换为的模拟电压增大,LED灯的亮度增加。同时,将采样的数字信号通过数码管显示。从而完成整个功能。 2.3.1任务原理2

将给定的程序模块合在一个顶层模块中,不使用图形文件作为顶层:使用verilog VHDL建立顶层文件,在顶层文件中设置连线型变量,调用事先写好的模块,用线型变量将两个模块需要连接的管脚连接在一起,从而形成一个完整功能的大模块。

2.4 实验流程图

Start初始化TLC5620访问时序判断按键N复位NKEYnY清零保持原有数据保持原有数据Yn通道采集数字量D/A转换数码管显示 3 FPGA所用的管脚分配

选用FPGA为Altera公司的CycloneII系列EP2C8Q208C8。主时钟50MHz。管脚分配如下。

4 实验结果

1、按不同的通道,数码管显示数字输入量,数字变化的频率和程序模块中分频的频率一致;停止按键,则数字不发生变化,继续按相同通道的按键,则数码管继续计数;若按下复位键,则数码管显示清零。………

2、当数字输入显示超过1500时,可以观察到转化成模拟量的电压足以使LED灯发光,并且输入数字量越大,转化成的模拟电压越高,观察到的LED发光越亮。………

3、当将程序修改成为只有一个通道的,同样可以实现显示,数字量转化为模拟量的变化。同样,将程序改为一个总程序时,也可以实现相应功能。……….

4、附实验结果照片:(注:可以多附几张实验现象照片)

5 实验心得

通过这次实验,第一、我学到了一个有时序功能的器件如何用verilog语言实现其功能。在阅读程序、

修改程序的过程中我更加熟悉了verilog语言,掌握了基本的编写程序的技巧和能力。第二、我认识到了实际用软件实现相应功能,原理来源于数字电路的基础知识,但又区别与课本上的内容,学习数字电路课程时,我们从门电路的角度出发,通过真值表、表达式、卡诺图、状态表、状态转换图、特征方程等方式用图形法,或者基本的逻辑器件实现想要的功能。而学习了verilog语言,我意识到,不能从原有的思维方式出发进行分析和编程,必须建立整体的概念,从输入输出的整体功能出发用程序建立模块。并通过模块和模块的嵌套或者连接实现相应功能。第三、通过修改程序的联系,我体会到了如何结合实际模块的时序功能用程序实现对器件的控制,比如TLC5620的输入数据结构是11位的2进制数,但是每位都表达的是不同的信息:9~10位是通道选择,8位是输出参考,剩下的是正真要转化的数据。数据串行输入,必须按照一定的时序接受识别才能正确完成转化。

为了在课堂上完成这次实验,课下真的需要下一番功夫。首先,自己认真提前学习的语言的编程,又在课上听老师讲解重点。课下自己编写了一些简单的小程序,以熟悉语言,但是在课上分析5620的整体程序还是有一定困难,在老师的讲解下,才慢慢理解。在理解的基础上修改程序很简单,但是想要自己独立编写这样一个程序,我想,还需要很长时间的实践才能得以实现。所以,还有许多需要努力的地方。

通过这次实验,学到了很多东西,体会到了自己实现一个程序功能的小小喜悦,也认识到了自己只是FPGA道路上的新手,还有很多未知的知识需要学习。真正学习的历程需要在课下多下功夫,希望通过这学期的学习自己能熟练掌握一些编程的技术,培养良好的思维模式。

6 参考文献 (注:附你实验中查阅或参考的文献资料)

[1] 王金明. 《数字系统设计与Verilog HDL》第3版、第2版, 电子工业出版社, 2009、2005. TP271/W24.

[2] 夏宇闻. 《Verilog数字系统设计教程》, 北京航空航天大学出版社, 第1、2版, 2008. TP312VH/X31.

[3] 蒋璇,臧春华. 《数字系统设计与PLD应用技术》, 电子工业出版社, TP271/J63.

[4] 侯伯亨,顾新. 《VHDL硬件描述语言与数字逻辑电路设计》(修订版), 西安电子科技大学出版社. TP312/H490.

[5] (美)John 威廉斯著; 李林,陈亦欧,郭志勇译. 《Verilog数字VLSI设计教程》, 电子工业出版社. 2010.7.

[6] 潘松,黄继业. 《EDA技术实用教程》, 科学出版社, 2006. TN702/P18.

[7] [8]

附录:实验程序清单

//TASK 1:单通道数码管计数显示 //D/A 5620 运行程序顶层文件: module

top(clk,reset,key,tlc5620_clk,tlc5620_data,tlc5620_load,tlc5620_ldac,sel,ky1,ledcom,leddata); input clk; input reset; input key; output tlc5620_clk; output tlc5620_data; output tlc5620_load; output tlc5620_ldac; output[2:0] sel; output ky1; output[7:0] ledcom; output[7:0] leddata; wire a; wire[10:0] b;

tlc5620(.clk(clk),.rst(reset),.write_n(a),.wr_data(b),.dac_clk(tlc5620_clk),.dac_data(tlc5620_data),.dac_load(tlc5620_load),.dac_ldac(tlc5620_ldac));

dac_test(.clk(clk),.rst(reset),.key(key),.wr_n(a),.wr_data(b),.seg_com(ledcom),.seg_data(leddata));

assign ky1=0; assign sel[2]=0; assign sel[1]=0; assign sel[0]=1;

endmodule

//D/A 5620驱动程序: module

tlc5620(clk,rst,write_n,wr_data,dac_clk,dac_data,dac_load,dac_ldac);

input clk; input rst;

input write_n; input[10:0] wr_data;

output dac_clk; output dac_data; output dac_load; output dac_ldac;

wire dac_done;

reg dac_clk_r; reg dac_data_r; reg [5:0] counter; reg [31:0] DCLK_DIV;

parameter CLK_FREQ = 'D50_000_000; //系统时钟50MHZ

parameter DCLK_FREQ = 'D1_000_000; //AD_CLK输出时钟1M/2HZ

always @(posedge clk)

if(DCLK_DIV < (CLK_FREQ / DCLK_FREQ)) DCLK_DIV <= DCLK_DIV+1'b1; else begin

DCLK_DIV <= 0; dac_clk_r <= ~dac_clk_r; end

always @(posedge dac_clk_r or negedge rst) begin if(!rst)

counter <= 0; else

if(counter<='d13)

counter <= counter + 1'b1; else

counter <= 0; end

assign dac_load = (counter == 4'd12) ? 1'b0 : 1'b1;

assign dac_clk = (counter > 'd0 && counter < 'd12) ? dac_clk_r : 1'b0;

assign dac_ldac = (counter == 4'd13) ? 1'b0 : 1'b1; assign dac_done = (counter <= 4'd11) ? 1'b0 : 1'b1; assign dac_data = dac_data_r;

/*先高位,把11位数据传输给DAC芯片*/

always @(counter[3:0] or wr_data or dac_done or write_n) begin

if(!dac_done && !write_n) case(counter[3:0])

4'd1: dac_data_r <= wr_data[10]; 4'd2: dac_data_r <= wr_data[9]; 4'd3: dac_data_r <= wr_data[8]; 4'd4: dac_data_r <= wr_data[7]; 4'd5: dac_data_r <= wr_data[6]; 4'd6: dac_data_r <= wr_data[5]; 4'd7: dac_data_r <= wr_data[4]; 4'd8: dac_data_r <= wr_data[3]; 4'd9: dac_data_r <= wr_data[2]; 4'd10: dac_data_r <= wr_data[1]; 4'd11: dac_data_r <= wr_data[0]; default: dac_data_r <= 1'b1; endcase else

dac_data_r <= 1'b1; end

endmodule

//D/A 5620 测试程序: /* DAC_TLC5620测试模块

* 按KEY1键,通道A的电压值递增; * 通道的电压值显示于数码管. */ module

dac_test(clk,rst,key,wr_n,wr_data,seg_com,seg_data); input clk; input rst; Input key; output wr_n; output [10:0] wr_data; output [7:0]seg_data; output [7:0]seg_com;

parameter CLK_FREQ = 'D50_000_000; //系统时钟50MHZ

parameter DCLK_FREQ = 'D10; //AD_CLK输出时钟10/2HZ

always @(posedge clk)

if(DCLK_DIV < (CLK_FREQ / DCLK_FREQ)) DCLK_DIV <= DCLK_DIV+1'b1; else begin

DCLK_DIV <= 0; CLK_DIV <= ~CLK_DIV; end

/*高2位为通道选择,低8位为DA数据,第9位 RNG 为1时输出0到2倍Vref,为0时输出0到Vref*/ assign wr_data = {channel,1'b1,data_code_r}; assign wr_n = 1'b0;

always @(posedge CLK_DIV or negedge rst ) if(!rst) begin

key0_r <= 8'h00; data_code_r <= 8'h00; end else case(key) begin

channel <= 2'b00; key0_r <= key0_r + 1'b1; data_code_r <= key0_r; end

default : begin end endcase

/*将各通道的电压值显示于数码管上,单位mv */ always @(negedge rst or negedge CLK_DIV ) begin if(!rst) begin datain[0]<=8'b00000000; datain[1]<=8'b00000000; datain[2]<=8'b00000000; datain[3]<=8'b00000000;

datain[4]<=8'b00000000;

datain[5]<=8'b00000000; datain[6]<=8'b00000000; datain[7]<=8'b00000000;

end

else begin

/*电压值Vo=Vref * (RNG+1) * CODE / 256 */ vo_r = data_code_r * 13'd5000/9'd256; datain[0]<=vo_r;

datain[1]<=vo_r/10; datain[2]<=vo_r/100;

datain[3]<=vo_r/1000; datain[4]<=vo_r/10000; datain[5]<=vo_r/100000; datain[6]<=vo_r/1000000; datain[7]<=vo_r/10000000; end end

always @(posedge clk) begin count=count+1;

end

always @(count[14:12]) begin case(count[14:12]) 3'b000: begin

bcd_led = datain[0]; seg_com = 8'b00000001; end 3'b001: begin

bcd_led=datain[1]; seg_com=8'b00000010; end 3'b010: begin

bcd_led=datain[2]; seg_com=8'b00000100; end 3'b011: begin

bcd_led=datain[3]; seg_com=8'b00001000;

end 3'b100: begin

bcd_led=datain[4]; seg_com=8'b00010000; end 3'b101: begin

bcd_led=datain[5]; seg_com=8'b00100000; end 3'b110: begin

bcd_led=datain[6]; seg_com=8'b01000000; end 3'b111: begin

bcd_led=datain[7]; seg_com=8'b10000000;

end

endcase

end

always @(seg_com or bcd_led) begin case(bcd_led[3:0]) 4'h0:seg_data=8'hc0; 4'h1:seg_data=8'hf9; 4'h2:seg_data=8'ha4; 4'h3:seg_data=8'hb0; 4'h4:seg_data=8'h99; 4'h5:seg_data=8'h92; 4'h6:seg_data=8'h82; 4'h7:seg_data=8'hf8; 4'h8:seg_data=8'h80; 4'h9:seg_data=8'h90; 4'ha:seg_data=8'h88; 4'hb:seg_data=8'h83; 4'hc:seg_data=8'hc6; 4'hd:seg_data=8'ha1; 4'he:seg_data=8'h86;

4'hf:seg_data=8'h8e;

endcase

end endmodule

//TASK 2: 将两个模块合成一个 //D/A 5620 运行程序顶层文件: module

top(clk,reset,key,tlc5620_clk,tlc5620_data,tlc5620_load,tlc5620_ldac,sel,ky1,ledcom,leddata); input clk; input reset; input[3:0] key; output tlc5620_clk; output tlc5620_data; output tlc5620_load; output tlc5620_ldac; output[2:0] sel; output ky1; output[7:0] ledcom; output[7:0] leddata; wire a; wire[10:0] b;

tlc5620(.clk(clk),.rst(reset),.write_n(a),.wr_data(b),.dac_clk(tlc5620_clk),.dac_data(tlc5620_data),.dac_load(tlc5620_load),.dac_ldac(tlc5620_ldac));

dac_test(.clk(clk),.rst(reset),.key(key),.wr_n(a),.wr_data(b),.seg_com(ledcom),.seg_data(leddata));

assign ky1=0; assign sel[2]=0; assign sel[1]=0; assign sel[0]=1;

endmodule

////D/A 5620驱动程序: module

tlc5620(clk,rst,write_n,wr_data,dac_clk,dac_data,dac_load,dac_ldac);

parameter CLK_FREQ = 'D50_000_000; //系统时钟50MHZ

parameter DCLK_FREQ = 'D1_000_000; //AD_CLK输出时钟1M/2HZ

always @(posedge clk)

if(DCLK_DIV < (CLK_FREQ / DCLK_FREQ)) DCLK_DIV <= DCLK_DIV+1'b1; else begin

DCLK_DIV <= 0; dac_clk_r <= ~dac_clk_r; end

always @(posedge dac_clk_r or negedge rst) begin if(!rst)

counter <= 0; else

if(counter<='d13)

counter <= counter + 1'b1; else

counter <= 0; end

assign dac_load = (counter == 4'd12) ? 1'b0 : 1'b1; assign dac_clk = (counter > 'd0 && counter < 'd12) ? dac_clk_r : 1'b0;

assign dac_ldac = (counter == 4'd13) ? 1'b0 : 1'b1; assign dac_done = (counter <= 4'd11) ? 1'b0 : 1'b1; assign dac_data = dac_data_r;

/*先高位,把11位数据传输给DAC芯片*/

always @(counter[3:0] or wr_data or dac_done or write_n) begin

if(!dac_done && !write_n) case(counter[3:0])

4'd1: dac_data_r <= wr_data[10]; 4'd2: dac_data_r <= wr_data[9]; 4'd3: dac_data_r <= wr_data[8]; 4'd4: dac_data_r <= wr_data[7]; 4'd5: dac_data_r <= wr_data[6]; 4'd6: dac_data_r <= wr_data[5]; 4'd7: dac_data_r <= wr_data[4]; 4'd8: dac_data_r <= wr_data[3]; 4'd9: dac_data_r <= wr_data[2]; 4'd10: dac_data_r <= wr_data[1]; 4'd11: dac_data_r <= wr_data[0]; default: dac_data_r <= 1'b1; endcase else

dac_data_r <= 1'b1; end

endmodule

/////D/A 5620 测试程序: /* DAC_TLC5620测试模块

* 按KEY1键,通道D的电压值递增; * 按KEY2键,通道C的电压值递增; * 按KEY3键,通道B的电压值递增; * 按KEY4键,通道A的电压值递增; * 各通道的电压值显示于数码管. */ module

dac_test(clk,rst,key,wr_n,wr_data,seg_com,seg_data);

reg [7:0] key3_r; reg [31:0] vo_r;

parameter CLK_FREQ = 'D50_000_000;//系统时钟50MHZ parameter DCLK_FREQ = 'D10;//AD_CLK输出时钟10/2HZ

always @(posedge clk)

if(DCLK_DIV < (CLK_FREQ / DCLK_FREQ)) DCLK_DIV <= DCLK_DIV+1'b1; else begin

DCLK_DIV <= 0; CLK_DIV <= ~CLK_DIV; end

/*高2位为通道选择,低8位为DA数据,第9位 RNG 为1时输出0到2倍Vref,为0时输出0到Vref*/ assign wr_data = {channel,1'b1,data_code_r}; assign wr_n = 1'b0;

/*根据按键不同,选择不同的DA通道,其值递增*/ always @(posedge CLK_DIV or negedge rst ) if(!rst) begin

key0_r <= 8'h00; key1_r <= 8'h00; key2_r <= 8'h00; key3_r <= 8'h00; data_code_r <= 8'h00;

end else case(key)

4'b1110 : begin //key4 channel <= 2'b00; key0_r <= key0_r + 1'b1; data_code_r <= key0_r; end 4'b1101 : begin //key3 channel <= 2'b01; key1_r <= key1_r + 1'b1; data_code_r <= key1_r; end 4'b1011 : begin //key2 channel <= 2'b10; key2_r <= key2_r + 1'b1; data_code_r <= key2_r; end 4'b0111 : begin //key1 channel <= 2'b11; key3_r <= key3_r + 1'b1; data_code_r <= key3_r; end default : begin end endcase

/*将各通道的电压值显示于数码管上,单位mv */ always @(negedge rst or negedge CLK_DIV ) begin if(!rst) begin datain[0]<=8'b00000000; datain[1]<=8'b00000000; datain[2]<=8'b00000000; datain[3]<=8'b00000000; datain[4]<=8'b00000000; datain[5]<=8'b00000000; datain[6]<=8'b00000000; datain[7]<=8'b00000000;

end

else begin

/*电压值Vo=Vref * (RNG+1) * CODE / 256 */

vo_r = data_code_r * 13'd5000/9'd256;

datain[0]<=vo_r; /*% 表示取模*/

datain[1]<=vo_r/10; datain[2]<=vo_r/100;

datain[3]<=vo_r/1000;

end

end

always @(posedge clk) begin count=count+1;

end

always @(count[14:12]) begin case(count[14:12]) 3'b000: begin

bcd_led = datain[0]; //数码管扫描 seg_com = 8'b00000001; //数码管共阳极 end 3'b001: begin

bcd_led=datain[1]; seg_com=8'b00000010; end 3'b010: begin

bcd_led=datain[2]; seg_com=8'b00000100; end 3'b011: begin

bcd_led=datain[3]; seg_com=8'b00001000; end 3'b100: begin

bcd_led=datain[4]; seg_com=8'b00010000; end 3'b101: begin

bcd_led=datain[5]; seg_com=8'b00100000; end 3'b110: begin

bcd_led=datain[6]; seg_com=8'b01000000; end 3'b111: begin

bcd_led=datain[7]; seg_com=8'b10000000;

end

endcase

end

always @(seg_com or bcd_led) begin case(bcd_led[3:0]) 4'h0:seg_data=8'hc0; //11000000 显示 0 4'h1:seg_data=8'hf9; //11111001 显示 1 4'h2:seg_data=8'ha4; //..... 4'h3:seg_data=8'hb0; //..... 4'h4:seg_data=8'h99; //..... 4'h5:seg_data=8'h92; 4'h6:seg_data=8'h82; 4'h7:seg_data=8'hf8; 4'h8:seg_data=8'h80; 4'h9:seg_data=8'h90; 4'ha:seg_data=8'h88; 4'hb:seg_data=8'h83; 4'hc:seg_data=8'hc6; 4'hd:seg_data=8'ha1; 4'he:seg_data=8'h86;

4'hf:seg_data=8'h8e;

endcase

end

endmodule

本文来源:https://www.bwwdw.com/article/epgg.html

Top