Sending 32 bit data over USART: Garbage data received!

Go To Last Post
67 posts / 0 new

Pages

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

100uF is probably a bit too vicious. We want reasonable high frequency performance and 100uF electros aren't good for that task. Ceramic caps are what you need.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

I see. Well like I mentioned in my last edit, I'll swing by TechShop and see if they don't have what I need. Perhaps I'll order some 100nf capacitors online.

Thomas Brannan | thomascbrannan@gmail.com

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

I'm just curious why anyone (but a nuclear scientist) would ever choose %E over %f in a printf(). Do you really find:

Vcc = 5.023661E+00 
Vcc = 5.001334E+00 
Vcc = 4.979204E+00 
Vcc = 4.979204E+00 
Vcc = 4.979204E+00 
Vcc = 4.979204E+00 
Vcc = 4.979204E+00 
Vcc = 4.979204E+00 
Vcc = 4.979204E+00 
Vcc = 4.979204E+00 
Vcc = 4.979204E+00 
Vcc = 4.979204E+00 
Vcc = 4.979204E+00 

to be more readable than

Vcc = 5.02
Vcc = 5.00
Vcc = 4.98
Vcc = 4.98
Vcc = 4.98
Vcc = 4.98
Vcc = 4.98
Vcc = 4.98
Vcc = 4.98
Vcc = 4.98
Vcc = 4.98
Vcc = 4.98
Vcc = 4.98

that you would have got if you use %.2f in printf()?

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

I say for the 3rd time:

Print the raw ADC values.

 

Then build your formulas 1 step at a time and print intermediate results.

 

Using doubles sounds redicilous to me. with using doubles here you gain nothing over floats.

Even floats are overkill

 

you're using a thermo nuclear weapon when you need a pee shooter.

 

Take small steps, & check calculations with a desktop calculator.

You will see immediately what & where errors occur.

This is much better than typing in some 10 line formula you found on the 'net and then having no idea where it went wrong.

 

If you do it in small steps then you will have developed the software yourself faster than you can type your questions here.

 

 

 

 

 

Paul van der Hoeven.
Bunch of old projects with AVR's:
http://www.hoevendesign.com

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Paulvdh wrote:
Using doubles sounds redicilous to me. with using doubles here you gain nothing over floats. Even floats are overkill
That's especially true if using avr-gcc because sizeof(float)==sizeof(double)==4. They are all 32 bit, no difference whether you use the word "float" or "double" in the accuracy you achieve.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Paul, we did get some raw values and I was able to validate the calcs. Thomas, to his credit, is putting the effort in.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Well, if one decides not to use floats

a) generated binary is (a little) smaller

b) no use to link to a special library.

With two extra variables, you can manage to display temperature in degrees and tens (which is overkill, sensor "accurcy being 1 or 2 C) )

(BTW : floats are very useful if one wishes to do some trigonometry, say; here, for ONE -maybe two- linear formula, it seems overkill)

 

Testing this is not that difficult

$ cat temp.c
#include <stdio.h>
int main() {
    int16_t A, tempReading, temperatureDeciDegreesCelsius;

    for (tempReading = 0; tempReading < 555; tempReading+= 50) {
        uint32_t millivolts = (tempReading * 5000) / 1023; // previous correction
        temperatureDeciDegreesCelsius= (millivolts - 500)  ;

        int intTemp = temperatureDeciDegreesCelsius/10,
        fracTemp = temperatureDeciDegreesCelsius % 10; 
        if (temperatureDeciDegreesCelsius < 0) { 
           intTemp = - ((-temperatureDeciDegreesCelsius)/10); 
           fracTemp = -temperatureDeciDegreesCelsius % 10;
        }
 /* edited : 3 lines added to obtain not too ridiculous results when it freezes
        printf("temp : <%d>  %d mV %d.%01d °C \n", tempReading, millivolts,
               intTemp , fracTemp);
    }
    return (0);
}
leads to the following result

 

lead to the following result (truncated, not to boil the sensor)

$ astyle temp.c && gcc temp.c && ./a
Formaté    /home/briond/temp.c
temp : <0>  0 mV -50.0 °C
temp : <50>  244 mV -25.-6 °C # new soft corrects this ridiculous behavior
temp : <100>  488 mV -1.-2 °C
temp : <150>  733 mV 23.3 °C
temp : <200>  977 mV 47.7 °C
temp : <250>  1221 mV 72.1 °C
temp : <300>  1466 mV 96.6 °C
temp : <350>  1710 mV 121.0 °C
temp : <400>  1955 mV 145.5 °C

 

 

Oh, btw : why do F_CPU (used for delay) and FOSC (used for BAUDRATE? sometimes) differ . Do you switch Xals while serial receiving/transmitting? Or is one of them unused, leading to confusion?

 

 

Last Edited: Tue. Jul 25, 2017 - 01:15 PM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

TankEngine wrote:
Yeah, the lack of an electronics store is kinda surprising. Goes to show what a small city SF really is.

All electronics shops are dissapearing at quite a fast rate. Only the internet shops are remaining.

 

TankEngine wrote:
Here's a picture of my circuit, sorry

No need to apologise. On the contrary, it gives us a clean picture of what you are doing.

It would help a bit if you used shorter wires for the leds, and pulled them apart a bit.

This is not an electrical issue, but just visual. Try to figure out which led is connected to which pin from the picture...

KiCad is also not a replacement for Breadboards. It is an addition / extension.

Designing PCB's is a long cycle. Day's if done locally or Weeks to get PCB's from china.

 

TankEngine wrote:
My kit came with 100uF capacitors, think that would do the trick?

Clip the leads of one (about 7mm) and put it in the long rails (Red + and Blue -).

Put another one between GND and your sensor output.

Breadboards are Quick. No need to ask, just try it.

 

And get a bag of 100nF Ceramic caps

https://www.aliexpress.com/item/...

 

And with all the dissapearing shops & longer lead times it gets more and more interesting to get some assortments boxes, especially with ali / Ebay prices.

https://www.aliexpress.com/whole...

 

Resistors, Transistors, Capacitors / Elco's, Leds, Mechanical stuff.

 

PS: Have you printed the raw ADC values yet?

You  seem to have worked around it by now, but it probably would have saved you some time.

Paul van der Hoeven.
Bunch of old projects with AVR's:
http://www.hoevendesign.com

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Ah, I finally see what you all wanted. Here's sample output using %.2f instead of %E.

 

Vcc = 5.02      tempReading = 144       volts = 0.71    degreesCelcius = 20.71
Vcc = 4.98      tempReading = 173       volts = 0.84    degreesCelcius = 34.20
Vcc = 4.98      tempReading = 188       volts = 0.92    degreesCelcius = 41.50
Vcc = 4.96      tempReading = 188       volts = 0.91    degreesCelcius = 41.10
Vcc = 4.96      tempReading = 188       volts = 0.91    degreesCelcius = 41.10
Vcc = 4.96      tempReading = 188       volts = 0.91    degreesCelcius = 41.10
Vcc = 4.98      tempReading = 188       volts = 0.92    degreesCelcius = 41.50
Vcc = 4.98      tempReading = 188       volts = 0.92    degreesCelcius = 41.50
Vcc = 4.98      tempReading = 188       volts = 0.92    degreesCelcius = 41.50
Vcc = 4.96      tempReading = 188       volts = 0.91    degreesCelcius = 41.10
Vcc = 4.98      tempReading = 188       volts = 0.92    degreesCelcius = 41.50
Vcc = 4.98      tempReading = 188       volts = 0.92    degreesCelcius = 41.50
Vcc = 4.98      tempReading = 188       volts = 0.92    degreesCelcius = 41.50

 

You know, that is more readable.

 

I'm shopping online for components grab bags. Sparkfun, ali, ebay...

 

I'll be responding to some more of what's been posted soon.

 

EDIT: Rapidly falling down the ali express rabbit hole.

Thomas Brannan | thomascbrannan@gmail.com

Last Edited: Fri. Jul 28, 2017 - 11:55 PM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

So, I'm having a hard time understanding how to use fdevopen() for stdio redirection. If this is really obvious then I apologize. I've been trying to find an example of it for quite a while now.

 

I have found the official documentation @ http://www.nongnu.org/avr-libc/u...

 

What I can't find is a single example of how this works. Are my google skills weak, or is this an oversight? Gotta admit, I usually don't understand docs until I can relate it to an example, then the docs make sense.

 

I've found lots of examples of how to do stdio redirection in c using the FDEV_SETUP_STREAM macro. I'm thinking I may just go to using regular old c.

 

By the way I added capacitors to my circuit and the temperature is coming in much more accurate! Thanks!

Thomas Brannan | thomascbrannan@gmail.com

Last Edited: Mon. Jul 31, 2017 - 08:31 PM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

TankEngine wrote:
What I can't find is a single example of how this works.
Most people prefer the static allocation of a FILE struct at build time rather than the dynamic allocation of fdevopen() but as far as I can see the difference would simply be:

void    uart_init(void);
int	uart_putchar(char c, FILE *stream);
int	uart_getchar(FILE *stream);

FILE uart_str = FDEV_SETUP_STREAM(uart_putchar, uart_getchar, _FDEV_SETUP_RW);

int main(void) {
    uart_init();
    stdout = &uart_str;
    printf("hello");
}

now becomes...

void uart_init(void);
int	uart_putchar(char c, FILE *stream);
int	uart_getchar(FILE *stream);

FILE * pUART_str;

int main(void) {
    pUART_str = fdevopen(uart_putchar, uart_getchar);
    uart_init();
    stdout = pUART_str;
    printf("hello");
}

(untested!)

 

As you can see that doesn't really need pUART_str so could be simplified to:

void   uart_init(void);
int	uart_putchar(char c, FILE *stream);
int	uart_getchar(FILE *stream);

int main(void) {
    uart_init();
    stdout = fdevopen(uart_putchar, uart_getchar);
    printf("hello");
}

It's not entirely clear to me how the FILE structure that is allocated in fdevopen() would then be free()d ? Do you just fclose() ?

Last Edited: Tue. Aug 1, 2017 - 08:59 AM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Paulvdh wrote:
you're using a thermo nuclear weapon when you need a pee shooter.

LOL -- I'm sure "pea shooter" was meant, but the typo is thought-provoking. ;)

 

Indeed one is starting with a small integer number with ADC counts -- about 1000 max.  Even if "perfect" you only get about three significant digits.  No sense digging deeper.

 

 

You can put lipstick on a pig, but it is still a pig.

I've never met a pig I didn't like, as long as you have some salt and pepper.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Clawson, thanks to your example I was able to work out how to get STDIN and STDOUT working in avr-gcc. Thanks! Here's my code:

 

inline void uart_init();
int uart_getchar(FILE *stream);
int uart_putchar(char c, FILE *stream);

int main(void) {
  uart_init();
  stdin = stdout = fdevopen(uart_putchar, uart_getchar);
  char input[BUFSIZ]; // BUFSIZ is defined in stdio.
  printf("Hello, world...!\n");
  while (1) {
    if (fgets(input, sizeof(input), stdin) != NULL) {
      printf("%s\n", input);
    }
  }
}

Well, on to do the EEPROM calibration at last!

Thomas Brannan | thomascbrannan@gmail.com

Last Edited: Tue. Aug 1, 2017 - 11:32 PM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Got it, calibration mode is functional now. I'll make any improvements anyone suggests, but I'm going to tentatively say it's done now. Here's my code:

 

/* GccApplication2.cpp
 *
 * Created: 7/15/2017 11:32:42 PM
 * Author : Thomas Brannan
 *
 * This is starter kit project 3, the 'Love-O-Meter' (temperature sensor).
 *		... Note that this version uses an EXTERNAL temperature sensor.
 *
 * References:
 *		AVRFreaks guide to the ADC for a faster analogRead() @ https://www.avrfreaks.net/forum/tut-c-newbies-guide-avr-adc?page=all
 *		AVRFreaks guide to Serial communications (USART) @ https://www.avrfreaks.net/forum/tut-soft-using-usart-serial-communications?page=all
 *		qeewiki USART guide @ https://sites.google.com/site/qeewiki/books/avr-guide/usart
 *		Jame's blog Sample Code for atmega328p Serial Communication @ http://jamesgregson.blogspot.com/2012/07/sample-code-for-atmega328p-serial.html
 *		Max Embedded guide to AVR USART	@ http://maxembedded.com/2013/09/the-usart-of-the-avr/
 *		[TUT] [C] Bit manipulation (AKA "Programming 101") @ https://www.avrfreaks.net/forum/tut-c-bit-manipulation-aka-programming-101?page=all
 *		Transmitting 32 bit float in 8 bit UART	@ https://e2e.ti.com/support/dsp/tms320c6000_high_performance_dsps/f/115/t/12204
 *		Unions by cpluscplus.com @ http://www.cplusplus.com/doc/tutorial/other_data_types/
 *		Guide to USART, including redirecting STD I/O @ https://appelsiini.net/2011/simple-usart-with-avr-libc/
 *		Using Standard IO streams in AVR GCC @ http://www.embedds.com/using-standard-io-streams-in-avr-gcc/
 *		Newbie's Guide to AVR timers (see: ctc mode) @ https://www.avrfreaks.net/forum/tut-c-newbies-guide-avr-timers?name=PNphpBB2&file=viewtopic&t=50106
 *		Using the EEPROM memory in AVR-GCC @ https://www.avrfreaks.net/forum/tut-c-using-eeprom-memory-avr-gcc?page=all
 *		Secret Arduino Voltmeter @ https://provideyourown.com/2012/secret-arduino-voltmeter-measure-battery-voltage/
 *		ADC on atmega328 part 1 @ http://www.embedds.com/adc-on-atmega328-part-1/
 *		The ADC of the AVR @ http://maxembedded.com/2011/06/the-adc-of-the-avr/
 */ 

/* F_CPU..............Speed of ATmega328P is 8E6Hz
 * FOSC...............Clock speed is 2*F_CPU
 * USART_BAUDRATE.....9600 bits/s data transfer rate
 * BAUD_PRESCALE......Equation for BAUD_PRESCALE from qeewiki
 *					  With our 16E6 clock frequency, this equation sets a ~103 prescale, which results in an acceptable 0.2% error
 */
#define F_CPU 8000000UL
#define FOSC 16000000UL
#define USART_BAUDRATE 9600
#define BAUD_PRESCALE FOSC/16/USART_BAUDRATE - 1	

/* avr/io.h is standard
 * stdio.h is used for printf()
 * avr/eeprom.h is used to read/write from nonvolatile memory
 * util/delay.h is used for _delay_ms()
 * inttypes.h would be used for integer types???
 */
#include <avr/io.h>
#include <stdio.h>
#include <avr/eeprom.h>
#include <util/delay.h>
#include <stdlib.h>
#include <string.h>

// Global variables
float EEMEM data_location;
char input_s[BUFSIZ];
float input_f;

// uart_putchar sends a single byte over USART.
/* return int			... Error if not 0.
 * param char c		    ... The byte of data to write to USART.
 * param FILE* stream	... The direction of the data?
 */
int uart_putchar(char c, FILE* stream) {
    if (c == '\n') {
        uart_putchar('\r', stream);
    }
    loop_until_bit_is_set(UCSR0A, UDRE0);
    UDR0 = c;
	return 0;
}

// uart_getchar writes a single byte over USART
/* return UDR0		   ... The I/O register, returns this because it is the data that has been received
 * param FILE* stream  ...
 */
int uart_getchar(FILE* stream) {
    loop_until_bit_is_set(UCSR0A, RXC0);
    return UDR0;
}

// readVcc() is taken from the 'Secret Voltmeter' article
/* I (Thomas Brannan) have made the following three modifications to readVcc():
 *   ... I have  tried modifying the function to reset the ADMUX MUX[3:1] bits
 *   ... I have made it return the number of volts instead of millivolts
 *   ... I have made it read ADCL and ADCH at the same time with result = ADC
 */
float readVcc() {
	// Save the state of the ADMUX register so we can reset it when we're done here
	uint8_t tempADMUX = ADMUX;

	// Read 1.1V reference against AVcc
	// set the reference to Vcc and the measurement to the internal 1.1V reference
	#if defined(__AVR_ATmega32U4__) || defined(__AVR_ATmega1280__) || defined(__AVR_ATmega2560__)
		ADMUX = _BV(REFS0) | _BV(MUX4) | _BV(MUX3) | _BV(MUX2) | _BV(MUX1);
	#elif defined (__AVR_ATtiny24__) || defined(__AVR_ATtiny44__) || defined(__AVR_ATtiny84__)
		ADMUX = _BV(MUX5) | _BV(MUX0);
	#elif defined (__AVR_ATtiny25__) || defined(__AVR_ATtiny45__) || defined(__AVR_ATtiny85__)
		ADMUX = _BV(MUX3) | _BV(MUX2);
	#else
		ADMUX = _BV(REFS0) | _BV(MUX3) | _BV(MUX2) | _BV(MUX1);
	#endif  

	_delay_ms(2);						// Wait for Vref to settle.
	ADCSRA |= _BV(ADSC);				// Start conversion.
	while (bit_is_set(ADCSRA,ADSC));	// Wait while measuring.
	float result = ADC;					// Determine result; Vcc in volts.
	ADMUX = tempADMUX;					// Reset the value of the ADMUX register.
	result = 1125.3F / result;			// Calculate Vcc (in V); 1125.3 = 1.1*1023.
	return result;						// Return the value of Vcc in volts.s
}

// readADC() loosely based on function @ http://maxembedded.com/2011/06/the-adc-of-the-avr/
uint16_t readADC(uint8_t c) {
	c &= 0b00001111;						// Clear all bits of c except 4 least signifigtant bits; used to set ADMUX register's MUX[3:0] bits.
	uint8_t tempADMUX = ADMUX;				// Save the value of ADMUX.
	ADMUX = 0x0;							// Clear ADMUX.
	ADMUX |= (_BV(REFS0) | c);				// Measure channel designated by c against Vcc reference.
	_delay_ms(2);							// Wait for Vref to settle.
	ADCSRA |= _BV(ADSC);					// Start conversion.
	while (bit_is_set(ADCSRA,ADSC)) {};		// Wait while measuring.
	uint16_t result = ADC;					// Capture the result of the conversion.
	ADMUX = tempADMUX;						// Restore ADMUX.
    return result;							// Return the result of the conversion.
}

// usart_init sets up serial communication
/* For the UBRR0H & UBRR0L registers...
 *   ... UBRROH must be set with the most signifigant bits of BAUD_PRESCALE.
 *   ... UBRROL must be set with the least signifigant bits of BAUD_PRESCALE.
 * For the UCSR0B register...
 *   ... Setting TXEN0 enables the USART transmister.
 *   ... Setting RXEN0 enables the USART reciever.
 * For the UCSR0C register...
 *   ... Setting UCSZ01 and UCSZ00 will set the frame size to 9.
 */
inline void usart_init() {
	UBRR0H = ((BAUD_PRESCALE)>> 8);
	UBRR0L = BAUD_PRESCALE;
	UCSR0B |= (_BV(TXEN0) | _BV(RXEN0));
	UCSR0C |= (_BV(UCSZ01) | _BV(UCSZ00));
}

void calibrate_TMP36GZ() {
	printf("Calibration mode!\nTo calibrate temperature sensor TMP36GZ, enter float equivalent to correct temperature divided by this device's measured temperature.\n");
	printf("\tEnter -q to quit calibration mode.\n\tEnter -r to output memory contents.\n\tEnter -e to erase memory contents.\n\tEnter a float to write data.\n");
	while (1) {
		if (fgets(input_s, sizeof(input_s), stdin) != NULL) {
			if (strncmp(input_s, "-r", 2) == 0) {
				printf("Memory contents: %.5f\n", eeprom_read_float(&data_location));
			} else if (strncmp(input_s, "-e", 2) == 0) {
				printf("Memory erased!\n");
				eeprom_update_float(&data_location, 0.0);
			} else if (strncmp(input_s, "-q", 2) == 0) {
				printf("Exited calibration mode!\n");
				break;
			} else {
				input_f = strtod(input_s, NULL);
				if (input_f != 0) {
					printf("Data written to memory: %.5f\n", input_f);
					eeprom_update_float(&data_location, input_f);
				} else {
						printf("...ERROR: invalid input: \n");
				}
			}
		}
	}
}

// Main()
int main(void) {
	// Set up analog input
	/* Refer to section 24.9 of the datasheet for a discussion of registers!
	 * For the ADMUX register, see section 24.5 'Changing Channel or Reference Selection'...
	 *   ... Setting REFS0 without REFS1 will make voltage reference be AVCC with external capacitor at AREF pin.
	 * For the ADCSRA register, see section ???...
	 *   ... Setting the ADATE bit will put the ADC in auto triggering mode, so that we do not have to set a bit for every conversion.
	 *   ... Setting the ADSC bit will start ADC conversions.
	 *   ... Setting the DPS2, ADPS1 and ADPS0 bits of the ADCSRA register will set the prescaler to 128; ADCfrequency = F_CPU/prescaler = 8E6Hz/128 = 125kHz
	 *   ... Setting the ADEN bit in the ADSCRA register activates the ADC.
	 */
	ADMUX |= _BV(REFS0);
	ADCSRA |= (_BV(ADEN) | _BV(ADPS2) | _BV(ADPS1) | _BV(ADPS0));

	// Set up timer
	/* For the TCCR1A register...
	 *   ... Setting WGM12 without WGM11 or WGM10 will put the counter in CTC mode.
	 * For the TCCR1B register...
	 *   ... Setting CS12 without CS11 or CS10 will set the prescale to 256.
	 * For the OCR1A register...
	 *   ... Setting this register to 31249 will mean that each second the timer will set a flag in TIFR1 bit OCF1A. ERROR: It updates too slowly!
	 */
	TCCR1A |= _BV(WGM12);
	OCR1A = 31249;
	TCCR1B |= (_BV(CS12));

	// Set up Serial communication
	usart_init();

	// Redirect STDOUT to USART
	stdin = stdout = fdevopen(&uart_putchar, &uart_getchar);

	// Configure GPI/O pins 2, 3, and 4 as OUTPUT.
	DDRD |= (_BV(DDD4) | _BV(DDD3) | _BV(DDD2));

	// Declare some variables
	uint16_t tempReading;
	float volts;
	float degreesCelcius;
	float vcc;
	float calibrationRatio;

	// Possibly calibrate the sensor
	printf("Enter -c for calibration mode. Enter anything else to continue.\n");
	if ((fgets(input_s, sizeof(input_s), stdin) != NULL) && (strncmp(input_s, "-c", 2) == 0)) {
		calibrate_TMP36GZ();
	}
	calibrationRatio = eeprom_read_float(&data_location);

	// Main While Loop
	/* Once per second...
	 *   ... Calculate the temperature.
	 *   ... Update Serial communication
	 *   ... Control 3 LEDs
	 */
    while (1) {

		// Check to see if one second has passed.
		if (TIFR1 & _BV(OCF1A)) {
			// Clear the OCF1A flag in TIFR by setting it (this is an unusual bx common to interrupt flags in the AVR)
			TIFR1 = _BV(OCF1A);
			// Calculate the temperature in celcius.
			vcc = readVcc();
			tempReading = readADC(0);
			volts = (tempReading * vcc) / 1023.0F;
			degreesCelcius = (volts - 0.5F) * 100.0F * calibrationRatio;
			// Update Serial communication
			printf("Vcc = %.2f\ttempReading = %u\tvolts = %.2f\tcalibrationRatio = %.5f\tdegreesCelcius = %.2f\n", vcc, tempReading, volts, calibrationRatio, degreesCelcius);
			// Turn LEDs ON/OFF to visually represent degreesCelcius.
			if (degreesCelcius < 15) {
				PORTD = 0x00;
			} else if (degreesCelcius < 25) {
				PORTD = (_BV(PORTD3) | _BV(PORTD2));
			} else {
				PORTD = (_BV(PORTD4) | _BV(PORTD3) | _BV(PORTD2));
			}
		}
    }
}

Here's some sample output:

 

Enter -c for calibration mode. Enter anything else to continue.
Calibration mode!
To calibrate temperature sensor TMP36GZ, enter float equivalent to correct temperature divided by this device's measured temperature.
        Enter -q to quit calibration mode.
        Enter -r to output memory contents.
        Enter -e to erase memory contents.
        Enter a float to write data.
Memory contents: 0.82630
Exited calibration mode!
Vcc = 5.00      tempReading = 156       volts = 0.76    calibrationRatio = 0.82630      degreesCelcius = 21.70
Vcc = 4.96      tempReading = 163       volts = 0.79    calibrationRatio = 0.82630      degreesCelcius = 23.95
Vcc = 4.96      tempReading = 163       volts = 0.79    calibrationRatio = 0.82630      degreesCelcius = 23.95
Vcc = 4.96      tempReading = 163       volts = 0.79    calibrationRatio = 0.82630      degreesCelcius = 23.95
Vcc = 4.96      tempReading = 163       volts = 0.79    calibrationRatio = 0.82630      degreesCelcius = 23.95
Vcc = 4.96      tempReading = 163       volts = 0.79    calibrationRatio = 0.82630      degreesCelcius = 23.95
Vcc = 4.96      tempReading = 163       volts = 0.79    calibrationRatio = 0.82630      degreesCelcius = 23.95
Vcc = 4.96      tempReading = 163       volts = 0.79    calibrationRatio = 0.82630      degreesCelcius = 23.95
Vcc = 4.96      tempReading = 163       volts = 0.79    calibrationRatio = 0.82630      degreesCelcius = 23.95
Vcc = 4.96      tempReading = 163       volts = 0.79    calibrationRatio = 0.82630      degreesCelcius = 23.95
Vcc = 4.96      tempReading = 163       volts = 0.79    calibrationRatio = 0.82630      degreesCelcius = 23.95
Vcc = 4.96      tempReading = 163       volts = 0.79    calibrationRatio = 0.82630      degreesCelcius = 23.95
Vcc = 4.96      tempReading = 163       volts = 0.79    calibrationRatio = 0.82630      degreesCelcius = 23.95
Vcc = 4.96      tempReading = 163       volts = 0.79    calibrationRatio = 0.82630      degreesCelcius = 23.95
Vcc = 4.96      tempReading = 163       volts = 0.79    calibrationRatio = 0.82630      degreesCelcius = 23.95
Vcc = 4.96      tempReading = 163       volts = 0.79    calibrationRatio = 0.82630      degreesCelcius = 23.95
Vcc = 4.98      tempReading = 163       volts = 0.79    calibrationRatio = 0.82630      degreesCelcius = 24.24
Vcc = 4.98      tempReading = 163       volts = 0.79    calibrationRatio = 0.82630      degreesCelcius = 24.24
Vcc = 4.96      tempReading = 163       volts = 0.79    calibrationRatio = 0.82630      degreesCelcius = 23.95
Vcc = 4.96      tempReading = 163       volts = 0.79    calibrationRatio = 0.82630      degreesCelcius = 23.95
Vcc = 4.96      tempReading = 163       volts = 0.79    calibrationRatio = 0.82630      degreesCelcius = 23.95
Vcc = 4.96      tempReading = 163       volts = 0.79    calibrationRatio = 0.82630      degreesCelcius = 23.95
Vcc = 4.96      tempReading = 163       volts = 0.79    calibrationRatio = 0.82630      degreesCelcius = 23.95
Vcc = 4.96      tempReading = 163       volts = 0.79    calibrationRatio = 0.82630      degreesCelcius = 23.95

 

Thanks to everyone who's helped!

 

EDIT: Looks like it drifts off over time, temperatures steadily increase even though the room is the same temp. I assume this is because of the hardware. I'm going to be waiting for a while before I reieve the 100nF capacitors in the mail, maybe switching to those instead of the 100uF capacitors would fix the upwards drift.

Thomas Brannan | thomascbrannan@gmail.com

Last Edited: Sat. Aug 5, 2017 - 04:44 AM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

TankEngine wrote:
// Clear the OCF1A flag in TIFR by setting it (this is an unusual bx common to interrupt flags in the AVR)

Err no. Many other micros before the AVR and many after it did it similar. How else does one atomically clear a bit?

 

 

What happens if the tmp36 is disconnected or otherwise fails? You could add some code to detect this quite easily. Instead of getting stupid temperature readings, you'd get a nice message telling you the tmp36 has failed.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Kartman wrote:

TankEngine wrote:
// Clear the OCF1A flag in TIFR by setting it (this is an unusual bx common to interrupt flags in the AVR)

Err no. Many other micros before the AVR and many after it did it similar. How else does one atomically clear a bit?

 

I see. Thought I remembered reading that this was particular to the AVR, guess not though.

 

Kartman wrote:
What happens if the tmp36 is disconnected or otherwise fails? You could add some code to detect this quite easily. Instead of getting stupid temperature readings, you'd get a nice message telling you the tmp36 has failed.

 

Ok, that's a cool idea. I could do that.

 

EDIT: I got the other capacitor values in the mail surprisingly early. I've tried the 100nF caps and it doesn't seem to be as accurate with those on. I've got my multimeter now too, I can post measurements if those are of interest.

 

EDIT 2: Seems most accurate with a 100nF capacitor between the sensor and ground plus a 100uF cap between power and ground. But it still slowly climbs.

 

EDIT 3: Sorry if so many edits is annoying! I noticed that the readings are a lot cooler when I block the light from the LEDs from getting to the TMP36. I've commented out the code that turns the LEDs on and now my readings have stopped climbing! So that solves that little mystery.

Thomas Brannan | thomascbrannan@gmail.com

Last Edited: Sun. Aug 6, 2017 - 03:46 AM

Pages