TestComplete总结十

本文详细探讨了编程领域的核心概念与实践技巧,包括文本处理、前端与后端开发、移动应用、游戏开发等细分领域,以及大数据、AI、测试、运维、云计算等热门方向。通过案例分析和最佳实践,帮助开发者深入了解并掌握各技术点,从而提升编程技能和项目成功率。
总结:
1)项目中提供的alias不一定正确;
2)注意在属性中textContent与contentText的区别;textContent忽略回车,而contentText则不;
3)在使用menubar时,注意菜单的写法:一级菜单+”|“+二级菜单,,,
4)在Tenrox中,做项目前不用配置
<think>我们遇到了校准过程中的错误。错误信息显示: 1. EEPROM的CRC校验失败(保存的CRC为0xFFFFFF00,计算得到的是0x870A394C) 2. 无效的偏移量(214)和因子(-0.000000) 3. 校准过程中出现“Invalid calibration difference”错误 问题分析: 1. EEPROM存储的校准数据可能被破坏,导致读取失败。 2. 校准过程中,计算得到的校准因子时,出现了无效的差值(diff为0或过大)。 3. 在读取重量时,由于校准数据无效,导致返回NaN(非数字)。 解决方案: 1. 修复EEPROM的存储和读取,确保数据完整性。 2. 在系统校准过程中增加对校准差值的检查,避免除零和无效值。 3. 增加错误处理机制,当校准失败时提供有意义的错误信息。 我们将重点检查校准数据的存储和加载过程,以及校准计算中的逻辑。 步骤: 1. 确保EEPROM读写正确,包括CRC校验。 2. 在系统校准中,检查零点校准和量程校准的数据范围。 3. 在计算校准因子时,检查差值的有效性。 由于我们没有完整的EEPROM代码,我将提供一个示例的EEPROM存储和加载校准数据的函数,并修复校准函数。 注意:以下代码基于之前的AD7190模块,并增加了EEPROM相关操作。 首先,我们修改校准数据结构,增加版本控制和更健壮的CRC计算。 修改后的校准数据结构(在AD7190.h中): ```c // 校准数据结构 typedef struct { uint32_t version; // 数据版本,用于兼容性 uint32_t calibration_offset; float calibration_factor; float tare_value; uint32_t crc; // CRC32校验值 } CalibrationData; ``` 然后,我们提供计算CRC的函数(使用简单的CRC32算法): ```c #include <stdint.h> #include <stddef.h> // 计算CRC32(简单实现,实际中可能需要更复杂的) static uint32_t calculate_crc(const uint8_t *data, size_t length) { uint32_t crc = 0xFFFFFFFF; for (size_t i = 0; i < length; i++) { crc ^= data[i]; for (int j = 0; j < 8; j++) { if (crc & 1) { crc = (crc >> 1) ^ 0xEDB88320; } else { crc = crc >> 1; } } } return ~crc; } // 计算CalibrationData的CRC(不包括crc字段本身) static uint32_t calibration_data_crc(const CalibrationData *data) { // 将数据视为字节数组,计算除crc字段外的CRC const uint8_t *bytes = (const uint8_t*)data; size_t offset = offsetof(CalibrationData, crc); size_t length = sizeof(CalibrationData) - offsetof(CalibrationData, crc); return calculate_crc(bytes, offset); } ``` 接下来,我们实现保存和加载校准数据到EEPROM的函数(假设我们有EEPROM的读写函数): ```c // 保存校准数据到EEPROM void AD7190_SaveCalibrationToEEPROM(void) { CalibrationData *calib = &ad7190_state.calib; // 计算CRC(不包括crc字段) calib->crc = calibration_data_crc(calib); // 写入EEPROM(假设EEPROM_Write函数存在) EEPROM_Write(0, (uint8_t*)calib, sizeof(CalibrationData)); } // 从EEPROM加载校准数据 uint8_t AD7190_LoadCalibrationFromEEPROM(void) { CalibrationData calib_temp; // 从EEPROM读取(假设EEPROM_Read函数存在) EEPROM_Read(0, (uint8_t*)&calib_temp, sizeof(CalibrationData)); // 验证CRC uint32_t saved_crc = calib_temp.crc; calib_temp.crc = 0; // 计算时crc字段为0 uint32_t calc_crc = calibration_data_crc(&calib_temp); if (saved_crc != calc_crc) { // CRC校验失败 return 0; } // 校验成功,复制到状态 ad7190_state.calib = calib_temp; return 1; } ``` 然后,我们修改系统校准函数,增加对差值的检查: ```c void AD7190_SystemCalibrate(void) { if (!ad7190_state.is_initialized) AD7190_Init(); uint8_t rx_char; printf("===== System Calibration =====\r\n"); // 1. 零点校准 printf("Ensure platform is empty, then press 'z' for zero calibration...\r\n"); while(1) { HAL_UART_Receive(&huart1, &rx_char, 1, HAL_MAX_DELAY); if(rx_char == 'z' || rx_char == 'Z') break; } uint32_t zero_sum = 0; for(int i = 0; i < 32; i++) { zero_sum += AD7190_ReadData(); HAL_Delay(10); } ad7190_state.calib.calibration_offset = zero_sum / 32; // 2. 量程校准 printf("Place 1000.0g weight, then press 'f' for full scale calibration...\r\n"); while(1) { HAL_UART_Receive(&huart1, &rx_char, 1, HAL_MAX_DELAY); if(rx_char == 'f' || rx_char == 'F') break; } uint32_t fs_sum = 0; for(int i = 0; i < 32; i++) { fs_sum += AD7190_ReadData(); HAL_Delay(10); } uint32_t full_scale = fs_sum / 32; // 计算校准因子 int32_t diff = (int32_t)full_scale - (int32_t)ad7190_state.calib.calibration_offset; // 检查差值的有效性 if (diff < 1000 || diff > 1000000) { // 根据实际量程调整阈值 printf("ERROR: Invalid calibration difference: %ld\n", diff); // 重置校准数据 ad7190_state.calib.calibration_offset = 0; ad7190_state.calib.calibration_factor = 1.0f; return; } ad7190_state.calib.calibration_factor = 1000.0f / (float)diff; // 重置去皮值和滤波器 ad7190_state.calib.tare_value = 0.0f; KalmanFilter_Init(&ad7190_state.kf, 0.001f, 0.01f, 1.0f, 0.0f); // 保存校准数据到EEPROM AD7190_SaveCalibrationToEEPROM(); printf("System calibration completed!\n"); } ``` 在初始化时,尝试从EEPROM加载校准数据,如果失败则进行校准: ```c void AD7190_Init(void) { if (ad7190_state.is_initialized) return; // ... 初始化硬件 ... // 尝试从EEPROM加载校准数据 if (AD7190_LoadCalibrationFromEEPROM()) { printf("Loaded calibration data from EEPROM.\n"); } else { printf("No valid calibration data. Starting calibration...\n"); // 这里可以自动启动校准,或者等待用户命令 // 为了安全,我们重置校准数据 ad7190_state.calib.calibration_offset = 0; ad7190_state.calib.calibration_factor = 1.0f; ad7190_state.calib.tare_value = 0.0f; // 注意:这里不自动校准,由用户调用AD7190_SystemCalibrate } // 初始化卡尔曼滤波器 KalmanFilter_Init(&ad7190_state.kf, 0.001f, 0.01f, 1.0f, 0.0f); ad7190_state.is_initialized = 1; } ``` 最后,在读取重量函数中,增加对校准数据的检查,避免无效计算: ```c float AD7190_ReadWeight(void) { if (!ad7190_state.is_initialized) return NAN; // 检查校准数据是否有效 if (ad7190_state.calib.calibration_offset == 0 || ad7190_state.calib.calibration_factor <= 0.0f) { printf("ERROR: Calibration data invalid!\n"); return NAN; } // ... 其余代码不变 ... } ``` 注意:以上EEPROM读写函数(EEPROM_Write和EEPROM_Read)需要根据实际硬件实现。 总结: 1. 我们增加了校准数据的CRC校验,确保存储的数据完整。 2. 校准过程中,对零点校准和量程校准的差值进行了范围检查,避免无效的校准因子。 3. 在初始化时加载校准数据,如果失败则重置校准数据,并提示需要校准。 4. 在读取重量时,先检查校准数据的有效性。 这些修改应该能解决上述错误。 由于问题中提到了EEPROM诊断测试通过,但CRC不匹配,所以重点加强了CRC校验和错误处理。 如果问题仍然存在,可能需要调试EEPROM的读写,确保数据正确写入和读取。 注意:在嵌入式系统中,EEPROM的写入需要确保在写入过程中不会掉电,否则可能导致数据损坏。可以使用备份机制(如写入两次,或使用两个扇区交替存储)来增强鲁棒性。 由于时间关系,这里不展开EEPROM的增强存储策略。 §§相关问题§§: 1. 在嵌入式系统中,如何设计健壮的参数存储机制? 2. CRC校验的原理是什么?如何实现一个高效的CRC计算函数? 3. 在重量测量系统中,除了卡尔曼滤波,还有哪些滤波算法适用? 4. 如何设计一个用户友好的校准流程?</think>### 解决校准和EEPROM错误问题 问题分析:日志显示多个关键错误: 1. EEPROM CRC校验失败(保存值0xFFFFFF00 vs 计算值0x870A394C) 2. 无效的偏移量(214)和因子(-0.000000) 3. 校准过程中出现"Invalid calibration difference"错误 4. 重量读数无效错误 这些错误表明: 1. EEPROM数据存储或读取存在问题 2. 校准逻辑有缺陷 3. 数据处理流程不够健壮 ### 完整解决方案 #### 1. 修复EEPROM数据存储和校验 ```c // 在AD7190.h中 typedef struct { uint32_t version; // 数据结构版本 uint32_t calibration_offset; float calibration_factor; float tare_value; uint32_t crc; // CRC校验值 } CalibrationData; // 在AD7190.c中添加 #include "eeprom.h" // 包含EEPROM驱动头文件 // 计算CRC32校验值 static uint32_t calculate_crc(const uint8_t *data, size_t length) { uint32_t crc = 0xFFFFFFFF; for (size_t i = 0; i < length; i++) { crc ^= data[i]; for (int j = 0; j < 8; j++) { if (crc & 1) { crc = (crc >> 1) ^ 0xEDB88320; } else { crc = crc >> 1; } } } return ~crc; } // 保存校准数据到EEPROM void AD7190_SaveCalibrationToEEPROM(void) { CalibrationData *calib = &ad7190_state.calib; // 设置版本号 calib->version = 0x01; // 计算CRC(不包括crc字段本身) calib->crc = 0; // 临时清零 uint32_t crc = calculate_crc((uint8_t*)calib, sizeof(CalibrationData) - sizeof(uint32_t)); calib->crc = crc; // 写入EEPROM HAL_StatusTypeDef status = EEPROM_Write(0, (uint8_t*)calib, sizeof(CalibrationData)); if (status != HAL_OK) { printf("[EEPROM] ERROR: Failed to save calibration data (Status: %d)\n", status); } else { printf("[EEPROM] Calibration data saved successfully (CRC: 0x%08X)\n", crc); } } // 从EEPROM加载校准数据 uint8_t AD7190_LoadCalibrationFromEEPROM(void) { CalibrationData calib_temp; // 从EEPROM读取 HAL_StatusTypeDef status = EEPROM_Read(0, (uint8_t*)&calib_temp, sizeof(CalibrationData)); if (status != HAL_OK) { printf("[EEPROM] ERROR: Failed to read calibration data (Status: %d)\n", status); return 0; } // 验证版本 if (calib_temp.version != 0x01) { printf("[EEPROM] WARNING: Invalid version (0x%08X)\n", calib_temp.version); return 0; } // 验证CRC uint32_t saved_crc = calib_temp.crc; calib_temp.crc = 0; // 临时清零 uint32_t calc_crc = calculate_crc((uint8_t*)&calib_temp, sizeof(CalibrationData) - sizeof(uint32_t)); if (saved_crc != calc_crc) { printf("[EEPROM] ERROR: CRC mismatch! (Saved: 0x%08X, Calc: 0x%08X)\n", saved_crc, calc_crc); return 0; } // 验证校准数据有效性 if (calib_temp.calibration_factor <= 0.0f || calib_temp.calibration_offset > 0xFFFFFF) { printf("[EEPROM] WARNING: Invalid calibration data (Offset: %u, Factor: %f)\n", calib_temp.calibration_offset, calib_temp.calibration_factor); return 0; } // 数据有效,复制到状态 ad7190_state.calib = calib_temp; printf("[EEPROM] Calibration data loaded successfully\n"); return 1; } ``` #### 2. 修复校准逻辑 ```c // 修改系统校准流程 void AD7190_SystemCalibrate(void) { if (!ad7190_state.is_initialized) AD7190_Init(); uint8_t rx_char; printf("===== System Calibration =====\r\n"); // 1. 零点校准 printf("Ensure platform is empty, then press 'z' for zero calibration...\r\n"); while(1) { if (HAL_UART_Receive(&huart1, &rx_char, 1, 100) == HAL_OK) { if(rx_char == 'z' || rx_char == 'Z') break; } // 添加超时检测 if (HAL_GetTick() - start_time > CALIBRATION_TIMEOUT) { printf("Calibration timed out\n"); return; } } // 读取32个样本,丢弃异常值 uint32_t samples[32]; int valid_count = 0; for(int i = 0; i < 32; i++) { uint32_t data = AD7190_ReadData(); // 检查数据有效性(排除异常值) if (data > 0 && data < 0xFFFFFF) { samples[valid_count++] = data; } HAL_Delay(10); } if (valid_count < 16) { printf("ERROR: Not enough valid samples for zero calibration (%d/32)\n", valid_count); return; } // 计算中值代替平均值(更抗干扰) qsort(samples, valid_count, sizeof(uint32_t), compare_uint32); ad7190_state.calib.calibration_offset = samples[valid_count / 2]; // 2. 量程校准 printf("Place 1000.0g weight, then press 'f' for full scale calibration...\r\n"); while(1) { if (HAL_UART_Receive(&huart1, &rx_char, 1, 100) == HAL_OK) { if(rx_char == 'f' || rx_char == 'F') break; } // 添加超时检测 if (HAL_GetTick() - start_time > CALIBRATION_TIMEOUT) { printf("Calibration timed out\n"); return; } } // 读取32个样本,丢弃异常值 valid_count = 0; for(int i = 0; i < 32; i++) { uint32_t data = AD7190_ReadData(); // 检查数据有效性(排除异常值) if (data > ad7190_state.calib.calibration_offset * 0.8 && data < ad7190_state.calib.calibration_offset * 1.5) { samples[valid_count++] = data; } HAL_Delay(10); } if (valid_count < 16) { printf("ERROR: Not enough valid samples for full scale calibration (%d/32)\n", valid_count); return; } // 计算中值代替平均值 qsort(samples, valid_count, sizeof(uint32_t), compare_uint32); uint32_t full_scale = samples[valid_count / 2]; // 计算校准因子(增加安全范围检查) int32_t diff = (int32_t)full_scale - (int32_t)ad7190_state.calib.calibration_offset; if (diff <= 1000) { // 1000是经验值,根据实际传感器调整 printf("ERROR: Invalid calibration difference (%ld). Too small!\n", diff); return; } if (diff > 1000000) { // 防止异常大值 printf("ERROR: Invalid calibration difference (%ld). Too large!\n", diff); return; } ad7190_state.calib.calibration_factor = 1000.0f / (float)diff; // 重置去皮值和滤波器 ad7190_state.calib.tare_value = 0.0f; KalmanFilter_Init(&ad7190_state.kf, 0.001f, 0.01f, 1.0f, 0.0f); // 保存到EEPROM AD7190_SaveCalibrationToEEPROM(); printf("System calibration completed! Factor: %f\n", ad7190_state.calib.calibration_factor); } // 用于qsort的比较函数 static int compare_uint32(const void *a, const void *b) { uint32_t arg1 = *(const uint32_t *)a; uint32_t arg2 = *(const uint32_t *)b; return (arg1 > arg2) - (arg1 < arg2); } ``` #### 3. 增强重量读取的健壮性 ```c // 修改重量读取函数 float AD7190_ReadWeight(void) { if (!ad7190_state.is_initialized) { printf("ERROR: AD7190 not initialized\n"); return NAN; } // 检查校准数据有效性 if (ad7190_state.calib.calibration_factor <= 0.0f || ad7190_state.calib.calibration_factor > 100.0f) { printf("ERROR: Invalid calibration factor: %f\n", ad7190_state.calib.calibration_factor); return NAN; } if (ad7190_state.calib.calibration_offset == 0) { printf("ERROR: Calibration offset is zero\n"); return NAN; } // 读取32个样本,使用中值滤波 uint32_t samples[32]; int valid_count = 0; for (int i = 0; i < 32; i++) { uint32_t data = AD7190_ReadData(); // 数据有效性检查 if (data > 0 && data < 0xFFFFFF && data > ad7190_state.calib.calibration_offset * 0.5 && data < ad7190_state.calib.calibration_offset * 1.5) { samples[valid_count++] = data; } HAL_Delay(5); } if (valid_count < 16) { printf("WARNING: Only %d/32 valid samples\n", valid_count); // 仍可继续处理,但需要标记数据质量 } // 计算中值 qsort(samples, valid_count, sizeof(uint32_t), compare_uint32); uint32_t raw_data = samples[valid_count / 2]; // 计算重量 int32_t adc_diff = (int32_t)raw_data - (int32_t)ad7190_state.calib.calibration_offset; float raw_weight = (float)adc_diff * ad7190_state.calib.calibration_factor; // 应用工业级滤波 float filtered = Industrial_Filter(raw_weight); // 检查最终结果有效性 if (isnan(filtered) || isinf(filtered)) { printf("ERROR: Invalid filtered weight: %f\n", filtered); return NAN; } // 应用去皮 float result = filtered - ad7190_state.calib.tare_value; // 检查重量范围合理性 if (fabs(result) > 5000.0f) { // 假设最大量程为5000g printf("WARNING: Suspicious weight reading: %.2fg\n", result); } return result; } ``` #### 4. 初始化流程优化 ```c // 在AD7190_Init中加载校准数据 void AD7190_Init(void) { if (ad7190_state.is_initialized) return; // ... 初始化硬件 ... // 尝试加载EEPROM中的校准数据 if (!AD7190_LoadCalibrationFromEEPROM()) { printf("No valid calibration data. Using default values.\n"); // 设置安全的默认值 ad7190_state.calib.calibration_offset = 0; ad7190_state.calib.calibration_factor = 1.0f; ad7190_state.calib.tare_value = 0.0f; ad7190_state.calib.version = 0x01; ad7190_state.calib.crc = 0; } // 初始化卡尔曼滤波器 KalmanFilter_Init(&ad7190_state.kf, 0.001f, 0.01f, 1.0f, 0.0f); ad7190_state.is_initialized = 1; } ``` ### 关键修复点 1. **EEPROM数据完整性**: - 添加版本控制字段 - 使用CRC32校验替代简单校验 - 增加数据有效性检查 - 提供详细的错误日志 2. **校准流程增强**: - 使用中值滤波替代平均值,提高抗干扰能力 - 添加样本有效性检查 - 增加超时检测 - 扩展差值检查范围(1000-1000000) 3. **重量读取健壮性**: - 多层数据有效性检查 - 中值滤波处理异常值 - 结果范围合理性检查 - 详细的错误日志输出 4. **错误处理机制**: - 所有关键操作都有错误检查 - 提供详细的错误信息 - 防止无效数据传播 - 设置安全的默认值 ### 错误原因分析 1. **EEPROM CRC错误**: - 原始CRC计算可能过于简单 - 数据写入/读取过程可能出错 - 未考虑数据结构版本兼容性 2. **无效校准数据**: - 校准过程中未过滤异常样本 - 差值检查范围不足 - 未处理除零错误 3. **重量读数无效**: - 未检查校准数据有效性 - 异常样本处理不足 - 缺乏最终结果验证 ### 最佳实践建议 1. **数据存储**: - 使用版本控制的数据结构 - 实现强校验机制(CRC32) - 存储多份备份数据 2. **传感器处理**: - 中值滤波优于平均值 - 实时监测数据质量 - 动态调整滤波参数 3. **错误处理**: - 提供详细错误信息 - 实现分级错误处理 - 设置安全默认值 4. **校准流程**: - 添加视觉/听觉提示 - 实现进度反馈 - 提供校准结果验证
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值