ad7147 CapTouch控制器调试
最近项目上用到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
更多推荐

所有评论(0)