最近项目上用到ad7147,这是一颗电容-数字转换器(CDC),绝大数应用在按键上面,就是触碰到按键电容就会升高产生中断这样应用。但是我没用在按键,是需要它不断的的获取电容值。差别是我要一直开全工作模式,不用中断,不用环境校准。还有要注意的是有ad7147和ad7147-i两种型号,不带i的spi,带i的是iic的。注意别买错了。别问我为什么要提醒这个。

第一步,配置spi

        

        看规格书第37页可以知道,它是SPI模式3,双线,16位,msb先行。有了这些信息就可以配置了。我这里用到st的标准库,大家用不同主控的可以自行配置。

void SPI_AD7147_Init(void)
{
    GPIO_InitTypeDef GPIO_InitStructure;

    /*!< SPI_AD7147_SPI 时钟使能 */
    AD7147_SPI_CLK_INIT(AD7147_SPI_CLK, ENABLE);

     //设置引脚复用
    GPIO_PinAFConfig(AD7147_SPI_SCK_GPIO_PORT,AD7147_SPI_SCK_PINSOURCE,
                    AD7147_SPI_SCK_AF);
    GPIO_PinAFConfig(AD7147_SPI_MISO_GPIO_PORT,AD7147_SPI_MISO_PINSOURCE,
                    AD7147_SPI_MISO_AF);
    GPIO_PinAFConfig(AD7147_SPI_MOSI_GPIO_PORT,AD7147_SPI_MOSI_PINSOURCE,
                    AD7147_SPI_MOSI_AF);


    /*!< 配置 SPI_AD7147_SPI 引脚: SCK */
    GPIO_InitStructure.GPIO_Pin = AD7147_SPI_SCK_PIN ;
    GPIO_InitStructure.GPIO_Speed = GPIO_Speed_10MHz;
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF;
    GPIO_InitStructure.GPIO_OType= GPIO_OType_PP;
    GPIO_InitStructure.GPIO_PuPd= GPIO_PuPd_NOPULL;

    GPIO_Init(AD7147_SPI_SCK_GPIO_PORT,&GPIO_InitStructure);

    /*!<配置SPI_AD7147_SPI引脚:MISO */
    GPIO_InitStructure.GPIO_Pin= AD7147_SPI_MISO_PIN;
    GPIO_Init(AD7147_SPI_MISO_GPIO_PORT,&GPIO_InitStructure);

     /*!<配置SPI_AD7147_SPI引脚:MOSI */
    GPIO_InitStructure.GPIO_Pin= AD7147_SPI_MOSI_PIN;
    GPIO_Init(AD7147_SPI_MOSI_GPIO_PORT,&GPIO_InitStructure);

     /*!<配置SPI_AD7147_SPI引脚:CS */
    GPIO_InitStructure.GPIO_Pin= AD7147_SPI_CS_PIN;
    GPIO_InitStructure.GPIO_Mode= GPIO_Mode_OUT;
    GPIO_Init(AD7147_SPI_CS_GPIO_PORT,&GPIO_InitStructure);
    SPI_AD7147_CS_HIGH;

    SPI_InitTypeDef SPI_InitStructure;
    /*AD7147_SPI模式配置*/
    //AD7147芯片支持SPI模式3,据此设置CPOLCPHA
    SPI_InitStructure.SPI_Direction= SPI_Direction_2Lines_FullDuplex;
    SPI_InitStructure.SPI_Mode= SPI_Mode_Master;
    SPI_InitStructure.SPI_DataSize= SPI_DataSize_16b;
    SPI_InitStructure.SPI_CPOL= SPI_CPOL_High;
    SPI_InitStructure.SPI_CPHA= SPI_CPHA_2Edge;
    SPI_InitStructure.SPI_NSS= SPI_NSS_Soft;
    SPI_InitStructure.SPI_BaudRatePrescaler= SPI_BaudRatePrescaler_16;
    SPI_InitStructure.SPI_FirstBit= SPI_FirstBit_MSB;
    SPI_InitStructure.SPI_CRCPolynomial = 7;

    SPI_Init(AD7147_SPI,&SPI_InitStructure);

    SPI_Cmd(AD7147_SPI, ENABLE);
}

以上就是st标准库配置spi,我这里用的是软件cs脚。

spi配置好后我们写一下接受和发送函数

/**
  * @brief  使用spi发送一个字节
  * @param  byte:要发送的数据
  * @retval 返回接收到的数据
  */
static uint16_t SPI_AD7147_SendByte(uint16_t byte)
{
  SPITimeout = SPIT_FLAG_TIMEOUT;

  /* 等待发送缓冲区为空,txe事件 */
  while (SPI_I2S_GetFlagStatus(AD7147_SPI, SPI_I2S_FLAG_TXE) == RESET)
   {
    if((SPITimeout--) == 0) return SPI_TIMEOUT_UserCallback(0);
   }

  /* 写入数据寄存器,把要写入的数据写入发送缓冲区 */
  SPI_I2S_SendData16(AD7147_SPI, byte);
  

  SPITimeout = SPIT_FLAG_TIMEOUT;

  /* µÈ´ý½ÓÊÕ»º³åÇø·Ç¿Õ£¬RXNEʼþ */
  while (SPI_I2S_GetFlagStatus(AD7147_SPI, SPI_I2S_FLAG_RXNE) == RESET)
   {
    if((SPITimeout--) == 0) return SPI_TIMEOUT_UserCallback(1);
   }


  /* 读取数据寄存器,获取接受缓冲区数据 */
  return SPI_I2S_ReceiveData16(AD7147_SPI);
}

/**
  * @brief  使用spi接收一个字节
  * @param  
  * @retval 返回接收到的数据
  */
static uint16_t SPI_AD7147_ReadByte(void)
{
  return (SPI_AD7147_SendByte(Dummy_Byte));
}

/**
  * @brief  使用SPI批量发送一个数组
  * @param  pBuffer:指向要发送的数据数组
  * @param  Length:要发送的数据长度
  * @retval 无
  */
void WriteToAD7147(uint16_t RegisterAddress ,uint16_t Length,uint16_t* pBuffer,  uint8_t OffsetInBuffer)
{
    uint16_t ControlValue;

    //Create the 16-bit header
	  ControlValue = 0xE000 | (RegisterAddress & 0x03FF);

    SPI_AD7147_CS_LOW;

    SPI_AD7147_SendByte(ControlValue);
    uint16_t i;
    for(i = 0; i < Length; i++)
    {
        SPI_AD7147_SendByte(pBuffer[i+OffsetInBuffer]);
    }
    
    SPI_AD7147_CS_HIGH;
}

/**
  * @brief  使用SPI批量读取数据到数组
  * @param  pBuffer:指向接收数据的数组
  * @param  Length:要读取的数据长度
  * @retval 无
  */
void ReadFromAD7147(uint16_t RegisterAddress, uint16_t Length ,uint16_t* pBuffer,uint8_t OffsetInBuffer)
{
    uint16_t ControlValue;
    uint16_t i;

    ControlValue = 0xE400 | (RegisterAddress & 0x03FF);

    SPI_AD7147_CS_LOW;

    SPI_AD7147_SendByte(ControlValue);
    for(i = 0; i < Length; i++)
    {
        pBuffer[i] = SPI_AD7147_ReadByte();
    }
    SPI_AD7147_CS_HIGH;

}

/**
  * @brief  等待超时回调函数
  * @param  None.
  * @retval None.
  */
static  uint16_t SPI_TIMEOUT_UserCallback(uint8_t errorCode)
{
  /* 等待超时后的处理,输出错误信息 */
  DistanceDisplay(111,0,1);
  printf("SPI 等待超时!errorCode = %d",errorCode);
  return 0;
}

上面写了 四个函数

SPI_AD7147_SendByte() 发送一个字节

SPI_AD7147_ReadByte()接收一个字节

WriteToAD7147()发送一个数组

ReadFromAD7147()接收一个数组

注意上面代码里的:

ControlValue = 0xE000 | (RegisterAddress & 0x03FF);

和ControlValue = 0xE400 | (RegisterAddress & 0x03FF);,

是有一个规则的,【15:11】是11100,【10】读是1,写是0,【9:0】是地址,

所以我们发地址前要处理一下。

         到这里spi就算配好了。我这里没讲spi原理,如果想了解spi的详细知识的,我推荐去看

野火的SPI—读写串行FLASH那期课程,很详细还有配套图书。不是打广告,我就是看这个学的。

第二部,硬件验证

         spi配好后,就可以通过读取器件的id号来验证了板子有没有焊好,器件对不对,spi是否正常通讯了等等。。。。

   如图,0x017是设备id的寄存器地址,【15:4】是设备id,【3:0】是版本号

 

void read_idAD7147(void)
{
  uint16_t ControlValue = 0xE400 | (0x17 & 0x03FF);
  SPI_AD7147_CS_LOW;

  SPI_AD7147_SendByte(ControlValue);
  AD7147Registers[23] = SPI_AD7147_ReadByte(); // Read ID register

  SPI_AD7147_CS_HIGH;

  printf("read_idAD7147......\r\n");
  printf("id = %d......\r\n",AD7147Registers[23]);
}

        SPI_AD7147_CS_LOW;和 SPI_AD7147_CS_HIGH;是cs脚的拉高和拉低,我们spi的cs是软件处理。

        不出意外的话我们就可以打印设备id,我这里打印的是0x1471,只要前三位是0x147就是没问题的。

        收到id后就证明硬件,通讯没问题了,可以开始接下来的调试了。如果没收到就要借助逻辑分析仪,万用表来查找一下问题了。

第三步,初始化

规格书第40页有讲上电后的初始化流程,先配置0x080到0xdf,在配置0x000到0x007,最后配置下0x001。这里我也是按照这个流程初始话

#define	PWR_CONTROL					0x00	// RW	Power & conversion control
#define	STAGE_CAL_EN				0x01	// RW	Ambient compensation control register 0
#define	AMB_COMP_CTRL0				0x02	// RW	Ambient compensation control register 1
#define	AMB_COMP_CTRL1				0x03	// RW	Ambient compensation control register 2
#define	AMB_COMP_CTRL2				0x04	// RW	Ambient compensation control register 3
#define	STAGE_LOW_INT_EN			0x05	// RW	Interrupt enable register 0
#define	STAGE_HIGH_INT_EN			0x06	// RW	Interrupt enable register 1
#define	STAGE_COMPLETE_INT_EN		0x07	// RW	Interrupt enable register 2
#define	STAGE_LOW_LIMIT_INT			0x08	// R	Low limit interrupt status register 0
#define	STAGE_HIGH_LIMIT_INT		0x09	// R	High limit interrupt status register 1
#define	STAGE_COMPLETE_LIMIT_INT	0x0A	// R	Interrupt status register 2

void ConfigAD7147(void)
{
  uint16_t StageBuffer[8];
  //===========================
    //= Stage 0 - Not connected	=
    //===========================
    StageBuffer[0]=0xFFFF;	//Register 0x80   
    StageBuffer[1]=0x1FFE;  //Register 0x81   
    StageBuffer[2]=0x8700;	//Register 0x82   设置偏移值
    StageBuffer[3]=0x2626;	//Register 0x83
    StageBuffer[4]=60000;	//Register 0x84	
    StageBuffer[5]=60000;   	//Register 0x85
    StageBuffer[6]=60000;	//Register 0x86	
    StageBuffer[7]=60000;	//Register 0x87
  WriteToAD7147(STAGE0_CONNECTION, 8, StageBuffer, 0);
    //===========================
    //= Stage 1 - Not connected	=
    //===========================
    StageBuffer[0]=0xFFFF;	//Register 0x88
    StageBuffer[1]=0x1FFB;	//Register 0x89
    StageBuffer[2]=0x8700;	//Register 0x8A
    StageBuffer[3]=0x2626;	//Register 0x8B
    StageBuffer[4]=60000;	//Register 0x8C
    StageBuffer[5]=60000;	//Register 0x8D
    StageBuffer[6]=60000;	//Register 0x8E
    StageBuffer[7]=60000;	//Register 0x8F
	WriteToAD7147(STAGE1_CONNECTION, 8, StageBuffer, 0);

    //===========================
    //= Stage 2 - Not connected	=
    //===========================
    StageBuffer[0]=0xFFFF;	//Register 0x90
    StageBuffer[1]=0x1FEF;	//Register 0x91
    StageBuffer[2]=0x8700;	//Register 0x92
    StageBuffer[3]=0x2626;	//Register 0x93
    StageBuffer[4]=60000;	//Register 0x94
    StageBuffer[5]=60000;	//Register 0x95
    StageBuffer[6]=60000;	//Register 0x96
    StageBuffer[7]=60000;	//Register 0x97
	//WriteToAD7147(STAGE2_CONNECTION, 8, StageBuffer, 0);
  WriteToAD7147(STAGE2_CONNECTION, 8, StageBuffer, 0);
  
    
    //--------------------------------------------------------------------------//
    //-------------------------Bank 1 Registers---------------------------------//
    //--------------------------------------------------------------------------//
    //Initialisation of the first register bank but not the STAGE_CAL_EN
    AD7147Registers[PWR_CONTROL]=0x0020; 			//Register 0x00
    WriteToAD7147(PWR_CONTROL, 1, AD7147Registers, PWR_CONTROL);
	
	//Read high and low limit interrupt status before to enable the interrupts
	ReadFromAD7147(STAGE_LOW_LIMIT_INT, 3, AD7147Registers, STAGE_LOW_LIMIT_INT); //Registers 0x08 & 0x09 & 0x0A
    AD7147Registers[AMB_COMP_CTRL0]=0x3230;			//Register 0x02
    AD7147Registers[AMB_COMP_CTRL1]=0x01FF;			//Register 0x03
    AD7147Registers[AMB_COMP_CTRL2]=0xFFFF;			//Register 0x04
    AD7147Registers[STAGE_LOW_INT_EN]=0x0000;		//Register 0x05
    AD7147Registers[STAGE_HIGH_INT_EN]=0x0000;		//Register 0x06
    AD7147Registers[STAGE_COMPLETE_INT_EN]=0x0000;	//Register 0x07
    WriteToAD7147(AMB_COMP_CTRL0, 6, AD7147Registers, AMB_COMP_CTRL0);

    //Enable data path for all sequences
    AD7147Registers[STAGE_CAL_EN]=0xF000;			//Register 0x01
    WriteToAD7147(STAGE_CAL_EN, 1, AD7147Registers, STAGE_CAL_EN);

	//Read High and Low Limit Status registers to clear INT pin
	ReadFromAD7147(STAGE_LOW_LIMIT_INT, 3, AD7147Registers, STAGE_LOW_LIMIT_INT); //Registers 0x08 & 0x09 & 0x0A

}

这里我根据实际项目有一些修改,

大致意思是

在stage0上连接了cin7,stage1上连接了cin8,stage2上连接了cin9

全功工作模式,没用中断,不进行温度校准,3x256采样等

具体大家可以看下寄存器功能描述。

到这里就算初始化完成了。

第四步,取值

     

ad7147转换后的原始值在0x00b-0x016里,对应的stage0-stage11。

我在初始化中开启了stage0,stage1和stage2三个 。所以我到对应的寄存器地址取值就好

void read_numAD7147(void)
{
  uint16_t ControlValue = 0xE400 | (0x0b& 0x03FF);
  SPI_AD7147_CS_LOW;

  SPI_AD7147_SendByte(ControlValue);
  AD7147Registers[22] = SPI_AD7147_ReadByte(); // Read ID register

  SPI_AD7147_CS_HIGH;

  delay_ms(1);

  SPI_AD7147_CS_LOW;

  SPI_AD7147_SendByte(ControlValue+1);
  AD7147Registers[21] = SPI_AD7147_ReadByte(); // Read ID register

  SPI_AD7147_CS_HIGH;

  delay_ms(1);

  SPI_AD7147_CS_LOW;

  SPI_AD7147_SendByte(ControlValue+2);
  AD7147Registers[20] = SPI_AD7147_ReadByte(); // Read ID register

  SPI_AD7147_CS_HIGH;

  printf("read_numAD7147......\r\n");
  printf(" %d.%d.%d....\r\n",AD7147Registers[22],AD7147Registers[21],AD7147Registers[20]);
}

 这里如果能取到值就算完成了,如果你是应用在按键的化,就不需要取原始电容值,它支持判断电容值大小输出中断的。

      ok,本片文章就到这里了,如果用不懂得可以联系我13171016459

Logo

智能硬件社区聚焦AI智能硬件技术生态,汇聚嵌入式AI、物联网硬件开发者,打造交流分享平台,同步全国赛事资讯、开展 OPC 核心人才招募,助力技术落地与开发者成长。

更多推荐