fpga_feixiang 发表于 2020-3-2 12:39:07

AD采样的FPGA程序书写参考 Verilog代码

提供一段AD采样的FPGA程序
程序如下

Verilog源程序如下:
//---------------------------------------------------------------------------
//--      文件名                :      Ad_Module.v
//--      作者                :      ZIRCON
//--      描述                :      AD模块
//---------------------------------------------------------------------------

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

module Ad_Module
(      
      //Input
      CLK_50M,RST_N,
      //Output
      AD_CS,AD_CLK,AD_DATA,data_out
);
      
//---------------------------------------------------------------------------
//--      外部端口声明
//---------------------------------------------------------------------------
input                                        CLK_50M;                              //时钟的端口,开发板用的50M晶振
input                                        RST_N;                              //复位的端口,低电平复位
input                                        AD_DATA;                              //AD数据端口
output                              AD_CS;                              //AD片选端口
output                              AD_CLK;                              //AD时钟端口,最大不超过1.1MHz
output      [ 7:0]      data_out;                        //AD模数转换完成的数据输出


//---------------------------------------------------------------------------
//--      内部端口声明
//---------------------------------------------------------------------------
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                [ 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的下一个状态

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'd2 ) && (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'd10) && (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,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

endmodule

大鹏 发表于 2022-5-8 08:54:08

AD采样的FPGA程序书写参考 Verilog代码

zxopenhl 发表于 2023-12-18 14:36:01

AD采样的FPGA程序书写参考 Verilog代码
页: [1]
查看完整版本: AD采样的FPGA程序书写参考 Verilog代码