基础篇-verilog-单路串行ADC-TLC549

注明:虽然此实验来自于诸多入门教程,其中包括gao石的,但我个人觉得他的时序写的不好,没有完全遵循芯片的时序,它直接用AD——CLK的上升沿读取AD_DATA, 但是,事实上,芯片时序,并不是在8位全在上升沿读取。
8位串行模数转换器
8位开关电容逐次逼近的方法实现A/D
内部具有4MHz的系统时钟,转换速度小于17us
允许的最大转换速率是40000次/s(一个周期,采样下来,再读取。)
电源3V到6V
方便采用3线串行接口方式与各种微处理器进行连接

1

2
4
在这里插入图片描述

最高有效位(A7)在CS降低后自动置于数据输出总线上。剩下的7位(a6 - a0)在前7个I / O时钟的边缘上被锁定了。B7-B0遵循同样的方式。
根据NOTEs的意思,也就是DA_DATA遵循某种时序串行吐出data,那么,在何时才吐出的是DATA的哪一位呢?
这就要遵循一定的时序关系。
这种关系便是:
在第一个CLK的上升沿读取A7,第一个CLK到第六个CLK的下降沿读取A6——A0。
思路:状态机:3个状态
1:转换状态(也可视作初始状态)
2:1.4us(CS由高变低状态)
3:DA_CLK(采样状态)
//-----------------------------------------------------------------------------2018.11.6 23:00
//------------------------------------------------------------------------------- 明日再来写
7
系统时钟是4M,并非是采样时钟,注意采样在SAMPLE阶段,也就是后4个时钟周期进行的。外接时钟速率1.1M并不是指的采样速率,那是接口读取速率。串行芯片,我门需要注意的是一个周期,采样时间+转换时间=1/40_000 而在并行芯片中,往往是给的CLOCK即采样时钟。
下图是AD904芯片时序,在DATA_change阶段进行采样,并进行完成相关的量化。

下面的代码,串行TLC549,采样后,存储在8位寄存器当中

module AD_TLC549
#(
	parameter T_conv=12'd850,//转换时间50M*17us=850
	parameter T_su=8'd70,//准备时间50M*1.4us=70us
	parameter AD_CLK_nop=4'd8,//定义8个AD_CLK
	parameter AD_CLK_circle_time=6'd46,//0.92us
	parameter AD_CLK_circle_time_half=6'd23  //23*50=0.46us
)
(
input sys_clk,
input RST_N,
input AD_DATA,
//-------------------
output AD_CLK,
output CS_N,

output reg [AD_CLK_nop-1:0] AD_out_DATA //串行的AD_DATA转并行的8位寄存器




);

wire AD_CLK_edg;
reg AD_out_reg_finish;//串行转并行完成标志
reg [11:0] T_conv_cnt=0;//转换时间的计数器
reg [7:0] T_su_cnt=0;//准备时间的计数器
reg [3:0] AD_CLK_cnt=0;//AD_CLK个数计数器
reg [5:0]    AD_CLK_circle_time_cnt=0;//一个AD_CLK的高/低电平时间计数器
reg AD_CLK_reg_reg;//用于缓存一拍AD_CLK,实现下降沿检测



//设置输出寄存器
reg AD_CLK_reg=0;
reg CS_N_reg;

reg [AD_CLK_nop-1:0] AD_out_reg;





//采用三段式状态机
/*有限状态机,三段式建模风格*/
/*三个过程*/
//状态编码
localparam  transition_state = 3'b001,//数据转换状态
				ready_1_4_state  = 3'b010,//准备采样状态
				Acess_sample_state     = 3'b100;//采样状态
//这里可以把数据转换状态视作初始状态,1没有时钟,2 CS_N为高,也无效。
reg  [2:0]  now_state=transition_state;
reg  [2:0]	next_state=transition_state;

//1.实现状态转换:实现当前状态now_state到next_state的转换
always @ (posedge sys_clk)
begin
	if(!RST_N)
		now_state<=transition_state;
	else
	   now_state<=next_state;
end
//2.设置状态切换条件,产生下一个状态
always@(*)
begin
	case(now_state)
	
	 transition_state:
							if(T_conv_cnt==T_conv)   //如果转换时间36
							next_state=ready_1_4_state;
							else
							next_state=transition_state;
	 
	 ready_1_4_state:
							if(T_su_cnt==T_su)
							next_state=Acess_sample_state;
							else
							next_state=ready_1_4_state;							
	 Acess_sample_state:
							if(AD_CLK_cnt<AD_CLK_nop)
							next_state=Acess_sample_state;
							else
							next_state=transition_state;							

	 default:;
	 
	 endcase
	 
end

//3.产生每个状态机的条件输出值
always @ (posedge sys_clk)
begin
	case(next_state)
			 transition_state:
									begin
	      						T_conv_cnt<=T_conv_cnt+1;
									T_su_cnt<=0;
									AD_CLK_cnt<=0;
									end
	      						
	       
	       ready_1_4_state:
									begin
         						T_su_cnt<=T_su_cnt+1;
									T_conv_cnt<=0;
									end
         						
		    Acess_sample_state:
									begin
										if (AD_CLK_edg)
											AD_CLK_cnt <= AD_CLK_cnt + 1'b1;
										else
											AD_CLK_cnt <= AD_CLK_cnt;
									end
	endcase
											 
end
//4.设置每个输出值
//1.CS_N的输出值
always@(posedge sys_clk)
begin
   if(!RST_N)
	   begin
		CS_N_reg<=1;     //
		end	    
	else if(now_state==transition_state)
	   begin
		CS_N_reg<=1;     //
		end
	else 
	   begin
		CS_N_reg<=0;   //CS_N低电平有效
		end	
end
assign CS_N=CS_N_reg;

//2.AD_CLK的输出值
always@(posedge sys_clk)
begin

	if(!RST_N)
	AD_CLK_circle_time_cnt<=0;
	else if(now_state==Acess_sample_state)
	AD_CLK_circle_time_cnt<=(AD_CLK_circle_time_cnt<AD_CLK_circle_time-1)?(AD_CLK_circle_time_cnt+1'b1):0;
	else
	AD_CLK_circle_time_cnt<=0;
end

always@ (posedge sys_clk)
begin
	if(!RST_N)
	AD_CLK_reg<=0;
	else if(now_state==Acess_sample_state)
	AD_CLK_reg <= (AD_CLK_circle_time_cnt <=AD_CLK_circle_time_half-1) ? 1'b1 : 1'b0;
	else
	AD_CLK_reg<=0;
end
//3.AD_CLK_nop_edg控制
always @ (posedge sys_clk)
begin
	AD_CLK_reg_reg<=AD_CLK_reg; //寄存一拍
end


 assign AD_CLK_edg = AD_CLK_reg_reg&(~AD_CLK_reg);//判断下降沿
 
 assign AD_CLK=AD_CLK_reg;
  
  
//4.AD_DATA_reg控制读取........控制在什么时候,把串行AD_DATA的数据写入多位的寄存器AD_DATA_reg之中,时机不对,自然写入的数肯定就不对
always @ (posedge sys_clk)
begin
	if((now_state==ready_1_4_state)&(next_state==Acess_sample_state))
    AD_out_reg[AD_CLK_nop-1]<=AD_DATA;
	 
	else if(AD_CLK_edg&(AD_CLK_cnt<=AD_CLK_nop-1))
	AD_out_reg[AD_CLK_nop-1-1:0]<={AD_out_reg[AD_CLK_nop-1-1-1:0],AD_DATA};//移位循环实现串行转并行
	
	else if(AD_CLK_cnt==AD_CLK_nop)//在第8个时钟下降沿的时候,代表了AD_DATA_reg已经移位完成,之所以没有刚好设置第7个下降沿,是担心第7个下降沿还在读取。
	AD_out_reg_finish<=1;
	
	else
   begin
	AD_out_reg<=AD_out_reg;
	AD_out_reg_finish<=0;	
	end
	
end

always @ (posedge sys_clk)
begin
	if(AD_out_reg_finish==1)  //只有在读取8位完毕后,再将这8位数更新
	AD_out_DATA<=AD_out_reg;
	else
	AD_out_DATA<=AD_out_DATA;
end


endmodule


         						


         						
// Copyright (C) 1991-2013 Altera Corporation
// Your use of Altera Corporation's design tools, logic functions 
// and other software and tools, and its AMPP partner logic 
// functions, and any output files from any of the foregoing 
// (including device programming or simulation files), and any 
// associated documentation or information are expressly subject 
// to the terms and conditions of the Altera Program License 
// Subscription Agreement, Altera MegaCore Function License 
// Agreement, or other applicable license agreement, including, 
// without limitation, that your use is for the sole purpose of 
// programming logic devices manufactured by Altera and sold by 
// Altera or its authorized distributors.  Please refer to the 
// applicable agreement for further details.

// *****************************************************************************
// This file contains a Verilog test bench template that is freely editable to  
// suit user's needs .Comments are provided in each section to help the user    
// fill out necessary details.                                                  
// *****************************************************************************
// Generated on "11/08/2018 16:19:41"
                                                                                
// Verilog Test Bench template for design : AD_TLC549
// 
// Simulation tool : ModelSim (Verilog)
// 

`timescale 1 ns/ 1 ps
module AD_TLC549_vlg_tst();
// constants                                           
// general purpose registers
reg eachvec;
// test vector input registers
reg AD_DATA;
reg RST_N;
reg sys_clk;
// wires                                               
wire AD_CLK;
wire [7:0]  AD_out_DATA;
wire CS_N;

// assign statements (if any)                          
AD_TLC549 i1 (
// port map - connection between master ports and signals/registers   
	.AD_CLK(AD_CLK),
	.AD_DATA(AD_DATA),
	.AD_out_DATA(AD_out_DATA),
	.CS_N(CS_N),
	.RST_N(RST_N),
	.sys_clk(sys_clk)
);
initial                                                
begin                                                                                           
$display("Running testbench");  
#0 sys_clk=0;
#0 RST_N=0;
#40 RST_N=1;
#0 AD_DATA=1;

                       
end 
//------------------------------------------                                                   
always                                                                
begin                                                  
 #10 sys_clk=~sys_clk; 


 
end                                                    
endmodule





5
在第8个AD_clk过后才更新AD_out_DATA


整体效果:
在这里插入图片描述

符合AD_CLK 一个周期0.92us,半个周期长度也符合,检查了

符合1.4us

在这里插入图片描述
6
以下是工程连接:
https://download.csdn.net/download/ciscomonkey/10773104

  • 3
    点赞
  • 38
    收藏
    觉得还不错? 一键收藏
  • 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、付费专栏及课程。

余额充值