ADC芯片TLC549 Verilog

ref

TLC549引脚图
在这里插入图片描述
REF+:正基准电压输入 2.5V≤REF+≤Vcc+0.1。

REF-:负基准电压输入端,-0.1V≤REF-≤2.5V。且要求:(REF+)-(REF-)≥1V。

VCC:系统电源3V≤Vcc≤6V。

GND:接地端。

/CS:芯片选择输入端,要求输入高电平 VIN≥2V,输入低电平 VIN≤0.8V。

DATA OUT:转换结果数据串行输出端,与 TTL 电平兼容,输出时高位在前,低位在后。

ANALOGIN:模拟信号输入端,0≤ANALOGIN≤Vcc,当 ANALOGIN≥REF+电压时,转换结果为全"1"(0FFH),ANALOGIN≤REF-电压时,转换结果为全"0"(00H)。

I/O CLOCK:外接输入/输出时钟输入端,同于同步芯片的输入输出操作,无需与芯片内部系统时钟同步。
在这里插入图片描述

https://www.cnblogs.com/yuphone/archive/2011/04/24/2026377.html

`define AD_CLK_TIME 10'd45

`define AD_CLK_TIME_HALF 10'd22

module AD

(

input   sys_clk_50m,

input   rst_n,

output reg  poc_ad_cs,  //TLC549的片选

output reg  poc_ad_clk, //TLC549的I/O CLOCK

input pid_ad_data,  //TLC549的数据串行输出端,相对于FPGA为输入

output reg [3:0]    o_vol_int,  //转换后输出电压的整数部分

output reg [3:0]    o_vol_dec   //转换后输出电压的小数部分

);

reg n_ad_cs;    //AD_CS的下一个状态

reg n_ad_clk;   //AD_CLK的下一个状态

reg [ 2:0]  ad_fsm_cs;  //状态机的当前状态

reg [ 2:0]  ad_fsm_ns;  //状态机的下一个状态

wire    [ 3:0]  n_o_vol_int;    //o_vol_int的下一个状态

wire    [ 3:0]  n_o_vol_dec;    //o_vol_dec的下一个状态

reg [ 5:0]  time_cnt;   //用于记录一个时钟所用时间的定时器

reg [ 5:0]  n_time_cnt; //time_cnt的下一个状态

reg [ 5:0]  bit_cnt;    //用来记录时钟周期个数的计数器

reg [ 5:0]  n_bit_cnt;  //bit_cnt的下一个状态

reg [ 7:0]  data_out;   //用来保存稳定的AD数据

reg [ 7:0]  n_data_out; //data_out的下一个状态

reg [ 7:0]  ad_data_reg;    //用于保存数据的移位寄存器

reg [ 7:0]  n_ad_data_reg;  //ad_data_reg_n的下一个状态

wire    [11:0]  mid1;   //数据转换电压的整数部分

wire    [11:0]  mid2;   //数据转换电压的小数部分

parameter   FSM_IDLE    = 3'h0; //状态机的初始状态;

parameter   FSM_READY   = 3'h1; //满足CS有效时的第一个1.4us的延时状态

parameter   FSM_DATA    = 3'h2; //读取8个数据状态

parameter   FSM_WAIT_CONV   = 3'h3; //等待转换状态,等待17us;

parameter   FSM_END = 3'h4; //结束的状态

/********************************************

状态机转换

********************************************/

always @ (posedge sys_clk_50m or negedge rst_n)

if (!rst_n)

ad_fsm_cs <= FSM_IDLE;

else

ad_fsm_cs <= ad_fsm_ns;

always @ (*)

begin

case(ad_fsm_cs)

FSM_IDLE:

if((bit_cnt == 6'd2 ) && (time_cnt == `AD_CLK_TIME))

ad_fsm_ns = FSM_READY;

else

ad_fsm_ns = ad_fsm_cs;

FSM_READY:

if((bit_cnt == 6'd1 ) && (time_cnt == `AD_CLK_TIME))

ad_fsm_ns = FSM_DATA;

else

ad_fsm_ns = ad_fsm_cs;

FSM_DATA:

if((bit_cnt == 6'd8 ) && (time_cnt == `AD_CLK_TIME))

ad_fsm_ns = FSM_WAIT_CONV;

else

ad_fsm_ns = ad_fsm_cs;

FSM_WAIT_CONV:

if((bit_cnt == 6'd18) && (time_cnt == `AD_CLK_TIME))

ad_fsm_ns = FSM_END;

else

ad_fsm_ns = ad_fsm_cs;

FSM_END:

ad_fsm_ns = FSM_READY;

default:ad_fsm_ns = FSM_IDLE;

endcase

end

/*********************************************************

时钟计数器,用以产生1.1M的时钟

*********************************************************/

always @ (posedge sys_clk_50m or negedge rst_n)

if  (!rst_n)

time_cnt <= 6'd0;

else

time_cnt <= n_time_cnt;

always @ (*)

if (time_cnt == `AD_CLK_TIME)

n_time_cnt = 6'd0;

else

n_time_cnt = time_cnt + 6'd1;

/*********************************************

位计数器

*********************************************/

always @ (posedge sys_clk_50m or negedge rst_n)

if (!rst_n)

bit_cnt <= 6'd0;

else

bit_cnt <= n_bit_cnt;

always @ (*)

begin

if (ad_fsm_cs != ad_fsm_ns)

n_bit_cnt = 6'h0;

else if ( time_cnt== `AD_CLK_TIME_HALF )

n_bit_cnt = bit_cnt + 6'h1;

else

n_bit_cnt = bit_cnt;

end

/*******************************************************

产生外接时钟输入端的时钟信号,频率为1.1M,占空比约为50%

********************************************************/

always @ (posedge sys_clk_50m or negedge rst_n)

if (!rst_n)

poc_ad_clk <= 1'b0;

else

poc_ad_clk <= n_ad_clk;

always @(*)

begin

if (ad_fsm_cs != FSM_DATA)

n_ad_clk = 1'b0;

else if ( time_cnt == `AD_CLK_TIME_HALF )

n_ad_clk = 1'b1;

else if (time_cnt == `AD_CLK_TIME)

n_ad_clk = 1'b0;

else

n_ad_clk = poc_ad_clk;

end

/****************************************************

对TLC549的片选信号进行控制

*****************************************************/

always @ (posedge sys_clk_50m or negedge rst_n)

if (!rst_n)

poc_ad_cs <= 1'b0;

else

poc_ad_cs <= n_ad_cs;

always @ (*)

if ((ad_fsm_cs == FSM_DATA) || (ad_fsm_cs == FSM_READY))

n_ad_cs = 1'b0;

else

n_ad_cs = 1'b1;

/******************************************************

对数据寄存器赋值

******************************************************/

always @ (posedge sys_clk_50m or negedge rst_n)

if (!rst_n)

ad_data_reg <= 8'd0;

else

ad_data_reg <= n_ad_data_reg;

always @ (*)

begin

if ((ad_fsm_cs == FSM_DATA) && (!poc_ad_clk) && (n_ad_clk))

n_ad_data_reg = {ad_data_reg[6:0],pid_ad_data};

else

n_ad_data_reg = ad_data_reg;

end

/*************************************************************

输出数据处理

*************************************************************/

always @ (posedge sys_clk_50m or negedge rst_n)

if (!rst_n)

data_out <= 8'd0;

else

data_out <= n_data_out;

always @ (*)

begin

if (ad_fsm_cs == FSM_END)

n_data_out = ad_data_reg;

else

n_data_out = data_out;

end

always @ (posedge sys_clk_50m or negedge rst_n)

if (!rst_n)

o_vol_int <= 4'd0;

else

o_vol_int <= n_o_vol_int;

always @ (posedge sys_clk_50m or negedge rst_n)

if (!rst_n)

o_vol_dec <= 4'd0;

else

o_vol_dec <= n_o_vol_dec;

assign mid1 = {2'h0,data_out[7:0],2'h0} + {4'h0,data_out[7:0]};

assign mid2 = {1'h0,mid1[7:0],3'h0} + {3'h0,mid1[7:0],1'h0};

assign n_o_vol_int = mid1[11:8];

assign n_o_vol_dec = mid2[11:8];

endmodule

//

显示在数码管上

//程序实现的功能:将测得模拟电压(0-255)转化数字电压显示在数码管上;
module adc_tlc549   //顶层模块;
     (
      clk,
      rst_n,
      analog_data,
      adc_cs_n,
      adc_clk,
      smg_sel,
      smg_data 
     
     );

input      clk;          //系统时钟,50MHZ;
input      rst_n;        //复位信号,低电平有效;
input      analog_data;  //模拟数据;
output     adc_cs_n;     //ADC_TLC549片选信号,低电平有效;
output     adc_clk;      //ADC_TLC549 I/O时钟,最大不超过1.1MHZ;
output[1:0]smg_sel;      //数码管片选;
output[7:0]smg_data;     //数码管段选;

wire adc_en;             //增加了adc_en使能信号来决定是否需要开启AD转换,当一个系统内部有多个模块时    
assign adc_en=1'b1;      //每一个模块都是可控制的,禁止使能,模块内部停止工作,此时功耗最低;

wire[3:0] vol_int;       //从A/D转换芯片输出的电压值的整数部分;
wire[3:0] vol_dec;       //从A/D转换芯片输出的电压值的小数部分;


adc_ctl     adc_ctl        //ADC控制模块
           (
            .clk(clk),
            .rst_n(rst_n),
            .analog_data(analog_data),
            .adc_en(adc_en),
            .adc_cs_n(adc_cs_n),
            .adc_clk(adc_clk),
            .vol_int(vol_int),
            .vol_dec(vol_dec)
                          
           );

smg        smg           //数码管模块
          (
           .clk(clk),
           .rst_n(rst_n),
           .data_1(vol_int),
           .data_2(vol_dec),
           .smg_sel(smg_sel),
           .smg_data(smg_data)
                
          ); 

endmodule                     
      

module adc_ctl    //ADC控制模块
      (
       clk,
       rst_n,
       analog_data,
       adc_en,
       adc_cs_n,
       adc_clk,
       vol_int,
       vol_dec   
        
      );

input      clk;             //系统时钟,50MHZ;
input      rst_n;           //复位信号,低电平有效;
input      analog_data;     //模拟数据;
input      adc_en;          //ADC使能信号;
output     adc_cs_n;        //ADC_TLC549片选信号,低电平有效;
output     adc_clk;         //ADC_TLC549 I/O时钟,最大不超过1.1MHZ;
output[3:0]vol_int;         //从A/D转换芯片输出的电压值的整数部分;
output[3:0]vol_dec;         //从A/D转换芯片输出的电压值的小数部分;

//1.1MHZ(909ns)   909ns/20ns=46=0x2E, 0x2E/2=0X17;
//17us   17000ns/20ns=850=0x352;
parameter ADC_CLK_CNT=6'h2e;
parameter ADC_CLK_HALF=6'h17;

parameter IDLE=     2'b00;   // 状态机的初始状态;
parameter READY=    2'b01;   // adc_cs_n有效时到adc_clk到第一个时钟到来时的状态,至少要1.4us;
parameter READ=     2'b10;   //是读ADC转化后数据的状态,8个时钟的上升沿逐位移入ADC数据线上的8位串行数据;
parameter WAIT_CONV=2'b11;   //是ADC正在转化数据需要消耗的时间,是17us;
reg[1:0] cstate;
reg[1:0] nstate;

reg[5:0] time_cnt;
always @ (posedge clk or negedge rst_n)
  begin
       if(!rst_n)
          time_cnt<=6'd0;
       else if(!adc_en) 
          time_cnt<=6'd0;
       else if(time_cnt==ADC_CLK_CNT) 
          time_cnt<=6'd0;
       else
          time_cnt<=time_cnt+1'b1;       
  end
  
reg [5:0] bit_cnt;
always @ (posedge clk or negedge rst_n)
  begin
        if(!rst_n)
           bit_cnt<=6'd0;
        else if(!adc_en)
       bit_cnt<=6'd0;    
        else if(cstate!=nstate)
           bit_cnt<=6'd0;        
        else if(time_cnt==ADC_CLK_HALF) 
          bit_cnt<=bit_cnt+1'b1;
                   
  end

always @ (posedge clk or negedge rst_n)
  begin
       if(!rst_n)
          cstate<=IDLE;
       else
          cstate<=nstate;   
  end  
  
always @ (*)
  begin
      
      
             case(cstate)
                 IDLE      :   
                           if((bit_cnt==6'h2)&&(time_cnt==ADC_CLK_CNT)&&(adc_en))
                              nstate=READY;
                           else
                              nstate=IDLE;
                 READY     :
                           if((bit_cnt==6'h1)&&(time_cnt==ADC_CLK_CNT))  //延时大约1.4us;
                              nstate=READ;
                           else
                              nstate=READY; 
                 READ      :
                           if((bit_cnt==6'h8)&&(time_cnt==ADC_CLK_CNT)) 
                              nstate=WAIT_CONV;
                           else
                             nstate=READ; 
                 WAIT_CONV : 
                            if((bit_cnt==6'h12)&&(time_cnt==ADC_CLK_CNT)) 
                                nstate=READY;
                            else
                                nstate=WAIT_CONV; 
                                  
                 default   :    nstate=IDLE;  
                               
             endcase                                               
        
            
  end

reg adc_clk_r;
always @ (posedge clk or negedge rst_n)
   begin
         if(!rst_n)
            adc_clk_r<=1'b0;
         else if(cstate!=READ)
            adc_clk_r<=1'b0; 
         else if(time_cnt==ADC_CLK_HALF)  
            adc_clk_r<=1'b1;
         else if(time_cnt==ADC_CLK_CNT)
            adc_clk_r<=1'b0;    
   end
   
assign adc_clk=adc_clk_r;

reg adc_cs_n_r;
always @ (posedge clk or negedge rst_n)
  begin
        if(!rst_n)
           adc_cs_n_r<=1'b0;
        else if(!adc_en) 
           adc_cs_n_r<=1'b1;  
        else if((cstate==READY)||(cstate==READ)) 
           adc_cs_n_r<=1'b0;
        else
           adc_cs_n_r<=1'b1;     
           
  end
 
assign  adc_cs_n=adc_cs_n_r; 

// 脉冲边沿检测
reg adc_clk_1;
reg adc_clk_2;
always @ (posedge clk or negedge rst_n)
  begin
       if(!rst_n)
          begin
             adc_clk_1<=1'b0;
             adc_clk_2<=1'b0;
          end
       else
          begin
              adc_clk_1<=adc_clk;
              adc_clk_2<=adc_clk_1;
          end 
  end 
  
wire pos_clk;
assign  pos_clk=adc_clk_1&(~adc_clk_2) ;   //脉冲上升沿边沿检测;

reg[7:0] adc_data_r ;
always @(posedge clk or negedge rst_n)
  begin
         if(!rst_n)
           adc_data_r<=8'd0;
         else if((cstate==READ)&&(pos_clk)) 
           adc_data_r={adc_data_r[6:0],analog_data}; 
  end   

reg[7:0] adc_data;
always @(posedge clk or negedge rst_n)
  begin
        if(!rst_n)
          adc_data<=8'd0;
        else if(cstate==WAIT_CONV) 
          adc_data<=adc_data_r;   
  end

//将读到数字(0-255)转化成电压信号;
//adc_data/ff=voltage/5;
//voltage=5*adc_data/ff; 
//整数部分: =((adc_data<<2)+adc_data)>>8;
//小数部分: =((5adc_data&&0xff)*10)>>8;
wire[11:0] num_1;

assign num_1={2'h0,adc_data[7:0],2'h0}+{4'h0,adc_data[7:0]};  //5adc_data;

wire[11:0] num_2;

assign num_2={1'h0,num_1[7:0],3'h0}+{3'h0,num_1[7:0],1'h0};  //*10;

assign vol_int=num_1[11:8];    //整数部分
assign vol_dec=num_2[11:8];    //小数部分
      
endmodule
      

module smg       //数码管模块
          
      (
        clk,
        rst_n,
        data_1,
        data_2,
        smg_sel,
        smg_data
      );

input       clk ;
input       rst_n;
input[3:0]  data_1;
input[3:0]  data_2;
output[1:0] smg_sel;
output[7:0] smg_data;

parameter scan_num=16'hc350; //1ms;

reg[15:0] cnt;
always @(posedge clk or negedge rst_n)
  begin
       if(!rst_n)
          cnt<=16'd0;
       else if(cnt==scan_num)
          cnt<=16'd0;
       else   
         cnt<=cnt+1'b1;   
  end
  
reg smg_sel_num;
always @(posedge clk or negedge rst_n)
   begin
       if(!rst_n)
         smg_sel_num<=1'b0;
       else if(cnt==scan_num)
         smg_sel_num<=smg_sel_num+1'b1;  
   end



reg[1:0] smg_sel_r;
always @(*)        //数码管片选;   
  begin
      case(smg_sel_num)
          1'b0   : smg_sel_r=2'b01;
          1'b1   : smg_sel_r=2'b10;
          default: smg_sel_r=2'b11;
      endcase    
  end
assign smg_sel=smg_sel_r;
  
reg[3:0] smg_data_num;      //数码管要显示的数;
always @(*)
  begin
      case(smg_sel_num)
          1'b0    : smg_data_num=data_1;
          1'b1    : smg_data_num=data_2;
          default : smg_data_num=4'h0;
      endcase    
  end
  
reg[7:0] smg_data_r;
always @(*)              //是否要显示小数点 
     begin
         case(smg_sel_num)
            1'b0   : smg_data_r[7]=1'b0;
            1'b1   : smg_data_r[7]=1'b1;
            default: smg_data_r[7]=1'b1;
         endcase      
            
     end

always @ (*)
 begin
       case(smg_data_num)
          4'h0 :smg_data_r[6:0]=7'b100_0000;
          4'h1: smg_data_r[6:0]=7'b111_1001;
          4'h2: smg_data_r[6:0]=7'b010_0100;
          4'h3: smg_data_r[6:0]=7'b011_0000;
          4'h4: smg_data_r[6:0]=7'b001_1001;
          4'h5: smg_data_r[6:0]=7'b001_0010;
          4'h6: smg_data_r[6:0]=7'b000_0010;
          4'h7: smg_data_r[6:0]=7'b111_1000;
          4'h8: smg_data_r[6:0]=7'b000_0000;
          4'h9: smg_data_r[6:0]=7'b001_0000;
          default:smg_data_r[6:0]=7'b111_1111; 
       endcase   
          
 end  
assign smg_data=smg_data_r; 
endmodule

https://www.cnblogs.com/yuphone/archive/2011/04/24/2026377.html

  • 2
    点赞
  • 21
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
cyclone4 FPGA读写8位AD转换器TLC549实验Verilog逻辑源码Quartus11.0工程文件, FPGA型号为EP4CE6E22C8,可以做为你的学习设计参考。 ( clk, //系统50MHZ时钟 adc_sclk, //AD TLC549的时钟 data, //AD TLC549的数据口 cs, //AD TLC549的片选择 wei, //数码管的为选择 duan //数码管的7段码 ); input clk; input data; output cs; output adc_sclk; output[7:0] duan; output[3:0] wei; reg cs,adc_sclk,clk1k,clk1ms; reg[15:0] count; reg[24:0] count1ms; reg[3:0] cnt; reg[2:0] number; reg[1:0] state; reg[3:0] wei; reg ledcs; reg [7:0] duan; reg[7:0] dataout; reg[16:0] tenvalue; parameter sample=2'b00, display=2'b01; /**********产生100k的采集时钟信号*********/ always@(posedge clk) begin if(count<=250) count<=count+1'b1; else begin count<=0; adc_sclk<=~adc_sclk; end end /*******产生周期为1ms即1kHz的信号*********/ always@(posedge clk) begin if(count1ms>25'd25000) begin clk1ms<=~clk1ms; count1ms<=0; end else count1ms<=count1ms+1; end /*********AD采样程序**************/ always@(negedge adc_sclk) begin case(state) sample: begin cs<=0; dataout[7:0]<={dataout[6:0],data}; if(cnt>4'd7) begin cnt<=0; state<=display; end else begin cnt<=cnt+1; state<=sample; end end display: begin cs<=1;//关AD片选 tenvalue<=(tendata((dataout>>4)&8'b0000_1111)*16+ tendata(dataout&8'b0000_1111))*129;// //得到采集的数据 state<=sample; end default: state<=display; endcase end /***********2进制转十进制函数*************/ function[7:0] tendata;//返回一个4位的数字 input[7:0] datain; begin case(datain) 4'b00000000: tendata=4'd0;//0 4'b00000001: te

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值