项目实战之一:基于ADUC7061的Modbus智能传感器模块_第1页
项目实战之一:基于ADUC7061的Modbus智能传感器模块_第2页
项目实战之一:基于ADUC7061的Modbus智能传感器模块_第3页
项目实战之一:基于ADUC7061的Modbus智能传感器模块_第4页
项目实战之一:基于ADUC7061的Modbus智能传感器模块_第5页
已阅读5页,还剩6页未读, 继续免费阅读

付费下载

下载本文档

版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领

文档简介

项目实战之一:基于ADUC7061的Modbus智能传感器模块已经两周没写文章了,适逢金三银四,最近也打算换工作,好好把项目复盘下。目录项目实战之一:基于ADUC7061的Modbus智能传感器模块前言一、硬件二、软件1.CRC-16校验算法2.中位值平均滤波算法3.快速排序4.二分查找总结前言现在所在的这家公司是做仪器仪表的,所有的产品都是围绕传感器开发。传感器大部分来自美国Baseline和英国Alpha,一个上千;也有国产的,几百不等,不过说真的,性能差太多。这玩意核心还是材料,国产在这方面还有很长的路要走。靠卖传感器自然赚不到钱,主要收入还是靠产品定制。比如前一个客户需要TVOC,后一个客户需要NH3和H2S,只要稍微修改下就好了;传感器越多,仪表售价越高,特别是带显示的那种。由于是Modbus协议和4~20mA输出,所以在工业上用途很广。一、硬件我来这家公司的时候,源代码都没有,于是让我重新开发。硬件平台是ADUC7061,好家伙,内置24位ADC。于是我就自己画了个开发板,自己焊好,对于不擅长硬件的我来说,这MCU是真难焊。不过点灯成功的时候,还是成就感满满。这块芯片baidu上资料不多,直接开源了吧:二、软件当时老板提出的要求是:1、功能在原来的基础上增加多点标定、0.4-2V输出;2、输出协议改成RS485/Modbus协议;3、精度提升。于是软件功能模块很明显了:GPIO、ADC、DAC、UART、FLASH。软件算法主要用到了CRC-16校验、快速排序、中位值平均滤波、二分查找,其他好像也没了。1.CRC-16校验算法这个是比较常见的校验算法。//CRC校验//arr[]:要校验的数组//size:数组长度-2//比如010301010001D436,输入010301010001//输出CRC_tmp,(char)CRC_tmp和CRC_tmp>>8即D436u16CRC_Check(u8arr[350],u8size){ u16j,k,CRC_tmp=0xffff;//CRC寄存器初始值for(j=0;j<size;j++)//循环计算每个数据{CRC_tmp=arr[j]^CRC_tmp;//将八位数据与crc寄存器异或for(k=0;k<8;k++)//此处的8--指每一个char类型8bit,每bit都要处理{ if(CRC_tmp&0x01)//判断右移出的是不是1,如果是1则与多项式进行异或{CRC_tmp=CRC_tmp>>1;//先将数据右移一位CRC_tmp=CRC_tmp^0xa001; //与上面的多项式进行异或}else{CRC_tmp=CRC_tmp>>1; //如果不是1,则直接移出}}}returnCRC_tmp;}其他校验算法还有校验和、异或校验等。//校验和uint8_tCheckSum(uint8_t*Buf,uint8_tLen){uint8_ti=0;uint8_tsum=0;uint8_tchecksum=0;for(i=0;i<Len;i++){sum+=*Buf++;}checksum=sum&0xff;returnchecksum;}//异或校验uint8_tCheckXOR(uint8_t*Buf,uint8_tLen){uint8_ti=0;uint8_tx=0;for(i=0;i<Len;i++){x=x^(*(Buf+i));}returnx;}2.中位值平均滤波算法要提高精度,24bits的ADC已经足够高了,但是我测试中发现硬件并不能达到,于是还得在软件上增加滤波。一开始使用的是滑动平均滤波,测试中发现偶尔来一个干扰就会把平均值拉高;然后改成了中值滤波,发现又没有均值滤波稳定;于是就把两种滤波结合到了一起:#defineFilter_N9doublefilter(doubleADC_Rtd)//滑动均值滤波 {unsignedcharl,m;doublesum=0,value=0;doublefilter_buf[Filter_N];//滑动AdcBuf_Sliding[Sliding_N]=ADC_Rtd; if(Sliding_N==Filter_N){Sliding_N=0;}else{Sliding_N++;}for(l=0;l<Filter_N;l++){filter_buf[l+1]=AdcBuf_Sliding[l];}//冒泡排序 for(j=0;j<Filter_N-1;j++) {for(i=0;i<Filter_N-j;i++){if(AdcBuf_Filter[i]>AdcBuf_Filter[i+1]){temp=AdcBuf_Filter[i];AdcBuf_Filter[i]=AdcBuf_Filter[i+1];AdcBuf_Filter[i+1]=temp;}}}for(m=Filter_N/3+1;m<Filter_N*2/3+1;m++){//去掉最低1/3和最高1/3取平均sum+=filter_buf[m];value=sum*3/Filter_N;}return(value);}3.快速排序然后发现丢包有点高,把上面的冒泡排序改成了快速排序。intqusort(doubles[],intstart,intend)//快速排序{inti,j; //定义变量为基本整型i=start; //将每组首个元素赋给ij=end; //将每组末尾元素赋给js[0]=s[start]; //设置基准值while(i<j){while(i<j&&s[0]<s[j])j--; //位置左移if(i<j){s[i]=s[j];//将s[j]放到s[i]的位置上i++; //位置右移}while(i<j&&s[i]<=s[0])i++; //位置左移if(i<j){s[j]=s[i];//将大于基准值的s[j]放到s[i]位置j--; //位置左移}}s[i]=s[0]; //将基准值放入指定位置if(start<i)qusort(s,start,j-1);//对分割出的部分递归调用qusort()函数if(i<end)qusort(s,j+1,end);return0;}#defineFilter_N9doublefilter(doubleADC_Rtd)//滑动均值滤波{unsignedcharl,m;doublesum=0,value=0;doublefilter_buf[Filter_N];AdcBuf_Sliding[Sliding_N]=ADC_Rtd;//滑动if(Sliding_N==Filter_N){Sliding_N=0;}else{Sliding_N++;}for(l=0;l<Filter_N;l++){filter_buf[l+1]=AdcBuf_Sliding[l];}qusort(filter_buf,0,Filter_N);//快速排序for(m=Filter_N/3+1;m<Filter_N*2/3+1;m++)//去掉最低1/3和最高1/3取平均{sum+=filter_buf[m];value=sum*3/Filter_N;}return(value);}4.二分查找由于需要多点标定,浓度与ADC是成正线性关系,就满足了有序数列,于是就想到了用二分算法。#include<stdio.h>/*----------------------------------------------------------------------*Function:BinarySearch(int*arr,intkey,intmin,intmax)*Discription:二分查找首个大于等于指定数字的位置*Inputs:arr,指向被查找有序序列的指针;*key,被查找的数*min,左边界*msx,右边界*Outputs:none*return:-1,未找到;*-2,输入参数异常;*其他,被查找元素对应的数组下标*---------------------------------------------------------------------*/intBinarySearch(int*arr,intkey,intmin,intmax){intmid=0;if(arr==NULL){return-2;}else{while(min<=max){mid=(min+max)/2;if(arr[mid]<key){min=mid+1;//在右边}elseif(arr[mid]>key){min=mid-1;//在左边}else{if(min==max){returnmid;//找到}else{max=mid;//在左边或者mid}}}return-1;}}intmain(){inta[]={2,4,6,8,10,12,14},target=8;printf("等于%d的数组下标为%d\r\n",target,BinarySearch(a,target,0,sizeof(a)/4-1));return0;}//输出:等于8的数组下标为3根据实际项目需求改动:每次标定后,利用快速排序将标定的ADC从小到大写入;每次读取浓度时,计算实时ADC处于哪个区间,就可以快速计算出浓度。这就变成了一道算法题:查找首个大于等于指定数字的位置,注意(min+max)/2越界:#include<stdio.h>/*----------------------------------------------------------------------*Function:BinarySearch(int*arr,intkey,intmin,intmax)*Discription:二分查找首个大于等于指定数字的位置*Inputs:arr,指向被查找有序序列的指针;*key,被查找的数*min,左边界*msx,右边界*Outputs:none*return:-1,未找到;*-2,输入参数异常;*其他,被查找元素对应的数组下标*---------------------------------------------------------------------*/intBinarySearch(int*arr,intkey,intmin,intmax){intmid=0;if(arr==NULL){return-2;}else{while(min<=max){mid=min+((max-min)>>2);if(arr[mid]<key){min=mid+1;//在右边}else{if(min

温馨提示

  • 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
  • 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
  • 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
  • 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
  • 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
  • 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
  • 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。

最新文档

评论

0/150

提交评论