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;

时间: 2024-10-06 00:29:25

verilog语言实现TCL549(AD)转换的相关文章

verilog实验3:AD转换后串口输出到PC端

一.实验任务 通过tcl549AD转换芯片将模拟电压信号转换为数字信号,并通过串口显示到电脑上.此AD转换芯片为串行转换芯片,且转换速率要和串口选择的速率匹配.等待串口发送完后,再进行下一次AD转换.就实际应用而言,此转换速率有点低. 二.代码开发 根据AD芯片的芯片手册编写程序.以下为顶层程序. //将实时转换的数字结果通过串口传输到PC上 module adc_top ( clk, rst, ad_cs_out,//--TLC549片选信号 ad_clk_out,//--TLC549时钟信号

Verilog语言

Verilog HDL是一种硬件描述语言(HDL:Hardware Description Language),以文本形式来描述数字系统硬件的结构和行为的语言,两种HDL均为IEEE标准.Verilog HDL和VHDL是世界上最流行的两种硬件描述语言,都是在20世纪80年代中期开发出来的. Verilog是由Gateway Design Automation公司的工程师Prabhu Goel和菲尔·莫比(Phil Moorby)发明的.1990年,Gateway设计自动化被Cadence公司收

STM32F10X入门指南---AD转换

首先,点击下面的链接下载我们需要使用的代码.链接 1.添加必要的文件: 之前我们说过,有三个文件是必须添加的,这三个文件分别是:startup_stm32f10x_xd.s ,stm32f10x_rcc.c ,system_stm32f10x.c.其中,前面的xd是根据你的芯片的容量来选择的.这三个文件都可以在千帆提供的代码中找到.文件路径:Core.rar\Core\STM32\Source\Must . 另外,如果想操作IO口,必须添加千帆的一个库文件DeviceBase.cpp.文件路径:

C语言---整型字符串转换

C语言提供了几个标准库函数,能够将随意类型(整型.长整型.浮点型等)的数字转换为字符串.下面是用itoa()函数将整数转 换为字符串的一个样例: # include <stdio.h>    # include <stdlib.h> void main (void)    {    int num = 100;    char str[25];    itoa(num, str, 10);    printf("The number ’num’ is %d and the

(七)ADC0809 模数转换的学习 AD转换

ADC0808 引脚功能各引脚功能如下: 1-5和26-28(IN0-IN7):8路模拟量输入端 8.14.15和17-21:8位数字量输出端 22(ALE):地址锁存允许信号,输入,高电平有效. 6(START): A/D转换启动脉冲输入端,输入一个正脉冲(至少100ns宽)使其启动(脉冲上升沿使0809复位,下降沿启动A/D转换). 7(EOC): A/D转换结束信号,输出,当A/D转换结束时,此端输出一个高电平(转换期间一直为低电平). 9(OE):数据输出允许信号,输入,高电平有效.  

C语言 字符串和数字转换函数

atof(将字符串转换成浮点型数) 相关函数 atoi,atol,strtod,strtol,strtoul 表头文件 #include <stdlib.h> 定义函数 double atof(const char *nptr); 函数说明 atof()会扫描参数nptr字符串,跳过前面的空格字符,直到遇上数字或正负符号才开始做转换,而再遇到非数字或字符串结束时('\0')才结束转换,并将结果返回.参数nptr字符串可包含正负号.小数点或E(e)来表示指数部分,如123.456或123e-2.

s5pv210 AD转换

1:ADC:Analog-to-Digital Converter,模拟信号转数字信号,自然界一般为模拟信号,而SoC需要数字信号,所以之间通信需要ADC. 2:转换原理: 以逐次逼近式AD转换为例: 这里以8位为例,而S5pv210SoC是可选10bit.12bit: (1) 首先发出"启动信号"信号S.当S由高变低时,"逐次逼近寄存器SAR"清0,DAC输出Vo=0,"比较器"输出1.当S变为高电平时, "控制电路"使SA

STM8S AD转换

终于把bochs和gdb连起来了,下面描述下步骤以作记录. 1.安装bochs 前面有篇文章介绍了bochs源码编译安装过程,这里安装也非常相似,只是命令稍微有些不同 ./configure --enable-gdb-stub make make install 2.下载调试映像 http://oldlinux.org/Linux.old/bochs/linux-0.11-gdb-rh9-050619.tar.gz 在这里下载压缩包,里面含有不少东西,要在ubuntu下使用需要修改配置的内容,参

Verilog语言:还真的是人格分裂的语言

人气腹语术师天愿在现场披露了被人偶搭档夺取灵魂的腹语术师将妻子杀害的表演节目.天愿真的陷入了多重人格,命令自己杀害妻子和子的人偶的人格出现了.为了不(让自己)杀害和弟子登川有外遇的妻子,天愿提出委托想要监视,然而第二天早上,和子真的被杀害的事件发生了.天愿坦白很可能是在自己的意识失去的时候杀害的--"(----"真相只有一个"<名侦探柯南>一向是老衲喜欢的动画片)这个是第806回<腹语師的错觉>的介绍. 人有双重人格,或者叫人格分裂,那么语言呢?Ver