使用AVR atmega8在C中出现意外的浮动行为

使用AVR atmega8在C中出现意外的浮动行为,第1张

概述我一直试图弄清楚为什么我不能通过将unsigned int乘以浮点值来获得合理的值. 像65535 * 0.1这样的东西按预期工作,但是浮点数与来自内存的uint相乘会产生疯狂的值.我有一个函数读取ADC并返回一个uin16_t.有了这个值,我将它打印到一个4位数的LED显示屏上,工作正常. 将相同的值与1.0相乘会返回完全不同的东西(对于我的显示来说太大了,所以我真的不知道它是什么). 我的代码 我一直试图弄清楚为什么我不能通过将unsigned int乘以浮点值来获得合理的值.

像65535 * 0.1这样的东西按预期工作,但是浮点数与来自内存的uint相乘会产生疯狂的值.我有一个函数读取ADC并返回一个uin16_t.有了这个值,我将它打印到一个4位数的LED显示屏上,工作正常.
将相同的值与1.0相乘会返回完全不同的东西(对于我的显示来说太大了,所以我真的不知道它是什么).

我的代码在下面,但争用的区域在main()的底部.任何帮助都会很棒.谢谢

main.c中:

#include <avr/io.h>#include <util/delay.h>#include <avr/interrupt.h>#include <stdint.h>#define BAUD 9600#include <util/setbaud.h>#define disP_BRIGHT_CMD     'z'#define disP_reset          'v'#define ADC_AVG            3 volatile uint8_t  hi,lo;volatile uint16_t result; ISR(ADC_vect){     lo = ADCL;     hi = ADCH;     MCUCR &= ~_BV(SE); //Clear enable sleep } voID initSerial(voID){    // set baud rate    UBRR0H = UBRRH_VALUE;    UBRR0L = UBRRL_VALUE;    // set frame format    UCSR0C |= (0x3 << UCSZ00); // 8n1    // set enable tx/rx    UCSR0B = _BV(RXEN0) | _BV(TXEN0);}voID initADC(voID){    // AVCC and ADC0    ADMUX   = _BV(REFS0);     // Enable,div128,+ 1st setup    ADCSRA  |= _BV(ADEN)|_BV(ADSC)|_BV(ADPS2)|_BV(ADPS1)|_BV(ADPS0)|_BV(ADIE);}uint16_t readADC(voID){    uint16_t average=0;    // Start Conversion    ADCSRA |= _BV(ADSC);    for (char i=0;i<ADC_AVG;i++) {        MCUCR   |= _BV(SE);        ADCSRA  |= _BV(ADSC);        __asm volatile("sleep");        MCUCR   &= ~_BV(SE);        result  = (hi<<8);        result  |= lo;        average += result;    }    average /= ADC_AVG;    return average;    }voID sendByte(char val){    while (! (UCSR0A & (1<<UDRE0)) ); //wait until tx is complete    UDR0 = val;}/* * Convert voltage to temperature based on a negative coefficIEnt for MAX6613 */uint16_t analogToTemp(uint16_t val){  uint16_t temp;  //v     = 5 * (val/1023.0);  //temp  = (1.8455 - (5.0*(val/1023.0)))/0.01123;  temp  = (1.8455 - (5.0*(val/1023.0)))*89;  //temp = val * M_PI;  //v     = 5 * ( val/1024);  //temp  = (2 - v) * 89;  return temp;}voID initdisplay(){    sendByte(disP_reset);    sendByte(disP_BRIGHT_CMD);    sendByte(0);}voID serialSegments(uint16_t val) {    // 4 digit display  sendByte(val / 1000);  sendByte((val / 100) % 10);  sendByte((val / 10) % 10);  sendByte(val % 10);  }int main(voID){    uint16_t calc=0,sense=0;    DDRB    |= _BV(DDB5);    PORTB   |= _BV(PORTB5);    initSerial();    initADC();    initdisplay();    sei();    MCUCR   |= (1 << SM0); // Setting sleep mode to "ADC Noise Reduction"     MCUCR   |= (1 << SE);  // Sleep enable     for(;;) {        //PORTB   ^= _BV(PORTB5);        if (calc>=9999){ // I can't see the real value. Max val on display is 9999        //if (sense>=330){            PORTB |= _BV(PORTB5);        } else {            PORTB &= ~_BV(PORTB5);        }        sense   = readADC();        //calc    = sense*1.0;      // refuses to calculate properly    calc    = analogToTemp(sense);  // a bunch of zeroes        //calc = 65535*0.1;         // a-ok        serialSegments(calc);        _delay_ms(500);        serialSegments(sense);        _delay_ms(500);    }    return 0;}

Makefile文件:

# AVR-GCC MakefilePROJECT=Temp_displaySOURCES=main.cCC=avr-gccOBJcopY=avr-objcopyMMCU=atmega328pOSC_HZ=16000000ulOPTIMISATION=2PORT=/dev/ttyUSB0CFLAGS=-mmcu=${MMCU} -std=gnu99 -Wall -O${OPTIMISATION}  -DF_cpu=${OSC_HZ} -lm -lc ${PROJECT}.hex: ${PROJECT}.out    ${OBJcopY} -j .text -O ihex ${PROJECT}.out ${PROJECT}.hex    avr-size ${PROJECT}.out$(PROJECT).out: $(SOURCES)    ${CC} ${CFLAGS} -I./ -o ${PROJECT}.out ${SOURCES}program: ${PROJECT}.hex    stty -F ${PORT} hupcl    avrdude -V -F -c arduino -p m168 -b 57600 -P ${PORT} -U flash:w:${PROJECT}.hexclean:    rm -f ${PROJECT}.out    rm -f ${PROJECT}.hex

编辑:
好的,我在某种程度上简化了代码

#include <avr/io.h>#include <util/delay.h>#include <stdint.h>#define BAUD 9600#include <util/setbaud.h>#define disP_BRIGHT_CMD     'z'#define disP_reset          'v'voID initSerial(voID){    // set baud rate    UBRR0H = UBRRH_VALUE;    UBRR0L = UBRRL_VALUE;    // set frame format    UCSR0C |= (0x3 << UCSZ00); // 8n1    // set enable tx/rx    UCSR0B = _BV(TXEN0);}voID sendByte(char val){    while (! (UCSR0A & (1<<UDRE0)) ); //wait until tx is complete    UDR0 = val;}voID initdisplay(){    sendByte(disP_reset);    sendByte(disP_BRIGHT_CMD);    sendByte(0);}voID serialSegments(uint16_t val) {    // 4 digit display  sendByte(val / 1000);  sendByte((val / 100) % 10);  sendByte((val / 10) % 10);  sendByte(val % 10);  }int main(voID){    uint16_t i=0,val;    DDRB    |= _BV(DDB5);    initSerial();    initdisplay();    for(;;) {        val = (uint16_t)(i++ * 1.5);        serialSegments(i);        _delay_ms(500);        serialSegments(val);        _delay_ms(500);        if (val > 9999){            PORTB |= _BV(PORTB5);        } else {            PORTB &= ~_BV(PORTB5);        }    }    return 0;}
解决方法 非浮点浮点常量是double而不是float类型.

使用f后缀具有浮点字面值,例如0.1f

这可能会产生巨大的开销,因为像atmega8这样的MCU没有浮点单元,并且所有浮点运算都必须通过实现在固件中实现.

对于像atmega8这样的小型设备,通常会尝试避免使用浮动 *** 作,因为没有FPU,它们在cpu周期中非常昂贵.

现在没有理由实现不能正确翻译表达式,如:

calc = sense * 1.0;

当calc和sense是uint16_t类型时.

总结

以上是内存溢出为你收集整理的使用AVR atmega8在C中出现意外的浮动行为全部内容,希望文章能够帮你解决使用AVR atmega8在C中出现意外的浮动行为所遇到的程序开发问题。

如果觉得内存溢出网站内容还不错,欢迎将内存溢出网站推荐给程序员好友。

欢迎分享,转载请注明来源:内存溢出

原文地址: http://outofmemory.cn/langs/1229908.html

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
上一篇 2022-06-06
下一篇 2022-06-06

发表评论

登录后才能评论

评论列表(0条)

保存