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