上期我们暂时的解决了数据连续性问题,但是我们发现我们的ADC采样似乎有非常大的噪声,因此我决定利用外部ADC芯片来替换到噪声非常大的板载ADC的噪声非常大。

我们对ADC信号进行傅里叶变换,可以看到ADC的噪声还是非常大的。

因此我们决定使用外部ADC来提高精度。

ADC选型

MAX11606 是美信 公司推出的低噪声累加型ADC芯片,并且其四通道的设计符合我们的需求,87KHZ的采样率也是满足我们的使用要求,支持IIC通讯。

所以我决定使用这块ADC芯片来制作我的外部

ADC模块。我们参考芯片手册可以了解这块芯片的相关

查看芯片手册,其中MAX11606的供电电源可以到达5V,参考电平也可以到达5V(纠正,这个是外部参考,我们使用内部参考为4.096V)满足我们的0~3.3V的使用需求。

DAC选型

DAC芯片我们选择微芯公司的MCP4822,MCP4822具有12位精度,SPI通讯双通道芯片

MCP4822的快速沉降时间为4.5us,压摆率为0.55V/us,足够满足我们的要求(我的前置运放LM324是0.5V/us的压摆率二者差不多)

并且,其信噪比也很低,非常适合于我们的项目。

(这两块芯片是我找了好久好久的电路比较简单,速度快,分辨率高以及最最最最最重要的价格便宜并且嘉立创上面有库存的器件)

电路设计

绘制我们的原理图部分,其中红色方框为数字地与模拟地,数字电源和模拟电源的隔离。

蓝色方框为IIC和SPI的上拉电阻。

我们利用ESP32的SPI,CS连D5,SCK连D18,DIN连D23,LDNC选择一个(我选择D17)。

IIC部分,SCL连D22,SDA连D21。

MCP4822驱动编写

我们查看MCP4822的手册。

MCP4822的命令由:4个配置位+12位数据组成。

从高到低分别是:通道选择,无关位,增益控制位以及输出控制。

例如我们想要使用通道A,增益为2,并且可输出,那么设置为0001,对应的十六进制是0x1;


void SPI_Init()
{
    // 初始化对应VSPI接口,得到SPI对象
  vspi = new SPIClass(VSPI);
 vspi->begin(VSPI_SCLK, VSPI_MISO, VSPI_MOSI, VSPI_SS); //SCLK, MISO, MOSI, SS
  pinMode(vspi->pinSS(), OUTPUT); //VSPI SS
  pinMode(LDAC, OUTPUT); 
}

初始化我们的SPI,begin参数中传入我们的SPI引脚。

接着我们编写我们的写命令函数。


void spiCommand(SPIClass *spi, uint8_t cmd,uint16_t value) {
  // 设置SPI对应模式
  uint32_t data = cmd<<12|value;
  spi->beginTransaction(SPISettings(spiClk, MSBFIRST, SPI_MODE0));
  digitalWrite(spi->pinSS(), LOW); // NSS低电平,数据开始传输
  spi->write16(data);
  digitalWrite(spi->pinSS(), HIGH); // NSS高电平,数据截止传输
  digitalWrite(LDAC,LOW);
  digitalWrite(LDAC,HIGH);
  spi->endTransaction();
}

我们将cmd命令左移12位,接着加上我们的值就构成了我们要发送的命令,接着我们开始SPI的传输,并且拉低SS片选信号。接着传入我们拼接好的数据,接着拉低LDAC使的数据写入寄存器开始工作,关闭SPI传输。


 //use the SPI buses
  for(float i = 0;i<2*3.14;i+=0.01)
  {
    spiCommand(vspi, 0x1,((sin(i))+1)*2096/4); // junk data to illustrate usage
  }

在主函数中我们设置一个For循环让DAC输出一个正弦波。

可以看到DAC可以正常地工作。

MAX11606驱动编写

MAX11606是使用IIC驱动,首先我们需要在头文件中引入ESP32 Arduino的IIC库:


#include 

 

之后启动IIC,由于MPU作为主机,因此begin函数不需要传入参数,如果作为从机和其他主机通讯就需要输入地址。


Wire.begin();

查阅MAX11606手册得知,该芯片的从机地址是0x34 上述的两张表用来配置启动设置,我们需要的是:选择内部Vref,外部时钟,单极输入,不重置。扫描方式为连续扫描,通道选择1,单端输入。


Wire.beginTransmission(0x34);
  Wire.write(0xC);//一个字节一个字节的发
  Wire.write(0xA);
  Wire.endTransmission(true);
  int result = Wire.endTransmission();
  Wire.beginTransmission(0x34);
  Wire.write(0x6);
  Wire.write(0x7);
  result = Wire.endTransmission();
  if (result == 0) {
    Serial.println("命令发送成功");
  } else {
    Serial.println("命令发送失败");
  }

之后定义读取的函数。


void IIC_Read()
{
   int deviceAddress = 0x34;
  uint16_t result = 0;
  // 请求读取数据,读取2个字节
  Wire.requestFrom(deviceAddress, 2);

  // 等待数据可用
  while (Wire.available() < 2) {
    // 等待数据
  }

  // 读取数据并输出到串口
    int TT = Wire.read();
    //result = result<<8;
    result = Wire.read();
    TT=(TT-252);
    result = (TT<<8)|result;
    Serial.print("A:");
    Serial.println(result);
}

由于读取的数据是2+8

嘉立创PCB

还没有评论,抢个沙发!