MoistureSoftware/Source/AD7190.c

706 lines
20 KiB
C
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

#include "spi.h"
#include "APPDEF.H"
#include "math.h"
#include "string.h"
#include "stdio.h"
// AD7190寄存器地址定义
#define AD7190_REG_COMM 0x00 << 3
#define AD7190_REG_STAT 0x00 << 3
#define AD7190_REG_MODE 0x01 << 3
#define AD7190_REG_CONF 0x02 << 3
#define AD7190_REG_DATA 0x03 << 3
#define AD7190_REG_GPOC 0x05 << 3
// AD7190命令定义
#define AD7190_CMD_NOP 0xFF
#define AD7190_CMD_WR 0x00
#define AD7190_CMD_RD 0x40
// AD7190配置寄存器位掩码
#define AD7190_CONF_CHOP 0x800000
#define AD7190_CONF_REFSEL2 0x100000
// AD7190配置寄存器通道选择
#define AD7190_CONF_CH7 0x008000
#define AD7190_CONF_CH6 0x004000
#define AD7190_CONF_CH5 0x002000
#define AD7190_CONF_CH4 0x001000
#define AD7190_CONF_CH3 0x000800
#define AD7190_CONF_CH2 0x000400
#define AD7190_CONF_CH1 0x000200
#define AD7190_CONF_CH0 0x000100
// AD7190配置寄存器
#define AD7190_CONF_BURNOUT 0x000080
#define AD7190_CONF_REFDET 0x000040
#define AD7190_CONF_BUF 0x000010
#define AD7190_CONF_UB 0x000008
// AD7190配置寄存器增益定义
#define AD7190_CONF_GAIN_1 0x000000
#define AD7190_CONF_GAIN_8 0x000003
#define AD7190_CONF_GAIN_16 0x000004
#define AD7190_CONF_GAIN_32 0x000005
#define AD7190_CONF_GAIN_64 0x000006
#define AD7190_CONF_GAIN_128 0x000007
// AD7190配置寄存器工作模式定义
#define AD7190_CONF_MODE_CONT 0x000000
#define AD7190_CONF_MODE_ZEROSEL 0x800000
#define AD7190_CONF_MODE_FullSEL 0xA00000
#define AD7190_CONF_MODE_FS9_0 0x0003FF // 4.7Hz
#define AD7190_CONF_MODE_FS9_02 0x0001E0//10Hz
#define AD7190_CONF_MODE_FS9_03 0x000096//50Hz
#define AD7190_CONF_MODE_InCLK 0x080000// 4.92 MHz内部时钟 MCLK2引脚为三态
// AD7190 电桥开关
#define AD7190_GPOCON_BDPSW 0x40
void AD7190_WriteRegister(uint8_t regAddr, uint32_t regValue)
{
SPI1_ReadWrite(AD7190_CMD_WR | regAddr);
SPI1_ReadWrite((regValue >> 16) & 0xFF);
SPI1_ReadWrite((regValue >> 8) & 0xFF);
SPI1_ReadWrite(regValue & 0xFF);
}
uint32_t AD7190_ReadRegister(uint8_t regAddr)
{
uint32_t regValue = 0;
SPI1_ReadWrite(AD7190_CMD_RD | regAddr);
regValue = SPI1_ReadWrite(0xFF);
regValue = (regValue << 8) + SPI1_ReadWrite(0xFF);
regValue = (regValue << 8) + SPI1_ReadWrite(0xFF);
return regValue;
}
void AD7190_WriteRegisterOnce(uint8_t regAddr, uint8_t regValue)
{
SPI1_ReadWrite(AD7190_CMD_WR | regAddr);
SPI1_ReadWrite(regValue);
}
uint8_t AD7190_ReadRegisterOnce(uint8_t regAddr)
{
uint32_t regValue = 0;
SPI1_ReadWrite(AD7190_CMD_RD | regAddr);
regValue = SPI1_ReadWrite(0xFF);
return regValue;
}
bool AD7190_WaitForReady(uint32_t timeout)
{
uint32_t count = 0;
while (GPIO_ReadInputDataBit(GPIOA, GPIO_Pin_6) && (count < timeout))
{
delay_us(1);
count++;
}
if (count >= timeout)
{
return false;
}
else
{
return true;
}
}
//extern uint16_t Read_Internal_Temperature();
//// AD7190函数读取AD转换结果
//float V25 = 1.43; // 25 度时的传感器电压(mV)
// float Avg_Slope = 4.3; // 传感器电压与温度之间的平均斜率(mV/°C)
// // 获取 ADC 参考电压值(一般为 3.3V
// float Vref = 3.3; // 参考电压值(V)
//float TemperatureIn;
uint8_t ErrCount;
uint16_t DifErrCount;
uint32_t lastdata = 0;
uint32_t UseuLBuf[20];
uint32_t UseuLBuf2[20];
uint16_t BufIndex = 0;
// 计算一组数字的平均值
float calculateAverage(uint32_t arr[], int size)
{
double sum = 0.0;
// 计算总和
int i;
for (i = 0; i < size; i++)
{
sum += arr[i];
}
// 计算平均值
double average = sum / size;
return average;
}
void bubbleSort(uint32_t *arr, int n) {
int i, j, temp;
for (i = 0; i < n-1; i++) {
for (j = 0; j < n-i-1; j++) {
if (arr[j] > arr[j+1]) {
// 交换 arr[j] 和 arr[j+1]
temp = arr[j];
arr[j] = arr[j+1];
arr[j+1] = temp;
}
}
}
}
/**
***********************************************************
* @brief printf函数默认打印输出到显示器如果要输出到串口
必须重新实现fputc函数将输出指向串口称为重定向
* @param
* @return
***********************************************************
*/
int fputc(int ch, FILE *f)
{
while (!(READ_BIT(USART1->SR, USART_SR_TXE))) {
delay_us(100);
}
USART1->DR = ch;
return ch;
}
float average;
float center;
int ErrcountAdd = 0;
int DifErrCountAdd = 0;
uint32_t AD7190_ReadData( void )
{
uint32_t data = 0;
if(AD7190_WaitForReady(50000))
{
data = AD7190_ReadRegister(AD7190_REG_DATA);
if(fabs((int)data - (int)lastdata) > 100000 )
{
DifErrCount ++;
DifErrCountAdd++;
}
else
{
DifErrCount = 0;
}
lastdata = data;
if((data > 8388608) || (data < 100 ))
{
ErrCount++;
ErrcountAdd++;
}
else
{
ErrCount = 0;
}
}
else
{
ErrCount++;
ErrcountAdd++;
}
if(ErrCount > 3 || DifErrCount > 20)
{
uint32_t modeReg;
SPI1_Configuration();
SPI1_ReadWrite(0xFF);
SPI1_ReadWrite(0xFF);
SPI1_ReadWrite(0xFF);
SPI1_ReadWrite(0xFF);
SPI1_ReadWrite(0xFF); // 40个脉冲复位ADC
osDelay(50);
// 配置寄存器:通道选择、参考电压源、增益和工作模式
// 打开PSW
uint8_t GPOC = AD7190_ReadRegisterOnce(AD7190_REG_GPOC);
GPOC |= AD7190_GPOCON_BDPSW;
AD7190_WriteRegisterOnce(AD7190_REG_GPOC, GPOC);
osDelay(5);
uint32_t config = AD7190_CONF_GAIN_128 | AD7190_CONF_UB | AD7190_CONF_BUF | AD7190_CONF_CH0;// 0x0000011F;
AD7190_WriteRegister(AD7190_REG_CONF, config);
osDelay(5);
// 连续转换模式
modeReg = AD7190_CONF_MODE_FS9_0 | AD7190_CONF_MODE_InCLK;
AD7190_WriteRegister(AD7190_REG_MODE, modeReg);
ErrCount = 0;
osDelay(500);
if(AD7190_WaitForReady(50000))
{
data = AD7190_ReadRegister(AD7190_REG_DATA);
}
}
return data;
}
// 定义卡尔曼滤波器的参数结构体
typedef struct
{
double x; // 状态估计值
double P; // 状态协方差
double Q; // 过程噪声协方差
double R; // 观测噪声协方差
double K; // 卡尔曼增益
} KalmanFilter;
KalmanFilter kf2;
// 初始化卡尔曼滤波器
void kalman_filter_init2(KalmanFilter *kf, float initial_x, float initial_P, float process_noise, float measurement_noise)
{
kf->x = initial_x;
kf->P = initial_P;
kf->Q = process_noise;
kf->R = measurement_noise;
}
// 更新卡尔曼滤波器状态
void kalman_filter_update2(KalmanFilter *kf, float measurement)
{
// 预测步骤
float x_pred = kf->x; // 预测的状态值
float P_pred = kf->P + kf->Q; // 预测的状态协方差
// 更新步骤
kf->K = P_pred / (P_pred + kf->R); // 计算卡尔曼增益
kf->x = x_pred + kf->K * (measurement - x_pred); // 更新状态估计值
kf->P = (1 - kf->K) * P_pred; // 更新状态协方差
}
uint8_t FollowCount = 0; // 零点跟踪计数
uint8_t TimeCount = 0; // 蠕变时间计数
uint32_t FliterCount = 0; // 长期抑制计数
uint16_t SetZeroCount = 0; // 卸载归零计数
int32_t ADvalue2 = 0; // ADC采样原始值
double ADvalue2filter = 0.0f; // ADC采样卡尔曼滤波值
double ADvalue2filterOld = 0; // 上次ADC采样卡尔曼滤波值
double WeightData2Temp = 0.0f; // 本次ADvalue2filter计算重量值
double WeightData2TempOld; // 上次ADvalue2filter计算重量值
double WeightData2Finally = 0.0f; // 最终输出前重量值
double UninstiallRefWeight= 0.0f; // 卸载重物时的重量值
double WeightZeroOld = 0; // 上次稳定状态时零点值
struct uCalibrateWeight CalibrateWeight2; //传感器 斜率 零点
double WeightData2 = 0.0f; // 最终输出重量值
bool weightChanging = false; // 传感器稳定标志
bool weight11g = false; // 传感器稳定标志
float ZeroWeightOld;
float ZeroWeightChange;
float LowFecAlpha = 0.95f; // 超低频波动抑制系数,发生突变时偏向跟踪新值,相对稳定时跟踪旧值
float WeightRefStart = 0;
uint8_t i;
#define ChangeMax 10
#define ZeroTrackMax 0.050f
#define FollowMax 0.030f
#define FliterCountMax 200
#define FollowDlteaMax 0.001f
#define FollowAlpha 0.9999f // 长期数据跟踪系数
void AD7190_Run(const void *p_arg)
{
uint8_t FilterQOld, SensorQOld, ZeroTrackOld, RuBianLiangOld, ruBianTimeOld;
int8_t RubianLiang, RubianTime;
float ZeroTrackTime, ZeroTrackRange;
osDelay(600);
ADvalue2 = AD7190_ReadData();
osDelay(200);
ADvalue2 = AD7190_ReadData();
ADvalue2filterOld = ADvalue2filter = ADvalue2;
kalman_filter_init2(&kf2, ADvalue2, 1.0, 0.001, 0.1);
WeightZeroOld = CalibrateWeight2.WeightZero;
for (;;)
{
if (FilterQOld != Set.FilterQ)
{
FilterQOld = Set.FilterQ;
switch (Set.FilterQ) // 滤波器信任度 信任度越高 反应越慢数据显示越稳定
{
case 0:
kf2.Q = 0.1;
break;
case 1:
kf2.Q = 0.08;
break;
case 2:
kf2.Q = 0.06;
break;
case 3:
kf2.Q = 0.04;
break;
case 4:
kf2.Q = 0.02;
break;
case 5:
kf2.Q = 0.009;
break;
case 6:
kf2.Q = 0.007;
break;
case 7:
kf2.Q = 0.005;
break;
case 8:
kf2.Q = 0.003;
break;
case 9:
kf2.Q = 0.001;
break;
default:
break;
}
}
if (SensorQOld != Set.SensorQ)
{
SensorQOld = Set.SensorQ;
switch (Set.SensorQ) // 传感器信任度 信任度越高 反应越迅速,数据波动越大 显示越不稳定
{
case 0:
kf2.R = 0.5;
break;
case 1:
kf2.R = 0.3;
break;
case 2:
kf2.R = 0.1;
break;
case 3:
kf2.R = 0.08;
break;
case 4:
kf2.R = 0.06;
break;
case 5:
kf2.R = 0.04;
break;
case 6:
kf2.R = 0.02;
break;
case 7:
kf2.R = 0.009;
break;
case 8:
kf2.R = 0.005;
break;
case 9:
kf2.R = 0.001;
break;
default:
break;
}
}
if (ZeroTrackOld != Set.ZeroTrack) // 零点跟踪 跟踪级别越高 原始数据发生缓慢变化时,最终数据不会发生变化的可能性越大。例如 当跟踪级别设置为9时那么如果原始数据在4秒内变化小于2.5mg那么最终数据不会发生变化。原理是cpu会将这4秒内变化的数据叠加到零点上相当于动态调零了。
{
ZeroTrackOld = Set.ZeroTrack;
switch (ZeroTrackOld)
{
case 0:
ZeroTrackTime = 20; // 连续20秒
ZeroTrackRange = 0; // 相邻两次采样数据小于0.000g
break;
case 1:
ZeroTrackTime = 15;
ZeroTrackRange = 0.0005;
break;
case 2:
ZeroTrackTime = 10;
ZeroTrackRange = 0.0005;
break;
case 3:
ZeroTrackTime = 7;
ZeroTrackRange = 0.0005;
break;
case 4:
ZeroTrackTime = 4;
ZeroTrackRange = 0.0005;
break;
case 5:
ZeroTrackTime = 4;
ZeroTrackRange = 0.0008;
break;
case 6:
ZeroTrackTime = 4;
ZeroTrackRange = 0.001;
break;
case 7:
ZeroTrackTime = 4;
ZeroTrackRange = 0.0015;
break;
case 8:
ZeroTrackTime = 4;
ZeroTrackRange = 0.002;
break;
case 9:
ZeroTrackTime = 4;
ZeroTrackRange = 0.0025;
break;
default:
break;
}
}
if (ruBianTimeOld != Set.RuBianTime) // 蠕变时间 级别越高 蠕变时间越短,蠕变越快 零为不蠕变
{
ruBianTimeOld = Set.RuBianTime;
switch (Set.RuBianTime)
{
case 0:
RubianTime = 100;
break;
case 1:
RubianTime = 60;
break;
case 2:
RubianTime = 30;
break;
case 3:
RubianTime = 20;
break;
case 4:
RubianTime = 15;
break;
case 5:
RubianTime = 10;
break;
case 6:
RubianTime = 8;
break;
case 7:
RubianTime = 6;
break;
case 8:
RubianTime = 4;
break;
case 9:
RubianTime = 2;
break;
default:
break;
}
}
if (RuBianLiangOld != Set.RuBianLiang) //蠕变量 可分正向蠕变和反向蠕变 零为不蠕变 当零点跟踪为0时 调零后观察一段时间的数据变化 如果数据持续变化为负数 则为负蠕变。反之为正蠕变。 负蠕变调整蠕变量为负数级别(谨慎调整 建议不调整)
{
RuBianLiangOld = Set.RuBianLiang;
switch (Set.RuBianLiang)
{
case 0:
RubianLiang = -5;
break;
case 1:
RubianLiang = -4;
break;
case 2:
RubianLiang = -3;
break;
case 3:
RubianLiang = -2;
break;
case 4:
RubianLiang = -1;
break;
case 5:
RubianLiang = 0;
break;
case 6:
RubianLiang = 1;
break;
case 7:
RubianLiang = 2;
break;
case 8:
RubianLiang = 3;
break;
case 9:
RubianLiang = 4;
break;
case 10:
RubianLiang = 5;
break;
default:
break;
}
}
osDelay(200);
ADvalue2 = AD7190_ReadData(); //4.7Hz 213ms
kalman_filter_update2(&kf2, ADvalue2); // 更新步骤
if(fabs(ADvalue2filter - kf2.x) < ChangeMax )
{
LowFecAlpha = 0.95; // 数据处于稳定状态 未有重量突变或小幅度连续单向改变时信任上次值
}
else
{
LowFecAlpha = 0.5; // 数据处于较大波动状态 有重量突变或小幅度连续单向改变时信任本次值
}
ADvalue2filter = kf2.x *(1-LowFecAlpha)+ADvalue2filter*LowFecAlpha;
// if(pageNum != 1)
// {
// if(WeightData2TempOld - WeightData2Temp > 0.500f) // 卸载重物
// {
// if(UninstiallRefWeight < 0.005f) // 如果未触发归零条件
// {
// UninstiallRefWeight = WeightData2TempOld;
// WeightZeroOld = CalibrateWeight2.WeightZero; // 备份零点原始值,以备不稳定状态下重新加载重物导致数据不准确
// }
// }
// else if(WeightData2TempOld - WeightData2Temp < -0.500f)//加载重物
// {
// UninstiallRefWeight = 0.0f;
// if( WeightZeroOld != CalibrateWeight2.WeightZero)
// {
// CalibrateWeight2.WeightZero = WeightZeroOld; // 置零未完成或零点跟踪未完成,恢复至改变前零点值,防止数据不准确
// }
// SetZeroCount = 0;
// }
// if(UninstiallRefWeight > 0.005f) // 卸载重物后接近归零时进行归零操作
// {
// if(SetZeroCount++ > 50 ) // 归零后重置触发归零条件
// {
//
// UninstiallRefWeight = 0.0f;
// WeightZeroOld = CalibrateWeight2.WeightZero;
// SetZeroCount = 0;
// }
// if(fabs(WeightData2Temp) < 0.100f && fabs(WeightData2Temp) > 0.004f) // 符合归零区间范围则缓慢归零
// {
// SetZeroCount = 0;
// CalibrateWeight2.WeightZero += WeightData2Temp / CalibrateWeight2.WeightSlope / 10;
// ZeroWeightChange = CalibrateWeight2.WeightSlope * (ADvalue2filter - CalibrateWeight2.WeightZero);
// }
// ZeroWeightOld = CalibrateWeight2.WeightSlope * (ADvalue2filter - WeightZeroOld);
// if( fabs(ZeroWeightOld) <= fabs(ZeroWeightChange) )
// {
// weight11g=0;
// CalibrateWeight2.WeightZero = WeightZeroOld;
// }
// else
// {
// weight11g=1;
// }
// }
// }
WeightData2TempOld = WeightData2Temp;
WeightData2Temp = CalibrateWeight2.WeightSlope * (ADvalue2filter - CalibrateWeight2.WeightZero);
// printf("%f,%f,%f,%.4f\n",Temperature,ADvalue2filter,WeightData2Temp,WeightData2Finally);
if( RubianLiang != 0 ) // 蠕变
{
if (TimeCount++ > 4 * RubianTime) // 动态称重时蠕变跟踪
{
TimeCount = 0;
if (CalibrateWeight2.WeightZero == WeightZeroOld)
{
CalibrateWeight2.WeightZero += RubianLiang;
}
WeightZeroOld = CalibrateWeight2.WeightZero;
}
}
if (fabs(WeightData2TempOld - WeightData2Temp) < ZeroTrackRange && fabs(WeightData2Temp) < ZeroTrackMax && ( pageNum != 1)) // 符合跟踪范围 型评 当示值为零或相当于毛重为0时 负的净重值,且未运行,且水分测定仪处于平衡稳定状态 才允许运行
{
if (FollowCount++ > 4 * ZeroTrackTime) // 零点动态跟踪
{
FollowCount = 0;
TimeCount = 0;
CalibrateWeight2.WeightZero += ADvalue2filter - ADvalue2filterOld;
WeightZeroOld = CalibrateWeight2.WeightZero;
ADvalue2filterOld = ADvalue2filter;
}
}
else
{
FollowCount = 0;
ADvalue2filterOld = ADvalue2filter;
}
if ( fabs(WeightData2Temp) > ZeroTrackMax && fabs(WeightData2TempOld - WeightData2Temp) < FollowDlteaMax && fabs(WeightData2Temp - WeightRefStart) < FollowMax && ( pageNum != 1)) //重量不变且大于零点跟踪范围未加热进行长期数据跟踪
{
if(FliterCount < FliterCountMax)
FliterCount++;
else
FliterCount = FliterCountMax;
WeightData2Finally = WeightData2Finally + (WeightData2Temp - WeightData2Finally) * ( 1.00000f - FollowAlpha * FliterCount / FliterCountMax);
}
else
{
WeightData2Finally = WeightRefStart = WeightData2Temp;
FliterCount = 0;
}
if (fabs(WeightData2 - WeightData2Finally) > 0.006f) // 变化大于50mg/s 置位传感器不稳定标志
{
weightChanging = 1;
}
else
{
weightChanging = 0;
}
if (fabs(WeightData2 - WeightData2Finally) > 0.0002f) // 数据滤波
{
WeightData2 = (int32_t)(WeightData2Finally * 10000) / 10000.0f;
}
else if(fabs(WeightData2Finally) < 0.001f)
{
WeightData2 = (int32_t)(WeightData2Finally * 10000) / 10000.0f;
}
}
}
osThreadDef(AD7190_Run, osPriorityNormal, 1, 0);
// AD7190函数初始化AD7190
void AD7190_Init()
{
uint32_t modeReg;
SPI1_Configuration();
SPI1_ReadWrite(0xFF);
SPI1_ReadWrite(0xFF);
SPI1_ReadWrite(0xFF);
SPI1_ReadWrite(0xFF);
SPI1_ReadWrite(0xFF); // 40个脉冲复位ADC
osDelay(50);
// 配置寄存器:通道选择、参考电压源、增益和工作模式
// 打开PSW
uint8_t GPOC = AD7190_ReadRegisterOnce(AD7190_REG_GPOC);
GPOC |= AD7190_GPOCON_BDPSW;
AD7190_WriteRegisterOnce(AD7190_REG_GPOC, GPOC);
osDelay(5);
uint32_t config = AD7190_CONF_GAIN_128 | AD7190_CONF_UB | AD7190_CONF_BUF | AD7190_CONF_CH0;// 0x0000011F;
AD7190_WriteRegister(AD7190_REG_CONF, config);
osDelay(5);
modeReg = AD7190_CONF_MODE_FS9_0 ;// 滤波器最低速率输出 执行上电校准
AD7190_WriteRegister(AD7190_REG_MODE, modeReg);
osDelay(5);
//连续转换模式
modeReg = AD7190_CONF_MODE_FS9_0 | AD7190_CONF_MODE_InCLK;
AD7190_WriteRegister(AD7190_REG_MODE, modeReg);
CalibrateWeight2.WeightSlope = 0.0001530345f;
// CalibrateWeight2.WeightZero = 745430;
osThreadCreate(osThread(AD7190_Run), NULL);
}