MoistureSoftware/Source/AD7190.c

562 lines
16 KiB
C
Raw Permalink 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"
// 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_CH_MASK 0x000F
#define AD7190_CONF_BURNOUT 0x0800
#define AD7190_CONF_REFSEL 0x0400
#define AD7190_CONF_GAIN_MASK 0x0038
#define AD7190_CONF_MODE_MASK 0x0C00
// AD7190配置寄存器增益定义
#define AD7190_CONF_GAIN_1 0x00
#define AD7190_CONF_GAIN_8 0x08
#define AD7190_CONF_GAIN_16 0x10
#define AD7190_CONF_GAIN_32 0x18
#define AD7190_CONF_GAIN_64 0x20
#define AD7190_CONF_GAIN_128 0x28
#define AD7190_CONF_GAIN_256 0x30
// 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
// 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;
// SPI1_ReadWrite(AD7190_CMD_RD | AD7190_REG_STAT);
// while ((SPI1_ReadWrite(0xFF) & 0x80) && (count < timeout)) {
// delay_us(1);
// count++;
// }
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;
uint32_t AD7190_ReadData()
{
uint32_t data = 0;
//uint16_t TempI;
if(AD7190_WaitForReady(50000))
{
data = AD7190_ReadRegister(AD7190_REG_DATA);
// TempI = Read_Internal_Temperature();
// // 将 ADC 值转换为电压值
// float V_ADC = (TempI * Vref) / 4095;
// // 计算温度值(摄氏度)
// TemperatureIn = ((V25 - V_ADC)*1000 / Avg_Slope) + 25.0;
if(data > 15000000)
{
ErrCount++;
}
else
{
ErrCount = 0;
}
}
else
{
ErrCount++;
}
if(ErrCount > 10)
{
SPI1_Configuration();
SPI1_ReadWrite(0xFF);
SPI1_ReadWrite(0xFF);
SPI1_ReadWrite(0xFF);
SPI1_ReadWrite(0xFF);
SPI1_ReadWrite(0xFF);
osDelay(50);
uint32_t modeReg;
// 配置寄存器:通道选择、参考电压源、增益和工作模式
// 打开PSW
uint8_t GPOC = AD7190_ReadRegisterOnce(AD7190_REG_GPOC);
GPOC |= AD7190_GPOCON_BDPSW;
AD7190_WriteRegisterOnce(AD7190_REG_GPOC, GPOC);
osDelay(5);
uint32_t config = 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_ReadRegister(AD7190_REG_MODE);
modeReg &= ~0x00E00000;
modeReg |= AD7190_CONF_MODE_ZEROSEL;
AD7190_WriteRegister(AD7190_REG_MODE, modeReg);
osDelay(5);
AD7190_WaitForReady(1000000);
modeReg &= ~0x00E00000;
modeReg |= AD7190_CONF_MODE_FullSEL;
AD7190_WriteRegister(AD7190_REG_MODE, modeReg);
osDelay(5);
AD7190_WaitForReady(1000000);
// 校准完成 切换回连续转换模式
modeReg = 0x000803FF;
AD7190_WriteRegister(AD7190_REG_MODE, modeReg);
ErrCount = 0;
osDelay(500);
if(AD7190_WaitForReady(50000))
{
data = AD7190_ReadRegister(AD7190_REG_DATA);
}
}
return data;
}
// AD7190函数读取AD转换结果并转换为实际电压值
// static void bubbleSort2(float *num)
//{
// float temp;
// int i, j;
// for (i = 0; i < 5; i++) {
// for (j = 0; j < 5 - i; j++) {
// if (num[j] > num[j + 1]) {
// // 交换相邻元素的值
// temp = num[j];
// num[j] = num[j + 1];
// num[j + 1] = temp;
// }
// }
// }
//} // 定义卡尔曼滤波器的参数结构体
typedef struct
{
float x; // 状态估计值
float P; // 状态协方差
float Q; // 过程噪声协方差
float R; // 观测噪声协方差
float 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; // 更新状态协方差
}
float WeightData2 = 0.0f;
float ADvalue2filter = 0.0f;
// static float bufferdata2[5];
// static float dataout2[5];
static float WeightData2Temp = 0.0f;
int32_t ADvalue2filterOld = 0;
int32_t ADvalue2 = 0;
uint8_t ic2 = 0;
uint8_t i;
int32_t data2 = 0;
struct uCalibrateWeight CalibrateWeight2;
uint8_t FollowCount = 0;
uint8_t TimeCount = 0;
int32_t WeightZeroOld = 0;
uint32_t modeRega;
uint32_t configa;
uint32_t configao;
bool weightChanging = false;
#include "APPDEF.H"
void AD7190_Run(const void *p_arg)
{
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;
uint8_t FilterQOld, SensorQOld, ZeroTrackOld, RuBianLiangOld, ruBianTimeOld;
int8_t RubianLiang, RubianTime;
float ZeroTrackTime, ZeroTrackRange;
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;
ZeroTrackRange = 0;
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(190);
ADvalue2 = AD7190_ReadData();
kalman_filter_update2(&kf2, ADvalue2); // 更新步骤
ADvalue2filter = kf2.x;
WeightData2Temp = CalibrateWeight2.WeightSlope * ((int32_t)ADvalue2filter - (int32_t)CalibrateWeight2.WeightZero);
if( RubianLiang != 0 )
{
if (TimeCount++ > 4 * RubianTime) // 动态称重时蠕变跟踪
{
TimeCount = 0;
if (CalibrateWeight2.WeightZero == WeightZeroOld)
{
CalibrateWeight2.WeightZero += RubianLiang;
}
WeightZeroOld = CalibrateWeight2.WeightZero;
}
}
if (fabs(WeightData2 - WeightData2Temp) < ZeroTrackRange)
{
if (FollowCount++ > 4 * ZeroTrackTime) // 零点动态跟踪
{
FollowCount = 0;
TimeCount = 0;
CalibrateWeight2.WeightZero += ADvalue2filter - ADvalue2filterOld;
ADvalue2filterOld = ADvalue2filter;
}
}
else
{
FollowCount = 0;
ADvalue2filterOld = ADvalue2filter;
}
if (fabs(WeightData2 - WeightData2Temp) > 0.01f)
{
weightChanging = 1;
}
else
{
weightChanging = 0;
}
if (fabs(WeightData2 - WeightData2Temp) > 0.001f) // 数据滤波
{
WeightData2Temp = (int32_t)(WeightData2Temp * 10000) / 10000.0f;
WeightData2 = WeightData2Temp;
}
}
}
osThreadDef(AD7190_Run, osPriorityNormal, 1, 0);
// AD7190函数初始化AD7190
void AD7190_Init()
{
SPI1_Configuration();
SPI1_ReadWrite(0xFF);
SPI1_ReadWrite(0xFF);
SPI1_ReadWrite(0xFF);
SPI1_ReadWrite(0xFF);
SPI1_ReadWrite(0xFF);
osDelay(50);
uint32_t modeReg;
// 配置寄存器:通道选择、参考电压源、增益和工作模式
// 打开PSW
uint8_t GPOC = AD7190_ReadRegisterOnce(AD7190_REG_GPOC);
GPOC |= AD7190_GPOCON_BDPSW;
AD7190_WriteRegisterOnce(AD7190_REG_GPOC, GPOC);
osDelay(5);
uint32_t config = 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_ReadRegister(AD7190_REG_MODE);
modeReg &= ~0x00E00000;
modeReg |= AD7190_CONF_MODE_ZEROSEL;
AD7190_WriteRegister(AD7190_REG_MODE, modeReg);
osDelay(5);
AD7190_WaitForReady(1000000);
modeReg &= ~0x00E00000;
modeReg |= AD7190_CONF_MODE_FullSEL;
AD7190_WriteRegister(AD7190_REG_MODE, modeReg);
osDelay(5);
AD7190_WaitForReady(1000000);
// 校准完成 切换回连续转换模式
modeReg = 0x000803FF;
AD7190_WriteRegister(AD7190_REG_MODE, modeReg);
CalibrateWeight2.WeightSlope = 0.0000818f;
CalibrateWeight2.WeightZero = 745430;
osThreadCreate(osThread(AD7190_Run), NULL);
}