智能称体脂称实现(代码与基本数据处理篇)
发布时间:2020-12-14 02:05:17 所属栏目:大数据 来源:网络整理
导读:(本文均出于个人理解而写,仅用于学习和交流,某些过程可能不一定正确,希望各位提出意见进行交流,共同进步) AFE4300的配置是比较简单的,从配置到处理基本的数据,主要有3个方面:SPI配置,AFE4300配置,基本的数据处理。(由于当时板子没做成一块,用ST
(本文均出于个人理解而写,仅用于学习和交流,某些过程可能不一定正确,希望各位提出意见进行交流,共同进步) AFE4300的配置是比较简单的,从配置到处理基本的数据,主要有3个方面:SPI配置,AFE4300配置,基本的数据处理。(由于当时板子没做成一块,用STM32产生1M时钟再用杜邦线连接时干扰较大,于是时钟没有用STM32产生) SPI配置与接口封装
STM32使用库函数来进行开发可以加快开发进度,为了方便,我们也使用了STM32的库函数,按照AFE4300的SPI配置说明,其初始化函数可参考如下:
void SPI2_Init(void) { GPIO_InitTypeDef GPIO_InitStructure; SPI_InitTypeDef SPI_InitStructure; RCC_APB2PeriphClockCmd( RCC_APB2Periph_GPIOB,ENABLE );//PORTB时钟使能 RCC_APB1PeriphClockCmd( RCC_APB1Periph_SPI2,ENABLE );//SPI2时钟使能 GPIO_InitStructure.GPIO_Pin = GPIO_Pin_13 | GPIO_Pin_14 | GPIO_Pin_15; GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP; //PB13/14/15复用推挽输出 GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; GPIO_Init(GPIOB,&GPIO_InitStructure);//初始化GPIOB GPIO_SetBits(GPIOB,GPIO_Pin_13|GPIO_Pin_14|GPIO_Pin_15); //PB13/14/15上拉 SPI_InitStructure.SPI_Direction = SPI_Direction_2Lines_FullDuplex; //设置SPI单向或者双向的数据模式:SPI设置为双线双向全双工 SPI_InitStructure.SPI_Mode = SPI_Mode_Master; //设置SPI工作模式:设置为主SPI SPI_InitStructure.SPI_DataSize = SPI_DataSize_8b; //设置SPI的数据大小:SPI发送接收8位帧结构 SPI_InitStructure.SPI_CPOL = SPI_CPOL_Low; //串行同步时钟的空闲状态为低电平,看手册 SPI_InitStructure.SPI_CPHA = SPI_CPHA_2Edge; //???串行同步时钟的第二个跳变沿(上升或下降)数据被采样 (两个都可以试试) SPI_InitStructure.SPI_NSS = SPI_NSS_Soft; //NSS信号由硬件(NSS管脚)还是软件(使用SSI位)管理:内部NSS信号有SSI位控制 SPI_InitStructure.SPI_BaudRatePrescaler = SPI_BaudRatePrescaler_256; //定义波特率预分频的值:波特率预分频值为256 SPI_InitStructure.SPI_FirstBit = SPI_FirstBit_MSB; //指定数据传输从MSB位还是LSB位开始:数据传输从MSB位开始 SPI_InitStructure.SPI_CRCPolynomial = 7; //CRC值计算的多项式 SPI_Init(SPI2,&SPI_InitStructure); //根据SPI_InitStruct中指定的参数初始化外设SPIx寄存器 SPI_Cmd(SPI2,ENABLE); //使能SPI外设 SPI2_ReadWriteByte(0xff);//启动传输 }另外有代码进行其他一些设置,为了方便使用SPI进行读写,在STM32的SPI读写函数的基础上,我们又封装了两个函数,spiWrite和spiRead。
spiWrite函数用于写寄存器,其调用方法非常简单,函数可参考如下:
/** *spiWrite - 写AFE4300寄存器 *@spiAddr:寄存器地址 *@spiData:16位的数据 */ void spiWrite (unsigned char spiAddr,unsigned short spiData) {//先发送地址,再发送数据高8,低8 SPI_AFE4300_CS = 1; SPI_AFE4300_CS = 0; //使能器件 SPI2_ReadWriteByte(spiAddr); SPI2_ReadWriteByte(spiData >> 8);// Load MSB write data SPI2_ReadWriteByte(spiData); // Load LSB write data SPI_AFE4300_CS = 1; }spiRead函数用于读寄存器,代码可参考如下: /** *spiRead - 读取AFE4300寄存器 *@spiAddr:寄存器地址 *返回unsigned short 类型的数据(16位) */ unsigned short spiRead(unsigned char spiAddr) { unsigned short spiData; SPI_AFE4300_CS = 1; SPI_AFE4300_CS = 0; //使能器件 spiData = SPI2_ReadWriteByte(0x20 | spiAddr); //发送读取状态寄存器命令,返回读取到的值 现在这个是没用的 spiData = (SPI2_ReadWriteByte(0x00)) << 8; // Read MSB data spiData |= SPI2_ReadWriteByte(0x00);// Read LSB data SPI_AFE4300_CS = 1; //取消片选 spiWrite (spiAddr,spiData); // Writeback read data due to feature bug on the BCM device return spiData; // Return SPI read data }有了这两个接口,对于AFE4300的配置就更加的方便和简洁。 AFE4300配置AFE4300的配置完全按照其datasheet所写进行初始化。其中复位引脚RST(53)低电平复位,高电平正常操作,在复位完成之后,即可开始对AFE4300进行初始化。
以IQ模式为例,其初始化可参考下面的一小段代码:
// Reset AFE4300 GPIO_ResetBits(GPIOG,GPIO_Pin_14); delay_ms(1); GPIO_SetBits(GPIOG,GPIO_Pin_14); //0x01 ADC_CONTROL_REGISTER1 这里很多位都是配置不同功能的 spiWrite(0x01,0x4170); //860SPS //DEVICE_CONTROL1 第0位和第2位 和电源相关 //开BMP还是体重 spiWrite(0x02,0x0000);//空的寄存器 spiWrite(0x03,0xFFFF); //空的寄存器 spiWrite(0x09,0x6006); //设置DAC频率 250k spiWrite(0x0E,0x00FF); //开一个电流的通道 0:+ 1:- spiWrite(0x0A,0x0408); //开一个电压测量通道 0:+ 1:- spiWrite(0x0B,0x0408); //分频 IQ_DEMOD_CLK BCM_DAC_FREQ // 1 1M 250K ! // 2 500K 125K ! // 4 250K 62.5K // 8 125K 31.25K // 16 62.5K 15.625K // 32 31.25K 7.8125K //开启IQ模式 spiWrite(0x0C,0x0800); //IQ_DEMOD_CLK_DIV_FAC:1分频 spiWrite(0x0F,0x0000);
配置好了之后即可进行ADC的读取。
基本的数据处理我们测量人体的阻抗得到的是一个复阻抗,如下面的公式所述
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?
由IQ调制解调的原理,最终可以得到I分量和Q分量如下:
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ??
进而有
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?
我们测量所得到的是I分量和Q分量的值,因此通过上述公式可以算出阻抗Z,但是还有一个系数K为止,芯片有几个引脚是用来连接校准电阻的,但是由于干扰的情况不同,K并不是唯一的,即K也是一个变量,会随着外界的环境而变。我们可以通过分别开启IQ通道读取IQ分量:
spiWrite(0x10,0x0063); //开启I通道 afe4300Data_new = spiRead(0);//读ADC spiWrite(0x10,0x0065); //开启Q通道 afe4300Data_new = spiRead(0);//读ADC
但是,直接读取ADC的值的时候,数据的波动是非常大的,因此需要采取滤波,至于采取什么滤波算法,因为之前接触到一些传感器的滤波都是使用卡尔曼滤波,出于学习的目的,我也是使用了卡尔曼滤波,卡尔曼滤波的相关学习可参考我的另一篇博客
项目应用中的卡尔曼滤波
。使用了卡尔曼滤波后数据变得比较稳定,但是K值怎么确定呢?我的做法是采用最小二乘法进行数据拟合。我们制作了一排电阻,其阻值由小到大,然后使用AFE4300对这些电阻进行测量,研究其测量值与真实值之间的关系,将结果使用matlab进行处理,代码如下(包含测试数据):
function AFE4300_Data clc; clear; close all; %a,b,保存实际测得的数据 x = [0.782586286 4.660827093 16.670862 20.89953036 27.18909184 32.8900304 45.89909348 57.44171326 84.29415621 102.9043944];%测量值 频率 y = [19.7 39.5 98.8 119.1 149.1 177.7 239.7 296.0 423.0 512.0];%实际值 hold on h1 = plot(x,y)%画出实际的曲线 legend([h1(1)],'实际曲线');%显示格式 p = polyfit(x,y,1)%进行线性拟合 p保存的系数从高到低 xlabel('测量值'); ylabel('真实值'); figure t=0:200; s = 4.8128*t + 18.0136; hold on h2 = plot(t,s,'r+') s = polyval(p,t);%画出拟合后的曲线 h3 = plot(t,'b') xlabel('测量值'); ylabel('真实值'); legend([h2(1) h3(1)],'算式拟合','拟合曲线');%显示格式可以看到结果呈现很好的线性,因此可以得到K值,K值算出来后,可用已经得到的K值,带回去测量那一排电阻,得到的结果与真实值很接近,因此这种做法应该是可行的。
按照这种方法可以得到人体的阻抗,当然这只是第一步,由阻抗在推算出其他的东西需要做非常多的工作,TI的工程师说有很多公司有很多的paper在研究这个。具体要自己再去看相关的论文。
关于AFE4300的参考电路和代码均上传到AFE4300参考资料
,供各位下载。
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?? (编辑:李大同) 【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容! |