ZY是一名热爱电子技术的老软件工程师,观望了两期Funpack活动后,在这一期上了车,功能实现得好,代码和说明还写得清楚明了,很值得学习。
以下,enjoy。
征得ZY同意,我们把他的整个工程文件共享出来,供大家学习。 链接: https://pan.baidu.com/s/1b2a7OyhuwjHHunwgs8N6HA 提取码: mweh
自我介绍
实现功能
测试方法,按上图将开发版与面包板以及其他器件连接好,将开发板(已下载好程序)的DEBUG USB口与PC端的USB口相连,PC端启动J-Link RTT Viewer,通过RTT Terminal连接开发版,见下图
RTT Terminal连接成功后会打印出操作指引,见下图
下一步将待测电阻插入面包板对应的孔位中,在RTT Terminal中输入测试指令1,等待约1秒,RTT Terminal中会输出电阻测试结果(单位欧姆),以及测试结果所对应的采样平均值与样本集的标准差。见下图
代码说明
static void resistor_estimation(void){float r = 0;// adc的参考值非常接近于16bit ADC的测量范围的最大值(32767),因此为了不在除法计算中丢失精度,因此使用乘法计算这类数值。 if (adc_ch0 > 32750) { r = 0.32767 * (32767 - adc_ch0);}// 除法计算对精度影响不大的情况使用除法计算。 else { float adcv = adc_ch0; r = (32767 - adcv) / adc_ch0 * 10000; } int32_t int_v = f2i (r); int32_t deci_v = f2i ((r - int_v) * 1000); APP_PRINT("Estimation of resistor at channel 0 is: %d.%d (Ohm)\r\n", int_v, deci_v);}
uint16_tuint16_t_cmp(const void *a, const void *b)
该函数用于qsort排序函数;
staticfsp_err_t re_sample(void)
该函数用于连续读取12次adc的采样值,丢弃前2次的采样值,并对后10次采样值排序,去掉最大与最小的两个值,而后对另外的8次采样值求平均值,以及计算这8次采样值向量的标准差,以下结合代码说明;
static fsp_err_t re_sample(void){ fsp_err_t err = FSP_SUCCESS; // Error statusuint16_t single_read = 0;//读取并丢弃第一次ADC采样的数据 err = R_ADC_Read (&g_adc_ctrl, ADC_CHANNEL_0, &single_read); if (FSP_SUCCESS != err) { APP_ERR_PRINT("** R_ADC_Read API on channel 0 failed ** \r\n"); return err; }R_BSP_SoftwareDelay (sample_delay, BSP_DELAY_UNITS_MILLISECONDS);//读取并丢弃第二次ADC采样的数据 err = R_ADC_Read (&g_adc_ctrl, ADC_CHANNEL_0, &single_read); if (FSP_SUCCESS != err) { APP_ERR_PRINT("** R_ADC_Read API on channel 0 failed ** \r\n"); return err; } R_BSP_SoftwareDelay (sample_delay, BSP_DELAY_UNITS_MILLISECONDS); uint16_t samples[10] = { 0x00 };uint32_t sum_of_adc_reads = 0;//连续读取10次ADC采样数据 for (uint8_t i = 0; i < 10; i++) { single_read = 0; err = R_ADC_Read (&g_adc_ctrl, ADC_CHANNEL_0, &single_read); if (FSP_SUCCESS != err) { APP_ERR_PRINT("** R_ADC_Read API on channel 0 failed ** \r\n"); return err; } if (1 > single_read || 32767 < single_read) { APP_ERR_PRINT("Read bad data on ADC channel 0, operation abort\r\n"); return FSP_ERR_ABORTED; } samples[i] = single_read; single_read = 0; R_BSP_SoftwareDelay (sample_delay, BSP_DELAY_UNITS_MILLISECONDS);}//对10次 ADC采样的数据排序 qsort (samples, 10, sizeof(uint16_t), uint16_t_cmp); uint16_t valid_samples[8] ={ 0x00 };//去除10次采样数据中的最大与最小值,并累加求和 for (uint8_t j = 0; j < 8; j++) { valid_samples[j] = samples[j + 1]; sum_of_adc_reads += samples[j + 1];}//计算过滤后的8次采样数据的标准差std_deviation = std_dv (valid_samples, 8);//计算过滤后的8次采样数据的平均值并赋值到adc_ch0变量 adc_ch0 = (uint16_t) (sum_of_adc_reads >> 3); return err;}
staticfsp_err_t adc_ch0_read(void)
该函数用于启动并校准16bits ADC,而后调用re_sample函数读取的通道0的数据,以下结合代码说明;
static fsp_err_t adc_ch0_read(void){fsp_err_t err = FSP_SUCCESS; // Error status//判断ADC是否处于被占用的状态 if (false == adc_busy){ //开启16 bits ADC模块 /* Open/Initialize ADC module */ err = R_ADC_Open (&g_adc_ctrl, &g_adc_cfg); if (FSP_SUCCESS != err) { APP_ERR_PRINT("** R_ADC_Open API failed ** \r\n"); return err; } // Delay for waiting for ADC be stable R_BSP_SoftwareDelay (5, BSP_DELAY_UNITS_MILLISECONDS);#ifdef BOARD_RA2A1_EK /* Set Reference Voltage Circuit Control register */ R_ADC0->VREFAMPCNT |= ((VREFADCG_VALUE << SHIFT_BY_ONE) | (VREFADCG_ENABLE << SHIFT_BY_THREE)); //根据芯片手册中的建议,16bits ADC使用前需要进行校准,这里调用函数校准ADC。 /* Calibrate the ADC */ err = adc_start_calibration (); if (FSP_SUCCESS != err) { APP_ERR_PRINT("** adc_start_calibration function failed ** \r\n"); return err; }#endif //调用HAL库中的函数,配置ADC,这里配置为连续读取模式 /* Configures the ADC scan parameters */ err = R_ADC_ScanCfg (&g_adc_ctrl, &g_adc_channel_cfg); if (FSP_SUCCESS != err) { APP_ERR_PRINT("** R_ADC_ScanCfg API failed ** \r\n"); return err; } //启动ADC采样 /* Start the ADC scan*/ err = R_ADC_ScanStart (&g_adc_ctrl); if (FSP_SUCCESS != err) { APP_ERR_PRINT("** R_ADC_ScanStart API failed ** \r\n"); return err; } adc_busy = true; //调用函数re_sample()函数进行ADC数据采样,前文有详细说明该函数。 err = re_sample (); if (FSP_SUCCESS != err) { APP_ERR_PRINT("** Sampling on ADC channel 0 failed ** \r\n"); return err; } uint8_t counter = 0; //基于调试结果分析,低阻值的电阻需要依赖采样的数据的一致性来保证测量精度,因此这里判断如果为低阻值数据,且采样数据标准差大于1.5则进行重新采样处理,共重试最多8次,直至采样数据符合要求,如果超过8次采样数据仍旧未能符合标准,则打印测量失败的通知到RTT Terminal提示用户。 if (32755 < adc_ch0 && 1.5f < std_deviation) { APP_PRINT( "Lower resistance value [1(Ohm) ~ 5(Ohm)] found and sampling quality too low, auto perform re-sampling...\r\n"); while (1.5f < std_deviation && 10 > counter) { err = re_sample (); if (FSP_SUCCESS != err) { APP_ERR_PRINT("** Sampling on ADC channel 0 failed ** \r\n"); return err; } counter++; } } if (32755 < adc_ch0 && 1.5f < std_deviation) { APP_ERR_PRINT("Sampling quality too low, operation abort\r\n"); } else { //输出样本质量评估的标准差数据 int32_t int_stddv = f2i (std_deviation); int32_t deci_stddv = f2i ((std_deviation - int_stddv) * 1000); APP_PRINT("Standard deviation of samples is: %d.%d, samples quality is %s\r\n", int_stddv, deci_stddv, std_deviation < 5 ? "GOOD" : "POOR"); //输出16 bits ADC采样的原始数据。 APP_PRINT("Sampling data at ADC channel 0 is: %d\r\n", adc_ch0); //输出待测电阻的估算阻值。 resistor_estimation (); } //停止ADC连续采样 err = R_ADC_ScanStop (&g_adc_ctrl); if (FSP_SUCCESS != err) { APP_ERR_PRINT("** R_ADC_ScanStop API failed ** \r\n"); return err; } adc_busy = false; //关闭ADC模块 err = R_ADC_Close (&g_adc_ctrl); if (FSP_SUCCESS != err) { APP_ERR_PRINT("** R_ADC_Close API failed ** \r\n"); return err; } } else { APP_PRINT("Resistor testing in progress\r\n"); } return err;}
staticfsp_err_t adc_start_calibration(void)
该函数用于校准ADC。
活动体会
征得ZY同意,我们把他的整个工程文件共享出来,供大家学习。 链接: https://pan.baidu.com/s/1b2a7OyhuwjHHunwgs8N6HA 提取码: mweh
END
硬禾学堂
硬禾团队一直致力于给电子工程师和相关专业的同学,带来规范的核心技能课程,帮助大家在学习和工作的各个阶段,都能有效地提升自己的职业能力。
硬禾学堂
我们一起在电子领域探索前进
关注硬禾服务号,随时直达课堂
点击阅读原文查看Funpack最新一期活动