|
最近我也在调试一个AD相关的项目,刚好测试了这段滤波代码,感觉确实波动很大。用了一个最基本的平均数滤波也比这个效果好。楼主可以试一试。 u16 Get_Adc_Average(u8 ch,u8 times) { u32 temp_val=0; u8 t; for(t=0;t<times;t++) { temp_val+= Get_ADC10bitResult(ch); delay_us(10); } return temp_val/times; } |
snchj 发表于 2019-11-26 21:23 这个硬件同我的想法一样,我的AD也用了47uF,对反应不用太快的检测大电容确实有效。 |
bh2030693 发表于 2019-11-23 22:50 其实我司在做项目时都是这样做,一般做锂电池电量检测开关保护都是在单片机采样脚前(尽量离IC脚要近)串个1K再用一个106P滤波,效果很好。如果要实时显示,做个一表或取个平均值就行。一个项目要软硬结合才是最好解决方法。 |
|
我也遇到这样的问题 我是用温度来控制继电器的打开和关闭 因为跳变导致继电器一直嗒嗒嗒 |
| 哪个并在上拉电阻上的电容有点诡异,并到NTC上倒可以理解! |
| 这是误差之内的数字可以接受啊,后起处理就行了 |
|
刚才看了这位朋友的程序,大概过程看明白了,那个温度函数没用过,详细原理暂时不了解。对这段程序做了个简单的修改。 主要是对ADC做了一点修改:因为每次要关闭ADC,所以下次打开应该等待稳定延时; 对计算函数做了一点简化:因为偏置电阻阻值10K等于Rp,所以抵消了一步计算; 对滤波做了一点修改:因为用左移代替除法能更快一点; 以上修改对结果估计也没啥帮助,只是共师兄习一下。因为没有条件测试,如有错误望网友及时指正。 #include <adc.h> #include "math.h" #define ADC_POWER 0x80 // ADC电源控制位 #define ADC_FLAG 0x10 // ADC完成标志位 #define ADC_START 0x08 // ADC起始控制位 #define ADC_SPEEDLL 0x00 // 540个时钟周期 // #define BUFF_LENGTH 12 const float Rp = 10000.0; // 10K const float T2 = (273.15 + 25.0); // T2 const float Bx = 3950.0; // B const float Ka = 273.15; /*---------------------------- 读取ADC结果 ----------------------------*/ uint GetADCResult(uchar ch) { ADC_CONTR = ADC_POWER | ADC_SPEEDLL; Delay2(2); // ADC上电延时 ADC_CONTR = ADC_POWER | ADC_SPEEDLL | ch | ADC_START; while (!(ADC_CONTR & ADC_FLAG)) { } //等待ADC转换完成 ADC_CONTR &= ~ADC_FLAG; // Close ADC return ((uint)ADC_RES << 2 | ADC_RESL); //返回ADC结果 } /****************滤波*****************/ #define BUFF_LENGTH 18 // 过滤函数数组长度 uint filter(uchar chnn) { uint i; uint j; uint uiTemp; uint uiSum; uint uiBuf[BUFF_LENGTH]; for (i = 0; i < BUFF_LENGTH; i++) { uiBuf[i] = GetADCResult(chnn); Delay2(2); } // 排序:把最大值移到数组最后,最小值留到数组最前 for (j = 0; j < BUFF_LENGTH - 1; j++) { for (i = 0; i < BUFF_LENGTH - 1 - j; i++) { if (uiBuf[i] > uiBuf[i + 1]) { uiTemp = uiBuf[i]; uiBuf[i] = uiBuf[i + 1]; uiBuf[i + 1] = uiTemp; } } } // 取中间(BUFF_LENGTH - 2)个数,求平均值 for (i = 1; i < BUFF_LENGTH - 1; i++) { uiSum += uiBuf[i]; } // uiSum = uiSum / (BUFF_LENGTH - 2); uiSum >>= 4; // uiSum / 16 return uiSum; } /********AD数值转换阻值**********/ /*double AD_R(uchar chn) { double adcDataTR; // 温敏电阻上的分压数据 double adcDataR; // 偏置电阻上的分压数据 double rT; // 温敏电阻阻值 adcDataTR = filter(chn); adcDataR = 1023 - adcDataTR; rT = 10000 / adcDataR * adcDataTR; return rT; }*/ /************阻值转换温度******************/ float Get_Temp(uchar chhhh) { // float Rt; float adcDataTr; // 温敏电阻上的分压的ADC数据 float temp; // Rt = AD_R(chhhh); adcDataTr = filter(chhhh); // like this R=5000, T2=273.15+25,B=3470, // RT=5000*EXP(3470*(1/T1-1/(273.15+25)), // temp = Rt / Rp; // = 10000 / adcDataR * adcDataTr / Rp; // 因为(Rp=上拉偏置电阻10000) // temp = adcDataTr / adcDataR; temp = adcDataTr / (1023 - adcDataTr); temp = log(temp); // ln(Rt/Rp) temp /= Bx; // ln(Rt/Rp)/B temp += (1 / T2); temp = 1 / (temp); temp -= Ka; temp += 0.5; // 加0.5误差矫正 temp = temp * 10; return temp; } /*---------------------------- 初始化ADC ----------------------------*/ void InitADC(void) { P1ASF = 0xff; //设置P1口为AD口 CLK_DIV &= ~0x20; ADC_RES = 0; //清除结果寄存器 ADC_RESL = 0; } /*---------------------------- 延时 ----------------------------*/ void Delay2(uint n) { uint x; while (n--) { x = 5000; while (x--); } } |
| 你这个是硬件问题,103P不要串联在电阻上,换成106P一边接地当滤波电容,这样就不会跳了。 |
邓文雄ABC 发表于 2018-4-8 09:35 并不是每次都是这样的,采集三次 可能出现的全都是572 572 572 也可能是573 572 572 |
| 求学,跟着各位大佬学习 |
| 三个值相加,取平均值使用。 |
| 如果数值在一个范围内稳定变化,可以在三个值取平均值,那不就很稳定了吗? |
|
NTC热敏电阻的温阻曲线是非线性的,用浮点计算的方法误差很大。一般用厂家提供的温阻表为基础制作数组表格,用ADC转换结果通过查表法获取温度值为佳。 与7楼意见相同! |
| 可以查表,然后换个算法试试。 |
大米饭 发表于 2018-4-7 10:00 不管你采用什么方法滤波都不容易得到非常稳定的数值,“采集数值一直在570 571 572 中来回跳转”说明你得到的数据已经足够稳定了,只是你对数据的后期处理不到位,才致使你感觉不稳定。 |
HEIZI555 发表于 2018-4-5 13:47 代码中已经包含滤波算法,并且尝试了多种滤波算法 均不能保证每次滤波后出现稳定数值 |
15861476366 发表于 2018-4-5 13:18 有滤波算法,依旧出现温度跳变,这个不知道怎么样才能解决,或者有什么更好的滤波算法 |
nklug 发表于 2018-4-4 20:53 我的代码中,包含了软滤波,主要是ADC采集数值一直在570 571 572 中来回跳转,致使计算得出的温度一直跳变 |
wulin 发表于 2018-4-4 15:42 讨论的问题并不是温度是否准确,而是ADC采集的数据出现浮动漂移,谢谢你的回答 |
| 网上有详细的滤波器算法说明,找找下 |
| 采用查表法,并使用较稳定电源。 |
| 不是说好了 24小时必答吗???求指教啊……那位前辈高人上帝老大来帮我一下 卡了好多天了 |
| 那位大神来帮帮我啊 怎么一个人都没有呢 求救啊 |