打印
[AVR单片机]

求帮忙看下这段GCC下的带浮点数的计算程序问题出在哪里?

[复制链接]
4475|29
手机看帖
扫描二维码
随时随地手机跟帖
跳转到指定楼层
楼主
本帖最后由 qin552011373 于 2013-3-13 21:23 编辑

麻烦给位帮我看看这个程序,程序是在GCC下写的
int Getv( int Vo2)
{
        int R12= 4927;//4700+248
        
        int Vi2 =2327;//       2327;
        int Vo1;
        float Rt;//R3;
        int Vi1;
        float Vi3;
        float Ii1;
        Vo1=(Vo2/2);
        Vi1=(Vi2+Vo1);
        Vi3=60000-Vi1;
        Ii1= Vi3/R12;
        Ii1=Ii1+60000/R12;
         
        Rt = Vi1*10/Ii1;
        Rt=Rt*10;
        return Rt;
}
这段程序是,通过MEGA8的adc读进来的电压值Vo2,换算出Rt的电阻值,计算过程如下
VO1=-VO2/W2
VI2-VI1=VO1/10
VI1=VI2+VO1/10
Ii1=(1.2v-VI1)/(R10+w23)
Rt=VI1/Ii1
然后查表,得到当前的温度


现在的问题是,当温度比较低的时候,也就是20几度的时候,可以正确读到温度值,温度越高,误差越大,当温度100度左右的时候,程序就会死掉
会是什么原因呢?我自己感觉像是因为用了float,数据溢出了,可是 我尝试过把数据类型改为int,结果所有的值都显示65335,然后程序就死掉了
求各位帮帮忙,分析一下什么原因引起的,我该如何修改?多谢了

放电大路分析op07.jpg (284.74 KB )

放电大路分析op07.jpg

相关帖子

沙发
qin552011373| | 2013-3-13 21:27 | 只看该作者
你可以在各个温度下测出对应的电压值  然后根据电压制作一张表  鉴于没有测试过电压和温度的关系  估计你按线性处理   误差太大了点

使用特权

评论回复
板凳
huangxz| | 2013-3-13 23:02 | 只看该作者
avr8系列不建议用浮点数,测温这种应用用16bit定点计算已经足够了,

使用特权

评论回复
地板
wangxxll111|  楼主 | 2013-3-14 09:14 | 只看该作者
这么一句
Vi3=60000-Vi1;gcc生成这么多句汇编?
     88c:        3c 01               movw        r6, r24
     88e:        88 24               eor        r8, r8
     890:        77 fc               sbrc        r7, 7
     892:        80 94               com        r8
     894:        98 2c               mov        r9, r8
     896:        50 e6               ldi        r21, 0x60        ; 96
     898:        e5 2e               mov        r14, r21
     89a:        5a ee               ldi        r21, 0xEA        ; 234
     89c:        f5 2e               mov        r15, r21
     89e:        01 2d               mov        r16, r1
     8a0:        11 2d               mov        r17, r1
     8a2:        d8 01               movw        r26, r16
     8a4:        c7 01               movw        r24, r14
     8a6:        86 19               sub        r24, r6
     8a8:        97 09               sbc        r25, r7
     8aa:        a8 09               sbc        r26, r8
     8ac:        b9 09               sbc        r27, r9
     8ae:        bc 01               movw        r22, r24
     8b0:        cd 01               movw        r24, r26
     8b2:        12 d3               rcall        .+1572           ; 0xed8
     8b4:        dc 01               movw        r26, r24
     8b6:        cb 01               movw        r24, r22

使用特权

评论回复
5
dqyubsh| | 2013-3-14 10:55 | 只看该作者
gcc做浮点运算,生成的代码超大,甚至有空间不够的可能,IAR要好太多。运算时,要注意以下几点:
1,防止除以0
2,防止很大数除以很小数,相反也是要避免的。
3,防止乘法生成很大数
4,浮点与整数做乘除法时,最好先转换成浮点或双精度浮点
5,最好用仿真器,看一下是否有上述问题。

使用特权

评论回复
评分
参与人数 1威望 +6 收起 理由
qin552011373 + 6 赞一个!
6
wangxxll111|  楼主 | 2013-3-14 12:14 | 只看该作者
dqyubsh 发表于 2013-3-14 10:55
gcc做浮点运算,生成的代码超大,甚至有空间不够的可能,IAR要好太多。运算时,要注意以下几点:
1,防止除 ...

多谢指教!
没有仿真器阿,只能一步一步用数码管挨个数字显示来看。
浮点与整数做乘法时,曾经按你说的(float)这样转换过,但我看到的显示的效果一样啊

使用特权

评论回复
7
cool_coder| | 2013-3-14 16:02 | 只看该作者
以前在ATMEGA上用GCC遇到过浮点运算除0程序死掉的问题,已经好多年了,现在还有类似问题?

使用特权

评论回复
8
dqyubsh| | 2013-3-15 10:43 | 只看该作者
cool_coder 发表于 2013-3-14 16:02
以前在ATMEGA上用GCC遇到过浮点运算除0程序死掉的问题,已经好多年了,现在还有类似问题? ...

除以0,非法,这是程序员自己应该解决的问题,而不是编译器解决的问题。难不成你希望编译器每次做除法之前,先判断一下除数是不是0?你不觉得这事效率很低吗?

如果一个浮点数,小于<0.01,那就高度警觉,是不是会当成0非法,即便能运算,精度也受影响。

为了适合乘除法,必须主动地约束两个数的大小。比如,如果用mm作单位可能会出问题,那就用cm,m作单位,最后显示的时候再人为地加个小数点。实际上,定义一个整数、浮点数,它的单位完全可以与实际的物理量的单位没有关联。这是嵌入式编程与Windows程序员的区别之一。

使用特权

评论回复
评分
参与人数 1威望 +4 收起 理由
qin552011373 + 4 很给力!
9
cool_coder| | 2013-3-15 13:47 | 只看该作者
dqyubsh 发表于 2013-3-15 10:43
除以0,非法,这是程序员自己应该解决的问题,而不是编译器解决的问题。难不成你希望编译器每次做除法之 ...

个人认为,楼上说的不错,但是不够全面。严格说这不是编译的问题,除了常数表达式是在编译时计算之外,有变量参与的运算都在运行时处理,这时起关键作用的是浮点库。对除零问题的处理,涉及到的是浮点数溢出的概念,而不是“先判断一下除数是不是0”。一个合格的浮点运算库,在结果溢出时,应该返回相应的特殊值来表达溢出状态,而不是使程序运行混乱。因此,在某种程度上说,这是开发工具链的问题。

使用特权

评论回复
评分
参与人数 1威望 +4 收起 理由
qin552011373 + 4 赞一个!
10
wangxxll111|  楼主 | 2013-3-15 15:25 | 只看该作者
cool_coder 发表于 2013-3-14 16:02
以前在ATMEGA上用GCC遇到过浮点运算除0程序死掉的问题,已经好多年了,现在还有类似问题? ...

呵呵,我这人比较懒,用的是很久以前,大概2005年吧,别人给的一个老版本的GCC,

使用特权

评论回复
11
wangxxll111|  楼主 | 2013-3-15 15:27 | 只看该作者
dqyubsh 发表于 2013-3-15 10:43
除以0,非法,这是程序员自己应该解决的问题,而不是编译器解决的问题。难不成你希望编译器每次做除法之 ...

我也在努力用你说的方法,把一些数字分解后 在加减乘除,可是有些麻烦,总是容易超过655535,没有找到比较好的分解方法
而且,我也看了,我的数据,不太可能出现0,或者是特别小的数,如0.01

使用特权

评论回复
12
wangxxll111|  楼主 | 2013-3-15 15:28 | 只看该作者
目前真是不知道该如何把这段程序改成一个有效的程序啊!

使用特权

评论回复
13
fp123123| | 2013-3-16 22:58 | 只看该作者
这程序写得太乱了,精简一下,改成这样

uint16_t Getv(uint16_t Vo2)
{
        Vo2 >>= 1;
        Vo2 += 2327;
        float Ii1 = 4927 / (120000.0f - Vo2);
        float Rt = Vo2 * 100.0f * Ii1;

        return (uint16_t)Rt;
}

使用特权

评论回复
14
fp123123| | 2013-3-16 23:00 | 只看该作者
看看这个等价的程序,你的一些数值的取值应该是错误的,自己找找错误吧

使用特权

评论回复
15
wangxxll111|  楼主 | 2013-3-18 09:02 | 只看该作者
fp123123 发表于 2013-3-16 22:58
这程序写得太乱了,精简一下,改成这样

uint16_t Getv(uint16_t Vo2)

多谢赐教,写的乱,可能是因为我对浮点不熟悉,所以想尽量把每个式子化成一个简单地计算,保证数值不溢出,所以把式子肢解的支离破碎的
你指的数值取值错误,是哪个方面?是对放大倍数的计算吗? 那么这个计算方法 应该没有问题吧?

使用特权

评论回复
16
fp123123| | 2013-3-18 10:56 | 只看该作者
本帖最后由 fp123123 于 2013-3-18 12:14 编辑

看错了,如果你的公式没错,计算应该是对的

M8的ADC是10位精度,结果范围0 - 1024
Vo2 = 0时 Rt = 0,Vo2 = 1024时 Rt = 2153 算错了

使用特权

评论回复
17
wangxxll111|  楼主 | 2013-3-18 11:22 | 只看该作者
fp123123 发表于 2013-3-18 10:56
看错了,如果你的公式没错,计算应该是对的

M8的ADC是10位精度,结果范围0 - 1024

:dizzy:,我希望的结果是,vo2=0时,Rt大概100,而不是0啊,看来我的参数真的是设置不合理啊?

使用特权

评论回复
18
fp123123| | 2013-3-18 12:16 | 只看该作者
不好意思, 上面的算错了, 用程序算了一下, 导入到EXCEL里画了个图, 从计算结果看, 不要乘上100.0f就对了



计算程序:

#include "stdafx.h"

#define uint16_t unsigned short

uint16_t Getv(uint16_t Vo2)
{
        Vo2 /= 2;
        Vo2 += 2327;
        float Ii1 = 4927 / (120000.0f - Vo2);
        float Rt = Vo2 * 100.0f * Ii1;

        return (uint16_t)Rt;
}

int main(int argc, char* argv[])
{
        FILE *fp = fopen("data.txt","wt");

        for(uint16_t Vo2=0; Vo2<=1024; Vo2+=16)
        {
                fprintf(fp,"%d %d\n", Vo2, Getv(Vo2));
        }

        fclose(fp);

        return 0;
}


使用特权

评论回复
19
dqyubsh| | 2013-3-18 21:38 | 只看该作者
cool_coder 发表于 2013-3-15 13:47
个人认为,楼上说的不错,但是不够全面。严格说这不是编译的问题,除了常数表达式是在编译时计算之外,有 ...

问题的关键,你不能写一个依靠编译器判断是否溢出的代码,应该在编程过程中就要仔细核对,并有效预防的。即便编译器这次帮了你,你能确保程序在其它编译环境下的可移植性吗?

使用特权

评论回复
20
cool_coder| | 2013-3-19 17:20 | 只看该作者
dqyubsh 发表于 2013-3-18 21:38
问题的关键,你不能写一个依靠编译器判断是否溢出的代码,应该在编程过程中就要仔细核对,并有效预防的。 ...

已经说过了,这不是编译的问题。现实的情况是,对于复杂的运算和无法确定的外部输入,总会有溢出的情况出现,这不是可以人为控制的。如果出现这种情况程序就发生混乱,是不可接受的。

使用特权

评论回复
发新帖 我要提问
您需要登录后才可以回帖 登录 | 注册

本版积分规则

个人签名:想要静下心来学学模电,还得及吗?

5

主题

81

帖子

1

粉丝