首页 > 代码库 > verilog语言实现TCL549(AD)转换

verilog语言实现TCL549(AD)转换

此文章为原创出自 V3学院 www.v3edu.org,FPGA培训专家

ADC 和 DAC 是模拟量和数字量之间不可或缺的桥梁。A/D 转换器是将各种模拟信号转换为抗干扰性更强的数字信号,直接进入数字计算机进行处理。

本设计采用V3学院基础开发板,采用TCL549进行模数转换,通过数码管显示电压值。TLC549 是一个 8 位的串行模数转换器,I/O所需最大时钟为1.1MHz。A/D 转换时间最大 17us,如图1所示,TCL549引脚图,管脚8和4分别接VCC和GND,管脚1和3分别接基准电压,管脚2为输入的电压信号,管脚7为输入的控制时钟,管脚6是最后输出的8bit数字信号。本设计将管脚1和3分别接GND和vcc2.5V。

技术分享

        图1 TCL549引脚图

如图2,为TCL549的时序图,时钟最大为1.1Mhz;从图中可以看出当 CS 拉低时,需要保持tsu(cs)段时间,这段时间>=1.4us,之后I/O_CLOCK开始工作,数据开始传输转换,但数据传出至少保持17us,I/O_CLOCK停止工作,数据传输完成。画出visio图,如图3所示,根据visio图编写转换代码。

 

技术分享

如图2 TCL549的时序图

技术分享

如图3 TCL549的时序图

1.本设计使用1MHZ时钟,产生1MHZ时钟模块如下:

module  freq(
        input   wire            clk,            //输入的系统时钟
        input   wire            rst_n,          //输入的系统复位

       
        output  reg             slow_clk        //输入1MHZ的慢时钟
        );
reg[5:0]        clk_cnt;
parameter       cnt1M = 6‘d24; //1MHZ时钟计数器
always  @(posedge clk or negedge rst_n)
        if(!rst_n)
                clk_cnt <= 0;
        else if(clk_cnt == cnt1M)    
                clk_cnt <= 0;
        else
                clk_cnt <= clk_cnt + 1‘b1;  
                
always  @(posedge clk or negedge rst_n)
        if(!rst_n)
                slow_clk <= 0;
        else if(clk_cnt == cnt1M)    
                slow_clk <= ~slow_clk; 
                        
endmodule

 

2.TCL549模数转换模块如下:

module  ad(
        input   wire            slow_clk,       //输入1MHZ的慢时钟
        input   wire            rst_n,          //输入的系统复位
        input   wire            AD_dat,         //输入的TCL549转换的数据
        
        output  wire            AD_CS_N,        //输出给TCL549的CS断,用于启动AD转换器工作        
        output  wire            AD_CLK,         //输出给TCL549的CLK断,用于AD转换器工作
        output  reg[11:0]       out_data        //传出12bit放大1000倍的电压数据
        );


reg[20:0]       cnt_1s;         //1s计数器,使TCL549 每1s工作一次
reg             flag_1s;        //1s计满标志位

reg             start_en;       //由于数据发送前要先保持至少1.7us的时间;TCL549开始工作后,计满2us拉低
reg             start_cnt;      //由于数据发送前要先保持至少1.7us的时间;对2us计数

reg             AD_EN;          //TCL549数据转换使能;
reg[2:0]        AD_cnt;         //数据转换8bit计数;

reg             end_en;         //由于数据传输结束后,要先保持至少17us的时间进行转换;计满17us拉低
reg[4:0]        end_cnt;        //由于数据传输结束后,要先保持至少17us的时间进行转换;对17us计数

reg[7:0]        tmp_data;       //用来存储正在转换的数据;
reg[7:0]        data;           //用来存储转换完成后的数据;

parameter       CNT1S = 21‘d999999;     //1s计慢值 (999999+1)*1us

assign  AD_CLK  = (AD_EN==1) ? slow_clk : 1‘b0 ;    //只有当数据开始转换时 AD_CLK才开始震荡,否则一直为低电平
assign  AD_CS_N = (start_en | AD_EN | end_en==1) ? 1‘b0 : 1‘b1;   //在TCL54工作时AD_CS一直为低;否则为高电平;



/**********************************************************************/
//1s计数器  
//1s计满标志;目的为了降低TCL549刷新频率,时TCL549每秒工作一次。
/**********************************************************************/ 
always  @(posedge slow_clk or negedge rst_n)
        if(!rst_n)
                cnt_1s <= 0;
        else if(cnt_1s == CNT1S)    
                cnt_1s <= 0;
        else
                cnt_1s <= cnt_1s + 1‘b1;
always  @(posedge slow_clk or negedge rst_n)
        if(!rst_n)
                flag_1s <= 0;
        else if(cnt_1s == CNT1S)    
                flag_1s <= 1;
        else
                flag_1s <= 0;
                
/**********************************************************************/
//由于数据发送前要先保持至少1.7us的时间后才可以发送数据;  
//计数计满2us拉低,
/**********************************************************************/          
always  @(posedge slow_clk or negedge rst_n)
        if(!rst_n)
                start_en <= 0;
        else if(flag_1s == 1)    
                start_en <= 1; //1s标志位来,TCL549开始工作,开始信号拉高
        else if(start_cnt==1) 
                start_en <= 0; //计慢2个时钟周期2us时,将开始信号拉低;
always  @(posedge slow_clk or negedge rst_n)
        if(!rst_n)
                start_cnt <= 0;
        else if(start_cnt==1)
                start_cnt <= 0;  
        else if(start_en==1)
                start_cnt <= start_cnt+1; 
        else
                start_cnt <= 0;
                              
/**********************************************************************/
//TCL549开始发送数据,AD_CLK开始工作,
//由于是8位AD芯片,所以只需要转换8次即可,
//及数据转换使能只需要保持8个时钟周期。
/**********************************************************************/                                  
always  @(posedge slow_clk or negedge rst_n)
        if(!rst_n)
                AD_EN <= 0;
        else if(start_cnt==1 && start_en==1)
                AD_EN <= 1;  
        else if(AD_cnt == 7) //计数器到7信号拉低,
                AD_EN <= 0;               
always  @(posedge slow_clk or negedge rst_n)
        if(!rst_n)
                AD_cnt <= 0;
        else if(AD_EN==1)
                AD_cnt <= AD_cnt+1; 
        else    
                AD_cnt <= 0;  

/**********************************************************************/
//TCL549发送数据结束后,AD_CLK停止工作,
//但需要等待至少17us数据才能输出,
//及数据转换到输出至少要保持17个时钟周期。
/**********************************************************************/     
always  @(posedge slow_clk or negedge rst_n)
        if(!rst_n)
                end_en <= 0;
        else if(AD_cnt==7 && AD_EN==1)
                end_en <= 1;  
        else if(end_cnt == 16)
                end_en <= 0; 
always  @(posedge slow_clk or negedge rst_n)
        if(!rst_n)
                end_cnt <= 0;
        else if(end_en==1)
                end_cnt <= end_cnt+1; 
        else    
                end_cnt <= 0; 
                
/**********************************************************************/
//将从TCL549读取出来的数据转换成8bit数据
//因为TCL549为8位AD芯片
/**********************************************************************/
always  @(posedge slow_clk or negedge rst_n)
        if(!rst_n)
                tmp_data <= 8‘h00;
        else if(AD_EN==1)
                tmp_data <= {tmp_data[6:0],AD_dat}; 

/**********************************************************************/
//当数据转换完后保持至少17us才能把数据输出,传给data储存器。
/**********************************************************************/              
always  @(posedge slow_clk or negedge rst_n)
        if(!rst_n)
                data <= 8‘h00;
        else if(end_cnt==16 && end_en==1)
                data <= tmp_data;  
                
/**********************************************************************/
//将8bit的数据计算成电压=(data*精度*电压最大值)/255;
/**********************************************************************/                  
always  @(posedge slow_clk or negedge rst_n)
        if(!rst_n)
                out_data <= 11‘h00;
        else 
                out_data <= (data*100*25)/255;                             
                
endmodule           

 3. 16进制转十进制BCD码代码模块如下:

module  BCD_CTRL(
        input   wire            slow_clk,
        input   wire            rst_n,
        input   wire[11:0]      in_data,

        output  reg[3:0]      units,
        output  reg[3:0]      tens,
        output  reg[3:0]      hundreds,
        output  reg[3:0]      thousand         
                );
                
                
integer i;
always  @(posedge slow_clk) 
        begin
            units    = 4‘d0;       
            tens     = 4‘d0;                            
            hundreds = 4‘d0;
            thousand = 4‘d0;
         
        for(i=0;i<12; i=i+1)
        begin
                if(units>=5)
                        units = units +3;
                if(tens>=5)
                        tens  = tens  +3; 
                if(hundreds>=5)
                        hundreds  = hundreds  +3;   
                if(thousand>=5)
                        thousand  = thousand  +3; 
         
                thousand    =  thousand <<1;
                thousand[0] =  hundreds[3];
                 
                hundreds    =  hundreds <<1;
                hundreds[0] =  tens[3];
                  
                tens        =  tens <<1;
                tens[0]     =  units[3]; 
                
                units       =  units <<1;
                units[0]    =  in_data[11-i];                                                                                                                        
        end     
        end 
endmodule     

4. 数码管显示功能代码模块如下:

module  seg_play(
        input   wire            clk  ,    //输入的1MHZ时钟
        input   wire            rst_n,    //输入的系统复位信号      
        input   wire[3:0]       units,    //显示第三个小数位;0.001v
        input   wire[3:0]       tens ,    //显示第二个小数位0.01v
        input   wire[3:0]       hundreds, //显示第一个小数位0.01v
        input   wire[3:0]       thousand, //显示整数部分  
        
       output   reg[2:0]        sel,      //数码管位选信号      
       output   reg[7:0]        seg       //数码管段选信号      

        );
        
reg[12:0]       sel_cnt;//位选刷新计数器
reg             sel_en; //位选信号使能,用于显示小数点
reg[3:0]        num;    //用来存储要显示的数据

parameter       SEL_NUM = 99; //单个数码管刷新时间;=(SEL_NUM+1)* 1us

//位选刷新计数;
always @(posedge clk or negedge rst_n)
       if(!rst_n)
              sel_cnt <= 0;
       else if(sel_cnt==SEL_NUM)
              sel_cnt <= 0;
       else
              sel_cnt <= sel_cnt+1;
              
//位选刷新,因为只有4个0--9的数据 ;故只需要点亮四个数码管即可,点亮的分别为:2号、3号、4号、5号数码管。             
always @(posedge clk or negedge rst_n)  
       if(!rst_n)
              sel <= 3‘b111; 
       else  if(sel==5 && sel_cnt==SEL_NUM) 
              sel <= 3‘d2;
       else if(sel_cnt==SEL_NUM)
              sel <= sel + 1 ;
              
//数码管没刷新一个周期就将sel_en取反一次,用于显示小数点。              
always @(posedge clk or negedge rst_n)
       if(!rst_n)
              sel_en <= 3‘b111; 
       else if(sel==5&&sel_cnt==SEL_NUM)
              sel_en <= ~sel_en;              

//传值储存,用于显示在数码管上
always @(posedge clk or negedge rst_n)
       if(!rst_n)
              num <= 0;
       else case(sel)
                3‘d2 :       num <= thousand;   //当数码管刷新到2号数码管时,将整数部分的数据存储在num中;
                3‘d3 :       num <= hundreds;   //当数码管刷新到3号数码管时,将第一个小数部分的数据存储在num中;
                3‘d4 :       num <= tens;       //当数码管刷新到4号数码管时,将第二个小数部分的数据存储在num中;
                3‘d5 :       num <= units;      //当数码管刷新到5号数码管时,将第三个小数部分的数据存储在num中;
                default:  
                             num <= 0;
       endcase                
              
 //数码管显示  
always @(posedge clk or negedge rst_n)
       if(!rst_n)
              seg <=  8‘hff; 
       else if(sel_en==0&&sel==2)       //当sel_en为0时,并且数码管刷新到二号数码管时,将小数点点亮;                  
                     seg <=  8‘h7f;     // 本次刷新不显示整数部分;在下一次数码管刷新时显示.            
       else case(num)                   //将num存储器中的数据显示到数码管上,刚好与sel同步。
                      0:     seg <= 8‘hc0;
                      1:     seg <= 8‘hf9;
                      2:     seg <= 8‘ha4;
                      3:     seg <= 8‘hb0;
                      4:     seg <= 8‘h99;
                      5:     seg <= 8‘h92;
                      6:     seg <= 8‘h82;   
                      7:     seg <= 8‘hf8;
                      8:     seg <= 8‘h80;
                      9:     seg <= 8‘h90;
                      10:    seg <= 8‘h88;
                      11:    seg <= 8‘h83;
                      12:    seg <= 8‘hc6;
                      13:    seg <= 8‘ha1;
                      14:    seg <= 8‘h86;
                      15:    seg <= 8‘h8e;
                      default:
                             seg <=  8‘hff;
                endcase           
          
endmodule  

5. 顶层连线布线:

技术分享

 

6.功能引脚绑定文件如下:

       

NET "seg[7]" LOC = P117;
NET "seg[6]" LOC = P121;
NET "seg[5]" LOC = P118;
NET "seg[4]" LOC = P116;
NET "seg[3]" LOC = P115;
NET "seg[2]" LOC = P114;
NET "seg[1]" LOC = P120;
NET "seg[0]" LOC = P119;
NET "sel[2]" LOC = P14;
NET "sel[1]" LOC = P15;
NET "sel[0]" LOC = P16;
NET "clk" LOC = P24;
NET "rst_n" LOC = P94;


NET "seg[7]" IOSTANDARD = LVCMOS33;
NET "seg[6]" IOSTANDARD = LVCMOS33;
NET "seg[5]" IOSTANDARD = LVCMOS33;
NET "seg[4]" IOSTANDARD = LVCMOS33;
NET "seg[3]" IOSTANDARD = LVCMOS33;
NET "seg[2]" IOSTANDARD = LVCMOS33;
NET "seg[1]" IOSTANDARD = LVCMOS33;
NET "seg[0]" IOSTANDARD = LVCMOS33;
NET "sel[2]" IOSTANDARD = LVCMOS33;
NET "sel[1]" IOSTANDARD = LVCMOS33;
NET "sel[0]" IOSTANDARD = LVCMOS33;
NET "clk" IOSTANDARD = LVCMOS33;
NET "rst_n" IOSTANDARD = LVCMOS33;

# PlanAhead Generated IO constraints 

NET "AD_CLK" IOSTANDARD = LVCMOS33;
NET "AD_CS_N" IOSTANDARD = LVCMOS33;
NET "AD_dat" IOSTANDARD = LVCMOS33;

# PlanAhead Generated physical constraints 

NET "AD_CLK" LOC = P126;
NET "AD_CS_N" LOC = P123;
NET "AD_dat" LOC = P124;

上板烧写,我们就实现了AD转换的过程,感谢大家对V3学院的支持,FPGA培训,就选v3学院,雄厚的师资,高深的技术,v3学院将在你的FPGA学习路上祝你一臂之力。

此文章为原创出自 V3学院 www.v3edu.org;

此文章为原创出自 V3学院 www.v3edu.org,FPGA培训专家

ADC 和 DAC 是模拟量和数字量之间不可或缺的桥梁。A/D 转换器是将各种模拟信号转换为抗干扰性更强的数字信号,直接进入数字计算机进行处理。

本设计采用V3学院基础开发板,采用TCL549进行模数转换,通过数码管显示电压值。TLC549 是一个 8 位的串行模数转换器,I/O所需最大时钟为1.1MHz。A/D 转换时间最大 17us,如图1所示,TCL549引脚图,管脚8和4分别接VCC和GND,管脚1和3分别接基准电压,管脚2为输入的电压信号,管脚7为输入的控制时钟,管脚6是最后输出的8bit数字信号。本设计将管脚1和3分别接GND和vcc2.5V。

技术分享

        图1 TCL549引脚图

如图2,为TCL549的时序图,时钟最大为1.1Mhz;从图中可以看出当 CS 拉低时,需要保持tsu(cs)段时间,这段时间>=1.4us,之后I/O_CLOCK开始工作,数据开始传输转换,但数据传出至少保持17us,I/O_CLOCK停止工作,数据传输完成。画出visio图,如图3所示,根据visio图编写转换代码。

 

技术分享

如图2 TCL549的时序图

技术分享

如图3 TCL549的时序图

1.本设计使用1MHZ时钟,产生1MHZ时钟模块如下:

module  freq(
        input   wire            clk,            //输入的系统时钟
        input   wire            rst_n,          //输入的系统复位

       
        output  reg             slow_clk        //输入1MHZ的慢时钟
        );
reg[5:0]        clk_cnt;
parameter       cnt1M = 6‘d24; //1MHZ时钟计数器
always  @(posedge clk or negedge rst_n)
        if(!rst_n)
                clk_cnt <= 0;
        else if(clk_cnt == cnt1M)    
                clk_cnt <= 0;
        else
                clk_cnt <= clk_cnt + 1‘b1;  
                
always  @(posedge clk or negedge rst_n)
        if(!rst_n)
                slow_clk <= 0;
        else if(clk_cnt == cnt1M)    
                slow_clk <= ~slow_clk; 
                        
endmodule

 

2.TCL549模数转换模块如下:

module  ad(
        input   wire            slow_clk,       //输入1MHZ的慢时钟
        input   wire            rst_n,          //输入的系统复位
        input   wire            AD_dat,         //输入的TCL549转换的数据
        
        output  wire            AD_CS_N,        //输出给TCL549的CS断,用于启动AD转换器工作        
        output  wire            AD_CLK,         //输出给TCL549的CLK断,用于AD转换器工作
        output  reg[11:0]       out_data        //传出12bit放大1000倍的电压数据
        );


reg[20:0]       cnt_1s;         //1s计数器,使TCL549 每1s工作一次
reg             flag_1s;        //1s计满标志位

reg             start_en;       //由于数据发送前要先保持至少1.7us的时间;TCL549开始工作后,计满2us拉低
reg             start_cnt;      //由于数据发送前要先保持至少1.7us的时间;对2us计数

reg             AD_EN;          //TCL549数据转换使能;
reg[2:0]        AD_cnt;         //数据转换8bit计数;

reg             end_en;         //由于数据传输结束后,要先保持至少17us的时间进行转换;计满17us拉低
reg[4:0]        end_cnt;        //由于数据传输结束后,要先保持至少17us的时间进行转换;对17us计数

reg[7:0]        tmp_data;       //用来存储正在转换的数据;
reg[7:0]        data;           //用来存储转换完成后的数据;

parameter       CNT1S = 21‘d999999;     //1s计慢值 (999999+1)*1us

assign  AD_CLK  = (AD_EN==1) ? slow_clk : 1‘b0 ;    //只有当数据开始转换时 AD_CLK才开始震荡,否则一直为低电平
assign  AD_CS_N = (start_en | AD_EN | end_en==1) ? 1‘b0 : 1‘b1;   //在TCL54工作时AD_CS一直为低;否则为高电平;



/**********************************************************************/
//1s计数器  
//1s计满标志;目的为了降低TCL549刷新频率,时TCL549每秒工作一次。
/**********************************************************************/ 
always  @(posedge slow_clk or negedge rst_n)
        if(!rst_n)
                cnt_1s <= 0;
        else if(cnt_1s == CNT1S)    
                cnt_1s <= 0;
        else
                cnt_1s <= cnt_1s + 1‘b1;
always  @(posedge slow_clk or negedge rst_n)
        if(!rst_n)
                flag_1s <= 0;
        else if(cnt_1s == CNT1S)    
                flag_1s <= 1;
        else
                flag_1s <= 0;
                
/**********************************************************************/
//由于数据发送前要先保持至少1.7us的时间后才可以发送数据;  
//计数计满2us拉低,
/**********************************************************************/          
always  @(posedge slow_clk or negedge rst_n)
        if(!rst_n)
                start_en <= 0;
        else if(flag_1s == 1)    
                start_en <= 1; //1s标志位来,TCL549开始工作,开始信号拉高
        else if(start_cnt==1) 
                start_en <= 0; //计慢2个时钟周期2us时,将开始信号拉低;
always  @(posedge slow_clk or negedge rst_n)
        if(!rst_n)
                start_cnt <= 0;
        else if(start_cnt==1)
                start_cnt <= 0;  
        else if(start_en==1)
                start_cnt <= start_cnt+1; 
        else
                start_cnt <= 0;
                              
/**********************************************************************/
//TCL549开始发送数据,AD_CLK开始工作,
//由于是8位AD芯片,所以只需要转换8次即可,
//及数据转换使能只需要保持8个时钟周期。
/**********************************************************************/                                  
always  @(posedge slow_clk or negedge rst_n)
        if(!rst_n)
                AD_EN <= 0;
        else if(start_cnt==1 && start_en==1)
                AD_EN <= 1;  
        else if(AD_cnt == 7) //计数器到7信号拉低,
                AD_EN <= 0;               
always  @(posedge slow_clk or negedge rst_n)
        if(!rst_n)
                AD_cnt <= 0;
        else if(AD_EN==1)
                AD_cnt <= AD_cnt+1; 
        else    
                AD_cnt <= 0;  

/**********************************************************************/
//TCL549发送数据结束后,AD_CLK停止工作,
//但需要等待至少17us数据才能输出,
//及数据转换到输出至少要保持17个时钟周期。
/**********************************************************************/     
always  @(posedge slow_clk or negedge rst_n)
        if(!rst_n)
                end_en <= 0;
        else if(AD_cnt==7 && AD_EN==1)
                end_en <= 1;  
        else if(end_cnt == 16)
                end_en <= 0; 
always  @(posedge slow_clk or negedge rst_n)
        if(!rst_n)
                end_cnt <= 0;
        else if(end_en==1)
                end_cnt <= end_cnt+1; 
        else    
                end_cnt <= 0; 
                
/**********************************************************************/
//将从TCL549读取出来的数据转换成8bit数据
//因为TCL549为8位AD芯片
/**********************************************************************/
always  @(posedge slow_clk or negedge rst_n)
        if(!rst_n)
                tmp_data <= 8‘h00;
        else if(AD_EN==1)
                tmp_data <= {tmp_data[6:0],AD_dat}; 

/**********************************************************************/
//当数据转换完后保持至少17us才能把数据输出,传给data储存器。
/**********************************************************************/              
always  @(posedge slow_clk or negedge rst_n)
        if(!rst_n)
                data <= 8‘h00;
        else if(end_cnt==16 && end_en==1)
                data <= tmp_data;  
                
/**********************************************************************/
//将8bit的数据计算成电压=(data*精度*电压最大值)/255;
/**********************************************************************/                  
always  @(posedge slow_clk or negedge rst_n)
        if(!rst_n)
                out_data <= 11‘h00;
        else 
                out_data <= (data*100*25)/255;                             
                
endmodule           

 3. 16进制转十进制BCD码代码模块如下:

module  BCD_CTRL(
        input   wire            slow_clk,
        input   wire            rst_n,
        input   wire[11:0]      in_data,

        output  reg[3:0]      units,
        output  reg[3:0]      tens,
        output  reg[3:0]      hundreds,
        output  reg[3:0]      thousand         
                );
                
                
integer i;
always  @(posedge slow_clk) 
        begin
            units    = 4‘d0;       
            tens     = 4‘d0;                            
            hundreds = 4‘d0;
            thousand = 4‘d0;
         
        for(i=0;i<12; i=i+1)
        begin
                if(units>=5)
                        units = units +3;
                if(tens>=5)
                        tens  = tens  +3; 
                if(hundreds>=5)
                        hundreds  = hundreds  +3;   
                if(thousand>=5)
                        thousand  = thousand  +3; 
         
                thousand    =  thousand <<1;
                thousand[0] =  hundreds[3];
                 
                hundreds    =  hundreds <<1;
                hundreds[0] =  tens[3];
                  
                tens        =  tens <<1;
                tens[0]     =  units[3]; 
                
                units       =  units <<1;
                units[0]    =  in_data[11-i];                                                                                                                        
        end     
        end 
endmodule     

4. 数码管显示功能代码模块如下:

module  seg_play(
        input   wire            clk  ,    //输入的1MHZ时钟
        input   wire            rst_n,    //输入的系统复位信号      
        input   wire[3:0]       units,    //显示第三个小数位;0.001v
        input   wire[3:0]       tens ,    //显示第二个小数位0.01v
        input   wire[3:0]       hundreds, //显示第一个小数位0.01v
        input   wire[3:0]       thousand, //显示整数部分  
        
       output   reg[2:0]        sel,      //数码管位选信号      
       output   reg[7:0]        seg       //数码管段选信号      

        );
        
reg[12:0]       sel_cnt;//位选刷新计数器
reg             sel_en; //位选信号使能,用于显示小数点
reg[3:0]        num;    //用来存储要显示的数据

parameter       SEL_NUM = 99; //单个数码管刷新时间;=(SEL_NUM+1)* 1us

//位选刷新计数;
always @(posedge clk or negedge rst_n)
       if(!rst_n)
              sel_cnt <= 0;
       else if(sel_cnt==SEL_NUM)
              sel_cnt <= 0;
       else
              sel_cnt <= sel_cnt+1;
              
//位选刷新,因为只有4个0--9的数据 ;故只需要点亮四个数码管即可,点亮的分别为:2号、3号、4号、5号数码管。             
always @(posedge clk or negedge rst_n)  
       if(!rst_n)
              sel <= 3‘b111; 
       else  if(sel==5 && sel_cnt==SEL_NUM) 
              sel <= 3‘d2;
       else if(sel_cnt==SEL_NUM)
              sel <= sel + 1 ;
              
//数码管没刷新一个周期就将sel_en取反一次,用于显示小数点。              
always @(posedge clk or negedge rst_n)
       if(!rst_n)
              sel_en <= 3‘b111; 
       else if(sel==5&&sel_cnt==SEL_NUM)
              sel_en <= ~sel_en;              

//传值储存,用于显示在数码管上
always @(posedge clk or negedge rst_n)
       if(!rst_n)
              num <= 0;
       else case(sel)
                3‘d2 :       num <= thousand;   //当数码管刷新到2号数码管时,将整数部分的数据存储在num中;
                3‘d3 :       num <= hundreds;   //当数码管刷新到3号数码管时,将第一个小数部分的数据存储在num中;
                3‘d4 :       num <= tens;       //当数码管刷新到4号数码管时,将第二个小数部分的数据存储在num中;
                3‘d5 :       num <= units;      //当数码管刷新到5号数码管时,将第三个小数部分的数据存储在num中;
                default:  
                             num <= 0;
       endcase                
              
 //数码管显示  
always @(posedge clk or negedge rst_n)
       if(!rst_n)
              seg <=  8‘hff; 
       else if(sel_en==0&&sel==2)       //当sel_en为0时,并且数码管刷新到二号数码管时,将小数点点亮;                  
                     seg <=  8‘h7f;     // 本次刷新不显示整数部分;在下一次数码管刷新时显示.            
       else case(num)                   //将num存储器中的数据显示到数码管上,刚好与sel同步。
                      0:     seg <= 8‘hc0;
                      1:     seg <= 8‘hf9;
                      2:     seg <= 8‘ha4;
                      3:     seg <= 8‘hb0;
                      4:     seg <= 8‘h99;
                      5:     seg <= 8‘h92;
                      6:     seg <= 8‘h82;   
                      7:     seg <= 8‘hf8;
                      8:     seg <= 8‘h80;
                      9:     seg <= 8‘h90;
                      10:    seg <= 8‘h88;
                      11:    seg <= 8‘h83;
                      12:    seg <= 8‘hc6;
                      13:    seg <= 8‘ha1;
                      14:    seg <= 8‘h86;
                      15:    seg <= 8‘h8e;
                      default:
                             seg <=  8‘hff;
                endcase           
          
endmodule  

5. 顶层连线布线:

技术分享

 

6.功能引脚绑定文件如下:

       

NET "seg[7]" LOC = P117;
NET "seg[6]" LOC = P121;
NET "seg[5]" LOC = P118;
NET "seg[4]" LOC = P116;
NET "seg[3]" LOC = P115;
NET "seg[2]" LOC = P114;
NET "seg[1]" LOC = P120;
NET "seg[0]" LOC = P119;
NET "sel[2]" LOC = P14;
NET "sel[1]" LOC = P15;
NET "sel[0]" LOC = P16;
NET "clk" LOC = P24;
NET "rst_n" LOC = P94;


NET "seg[7]" IOSTANDARD = LVCMOS33;
NET "seg[6]" IOSTANDARD = LVCMOS33;
NET "seg[5]" IOSTANDARD = LVCMOS33;
NET "seg[4]" IOSTANDARD = LVCMOS33;
NET "seg[3]" IOSTANDARD = LVCMOS33;
NET "seg[2]" IOSTANDARD = LVCMOS33;
NET "seg[1]" IOSTANDARD = LVCMOS33;
NET "seg[0]" IOSTANDARD = LVCMOS33;
NET "sel[2]" IOSTANDARD = LVCMOS33;
NET "sel[1]" IOSTANDARD = LVCMOS33;
NET "sel[0]" IOSTANDARD = LVCMOS33;
NET "clk" IOSTANDARD = LVCMOS33;
NET "rst_n" IOSTANDARD = LVCMOS33;

# PlanAhead Generated IO constraints 

NET "AD_CLK" IOSTANDARD = LVCMOS33;
NET "AD_CS_N" IOSTANDARD = LVCMOS33;
NET "AD_dat" IOSTANDARD = LVCMOS33;

# PlanAhead Generated physical constraints 

NET "AD_CLK" LOC = P126;
NET "AD_CS_N" LOC = P123;
NET "AD_dat" LOC = P124;

上板烧写,我们就实现了AD转换的过程,感谢大家对V3学院的支持,FPGA培训,就选v3学院,雄厚的师资,高深的技术,v3学院将在你的FPGA学习路上祝你一臂之力。

此文章为原创出自 V3学院 www.v3edu.org;

verilog语言实现TCL549(AD)转换