NerdKits - electronics education for a digital generation

You are not logged in. [log in]

NEW: Learning electronics? Ask your questions on the new Electronics Questions & Answers site hosted by CircuitLab.

Microcontroller Programming » Trouble with the log10 function

June 01, 2010
by Rufusthedog
Rufusthedog's Avatar

Hi All,

I'm just modifying the tempsensor to change the output for log output. I modified the code as follows and it won't compile. Any idea what I'm doing wrong?

From:

fprintf_P(&lcd_stream, PSTR("Temperature: %.2f"),temp_avg);

To:

fprintf_P(&lcd_stream, PSTR("Temperature: %.2f"),10*log10(temp_avg));

Thanks,

June 01, 2010
by Ralphxyz
Ralphxyz's Avatar

Comment the changed line out to confirm that is where the problem is coming from.

Your change looks good but then again ...

Ralph

June 01, 2010
by Rufusthedog
Rufusthedog's Avatar

Thanks Ralph,

If I change it to somethings like this, it works.

fprintf_P(&lcd_stream, PSTR("Temperature: %.2f"),10*(temp_avg));

It just doesn't compile when add in the LOG10 function, I'm sure I'm screwing up somewhere.

June 02, 2010
by Ralphxyz
Ralphxyz's Avatar

Possible you might try (10*(log10(temp_avg)).

Where is it failing? does x= log10(temp_avg) work?

Ralph

June 02, 2010
by Ralphxyz
Ralphxyz's Avatar

Ooops try (10*(log10(temp_avg))).

Ralph

June 02, 2010
by bretm
bretm's Avatar

Does the makefile include the -lm linker flag?

June 02, 2010
by Rufusthedog
Rufusthedog's Avatar

Hi Bretm,

It appears it doesn't have that flag, I will give that a try.

Thanks

Rufus

June 02, 2010
by Rufusthedog
Rufusthedog's Avatar

No, I was wrong, the-lm flag is there. I'm running this on Mac and I also tried under windows and get the same error.

Here is the Makefile:

GCCFLAGS=-g -Os -Wall -mmcu=atmega168

LINKFLAGS=-Wl,-u,vfprintf -lprintf_flt -Wl,-u,vfscanf -lscanf_flt -lm

AVRDUDEFLAGS=-c avr109 -p m168 -b 115200 -P /dev/tty.PL2303-0000101D

LINKOBJECTS=../libnerdkits/delay.o ../libnerdkits/lcd.o ../libnerdkits/uart.o

all: tempsensor-upload

tempsensor.hex: tempsensor.c make -C ../libnerdkits avr-gcc ${GCCFLAGS} ${LINKFLAGS} -o tempsensor.o tempsensor.c ${LINKOBJECTS} avr-objcopy -j .text -O ihex tempsensor.o tempsensor.hex

tempsensor.ass: tempsensor.hex avr-objdump -S -d tempsensor.o > tempsensor.ass

tempsensor-upload: tempsensor.hex avrdude ${AVRDUDEFLAGS} -U flash:w:tempsensor.hex:a

June 02, 2010
by bretm
bretm's Avatar

Does it work if you add this to your #include statements in the source?

#include <math.h>
June 02, 2010
by Rufusthedog
Rufusthedog's Avatar

Hi Bretm,

The Tempsensor code is the same that is part of Nerdkits and the <math.h> is called in the #include statements I just added the log10 function. I suspect the problem is with the makefile.

Rufus

 // tempsensor.c
 // for NerdKits with ATmega168
 // mrobbins@mit.edu

 #define F_CPU 14745600

 #include <stdio.h>
 #include <math.h>

 #include <avr/io.h>
 #include <avr/interrupt.h>
 #include <avr/pgmspace.h>
 #include <inttypes.h>

 #include "../libnerdkits/delay.h"
 #include "../libnerdkits/lcd.h"
 #include "../libnerdkits/uart.h"

 // PIN DEFINITIONS:
 //
 // PC0 -- temperature sensor analog input

 void adc_init() {
 // set analog to digital converter
 // for external reference (5v), single ended input ADC0
  ADMUX = 0;

  // set analog to digital converter
  // to be enabled, with a clock prescale of 1/128
  // so that the ADC clock runs at 115.2kHz.
  ADCSRA = (1<<ADEN) | (1<<ADPS2) | (1<<ADPS1) | (1<<ADPS0);

  // fire a conversion just to get the ADC warmed up
   ADCSRA |= (1<<ADSC);
  }

  uint16_t adc_read() {
  // read from ADC, waiting for conversion to finish
  // (assumes someone else asked for a conversion.)
  // wait for it to be cleared
  while(ADCSRA & (1<<ADSC)) {
   // do nothing... just hold your breath.
  }
  // bit is cleared, so we have a result.

  // read from the ADCL/ADCH registers, and combine the result
  // Note: ADCL must be read first (datasheet pp. 259)
  uint16_t result = ADCL;
  uint16_t temp = ADCH;
  result = result + (temp<<8);

  // set ADSC bit to get the *next* conversion started
  ADCSRA |= (1<<ADSC);

  return result;
 }

  double sampleToFahrenheit(uint16_t sample) {
  // conversion ratio in DEGREES/STEP:
  // (5000 mV / 1024 steps) * (1 degree / 10mV)
  //    ^^^^^^^^^^^      ^^^^^^^^^^
  //     from ADC         from LM34
  return sample * (5000.0 / 1024.0 / 10.0);  
 }

   int main() {
  // start up the LCD
   lcd_init();
    FILE lcd_stream = FDEV_SETUP_STREAM(lcd_putchar, 0, _FDEV_SETUP_WRITE);
    lcd_home();

   // start up the Analog to Digital Converter
   adc_init();

   // start up the serial port
   uart_init();
   FILE uart_stream = FDEV_SETUP_STREAM(uart_putchar, uart_getchar, _FDEV_SETUP_RW);
   stdin = stdout = &uart_stream;

   // holder variables for temperature data
   uint16_t last_sample = 0;
   double this_temp;
   double temp_avg;
   uint8_t i;

    while(1) {
   // take 100 samples and average them!
    temp_avg = 0.0;
    for(i=0; i<100; i++) {
    last_sample = adc_read();
    this_temp = sampleToFahrenheit(last_sample);

     // add this contribution to the average
     temp_avg = temp_avg + this_temp/100.0;
    }

    // write message to LCD
    lcd_home();
    lcd_write_string(PSTR("ADC: "));
    lcd_write_int16(last_sample);
    lcd_write_string(PSTR(" of 1024   "));
    lcd_line_two();
    fprintf_P(&lcd_stream, PSTR("Temperature: %.2f"), 10*log10(temp_avg));
    lcd_write_data(0xdf);
    lcd_write_string(PSTR("F      "));

   // write message to serial port
    printf_P(PSTR("%.2f degrees F\r\n"), temp_avg);
   }

    return 0;
    }
June 02, 2010
by mrobbins
(NerdKits Staff)

mrobbins's Avatar

Hi Rufus,

Does your compiler error say something like "relocation truncated to fit"? If so, give this a try:

1) In the Makefile, remove "-lm" from the end of the LINKFLAGS line:

LINKFLAGS=-Wl,-u,vfprintf -lprintf_flt -Wl,-u,vfscanf -lscanf_flt

2) In the Makefile, add "-lm" to the end of the LINKOBJECTS line:

LINKOBJECTS=../libnerdkits/delay.o ../libnerdkits/lcd.o ../libnerdkits/uart.o  -lm

3) Run "make".

This simply rearranges the order in which the compiler/linker bundles the math code with your code, ensuring that the math code comes last. For reasons that are a little bit voodoo, this tends to make it work. (There's a bug report about this issue from a while ago, but not too much detail in explaining it clearly.)

Please let me know if that works! And if not, please post the compiler's error message.

Mike

June 03, 2010
by Rufusthedog
Rufusthedog's Avatar

Hi Mike,

That worked! I suspected that was where the problem was but I'm not real familiar with makefiles yet.

Thanks for the help,

Rufus

Post a Reply

Please log in to post a reply.

Did you know that a microcontroller can measure an RC time constant? Learn more...