文章目录
基于SPI接口的ADC芯片功能
对ADC128S102模数转换芯片接口的实验进行了仿真验证,和上板测试。
一、ADC芯片及参数介绍
ADC:Analog-to-Digital Converter,模数转换器。通常是指将一个模拟信号转变为数字信号的电子元件。像我们生活中常见的温度,湿度,电压,电流这些能够用连续变化的物理量所表示的信息,都属于模拟信号;而数字信号则是在模拟信号的基础上进过采样,量化和编码而形成的,也就是由许多的0和1组成的信号。
code的就是对应出来的采样值。U=code*5/2^8
板载ADC的位置,主要看三个参数,分辨率、采样范围,采样速率。
ADC128S102对应的引脚接口示意图。
数字量每增加1,电压值也增加1LSB。1LSB=VA/4096,VA就是3.3V,
模拟电压的计算公式。以上就是ADC128S102的结构和对应的模数转换原理。
U=(code-0.5)*3/4096
对于做FPGA的驱动,主要就是去驱动
DOUT信号由谁发出,或者说由谁驱动?DOUT信号由谁接收,或者说由谁读取?
由ADC模数转换芯片产生信号,由FPGA芯片的读取并处理这些信号。
是在SCLK时钟的下降沿去读取DOUT的值,且DOUT值是在时钟周期的一半发生变化这个时候是信号最稳定的时候。
DIN穿行数据输入脚,Data输入,是FPGA提供给ADC芯片的。
单次采样时序逻辑图。
USER_CTRL用户控制逻辑
Conv, 对应convert转换。
(1)模块示意图
对应的模块示意图。
多次发送对应的时序图。
对于线性序列机,一旦你确定好他的时序,在一个时间段之内,它做什么事情都是完全确定的。
这个和状态机不一样,在按键消抖的时候,什么时候按下按键是不确定的,对应产生的高电平时间也是不确定的。
二、模块构建
一轮传输从CS降为低电平开始,到CS上升为高电平结束。连续转换的时序图是没有拉高的,一次转换是存在拉高的。
通过查询芯片手册,了解到CS和SCLK的时间间隔大约是10ns。
按照不同的时刻列出信号对应的变化值,汇总成为一个表,方便通过代码构建信号的输入输出关系。
对应的时刻转换表。
(1)设计思路
1.计数单元,定义两个计数器,用以表示时刻0~34.
2.对照时刻表,在0~34时刻,驱动信号进行相应变化。
(2)线性序列机结构
1.计数单元,本质是一个不停计数的计数器,用以计时得到最小时间单位。
2.序列计数器,用来标记每一个时间点
3.驱动部分,负责根据时刻表中各个信号的值,在对应时间点驱动信号变化。
1.模块构建
要让ADC开始工作,要配置其的采样通道,SCLK的工作频率其实是比较高的,并不会太低,太低会使得一轮转换的时间延长,从而使得ADC内部的采样保持电路带电压在转换过程中改变
LSM_CNT就是线性序列机的意思。
代码如下(示例):
module adc128s102(
Clk,
Reset_n,
Addr,
Conv_Go,
Conv_Done,
Data,
ADC_SCLK,
ADC_CS_N,
ADC_DIN,
ADC_DOUT
);
input Clk;
input Reset_n;
input [2:0]Addr;
input Conv_Go;
output reg Conv_Done; //转换完成信号,完成转换后产生一个时钟周期的高脉冲
output reg [11:0]Data; //ADC转换结果
output reg ADC_SCLK;
output reg ADC_CS_N;
output reg ADC_DIN;
input ADC_DOUT;
parameter CLOCK_FREQ = 50_000_000;
parameter SCLK_FREQ = 12_500_000;
parameter MCNT_DIV_CNT = CLOCK_FREQ/(SCLK_FREQ * 2)-1;
reg [7:0]DIV_CNT;
reg [5:0]LSM_CNT;
reg [11:0]Data_r;
reg [2:0]r_Addr;
reg Conv_En; //转换使能
always@(posedge Clk or negedge Reset_n)
if(!Reset_n)
Conv_En <= 1'd0;
else if(Conv_Go)
Conv_En <= 1'd1;
else if((LSM_CNT == 6'd34) && (DIV_CNT == MCNT_DIV_CNT))
Conv_En <= 1'd0;
else
Conv_En <= Conv_En;
always@(posedge Clk or negedge Reset_n)
if(!Reset_n)
DIV_CNT <= 0;
else if(Conv_En)begin
if(DIV_CNT == MCNT_DIV_CNT)
DIV_CNT <= 0;
else
DIV_CNT