使用AVR atmega8在C中出现意外的浮动行为
发布时间:2020-12-16 07:28:53 所属栏目:百科 来源:网络整理
导读:我一直试图弄清楚为什么我不能通过将unsigned int乘以浮点值来获得合理的值. 像65535 * 0.1这样的东西按预期工作,但是浮点数与来自内存的uint相乘会产生疯狂的值.我有一个函数读取ADC并返回一个uin16_t.有了这个值,我将它打印到一个4位数的LED显示屏上,工作
我一直试图弄清楚为什么我不能通过将unsigned int乘以浮点值来获得合理的值.
像65535 * 0.1这样的东西按预期工作,但是浮点数与来自内存的uint相乘会产生疯狂的值.我有一个函数读取ADC并返回一个uin16_t.有了这个值,我将它打印到一个4位数的LED显示屏上,工作正常. 我的代码在下面,但争用的区域在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 Makefile PROJECT=Temp_Display SOURCES=main.c CC=avr-gcc OBJCOPY=avr-objcopy MMCU=atmega328p OSC_HZ=16000000UL OPTIMISATION=2 PORT=/dev/ttyUSB0 CFLAGS=-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}.hex clean: 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类型时. (编辑:李大同) 【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容! |