集成电路技术分享

 找回密码
 我要注册

QQ登录

只需一步,快速开始

搜索
查看: 1329|回复: 0

FPGA学习之AD通信协议

[复制链接]
fpga_feixiang 发表于 2019-4-19 14:10:11 | 显示全部楼层 |阅读模式
在AD TLC549中,vcc引脚是 系统电源输入端,I/O CLOCK引脚是外接时钟输入端,DATA OUT是转换结果数据串行输出端,CS引脚是片选信号,GND是接地端,REF+引脚是正基准电压输入端,ANALOGIN引脚模拟信号输入端,REF-引脚是负基准电压输入端。



 在TCL549内部具有4MHZ的系统时钟,并且该时钟与I/O CLOCK是独立工作的,所以无需特殊的速度或相位匹配。

从时序图中,我们知道:

(1)当CS为高时,转换结果数据串行输出端DATA OUT处于高阻状态,此时I/O CLOCK也不起作用。

(2)当CS为低时,AD前一次转换的数据A的最高位A7立即出现在数据线DATA OUT上,其余的7位数据在I/O CLOCK的下降沿一次由时钟同步输出。因此,可在I/O CLOCK的上升沿读取数据;这里需注意:一:当CS变为低电平到I/O CLOCK第一个时钟到来至少要1.4us。二:I/O CLOCK不能超过1.1MHZ。

(3)读取8位数据后,AD开始转换这一次转换的采样数据B,以便下一次读取。转换时片选信号CS必须置高电平,每次转换的时间不超过17us,开始于CS变为低电平后I/O clock的第8个下降沿,没有转换完成标志信号;也没有启动控制端,只要读取前一次数据后马上就可以开始新的AD转换,转换完成后就进入保持状态。

三,AD实际应用

(1)在数码管上显示ANALOGIN引脚输入的电压。

(2)功能模块



(3)verilog代码

`define AD_CLK_TIME                        10'd45        //1.1M, 909ns,909 / (1 / 50M) = 45 =0x2D
`define AD_CLK_TIME_HALF        10'd22        //909ns / 2 = 454.5ns 45 / 2 = 22       

module Ad_Module
(       
        //Input
        CLK_50M,RST_N,
        //Output
        AD_CS,AD_CLK,AD_DATA,o_vol_int,o_vol_dec
);
       
//---------------------------------------------------------------------------
//--        外部端口声明
//---------------------------------------------------------------------------
input                                        CLK_50M;                                //时钟的端口,开发板用的50M晶振
input                                        RST_N;                                //复位的端口,低电平复位
input                                        AD_DATA;                                //AD数据端口
output                                AD_CS;                                //AD片选端口
output                                AD_CLK;                                //AD时钟端口,最大不超过1.1MHz
output        [ 3:0]        o_vol_int;                        //从A/D转换芯片输出的电压值的整数部分;
output        [ 3:0]        o_vol_dec;                        //从A/D转换芯片输出的电压值的小数部分;

//---------------------------------------------------------------------------
//--        内部端口声明
//---------------------------------------------------------------------------
reg                                        AD_CS;                                //AD片选信号端口
reg                                        AD_CS_N;                                //AD_CS的下一个状态
reg                                        AD_CLK;                                //AD时钟,最大不超过1.1MHz
reg                                        AD_CLK_N;                        //AD_CLK的下一个状态

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

reg                [ 3:0]        o_vol_int;                        //从A/D转换芯片输出的电压值的整数部分;
wire                [ 3:0]        o_vol_int_n;                //o_vol_int的下一个状态
reg                [ 3:0]        o_vol_dec;                        //从A/D转换芯片输出的电压值的小数部分;
wire                [ 3:0]        o_vol_dec_n;                //o_vol_dec的下一个状态

reg                [ 5:0]        time_cnt;                        //用于记录一个时钟所用时间的定时器
reg                [ 5:0]        time_cnt_n;                        //time_cnt的下一个状态
reg                [ 5:0]        bit_cnt;                                //用来记录时钟周期个数的计数器
reg                [ 5:0]        bit_cnt_n;                        //bit_cnt的下一个状态

reg                [ 7:0]        data_out;                        //用来保存稳定的AD数据
reg                [ 7:0]        data_out_n;                        //data_out的下一个状态
reg                [ 7:0]        ad_data_reg;                //用于保存数据的移位寄存器
reg                [ 7:0]        ad_data_reg_n;                //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;        //结束的状态

//---------------------------------------------------------------------------
//--        逻辑功能实现       
//---------------------------------------------------------------------------
//时序电路,用来给ad_fsm_cs寄存器赋值
always @ (posedge CLK_50M or negedge RST_N)
begin
        if(!RST_N)                                                                //判断复位
                ad_fsm_cs <= 1'b0;                                //初始化ad_fsm_cs值
        else
                ad_fsm_cs <= ad_fsm_ns;                        //用来给ad_fsm_ns赋值
end

//组合电路,用来实现状态机
always @ (*)
begin
        case(ad_fsm_cs)                                                //判断状态机的当前状态
                FSM_IDLE:
                                                                                                //3 x 0.909us = 2.727us用于初始化延时
                        if((bit_cnt == 6'd3 ) && (time_cnt == `AD_CLK_TIME))
                                ad_fsm_ns = FSM_READY;        //如果空闲状态完成就进入延时状态
                        else
                                ad_fsm_ns = ad_fsm_cs;        //否则保持原状态不变
                FSM_READY:
                                                                                                //2 x 0.909us = 1.818us用于延迟1.4us
                        if((bit_cnt == 6'd2 ) && (time_cnt == `AD_CLK_TIME))
                                ad_fsm_ns = FSM_DATA;        //如果延时状态完成就进入读取数据状态
                        else
                                ad_fsm_ns = ad_fsm_cs;  //否则保持原状态不变
                FSM_DATA:
                                                                                                //读取数据8位,1~8个时钟脉冲
                        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:
                                                                                                //19 x 0.909us = 17.271us用于延迟17us
                        if((bit_cnt == 6'd19) && (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

//时序电路,用来给time_cnt寄存器赋值
always @ (posedge CLK_50M or negedge RST_N)
begin
        if(!RST_N)                                                                //判断复位
                time_cnt <= 6'h0;                                        //初始化time_cnt值
        else
                time_cnt <= time_cnt_n;                        //用来给time_cnt赋值
end

//组合电路,实现0.909us的定时计数器
always @ (*)
begin
        if(time_cnt == `AD_CLK_TIME)                //判断0.909us时间
                time_cnt_n = 6'h0;                                //如果到达0.909us,定时器清零
        else
                time_cnt_n = time_cnt + 6'h1;        //如果未到0.909us,定时器继续加1
end

//时序电路,用来给bit_cnt寄存器赋值
always @ (posedge CLK_50M or negedge RST_N)
begin
        if(!RST_N)                                                                //判断复位
                bit_cnt <= 6'h0;                                        //初始化bit_cnt值
        else
                bit_cnt <= bit_cnt_n;                        //用来给bit_cnt赋值
end

//组合电路,用来记录时钟周期个数的计数器
always @ (*)
begin
        if(ad_fsm_cs != ad_fsm_ns)                        //判断状态机的当前状态
                bit_cnt_n = 6'h0;                                        //如果当前的状态不等于下一个状态,计时器就清零
        else if(time_cnt == `AD_CLK_TIME_HALF)//判断0.4545us时间
                bit_cnt_n = bit_cnt + 6'h1;        //如果到达0.4545us,计数器就加1
        else
                bit_cnt_n = bit_cnt;                                //否则计数器保持不变
end

//时序电路,用来给AD_CLK寄存器赋值
always @ (posedge CLK_50M or negedge RST_N)
begin
        if(!RST_N)                                                                //判断复位
                AD_CLK <= 1'h0;                                        //初始化AD_CLK值
        else
                AD_CLK <= AD_CLK_N;                                //用来给AD_CLK赋值
end

//组合电路,用来生成AD的时钟波形
always @ (*)
begin
        if(ad_fsm_cs != FSM_DATA)                        //判断状态机的当前状态
                AD_CLK_N = 1'h0;                                        //如果当前的状态不等于读取数据状态,AD_CLK_N就置0
        else if(time_cnt == `AD_CLK_TIME_HALF)//判断0.4545us时间
                AD_CLK_N = 1'h1;                                        //如果到达0.4545us,ADC_CLK_N就置1
        else if(time_cnt == `AD_CLK_TIME)//判断0.909us时间
                AD_CLK_N = 1'h0;                                        //如果到达0.909us,AD_CLK_N就置0
        else
                AD_CLK_N = AD_CLK;                                //否则保持不变
end

//时序电路,用来给AD_CS寄存器赋值
always @ (posedge CLK_50M or negedge RST_N)
begin
        if(!RST_N)                                                                //判断复位
                AD_CS <= 1'h0;                                                //初始化AD_CS值
        else
                AD_CS <= AD_CS_N;                                        //用来给AD_CS赋值
end

//组合电路,用来生成AD的片选波形
always @ (*)
begin
        if((ad_fsm_cs == FSM_DATA) || (ad_fsm_cs == FSM_READY))//判断状态机的当前状态
                AD_CS_N = 1'h0;//如果当前的状态等于读取数据状态或等于延时1.4us状态,AD_CS_N就置0
        else
                AD_CS_N = 1'h1;//如果当前的状态不等于读取数据状态或不等于延时1.4us状态,AD_CS_N就置1
end

//时序电路,用来给ad_data_reg寄存器赋值
always @ (posedge CLK_50M or negedge RST_N)
begin
        if(!RST_N)                                                                //判断复位
                ad_data_reg <= 8'h0;                                //初始化ad_data_reg值
        else
                ad_data_reg <= ad_data_reg_n;        //用来给ad_data_reg赋值
end

//组合电路,将AD线上的数据保存到移位寄存器中
always @(*)
begin
        if((ad_fsm_cs == FSM_DATA) && (!AD_CLK) && (AD_CLK_N))//判断每一个时钟的上升沿
                ad_data_reg_n = {ad_data_reg[6:0],AD_DATA};//将数据存入移位寄存器中,高位优先
        else
                ad_data_reg_n = ad_data_reg;        //否则保持不变
end

//时序电路,用来给data_out寄存器赋值
always @ (posedge CLK_50M or negedge RST_N)
begin
        if(!RST_N)                                                                //判断复位
                data_out <= 8'h0;                                        //初始化data_out值
        else
                data_out <= data_out_n;                        //用来给data_out赋值
end

//组合电路,将移位寄存器中的数据存入data_out中,可用于输出
always @ (*)
begin
        if(ad_fsm_cs == FSM_END)                        //判断复位
                data_out_n = ad_data_reg;                //初始化data_out值
        else
                data_out_n = data_out;                        //用来给data_out赋值
end

//时序电路,用来给o_vol_int寄存器赋值
always @ (posedge CLK_50M or negedge RST_N)
begin
        if(!RST_N)                                                                //判断复位
                o_vol_int <= 4'h0;                                //初始化o_vol_int值
        else
                o_vol_int <= o_vol_int_n;                //用来给o_vol_int赋值
end

//时序电路,用来给o_vol_dec寄存器赋值
always @ (posedge CLK_50M or negedge RST_N)
begin
        if(!RST_N)                                                                //判断复位
                o_vol_dec <= 4'h0;                                //初始化o_vol_dec值
        else
                o_vol_dec <= o_vol_dec_n;                //用来给o_vol_dec赋值
end

//将AD的8位数据转换成数码管显示电压
assign o_vol_int_n = mid1[11:8];//整数部分
assign o_vol_dec_n = mid2[11:8];//小数部分

// AD的电压计算公式:AD_DATA / FF = voltage / 5 (5V为ADC的参考电压)
// voltage = 5 * AD_DATA / FF
// voltage = 5 * AD_DATA >> 8

// voltage(整数部分) = ((AD_DATA << 2) + AD_DATA) >> 8
assign mid1 = {2'h0,data_out[7:0],2'h0} + {4'h0,data_out[7:0] };
// voltage(小数部分) = ((5 * AD_DATA & 0XFF) * 10 ) >> 8
assign mid2 = {1'h0,  mid1[7:0],3'h0} + {3'h0,  mid1[7:0],1'h0};

endmodule
您需要登录后才可以回帖 登录 | 我要注册

本版积分规则

关闭

站长推荐上一条 /1 下一条

QQ|小黑屋|手机版|Archiver|fpga论坛|fpga设计论坛 ( 京ICP备20003123号-1 )

GMT+8, 2025-4-30 20:24 , Processed in 0.056559 second(s), 19 queries .

Powered by Discuz! X3.4

© 2001-2023 Discuz! Team.

快速回复 返回顶部 返回列表