我一直试图弄清楚为什么我不能通过将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 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类型时.