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?

1
#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

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
// 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:

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

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

1
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 you can connect a computer keyboard to your microcontroller? Learn more...