工程代码_看老工程师写代码说明——Funpack第三期分享之二

ZY是一名热爱电子技术的老软件工程师,观望了两期Funpack活动后,在这一期上了车,功能实现得好,代码和说明还写得清楚明了,很值得学习。   以下,enjoy。

  • 自我介绍

  本人叫ZY,是一名软件工程师,从事软件开发工作十多年了,本身的工作是与互联网相关的应用系统设计开发工作,业余很喜欢电子技术,所以业余有空的时候会玩一些小的电子制作和开发的东西,之前有做过一些函数波形发生器、迷你示波器,探针等小东西。
  • 实现功能

  本次也是由于拿到板子太晚(12月10日到手),也就仅仅基于作业要求,实现了简单的电阻测量功能,后续会继续挖掘更好玩的功能,目前考虑会做一个简单的示波器,可以通过蓝牙或Wi-Fi把数据与Thingsboard结合实现,作业中使用了16bit的ADC,通过分压测试法实现了电阻测量功能。软件部分则是基于瑞萨提供的e2studio工具以及FSP2.1.0软件包,基于HAL库调用了ADC部分的函数实现的。软件部分采用了共计12次采样,抛弃前两次采样数据,再去掉最大最小值之后,求平均值的方式实现,同时计算采样数据的标准差用于评估测试结果的精准程度,这样可以在仅使用一只10K电阻分压的条件下,更好的提升测试精度。连接示意图如下:     28c5c48f2f1598ffce3f9d288316a926.png  

测试方法,按上图将开发版与面包板以及其他器件连接好,将开发板(已下载好程序)的DEBUG USB口与PC端的USB口相连,PC端启动J-Link RTT Viewer,通过RTT Terminal连接开发版,见下图

2f279e191d0e37e8e0870254d78f7458.png  

RTT Terminal连接成功后会打印出操作指引,见下图

777813bed6bfaf30df202c0465e03f5f.png  

下一步将待测电阻插入面包板对应的孔位中,在RTT Terminal中输入测试指令1,等待约1秒,RTT Terminal中会输出电阻测试结果(单位欧姆),以及测试结果所对应的采样平均值与样本集的标准差。见下图 

9a40ce92976905a262decfd94962a93c.png
  • 代码说明

hal_entry.c 该文件是程序入口,hal_entry函数中打印了欢迎信息,而后阻塞等待用户来自RTT Terminal的输入,用户输入后调用adc_ep.c文件中的read_process_input_from_RTT(void) 函数进行命令处理。   adc_ep.c 该文件是主要的程序文件,以下进行简要的介绍:   staticfloat std_dv(uint16_t samples[], uint8_t count) 该函数是计算adc样本向量的标准差,用以评估样本向量的采样置信度;   staticint32_t f2i(float ft) 该函数是将浮点数转换为整数型,因为RTT Print无法输出浮点数,因此用此函数将浮点数的整数部分与小数部分分别转换后输出;   staticvoid print_menus(void) 该函数用于输出菜单项;   fsp_err_tread_process_input_from_RTT(void) 该函数用于读取用户来自RTT Terminal的输入,调用点在hal_entry.c的hal_entry()函数中;   staticvoid resistor_estimation(void) 该函数是用于基于adc_ch0的值来估算当前待测电阻的阻值,以下结合代码说明;
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。
  • 活动体会

  首先简单说一下瑞萨的这块板子,拿到手的比较晚,大概在12月10号左右拿到的,所以了解的也十分有限,因为要赶在20号前交作业,所以还来不及很充分的去看这个板子的内容。这块评估板不论做工还是设计都是十分不错的,该有的都有,需要配置和调整的地方也设计的比较灵活,概览了一下板子的手册,发现板子可玩性还是比较强的。 其次再说一下e2studio这款开发工具,对于我个人来说,这个开发工具真是太合我心意了。首先我使用eclipse应该快有20年了,从上学到工作中这些年一直也都在使用这个开发工具,十分的熟悉,应该说瑞萨选择以eclipse作为基础来打造开发环境,也就是因为eclipse在过去的20年中已经深入民心了,大部分的工程师尤其是软件工程师应该都有使用eclipse的经验;另外e2studio针对调试和配置两个部分做了很好的扩展,虽然界面没有stm32的那么华丽,但是功能简洁实用,软件的稳定程度也很高,在使用过程中还未遇到明显的错误。 最后说一下Funpark活动,这个活动确实很棒,建立交流群让共同的爱好者有一个共同的目标,一起讨论交流,这个是十分愉快也十分难得的;另外还会请来高水平老师给大家进行培训,帮助大家尽量解决问题,扫清了我们完成任务的障碍;最后是硬禾这个平台,在前段时间板子没到的时候,去过硬禾的网站和电子森林的站点,里边的确是包含了非常多的技术干货,着实是能帮助到电子爱好者甚至是专业从业人士的。 再次感谢硬禾与Digikey能够给大家提供这样一个好玩又能学知识的活动,实在是很棒。
征得ZY同意,我们把他的整个工程文件共享出来,供大家学习。 链接: https://pan.baidu.com/s/1b2a7OyhuwjHHunwgs8N6HA 提取码: mweh

END

硬禾学堂

硬禾团队一直致力于给电子工程师和相关专业的同学,带来规范的核心技能课程,帮助大家在学习和工作的各个阶段,都能有效地提升自己的职业能力。

6e40f1705cedc904b8c8a585bef43b0a.png

硬禾学堂

我们一起在电子领域探索前进

关注硬禾服务号,随时直达课堂

       f1eddae66b76d589e3c81219c83c4d36.gif

点击阅读原文查看Funpack最新一期活动

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值