fpga+ADS1256

ADS1256芯片手册阅读笔记
特性:
24bit;高达30kSPS的数据输出速率;支持4通道差分输入或者8通道单端模拟输入;SPI串行接口;超低噪声。
内部结构:
在这里插入图片描述
电气特性:
在这里插入图片描述
在这里插入图片描述

引脚功能介绍:
在这里插入图片描述

串行接口时序:
在这里插入图片描述
在这里插入图片描述

输入复用

  1. AN0~AN7八个模拟输入;
  2. 八个输入可以是4组差分输入或者8个单端输入;
  3. 每个通道可以通过multiplexer register 配置成差分正输入(或者差分负输入);
    在这里插入图片描述

ADS1256原理图:
在这里插入图片描述
使用模式:
单次转换模式:
spi发送写寄存器wreg命令发送对应寄存器的值发送同步命令发送WAKEUP命令发送数据转换命令等待drdy为低电平时读取24bit数据。

单一通道的单次转换设计流程图:
在这里插入图片描述// SPI驱动
`// ============================================================
// File Name : spi_driver.v
// Function : spi driver
// Author : snjshping
// Date : 20191213
// ============================================================
module spi_driver
(
input Clock,
input Rst_n,

input 							iSpi_start_sig,
input 		 [23:0]		iSpi_wr_data,

input 							iSpi_miso,
output reg [23:0]		oSpi_rd_data,
output  						oSpi_rd_end,
output  						oSpi_wr_end,
output reg	 				oSpi_mosi,
output  						oSpi_sclk

);

reg [23:0] rWr_data_buff;
reg [23:0] rRd_data_buff;
reg [4:0] rClk_cnt;
reg rClk_valid;

assign oSpi_wr_end = (rClk_cnt[4:0] == 5’d30) ? 1’b1 : 1’b0;
assign oSpi_rd_end = (rClk_cnt[4:0] == 5’d30) ? 1’b1 : 1’b0;

always @(posedge Clock or negedge Rst_n)
begin
if(Rst_n == 1’b0)
begin
rClk_cnt[4:0] <= 5’d0;
end
else if(iSpi_start_sig == 1’b1)
begin
rClk_cnt[4:0] <= rClk_cnt[4:0] + 5’d1;
end
else
begin
rClk_cnt[4:0] <= 5’d0;
end
end

always @(posedge Clock or negedge Rst_n)
begin
if(Rst_n == 1’b0)
begin
oSpi_mosi <= 1’b0;
rWr_data_buff[23:0] <= 24’d0;
end
else
begin
case(rClk_cnt[4:0])
5’d0 : begin
oSpi_mosi <= 1’b0;
rWr_data_buff[23:0] <= iSpi_wr_data[23:0];
end
5’d1 : oSpi_mosi <= rWr_data_buff[23];
5’d2 : oSpi_mosi <= rWr_data_buff[22];
5’d3 : oSpi_mosi <= rWr_data_buff[21];
5’d4 : oSpi_mosi <= rWr_data_buff[20];
5’d5 : oSpi_mosi <= rWr_data_buff[19];
5’d6 : oSpi_mosi <= rWr_data_buff[18];
5’d7 : oSpi_mosi <= rWr_data_buff[17];
5’d8 : oSpi_mosi <= rWr_data_buff[16];
5’d9 : oSpi_mosi <= rWr_data_buff[15];
5’d10 : oSpi_mosi <= rWr_data_buff[14];
5’d11 : oSpi_mosi <= rWr_data_buff[13];
5’d12 : oSpi_mosi <= rWr_data_buff[12];
5’d13 : oSpi_mosi <= rWr_data_buff[11];
5’d14 : oSpi_mosi <= rWr_data_buff[10];
5’d15 : oSpi_mosi <= rWr_data_buff[9];
5’d16 : oSpi_mosi <= rWr_data_buff[8];
5’d17 : oSpi_mosi <= rWr_data_buff[7];
5’d18 : oSpi_mosi <= rWr_data_buff[6];
5’d19 : oSpi_mosi <= rWr_data_buff[5];
5’d20 : oSpi_mosi <= rWr_data_buff[4];
5’d21 : oSpi_mosi <= rWr_data_buff[3];
5’d22 : oSpi_mosi <= rWr_data_buff[2];
5’d23 : oSpi_mosi <= rWr_data_buff[1];
5’d24 : oSpi_mosi <= rWr_data_buff[0];
default : oSpi_mosi <= 1’b0;
endcase
end
end

always @(negedge Clock or negedge Rst_n)
begin
if(Rst_n == 1’b0)
begin
rClk_valid <= 1’b0;
rRd_data_buff[23:0] <= 24’d0;
oSpi_rd_data[23:0] <= 24’d0;
end
else
begin
case(rClk_cnt[4:0])
5’d0 : rClk_valid <= 1’b0;
5’d1 : rClk_valid <= 1’b1;
5’d2 : rRd_data_buff[23] <= iSpi_miso;
5’d3 : rRd_data_buff[22] <= iSpi_miso;
5’d4 : rRd_data_buff[21] <= iSpi_miso;
5’d5 : rRd_data_buff[20] <= iSpi_miso;
5’d6 : rRd_data_buff[19] <= iSpi_miso;
5’d7 : rRd_data_buff[18] <= iSpi_miso;
5’d8 : rRd_data_buff[17] <= iSpi_miso;
5’d9 : rRd_data_buff[16] <= iSpi_miso;
5’d10 : rRd_data_buff[15] <= iSpi_miso;
5’d11 : rRd_data_buff[14] <= iSpi_miso;
5’d12 : rRd_data_buff[13] <= iSpi_miso;
5’d13 : rRd_data_buff[12] <= iSpi_miso;
5’d14 : rRd_data_buff[11] <= iSpi_miso;
5’d15 : rRd_data_buff[10] <= iSpi_miso;
5’d16 : rRd_data_buff[9] <= iSpi_miso;
5’d17 : rRd_data_buff[8] <= iSpi_miso;
5’d18 : rRd_data_buff[7] <= iSpi_miso;
5’d19 : rRd_data_buff[6] <= iSpi_miso;
5’d20 : rRd_data_buff[5] <= iSpi_miso;
5’d21 : rRd_data_buff[4] <= iSpi_miso;
5’d22 : rRd_data_buff[3] <= iSpi_miso;
5’d23 : rRd_data_buff[2] <= iSpi_miso;
5’d24 : rRd_data_buff[1] <= iSpi_miso;
5’d25 : begin
rClk_valid <= 1’b0;
rRd_data_buff[0] <= iSpi_miso;
end
5’d26 : oSpi_rd_data[23:0] <= rRd_data_buff[23:0];
default : rClk_valid <= 1’b0;
endcase
end
end
assign oSpi_sclk = rClk_valid & Clock;

endmodule

/**************************************************************
spi_driver u0_spi_driver
(
.oSpi_sclk (),
.Rst_n (),

.iSpi_start_en	(),

.iSpi_wr_data		(),
.iSpi_iSpi_miso			(),
.oSpi_oSpi_mosi			(),
.oSpi_oSpi_sclk			(),
.oSpi_rd_data		(),

.oSpi_rd_done		(),
.oSpi_wr_done		()
);

**************************************************************/
// 时钟分频//=============================================================
// Module : freq_devide_test.v
// Function : 分频测试
// Date : 20191207
=============================================================
module freq_divide #
(
parameter FREQ_DIVIDE_FACTOR = 5’d24
)
(
input Clock ,
input Rst_n ,

output reg		oDivide_clk
);

reg [4:0] rDivide_cnt;

always @ ( posedge Clock or negedge Rst_n )
begin
if(Rst_n == 1’b0)
begin
rDivide_cnt[4:0] <= 5’d0;
end
else
begin
rDivide_cnt[4:0] <= (rDivide_cnt[4:0] == FREQ_DIVIDE_FACTOR) ? 5’d0 : (rDivide_cnt[4:0] + 5’d1);
end
end

always @ ( posedge Clock or negedge Rst_n )
begin
if(Rst_n == 1’b0)
begin
oDivide_clk <= 1’b1;
end
else
begin
oDivide_clk <= (rDivide_cnt[4:0] == FREQ_DIVIDE_FACTOR) ? (~oDivide_clk) : oDivide_clk;
end
end

endmodule`

// 顶层模块:```
// ============================================================
// File Name : ads1256_sample.v
// Function : realize A/D convert of ads1256 with 24bit
// Author : snjshping
// Date : 20191226
// Version : 2.0
// ============================================================
module ads1256_sample #
(
// register value
parameter STATUS_REG = 8’h01, // 状态寄存器
parameter MUX_REG = 8’h1f, // 通道寄存器
parameter ADCON_REG = 8’h20, // 控制寄存器
parameter DRATE_REG = 8’hf0, // 数据速率寄存器
parameter IO_REG = 8’he0 // IO寄存器
)
(
input Clock ,
input Rst_n ,

input									iStart_conv_en	,
input									iAd_dout				,
input									iAd_drdy				,	
                    	        				
output								oAd_sclk				,
output								oAd_din					,
output reg						oAd_cs_n				,
output 								oAd_reset_n			,
output  		[3:0]			oAd_dio					,
	                              			
output reg  [23:0]		oAd_value				,
output reg						oAd_conv_done

);

// ============================================================
// parameter define
// ============================================================

// register address
localparam STATUS_REG_ADDR = 4’h0;
localparam MUX_REG_ADDR = 4’h1;
localparam ADCON_REG_ADDR = 4’h2;
localparam DRATE_REG_ADDR = 4’h3;
localparam IO_REG_ADDR = 4’h4;
// command define
localparam WAKEUP = 8’h00;
localparam RDATA = 8’h01;
localparam RDATAC = 8’h03;
localparam SDATAC = 8’h0f;
localparam SELFCAL = 8’hf0;
localparam SELFOCAL = 8’hf1;
localparam SELFGCAL = 8’hf2;
localparam SYSOCAL = 8’hf3;
localparam SYSGCAL = 8’hf4;
localparam SYNC = 8’hfc;
localparam STANDBY = 8’hfd;
localparam RESET = 8’hfe;
// state define
localparam ST_IDLE = 10’b00_0000_0001;
localparam ST_TX_STATUS = 10’b00_0000_0010;
localparam ST_TX_ADCON = 10’b00_0000_0100;
localparam ST_TX_DRATE = 10’b00_0000_1000;
localparam ST_TX_IO = 10’b00_0001_0000;
localparam ST_TX_MUX = 10’b00_0010_0000;
localparam ST_TX_RDATA = 10’b00_0100_0000;
localparam ST_WAITING = 10’b00_1000_0000;
localparam ST_READ_DATA = 10’b01_0000_0000;
localparam ST_CONV_END = 10’b10_0000_0000;

//=============================================================
// wire define
//=============================================================
wire wSpi_rd_end ;
wire wSpi_wr_end ;
wire [23:0] wSpi_rd_data;
wire Clock_driv ;

//=============================================================
// reg define
//=============================================================
reg [9:0] rState ; // stete of state machine
reg [4:0] rDelay_cnt ; // delay counter
reg [23:0] rSpi_wr_data ;
reg rSpi_start_sig;

//-------------------------------------------------------------
//
//-------------------------------------------------------------
assign oAd_reset_n = 1’b1; // don’t reset ads1256
assign oAd_dio[3:0] = 4’b0000; //

//-------------------------------------------------------------
// one segment state machine
//-------------------------------------------------------------
always @ ( posedge Clock_driv or negedge Rst_n )
begin
if(Rst_n == 1’b0)
begin
oAd_cs_n <= 1’b1;
oAd_conv_done <= 1’b0;
rSpi_start_sig <= 1’b0;
rDelay_cnt[4:0] <= 5’d0;
rSpi_wr_data[23:0] <= 24’d0;
oAd_value[23:0] <= 24’d0;
rState[9:0] <= ST_IDLE;
end
else
begin
case(rState[9:0])
ST_IDLE : begin
oAd_cs_n <= 1’b1;
oAd_conv_done <= 1’b0;
rSpi_start_sig <= 1’b0;
rDelay_cnt[4:0] <= 5’d0;
rSpi_wr_data[23:0] <= 24’d0;
rState[9:0] <= (iStart_conv_en == 1’b1) ? ST_TX_STATUS : ST_IDLE;
end
ST_TX_STATUS : begin
oAd_cs_n <= 1’b0;
rSpi_start_sig <= 1’b1;
rSpi_wr_data[23:0] <= {4’h5,STATUS_REG_ADDR,8’h00,STATUS_REG}; // 写状态寄存器
rState[9:0] <= (wSpi_wr_end == 1’b1) ? ST_TX_ADCON : ST_TX_STATUS;
end
ST_TX_ADCON : begin
oAd_cs_n <= 1’b0;
rSpi_start_sig <= 1’b1;
rSpi_wr_data[23:0] <= {4’h5,ADCON_REG_ADDR,8’h00,ADCON_REG}; // 写A/D控制寄存器
rState[9:0] <= (wSpi_wr_end == 1’b1) ? ST_TX_DRATE : ST_TX_ADCON;
end
ST_TX_DRATE : begin
oAd_cs_n <= 1’b0;
rSpi_start_sig <= 1’b1;
rSpi_wr_data[23:0] <= {4’h5,DRATE_REG_ADDR,8’h00,DRATE_REG}; // 写数据速率寄存器
rState[9:0] <= (wSpi_wr_end == 1’b1) ? ST_TX_IO : ST_TX_DRATE;
end
ST_TX_IO : begin
oAd_cs_n <= 1’b0;
rSpi_start_sig <= 1’b1;
rSpi_wr_data[23:0] <= {4’h5,IO_REG_ADDR,8’h00,IO_REG}; // 写IO寄存器
rState[9:0] <= (wSpi_wr_end == 1’b1) ? ST_TX_MUX : ST_TX_IO;
end
ST_TX_MUX : begin
oAd_cs_n <= 1’b0;
rSpi_start_sig <= 1’b1;
rSpi_wr_data[23:0] <= {4’h5,MUX_REG_ADDR,8’h00,MUX_REG}; // 写输入通道寄存器
rState[9:0] <= (wSpi_wr_end == 1’b1) ? ST_TX_RDATA : ST_TX_MUX;
end
ST_TX_RDATA : begin
oAd_cs_n <= 1’b0;
rSpi_start_sig <= (wSpi_wr_end != 1’b1) ? 1’b1 : 1’b0;
if(iAd_drdy == 1’b0)
begin
rSpi_wr_data[23:0] <= {SYNC,WAKEUP,RDATA}; // 发送同步、唤醒、读数据命令
end
else ;
rState[9:0] <= (wSpi_wr_end == 1’b1) ? ST_WAITING : ST_TX_RDATA;
end
ST_WAITING : begin // 等待
oAd_cs_n <= 1’b0;
rSpi_start_sig <= 1’b0;
rSpi_wr_data[23:0] <= 24’d0;
rDelay_cnt[4:0] <= (rDelay_cnt[4:0] == 5’d6) ? 5’d0 : (rDelay_cnt[4:0] + 5’d1);
rState[9:0] <= (rDelay_cnt[4:0] == 5’d6) ? ST_READ_DATA : ST_WAITING;
end
ST_READ_DATA : begin // 读数据
oAd_cs_n <= 1’b0;
rSpi_start_sig <= (wSpi_rd_end != 1’b1) ? 1’b1 : 1’b0;
oAd_value[23:0] <= (wSpi_rd_end == 1’b1) ? wSpi_rd_data[23:0] : oAd_value[23:0];
rState[9:0] <= (wSpi_rd_end == 1’b1) ? ST_CONV_END : ST_READ_DATA;
end
ST_CONV_END : begin
oAd_cs_n <= 1’b0;
oAd_conv_done <= 1’b1;
rSpi_start_sig <= 1’b0;
rSpi_wr_data[23:0] <= 24’d0;
rState[9:0] <= ST_IDLE;
end
default : ;
endcase
end
end

spi_driver u0_spi_driver
(
.Clock ( Clock_driv ),
.Rst_n ( Rst_n ),

.iSpi_start_sig	( rSpi_start_sig),

.iSpi_wr_data		( rSpi_wr_data 	),
.iSpi_miso			( iAd_dout			),
.oSpi_mosi			( oAd_din				),
.oSpi_sclk			( oAd_sclk			),
.oSpi_rd_data		( wSpi_rd_data	),

.oSpi_rd_end 		( wSpi_rd_end		),
.oSpi_wr_end 		( wSpi_wr_end		)
);

//-------------------------------------------------------------
// generate division clock signal
//-------------------------------------------------------------
freq_divide #
(
.FREQ_DIVIDE_FACTOR ( 5’d24 )
)
u0_freq_divide
(
.Clock ( Clock ),
.Rst_n ( Rst_n ),

.oDivide_clk				( Clock_driv	)
);

endmodule

/**************************************************************
module ads1256_sample #
(
// register value
parameter STATUS_REG = 8’h01,
parameter MUX_REG = 8’h1f, //
parameter ADCON_REG = 8’h20,
parameter DRATE_REG = 8’hf0,
parameter IO_REG = 8’he0
)
(
.Clock (),
.Rst_n (),

.iStart_conv_en		(),
.iAd_dout					(),
.iAd_drdy					(),
        					
.oAd_sclk					(),
.oAd_din					(),
.oAd_cs_n					(),
.oAd_reset_n			(),
.oAd_dio					(),
           			  
.oAd_value				(),
.oAd_conv_done		()

);

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


<think>嗯,用户问为什么基类析构函数需要声明为虚函数。这个问题我记得和对象析构时的行为有关,特别是当用基类指针指向派生类对象的时候。如果基类析构函数不是虚的,那么当通过基类指针删除对象时,只会调用基类析构函数,而派生类的析构函数不会被调用,这会导致内存泄漏或者资源没有正确释放的情况。 比如,假设有一个基类Base和一个派生类Derived。如果Base的析构函数不是虚函数,而用户用Base*指针指向一个Derived对象,然后delete这个指针,这时候只会执行Base的析构函数,Derived的析构函数不会执行。这样,如果Derived类中有动态分配的内存或者其他资源需要释放,就会造成泄漏。 所以正确的做法是将基类析构函数声明为虚函数。这样,当通过基类指针删除派生类对象时,会先调用派生类的析构函数,再调用基类析构函数,确保所有资源都被正确释放。这也是为什么C++中,如果一个类被设计为基类(即会被其他类继承),通常需要将其析构函数设为虚函数的原因。 另外,如果基类析构函数不是虚的,而用户又可能通过基类指针删除派生类对象,这时候程序的行为是未定义的,可能导致各种问题。所以为了安全起见,基类析构函数应该声明为虚函数。不过,如果确定这个类不会被继承,或者不会通过基类指针来删除对象,那么可能不需要虚析构函数,这样可以避免虚表带来的额外开销。</think><< 基类析构函数需要声明为虚函数的主要原因是确保通过基类指针删除派生类对象时,能正确调用完整的析构函数链。具体原因如下: 1. **避免资源泄漏** 当通过基类指针删除派生类对象时,如果基类析构函数非虚,只会调用基类析构函数,导致派生类独有的资源(如动态内存、文件句柄等)未被释放。 2. **保证多态行为正确** 虚析构函数多态机制的一部分。当通过基类指针操作派生类对象时,虚析构函数确保调用正确的析构函数序列(派生类→基类)。 ```cpp class Base { public: virtual ~Base() { std::cout << "Base destructor\n"; } // 虚析构函数 }; class Derived : public Base { public: ~Derived() override { std::cout << "Derived destructor\n"; } }; int main() { Base* obj = new Derived(); delete obj; // 输出顺序:Derived destructor → Base destructor } ``` **解释** 如果基类析构函数声明为虚函数,上述代码中`delete obj`只会调用`Base`的析构函数,导致`Derived`类特有的资源未被清理。虚析构函数通过虚函数表(vtable)找到实际对象的析构函数入口,确保析构顺序正确。
评论 6
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值