一、生物阻抗测量理论简述
AD5940可以进行2线生物阻抗测量,使用的是一种伏安测量法。
- 将激励信号施加于未知阻抗上,测量未知阻抗阻抗的激励信号电压V1。
- 通过跨阻放大器TIA将流过未知阻抗的电流转换为由ADC测量的电压V2。
- 跨阻放大器的组织Rtia是可设置的,由V2与Rtai可计算出流过未知阻抗的电流I1.
- 对V1与I1进行DFT,即可获得各个频率点上未知阻抗电压与电流的实部与虚部,即可计算出赋值。
具体硬件测量原理请参考官方应用笔记与芯片手册。
二、两线制生物阻抗官方例程分析
仅以官方两线制生物阻抗例程AD5940_BIOZ-2Wire为例分析。
1、工程整体结构

主体代码有两个文件夹:AD5940Lib与Application
AD5940Lib:存放ad5940.c文件与ADICUP3029Port.c文件。
--ad5940.c为官方驱动文件,移植时不需要修改。
--ADICUP3029Port.c只适配官方驱动板ADuCM3029主控,需要根据移植主控进行修改,实现其中所有函数功能。
Application:存放main.c、AD5940Main.c与BIOZ-2Wire.c文件。
--main.c即为主函数入口,进行初始化及相关应用配置,完成后启动AD5940。
--AD5940Main.c包含AD5940初始化配置函数,根据应用需求主要改动此文件配置来应用AD5940。
--BIOZ-2Wire.c官方针对两线制应用写的驱动函数文件,不同例程中名称不同,但部分功能配置大体相同。移植时无需修改。
2、程序运行流程与功能函数分析
AD5940与主控是通过SPI进行通信的,因此官方例程中main入口主要执行了主控初始化,以及主控与AD5940连接的SPI引脚等初始化,完成后直接进入AD5940_Main()函数中。实际移植过程中根据需要自行修改。
进入AD5940_Main()函数后需要对AD5940的一些结构体进行初始化配置才能进行应用。
void AD5940_Main(void)
{
uint32_t temp;
AD5940PlatformCfg();
AD5940BIOZStructInit(); /* Configure your parameters in this function */
AppBIOZInit(AppBuff, APPBUFF_SIZE); /* Initialize BIOZ application. Provide a buffer, which is used to store sequencer commands */
AppBIOZCtrl(BIOZCTRL_START, 0); /* Control BIOZ measurement to start. Second parameter has no meaning with this command. */
while(1)
{
/* Check if interrupt flag which will be set when interrupt occurred. */
if(AD5940_GetMCUIntFlag())
{
AD5940_ClrMCUIntFlag(); /* Clear this flag */
temp = APPBUFF_SIZE;
AppBIOZISR(AppBuff, &temp); /* Deal with it and provide a buffer to store data we got */
BIOZShowResult(AppBuff, temp); /* Show the results to UART */
}
}
}
首先是AD5940PlatformCfg()函数,该函数主要对AD5940的时钟、FIFO、GPIO结构体进行初始化。具体每个结构体及其成员的作用含义参考文件定义中的注释。需要注意:
- 根据实际硬件原理图对AD5940时钟源进行选择,官方例程默认使用外部晶振为AD5940提供时钟
- 在GPIO配置部分,AD5941只有GPIO0、GPIO1、GPIO2三个IO口可以使用,并且IO口的复用功能不完全相同。
其次是AD5940BIOZStructInit()函数,该函数是要根据移植需求重点修改的。
pBIOZCfg->SeqStartAddr = 0;
pBIOZCfg->MaxSeqLen = 512; //激励信号长度
pBIOZCfg->SinFreq = 20e3; /*定频的激励信号频率当pBIOZCfg->SweepCfg.SweepEn = bTRUE 时生效*/
pBIOZCfg->RcalVal = 10000.0; /* 具体的Rcal阻值,官方评估版上为10K,实际要根据移植硬件电路板设置*/
pBIOZCfg->HstiaRtiaSel = HSTIARTIA_200; //Rtia阻值 默认使用内部Rtai
/* Configure Switch matrix */
pBIOZCfg->DswitchSel = SWD_CE0; //激励输出电极
pBIOZCfg->PswitchSel = SWP_CE0; //ADC正输入
pBIOZCfg->NswitchSel = SWN_AIN1; //ADC负输入
pBIOZCfg->TswitchSel = SWN_AIN1;
/* Configure Sweep Parameters */
pBIOZCfg->SweepCfg.SweepEn = bTRUE; //扫频开关
pBIOZCfg->SweepCfg.SweepStart = 1000; //起始频率
pBIOZCfg->SweepCfg.SweepStop = 200000.0; //终止频率
pBIOZCfg->SweepCfg.SweepPoints = 40; /* 频点数,最大为100,可根据扫频范围与频点数算扫频步长 */
pBIOZCfg->SweepCfg.SweepLog = bFALSE;
pBIOZCfg->BIOZODR = 5; /* ODR(Sample Rate) 5Hz */
pBIOZCfg->NumOfData = -1; /* -1是一直采样直到通过 AppBIOZCtrl()停止,其他数字及采样点数*/
AppBIOZInit(AppBuff, APPBUFF_SIZE)函数入参为buffer地址及其大小,这个buffer从起始地址开始往后按照顺序储存序列发生器命令,从结束地址往前存储寄存器变化值。该函数的作用主要是对于序列发生器以及FIFO的初始化配置,同时如果是第一次初始化,会按照设置的激励信号对Rtia进行测量并输出测量结果可以根据此来进行校准工作。移植时无特殊需求也不用修改。
最后是AppBIOZCtrl(BIOZCTRL_START, 0)函数,只有第一个输入参数是有用的,该函数相当于AD5940测量开关,第一个参数有BIOZCTRL_START、BIOZCTRL_STOPNOW、BIOZCTRL_STOPSYNC、BIOZCTRL_GETFREQ、BIOZCTRL_SHUTDOWN可以根据需求调用该函数和改变输入参数来控制AD5940。
至此AD5940的初始化就进行完了,开启测量后,通过AD5940_GetMCUIntFlag()函数读取AD5940传出的中断来判断当前频率点是否测量完毕,通过AD5940_ClrMCUIntFlag()函数清除中断。
通过调用AppBIOZISR(AppBuff, &temp)函数处理拿到的数据,该函数输入参数为buffer地址及其大小。到这一步FIFO中的数据是计算之前的,官方例程中又调用了AppBIOZDataProcess((int32_t*)pBuff,&FifoCnt)函数对数据进行处理,并且切换到写一个频率点,该函数输入函数为buffer地址和取到的点数。
最后BIOZShowResult(AppBuff, temp)函数会打印出计算后的结果。
3、烧录测试
硬件连接按照应用手册中连接,并且将阻抗测试板与评估板连接。

将扫频范围设置到1kHz到20kHz,40个频点,适当更改输出格式使结果便于查看。烧录后连接串口,波特率选择230400,按下复位键开始工作。此时阻抗测试板所有开关均为开启,测试板不会产生阻抗。

将阻抗测试板上控制电阻的S3开关分别关闭,可以观察到串口输出的实部结果产生变化。


4、官方上位机测试
官方提供了Analog Devices SensorPal上位机,可以直接对评估版进行配置。左侧为可以选择的应用程序,将其拖动到箭头所指位置。同时可以根据需求,对红框右侧参数进行修改配置。

完成配置设定后,进行测试,选择串口后点击箭头2所指图标

按照图示进行配置


然后完全关闭上位机,再次打开,即可看到测量键亮起,点击进行测量。(如果不重新进入上位机,测量按键不会亮起,未查明原因,尝试评估版复位也无效)

可以根据需求更改图像显示,观察测试结果与之前串口输出的300Ω结果一致。

三、移植工作
需要移植实现的主要文件是ADICUP3029Port.c,首先对该文件中的函数进行分析。
AD5940_ReadWriteNBytes(unsigned char *pSendBuffer,unsigned char *pRecvBuff,unsigned long length):该函数只需在 MOSI 线路上向 AD5940 发送 N 个字节,并在 MISO 线路上接收响应。该函数有 3 个输入参数。*pSendBuffer 是指向用于存储要传输的数据的缓冲区的指针。*pRecvBuff 是指向用于存储结果的缓冲区的指针。length 是缓冲区中要发送的字节数。
AD5940_CsClr(void):此功能只需将连接到 AD5940 的 CS 引脚的 GPIO 引脚驱动为低电平
AD5940_CsSet(void):此功能将连接到 AD5940 CS 引脚的 GPIO 引脚设置为高电平。
AD5940_RstSet(void):此功能将连接到 AD5940 复位引脚的 GPIO 驱动为高电平。
AD5940_RstClr(void):此功能驱动连接 AD5940 复位引脚的 GPIO 引脚为低电平,以启动硬件复位
AD5940_Delay10us(uint32_t time):此函数使用核心板上的 systick 计时器实现等待期。此功能因 MCU 而异。请注意正确实现此函数,以确保 AD5940 库正常工作。
AD5940_GetMCUIntFlag(void):此函数返回在外部中断处理程序中设置的中断标志的状态,以指示 AD5940 已生成中断。
AD5940_ClrMCUIntFlag(void):此函数清除中断状态标志。
AD5940_MCUResourceInit(void *pCfg):此函数为上面定义的函数初始化和配置主要外围设备。
- 1、GPIO 针对 SPI 接口、复位引脚和外部中断引脚进行了相应的配置
- 2、SPI 根据 AD5940 数据表进行配置
- 3、外部中断源在 Cortex Core 上的 NVIC 中使能
- 4、CS pin 和 Reset pin 设置为高电平。
Ext_Int0_Handler():当 AD5940 INTC 引脚生成中断以提醒 MCU 数据已准备就绪时,中断处理程序会处理对 MCU 的中断。它将 ucInterrupted 标志设置为 1。
为实现上述功能,用到的GPIO配置如下图所示

其余配置根据需求自行设置,生成工程后将官方例程中ad5940.c、AD5940Main.c、BIOZ-2Wire.c文件放入工程中。并新建一个STM32WLE5Port.c文件用来替代ADICUP3029Port.c。根据上述要实现的功能编写STM32WLE5Port.c文件
#include <AD5940.h>
#include "main.h"
#include "delay.h"
#include "spi.h"volatile static uint32_t ucInterrupted = 0; /* Flag to indicate interrupt occurred */
void AD5940_ReadWriteNBytes(unsigned char *pSendBuffer,unsigned char *pRecvBuff,unsigned long length)
{
HAL_SPI_TransmitReceive(&hspi1,pSendBuffer,pRecvBuff,length,(uint32_t)-1);
}void AD5940_CsClr(void)
{
HAL_GPIO_WritePin(MAD5941_CS_GPIO_Port,MAD5941_CS_Pin,GPIO_PIN_RESET);
}void AD5940_CsSet(void)
{
HAL_GPIO_WritePin(MAD5941_CS_GPIO_Port,MAD5941_CS_Pin,GPIO_PIN_SET);
}void AD5940_RstSet(void)
{
HAL_GPIO_WritePin(MAD5941_RESET_GPIO_Port,MAD5941_RESET_Pin,GPIO_PIN_SET);
}void AD5940_RstClr(void)
{
HAL_GPIO_WritePin(MAD5941_RESET_GPIO_Port,MAD5941_RESET_Pin,GPIO_PIN_RESET);
}void AD5940_Delay10us(uint32_t time)
{
delay_us(time * 10);
}uint32_t AD5940_GetMCUIntFlag(void)
{
return ucInterrupted;
}//AD5941外中断回调
void HAL_GPIO_EXTI_Callback(uint16_t GPIO_Pin)
{
if(GPIO_Pin == GPIO_PIN_0)
{
ucInterrupted = 1;
}
}
uint32_t AD5940_ClrMCUIntFlag(void)
{
ucInterrupted = 0;
return 1;
}/* Functions that used to initialize MCU platform */
uint32_t AD5940_MCUResourceInit(void *pCfg)
{
AD5940_CsSet();
AD5940_RstSet();
return 0;
}
在main.c中对相应的SPI、GPIO、USART等进行相应的初始化即可,后续参照官方例程和实际需要进行修改。详细代码这里不做说明,仅对一些需求配置进行解释。
首先,官方的初始化函数只有第一次配置时生效,如有需要在运行过程中更改测试频率等配置,需要在AD5940BIOZStructInit()函数中增加
pBIOZCfg->BIOZInited = bFALSE;
添加后再次初始化即可生效,可以通过增加输入参数的形式自行扫频。但是缺点是该配置增加后,每次初始化也会进行Rtia的读值工作,根据需要自行删除。
最后,根据需要修改串口输出显示的结果。

如有错误欢迎批评指正
如有侵权请联系作者
未经允许禁止转载