有没懂stm8的大佬,求助下
本帖最后由 沨の痕 于 2019-12-21 21:23 编辑起因改明纬拿来充电啥的,淘宝便宜的电压电流表线性太差了表现为低压低,到某个值后开始一直偏高,是一直继续变大
后来隔壁论坛找到了程序,电压是一直偏低,电流又不准,自己买st/link v2烧录调试,因为本身源码电压部分做了分区,参考下改回来,主要电流,可能是采样不是原程序设计,介绍说用2毫欧采样,我买了2毫欧康铜丝换上,手上4个表头,只有2个能校对电流,校对过程是数值大了康铜丝加锡,小了加大两线距离,另外2个校不了,不知道什么原因,1a下偏低1a上一直加大,换过st358,这里说下358真是坑,买的st358,st258,lm358,LM258,全部显示不一样,按道理分压电阻比例固定显示应该差不多,lm258显示到1A,换st358显示0.4A,st258显示0.8A
下面是源码电流部分,请教下是怎么算的,tmpin这个只说了ad采样,百度过ad值计算也没说,隔壁还有自动校准的源码就是不会搞
电路图R6换成1M
#define u8unsigned char
#define ucharunsigned char
#define uint unsigned int
#define sCnt 104
uint ms_count, tmpin, ADCBuff, ADValueV, ADValueI, ADCData, mA;
u8 pDataV=0, pDataI=0, vDotPS, cDotPS, VGain = 35, ampGain = 129, vFlag=0, iFlag=0;
unsigned long mV;//uint的话,mV最大只能到 65535mV,本电源80V,故用long
float voltRAW, curtRAW, Rs = 0.00218;
float ADVal_Av={0}, Val_Av={0};
float* Ad_Av(u8 ac) //每次只采样一个数据,采完sCnt个数据就更新结果,否则就显示上一次的结果
{
u8 num, pMaxV=0, pMaxV2=0, pMinV=0, pMinV2=0, pMaxI=0, pMaxI2=0, pMinI=0, pMinI2=0;
if(ac==4){ //电压
ADValueV = Get_Adc(ac);
Val_Av += ADValueV;
}else{ //电流
ADValueI = Get_Adc(ac);
Val_Av += ADValueI;
}
if(pDataV>=sCnt){ //电压数据采样完成,去除最大最小求平均
pDataV=0; vFlag=1;
for(num=0;num<sCnt;num++) {
if(ADValueV < ADValueV) pMinV = num;
if(ADValueV > ADValueV) pMaxV = num;
}
for(num=0;num<sCnt;num++) { //去掉次大次小
if(num != pMinV && ADValueV < ADValueV) pMinV2 = num;
if(num != pMaxV && ADValueV > ADValueV) pMaxV2 = num;
}
ADVal_Av = (Val_Av - ADValueV - ADValueV - ADValueV - ADValueV)/(sCnt-4);
//ADVal_Av = (Val_Av - ADValueV - ADValueV)/(sCnt-2); //只去掉最大最小的话,用这句
Val_Av=0;
}
if(pDataI>=sCnt){ //电流数据采样完成,去除最大最小求平均
pDataI=0; iFlag=1;
for(num=0;num<sCnt;num++) {
if(ADValueI < ADValueI) pMinI = num;
if(ADValueI > ADValueI) pMaxI = num;
}
for(num=0;num<sCnt;num++) { //如果还要去掉次大次小的话,就去掉注释
if(num != pMinI && ADValueI < ADValueI) pMinI2 = num;
if(num != pMaxI && ADValueI > ADValueI) pMaxI2 = num;
}
ADVal_Av = (Val_Av - ADValueI - ADValueI - ADValueI - ADValueI)/(sCnt-4);
//ADVal_Av = (Val_Av - ADValueI - ADValueI)/(sCnt-2); //只去掉最大最小的话,用这句
Val_Av=0;
}
return(ADVal_Av);
}
/*****电流数据处理***************************************
tmpin:采集的电流数据;
输出:电流值,单位:A
*********************************************************/
float ProcessCurrent(float tmpin)
{
float Temp;
Temp = tmpin * 3.3 / 1023 / ampGain / Rs; //单位:A
//下面是校正,应根据实际情况重新计算。本例中是将运放的反馈电阻 R6(180k)
//改成 1M后,放大系数ampGain由29变为129。
//取样电阻 Rs约为 2mR。
Temp = 1.385042 * Temp - 1.698751;
if(Temp<0) Temp=0;
return (Temp);
curtRAW = Ad_Av(3); //获取电流数据
if(iFlag==1){ //电流数据采集完成才进行以下计算,否则跳过,将显示上次数据
iFlag=0;
newData = ProcessCurrent(curtRAW);
Noise_Filter(0.5, 1, preCoef, preTrend, ADvalue, newData);
//ADvalue = newData; //不要上面的滤波时使用
mA = (uint)(ADvalue*1000);
if(mA > 9999){
cDotPS=4;
ADCBuff = mA / 100 % 10; //0.1A
ADCBuff = mA / 1000 % 10; //A
ADCBuff = mA / 1000 / 10; //十A
}else{
cDotPS=5;
ADCBuff = mA / 10 % 10; //0.01A
ADCBuff = mA / 100 % 10; //0.1A
ADCBuff = mA / 1000; //A
}
}
I_Show(3);
//asm("rim"); //开系统总中断,准备下次ADC采样
}
}
注意运放的输入电阻,不同的可能不同,导致分压值有偏差 不是有可调电阻吗?调那个跟标准值校准就行了.
两个数码管这么直驱,不怕芯片坏掉吗? 又不是精密运放线性失调电压失调电流都要补偿,而且用1M的电阻输入输出阻抗都不能忽略了 本帖最后由 捱多年 于 2019-12-21 22:06 编辑
浮点数我记得精度很低的小数点后6位真有用?百×了一下浮点数有效7位,那是有用的 本帖最后由 捱多年 于 2019-12-21 22:36 编辑
258比358数值大一倍看看是不是轨到轨的差别,Temp = tmpin * 3.3 / 1023 / ampGain / Rs; //单位:A这个不就是电流计算吗?Temp = 1.385042 * Temp - 1.698751;//这句是修正1.3那个是系数用于修正放大倍数电阻阻值的误差,1.6那个是偏移主要是修正失调电压
非线性得画图表得到补偿拟合曲线
捱多年 发表于 2019-12-21 22:18
258比358数值大一倍看看是不是轨到轨的差别,Temp = tmpin * 3.3 / 1023 / ampGain / Rs; //单位:A这个 ...
tmpin值不知道啊
本帖最后由 捱多年 于 2019-12-21 22:42 编辑
沨の痕 发表于 2019-12-21 22:30
tmpin值不知道啊
调用他那个已经给了参数tmpin啊float ProcessCurrent(float tmpin)
你看看谁调用ProcessCurrent,不过用中断的话你是看不出来的,而且也无需知道谁调用你需要的是temp
本帖最后由 沨の痕 于 2019-12-22 00:12 编辑
捱多年 发表于 2019-12-21 22:38
调用他那个已经给了参数tmpin啊float ProcessCurrent(float tmpin)
你看看谁调用ProcessCurrent,不过用中 ...
大佬,看不懂哦,没这方面基础
Temp = tmpin * 3.3 / 1023 / ampGain / Rs; //单位:A
//下面是校正,应根据实际情况重新计算。本例中是将运放的反馈电阻 R6(180k)
//改成 1M后,放大系数ampGain由29变为129。
//取样电阻 Rs约为 2mR。
Temp = 1.385042 * Temp - 1.698751;
上面Temp = tmpin * 3.3 / 1023 / 129 / 0.00218
Temp = 1.385042 * Temp - 1.698751;
能解析下这部分算法,还有ad值的算法能说下,线性为啥会低电流偏低,某个值后电流开始一直变大
donkey 发表于 2019-12-21 21:57
不是有可调电阻吗?调那个跟标准值校准就行了.
两个数码管这么直驱,不怕芯片坏掉吗? ...
想多了,线性不好不是靠个电阻就能调回来的。。。表现为低的时候偏低,某个值后转为一直加大,那个电阻是调整体线性,调低了高平衡,低的时候会更低,调高了,低平衡,高会更高,手上有2个调好了的,无论高低跟zt-x差0.06内
358就是这样的性能,不能抱怨358不好。
358是最便宜的运放,当然性能也是最差的 沨の痕 发表于 2019-12-21 23:46
大佬,看不懂哦,没这方面基础
Temp = tmpin * 3.3 / 1023 / ampGain / Rs; //单位:A
...
Temp = tmpin * 3.3 / 1023 / ampGain / Rs;中tmpin是调用 ProcessCurrent的程序提供,3.3为3.3V满量程电压,1023为满量程数值,ampGain是理论放大倍数,Rs9为理论取样电阻值。
由于放大倍数和取样电阻和实际有出入又由于放大倍数和取样电阻是一个比值所以只要在结果乘一个系数即可修正,便宜的运放输入失调电压比较大又要再加一个偏移量于是就有了x=ax+b就是程序中的Temp = 1.385042 * Temp - 1.698751;了
ProcessCurrent中遇到return就不会继续执行了感觉程序并不完整 非线性比较复杂,可能是运放达到临界状态造成的如电源电压限制偏置电流电压等造成的解决办法是提高运放的电源电压提供偏置电流电路图中就有加入;也可能AD器件造成的就是ad本身线性就不行某wifi串行模块里的ad就很奇葩。 如果只是减少误差可以这样如0.2A时电流偏小
if(Temp<0.2){Temp=实际电流/读数电流*Temp;}
如果需要精确只能查表但358实在没意义 捱多年 发表于 2019-12-22 02:28
如果只是减少误差可以这样如0.2A时电流偏小
if(Temp
是调不出线性,调好的那两个低高电流差0.06内,调不好的低电流偏低,1a以上开始不停加大,3a显示4A电流
你这个写法作者电压部分
float Temp;
Temp = tmpin * 3.3 * VGain / 1023; //单位:V
//下面是校正,应根据实际情况重新计算。其实不校正精度也不错
if(Temp<=0.5) Temp = 1.0 * Temp;
else if(Temp>0.5 && Temp<2.5) Temp = 0.98 * Temp + 0.28;
else if(Temp<6.5) Temp = 1.005 * Temp + 0.235;
else if(Temp<11.5) Temp = 1.00325 * Temp + 0.22925;
else if(Temp<36.5) Temp = 0.990417 * Temp + 0.385;
elseTemp = 0.988889 * Temp + 0.482222;
if(Temp<0) Temp=0;
return (Temp);
实际35V以上偏低,我按照这个改后面数能修正
else if(Temp<60.5) Temp = 0.988889 * Temp + 0.542222;
else if(Temp<75.5) Temp = 0.988889 * Temp + 0.642222;
elseTemp = 0.988889 * Temp + 0.752222;
电流部分
Temp = 1.385042 * Temp - 1.698751;
我按照他这样改
if(Temp<=0.5) Temp = 1.385042 * Temp - 1.498751; 不知道算法,低了0.2a想着减少后面的数加大
elseTemp = 1.385042 * Temp - 1.698751;
这样写没用,低电流部分修正,1a以上显示更高
f(Temp<0.2){Temp=实际电流/读数电流*Temp;},
你这个是不是0.2A以下电流,实际电流和读取电流填上去,0.2a以下调好的能显示,调不好1起码0.3A左右才会显示
本帖最后由 沨の痕 于 2019-12-22 10:22 编辑
捱多年 发表于 2019-12-22 01:41
Temp = tmpin * 3.3 / 1023 / ampGain / Rs;中tmpin是调用 ProcessCurrent的程序提供,3.3为3.3V满量程电 ...
ProcessCurrent就2部分
/*****电流数据处理***************************************
tmpin:采集的电流数据;
输出:电流值,单位:A
*********************************************************/
float ProcessCurrent(float tmpin)
{
float Temp;
Temp = tmpin * 3.3 / 1023 / ampGain / Rs; //单位:A
//下面是校正,应根据实际情况重新计算。本例中是将运放的反馈电阻 R6(180k)
//改成 1M后,放大系数ampGain由29变为129。
//取样电阻 Rs约为 2mR。
Temp = 1.385042 * Temp - 1.698751;
if(Temp<0) Temp=0;
return (Temp);
curtRAW = Ad_Av(3); //获取电流数据
if(iFlag==1){ //电流数据采集完成才进行以下计算,否则跳过,将显示上次数据
iFlag=0;
newData = ProcessCurrent(curtRAW);
Noise_Filter(0.5, 1, preCoef, preTrend, ADvalue, newData);
//ADvalue = newData; //不要上面的滤波时使用
mA = (uint)(ADvalue*1000);
if(mA > 9999){
cDotPS=4;
ADCBuff = mA / 100 % 10; //0.1A
ADCBuff = mA / 1000 % 10; //A
ADCBuff = mA / 1000 / 10; //十A
}else{
cDotPS=5;
ADCBuff = mA / 10 % 10; //0.01A
ADCBuff = mA / 100 % 10; //0.1A
ADCBuff = mA / 1000; //A
}
}
I_Show(3);
//asm("rim"); //开系统总中断,准备下次ADC采样
}
}
Temp = tmpin * 3.3 / 1023 / ampGain / Rs;
Temp = 1.385042 * Temp - 1.698751;
这两句我不理解的是temp和tmpin,temp读取电流数还是实际电流数,下面两个数 1.385042 1.698751是万用表量的还是怎么算出来x=ax+b后面不是减号吗
tmpin应该是从是ad读取到的数据,第一句的temp是理论的值,直接显示会和实际偏差较大,第二句的temp是修正后值也是显示的值。b可以是正也可以是负数啊看实际是正偏差还是负偏差,看您对if还不能熟练运用能不用else就别用了if可以嵌套使用到最后会把自己搞晕。先把temp修正一次保证中间一段的误差用if判断小于某数再修正一次再用大于某数修正一次基本就能满足要求了吧?差太多直接扔了吧累 float ProcessCurrent(float tmpin)
{
float Temp;
Temp = tmpin * 3.3 / 1023 / ampGain / Rs; //
//调整时用斜杠星号屏蔽下面语句
//电流为0时显示的值即为-b,确定b后输入一定的电流,实际电流/显示电流即为a值
/*Temp = 1.385042 * Temp - 1.698751;
if(Temp<0) Temp=0;*/
return (Temp);//到这里已经结束下面不会被执行了 本帖最后由 沨の痕 于 2019-12-22 15:47 编辑
捱多年 发表于 2019-12-22 12:25
float ProcessCurrent(float tmpin)
{
float Temp;
测试屏蔽Temp = 1.385042 * Temp - 1.698751;
电流显示1.2A
屏蔽下测试 实际 显示 有的会跳动
0.1991.39-1.4
0.3991.57
0.5981.75-1.76
0.8011.94-1.96
1.0002.12
http://www.51hei.com/bbs/dpj-102264-1.html这是原贴,源码都在帖子显示,有一部分没显示完,不重要的,原作者好像也是采样不是原配低电流小高电流大才重新编写的
好像公式有误,应该是a(x+b)才对,这个偏移量一直存在运算时应该首先减去,否则只有确定了A值才能得到b值,这样就不直观了
页:
[1]
2