设计背景:
数模转换器(Digital to Analog Converter)即DAC,是数字世界和interwetten与威廉的赔率体系 世界之间的桥梁。人类生活在模拟世界中,虽然数字器件及设备的比重日益增强,但是DAC的发展仍是必不可少的。
从航空航天、国防军事到民用通信、多媒体、数字信号处理等都涉及到DAC应用。DAC基本上由4个部分组成,即权电阻网络、运算放大器、基准电源和模拟开关。它是一种将二进制数字量形式的离散信号转换成以参考电压为基准的模拟量的转换器。
设计原理:
本设计采用串行数/模转换芯片TLC5620,TLC5620是一个拥有四路输出的数/模转换器,时钟频率最大可达到1MHz。TLC5620芯片接口如下:
该芯片主要有以下特点:四通道8位电压输出DA转换器、5V单电源供电、串行接口、高阻抗基准输入、可编程1或2输出范围、同时更新设备、内部上电复位、低功耗、半缓冲输出。该芯片主要应用于:可编程电源、数字控制放大器/误差器、移动通信、自动测试设备、研发过程检测和控制和信号合成等。
转换公式:V = REF*(CODE/256)* (1+RNG)
V:实际电压;REF:基准电压;CODE:输入8位数据;RNG:范围。
TLC5620的接口时序如下列图所示:
图2 LDAC控制更新(LDAC为低电平)
图3 LOAD控制更新(使用8位串行数据,LOAD为低电平)
图4 LDAC控制更新(使用8位串行数据)
如图1所示:当LOAD为高电平时,数据在CLK的下降沿被锁存至DATA,只要所有数据被锁存,则将LOAD拉低,将数据从串行输入寄存器传送到所选择的DAC。
如图2所示:串行编程期间LDAC为高电平,数据在LOAD为低电平时进行锁存,当LDAC变为低电平时传送至DAC输出。如图3、4所示:输入数据最高位(MSB)在前,数据传输使用两个8个时钟周期。
在本设计中运用的是图1的工作时序:
数据通道选择:
RNG:控制DAC输出范围。当RNG为低时,输出范围在基准电压和GND之间;当RNG为高时,输出范围为两倍的基准电压和GND。
设计架构图:
本设计驱动TLC5620将输入的数字量转换为实际的模拟量(电压),通过四个按键控制四路输出的电压变化,每按一次,电压值也随之上升,同时在数码管上也依次显示相应的值(依次为A1,A0,RNG,输入DATA)。本设计采用的开发板的基准电压为2.5V。设计架构图如下所示:
key_test模块通过四个按键输入的值,组合输出两个数据,11位的wr_data是TLC_DA模块解码所需的数据。20位的out_data是seg_num模块数码管显示所需的数据。
设计代码:
key_test模块代码如下:
0modulekey_test(//按键控制模块
1//端口信号:模块的输入输出接口
2inputclk,//50MHZ
3inputrst_n,//低电平复位
4input[3:0]key,//四个按键组合信号
5
6output[10:0]wr_data,//输出一帧数据,为DA模块的输入数字量
7output[19:0]out_data //输出数码管显示数据
8);
9
10//计数器时钟分频
11reg[30:0]cnt;
12regclk_r;//分频时钟:在消除抖动的时钟频率下进行按键的检测
13always@(posedgeclkornegedgerst_n)//按键消抖,时间为0.2s进行一次检测
14if(!rst_n)
15begin
16cnt<= 0;
17clk_r<= 0;
18end
19elseif(cnt< 30'd1000_0000)
20cnt<= cnt + 1'b1;
21else
22begin
23cnt<= 0;
24clk_r<= ~clk_r;
25end
26
27//按键为低电平有效,当检测到对应按键之后,相应数值加1,并显示相应的通道
28reg[7:0]data;//按键输入数据
29reg[1:0]channel;//通道选择
30reg[7:0]key1,key2,key3,key4;//相应四个按键
31always@(posedgeclk_rornegedgerst_n)
32if(!rst_n)
33begin
34key1<= 8'h00;
35key2<= 8'h00;
36key3<= 8'h00;
37key4<= 8'h00;
38data<= 8'h00;
39channel<= 2'b00;
40end
41else
42case(key)
434'b1110:begin//按键1:选择通道A,且输入数字量加1
44channel<= 2'b00;
45key1<= key1 + 1'b1;
46data<= key1;
47end
484'b1101:begin//按键2:选择通道B,且输入数字量加1
49channel<= 2'b01;
50key2<= key2 + 1'b1;
51data<= key2;
52end
534'b1011:begin//按键3:选择通道C,且输入数字量加1
54channel<= 2'b10;
55key3<= key3 + 1'b1;
56data<= key3;
57end
584'b0111:begin//按键4:选择通道D,且输入数字量加1
59channel<= 2'b11;
60key4<= key4 + 1'b1;
61data<= key4;
62end
63default:;
64endcase
65
66//用赋值语句将需要的数据组合起来,在此例中将RNG默认为1
67assignwr_data={channel,1'b1,data};assignout_data={{3'b000,channel[1]},3'b000,channel[0],4'h1,data};
68
69endmodule
TLC_DA模块代码如下:
0moduleTLC_DA(//输入数字量转换为模拟量模块,本实验用TLC5620
1//端口信号:模块的输入输出接口
2inputclk,//系统时钟50MHz
3inputrst_n,//低电平复位
4input[10:0]data_in,//输入一帧数据
5outputda_data,//串行数据接口
6outputda_clk,//串行时钟接口
7outputregda_ldac,//更新控制信号
8outputregda_load//串行加载控制接口
9);
10
11//计数器时钟分频:根据芯片内部的时序要求进行分频
12reg[30:0]cnt;
13wireda_clk_r;//TLC 5620内部时钟信号
14always@(posedgeclkornegedgerst_n)//满足协议中的时钟要求,在TLC 5620中时钟要求不大于1MHZ
15if(!rst_n)
16cnt<= 6'd0;
17else
18cnt<= cnt + 1'b1;
19
20assignda_clk_r=cnt[5];
21
22//接收时序状态机
23reg[2:0]state;
24reg[3:0]cnt_da;
25regda_data_r;
26regda_data_en;//限定da_data,da_clk的有效区域
27always@(posedgeda_clk_rornegedgerst_n)
28if(!rst_n)
29begin
30state<= 0;
31cnt_da<= 0;
32da_load<= 1;
33da_ldac<= 0;
34da_data_r<= 1'b1;
35da_data_en<= 0;
36end
37else
38case(state)
390:state<= 1;
401:begin
41da_load<= 1;
42da_data_en<= 1;
43if(cnt_da<= 10)
44begin
45cnt_da<= cnt_da + 1'b1;
46case(cnt_da)
470:da_data_r<= data_in[10];
481:da_data_r<= data_in[9];
492:da_data_r<= data_in[8];
503:da_data_r<= data_in[7];
514:da_data_r<= data_in[6];
525:da_data_r<= data_in[5];
536:da_data_r<= data_in[4];
547:da_data_r<= data_in[3];
558:da_data_r<= data_in[2];
569:da_data_r<= data_in[1];
5710:da_data_r<= data_in[0];
58default:;
59endcase
60state<= 1;
61end
62else
63begin
64cnt_da<= 0;
65state<= 2;
66da_data_en<= 0;
67end
68end
692:begin
70da_load<= 0;
71state<= 3;
72end
733:begin
74da_load<= 1;
75state<= 0;
76end
77default:state<= 0;
78endcase
79
80assignda_data=(da_data_en)?da_data_r:1'b1;
81assignda_clk=(da_data_en)?da_clk_r:1'b0;
82
83endmodule
seg_num模块代码如下:
0moduleseg_num(//数码管显示模块:选择数码管0-4共5个数码管显示{A1,A0,RNG,DATA}
1//端口信号:模块的输入输出接口
2inputclk,//系统时钟50MHz
3inputrst_n,//低电平复位
4input[19:0]data_in,//20位输入数据
5
6outputreg[7:0]seg,//数码管段选
7outputreg[2:0]sel//数码管位选
8);
9
10//通过查找表的方式,将相应位的数码管与数据的相应位一一对应
11reg[3:0]num;
12always@(*)
13case(sel)
144:num=data_in[3:0];//第五个数码管显示数据的低四位[3:0]
153:num=data_in[7:4];//第四个数码管显示数据的低四位[7:4]
162:num=data_in[11:8];//第三个数码管显示数据的低四位[11:8]
171:num=data_in[15:12];//第二个数码管显示数据的低四位[15:12]
180:num=data_in[19:16];//第一个数码管显示数据的低四位[19:16]
19default:;
20endcase
21
22//通过查找表的方式,将数据与数码管的显示方式一一对应
23always@(*)
24case(num)
250:seg<= 8'hC0; //8'b1100_0000
261:seg<= 8'hF9; //8'b1111_1001
272:seg<= 8'hA4; //8'b1010_0100
283:seg<= 8'hB0; //8'b1011_0000
294:seg<= 8'h99; //8'b1001_1001
305:seg<= 8'h92; //8'b1001_0010
316:seg<= 8'h82; //8'b1000_0010
327:seg<= 8'hF8; //8'b1111_1000
338:seg<= 8'h80; //8'b1000_0000
349:seg<= 8'h90; //8'b1001_0000
35default:seg<= 8'hFF; //8'b1111_1111
36endcase
37
38//计数器时钟分频:用cnt第10位的变化作为分频时钟
39reg[23:0]cnt;
40always@(posedgeclkornegedgerst_n)
41if(!rst_n)
42cnt<= 4'd0;
43else
44cnt<= cnt + 1'b1;
45//在分频时钟下,数码管的0-5位依次循环
46always@(posedgecnt[10]ornegedgerst_n)//分频时钟为2^10/50M
47if(!rst_n)
48sel<= 0;
49elseif(sel< 4)
50sel<= sel + 1'b1;
51else
52sel<= 0;
53
54endmodule
top顶层模块代码如下:
0moduletop(//顶层模块:将各个模块组合
1//外部接口
2inputclk,//系统时钟50MHz
3inputrst_n,//低电平复位
4input[3:0]key,//四个按键组成的按键信号,低电平有效
5
6outputda_data,//DA串行接口数据
7outputda_clk,//DA串行接口时钟
8outputda_ldac,//DA更新信号
9outputda_load,//DA串行接口加载控制信号
10output[7:0]seg,//数码管段选
11output[2:0]sel//数码管位选
12);
13//内部信号:模块内部的接口信号,比如模块TLC_DA的输出信号data_in,通过内部信号r_data与模块key_test的输入信号wr_data相连
14wire[10:0]wr_data;
15wire[19:0]out_data;//输入给数码管的数据
16
17//模块例化
18TLC_DATLC_DA_inst(//输入数字量转换为模拟量模块
19.clk(clk),
20.rst_n(rst_n),
21.da_clk(da_clk),
22.da_data(da_data),
23.da_ldac(da_ldac),
24.da_load(da_load),
25.data_in(wr_data)
26);
27
28key_testkey_test_inst(//按键控制模块
29.clk(clk),
30.rst_n(rst_n),
31.key(key),
32.wr_data(wr_data),
33.out_data(out_data)
34);
35
36seg_numseg_num_inst(//数码管显示模块
37.clk(clk),
38.rst_n(rst_n),
39.data_in(out_data),
40.seg(seg),
41.sel(sel)
42);
43
44endmodule
test顶层模块测试代码:
0`timescale1ns/1ns//设置仿真时间单位与精度分别为1ns/1ns
1//若设为`timescale 1ns/1ps (#200就是延时200 ns; 1ps就是仿真的精度)
2moduletest;//测试模块:主要是将激励信号赋相应的值,仿真之后观察波形,验证与实际功能是否一样
3
4//端口信号定义,激励信号为reg型
5regclk;
6regrst_n;
7reg[3:0]key;
8wire[7:0]seg;
9wire[2:0]sel;
10
11//模块例化
12toptop(
13.clk(clk),
14.rst_n(rst_n),
15.key(key),
16.seg(seg),
17.sel(sel)
18);
19
20//初始化激励,以及给相应激励赋值
21initial
22begin
23clk=0;rst_n=0;key=4'b1111;//在复位阶段,将激励赋初值
24
25#200rst_n=1;//在延时200ns后将复位信号置为1
26
27//实现按键1开,关
28#500000key=4'b1110;
29#500000key=4'b1111;
30
31end
32
33always#10clk=~clk;//时钟的表示,即每隔10ns翻转一次,一个周期的时间即为20ns,时钟为1/20ns = 50MHZ
34
35endmodule
仿真图:
由于仿真时间原因,这里只测试按键1按下时的数码管显示,显示为00100,表示通道A,RNG为1,输入数字量为00。之后实际下板验证,用万用表也可测出输入数字量对应的电压值。
-
dac
+关注
关注
43文章
2291浏览量
190980 -
数字信号处理
+关注
关注
15文章
560浏览量
45844 -
数模转换器
+关注
关注
14文章
1011浏览量
83166
原文标题:【FPGA学习】一文教你轻松实现数模转换的设计
文章出处:【微信号:elecfans,微信公众号:电子发烧友网】欢迎添加关注!文章转载请注明出处。
发布评论请先 登录
相关推荐
评论