diff main.c @ 312:ef64a178092f

- Some basic ADC code - Turn on -mcall-prologues - Put strings in program space, saves RAM
author Matt Johnston <matt@ucc.asn.au>
date Mon, 14 May 2012 00:22:57 +0800
parents fc96a51bdce6
children 52cb08a01171
line wrap: on
line diff
--- a/main.c	Fri May 11 22:12:11 2012 +0800
+++ b/main.c	Mon May 14 00:22:57 2012 +0800
@@ -9,6 +9,7 @@
 #include <avr/io.h>
 #include <avr/interrupt.h>
 #include <avr/sleep.h>
+#include <avr/pgmspace.h>
 #include <util/crc16.h>
 
 #include "integer.h"
@@ -28,12 +29,16 @@
 #define BAUD 9600
 #define UBRR ((F_CPU)/16/(BAUD)-1)
 
+#define NUM_MEASUREMENTS 300
+
 static int uart_putchar(char c, FILE *stream);
 static FILE mystdout = FDEV_SETUP_STREAM(uart_putchar, NULL,
         _FDEV_SETUP_WRITE);
 
 static uint8_t n_measurements;
-static uint8_t measurements[500];
+// stored as 1/5 degree above 0
+static uint8_t measurements[NUM_MEASUREMENTS];
+static uint8_t internal_measurements[NUM_MEASUREMENTS];
 
 // boolean flags
 static uint8_t need_measurement;
@@ -49,14 +54,27 @@
 static void deep_sleep();
 
 static void 
-uart_init(unsigned int ubrr)
+uart_on(unsigned int ubrr)
 {
     // baud rate
     UBRR0H = (unsigned char)(ubrr >> 8);
     UBRR0L = (unsigned char)ubrr;
-    UCSR0B = (1<<RXEN0)|(1<<TXEN0);
+    UCSR0B = _BV(RXCIE0) | _BV(RXEN0) | _BV(TXEN0);
     //8N1
-    UCSR0C = (1<<UMSEL00)|(3<<UCSZ00);
+    UCSR0C = _BV(UMSEL00) | _BV(UCSZ00);
+
+    // Power reduction register
+    PRR &= ~_BV(PRUSART0);
+}
+
+static void 
+uart_off()
+{
+    // Turn of interrupts and disable tx/rx
+    UCSR0B = 0;
+
+    // Power reduction register
+    PRR |= _BV(PRUSART0);
 }
 
 static int 
@@ -73,13 +91,13 @@
 {
     uint16_t crc = 0;
     int i;
-    printf("%d measurements\n", n_measurements);
+    printf_P(PSTR("%d measurements\n"), n_measurements);
     for (i = 0; i < n_measurements; i++)
     {
-        printf("%3d : %d\n", i, measurements[i]);
+        printf_P(PSTR("%3d : %d\n"), i, measurements[i]);
         crc = _crc_ccitt_update(crc, measurements[i]);
     }
-    printf("CRC : %d\n", crc);
+    printf_P(PSTR("CRC : %d\n"), crc);
 }
 
 static void
@@ -96,21 +114,21 @@
 static void
 read_handler()
 {
-    if (strcmp(readbuf, "fetch") == 0)
+    if (strcmp_P(readbuf, PSTR("fetch")) == 0)
     {
         cmd_fetch();
     }
-    else if (strcmp(readbuf, "clear") == 0)
+    else if (strcmp_P(readbuf, PSTR("clear")) == 0)
     {
         cmd_clear();
     }
-    else if (strcmp(readbuf, "btoff") == 0)
+    else if (strcmp_P(readbuf, PSTR("btoff")) == 0)
     {
         cmd_btoff();
     }
     else
     {
-        printf("Bad command\n");
+        printf_P(PSTR("Bad command\n"));
     }
 }
 
@@ -174,10 +192,65 @@
     sleep_mode();
 }
 
+static void 
+do_adc_335()
+{
+    PRR &= ~_BV(PRADC);
+
+    ADMUX = _BV(ADLAR);
+
+    // ADPS2 = /16 prescaler, 62khz at 1mhz clock
+    ADCSRA = _BV(ADEN) | _BV(ADPS2);
+    
+    // measure value
+    ADCSRA |= _BV(ADSC);
+    loop_until_bit_is_clear(ADCSRA, ADSC);
+    uint8_t low = ADCL;
+    uint8_t high = ADCH;
+    uint16_t f_measure = low + (high << 8);
+
+    // set to measure 1.1 reference
+    ADMUX = _BV(ADLAR) | _BV(MUX3) | _BV(MUX2) | _BV(MUX1);
+    ADCSRA |= _BV(ADSC);
+    loop_until_bit_is_clear(ADCSRA, ADSC);
+    uint8_t low_11 = ADCL;
+    uint8_t high_11 = ADCH;
+    uint16_t f_11 = low_11 + (high_11 << 8);
+
+    float res_volts = 1.1 * f_measure / f_11;
+
+    // 10mV/degree
+    // scale to 1/5 degree units above 0C
+    int temp = (res_volts - 2.73) * 500;
+    measurements[n_measurements] = temp;
+    // XXX something if it hits the limit
+
+    // measure AVR internal temperature against 1.1 ref.
+    ADMUX = _BV(ADLAR) | _BV(MUX3) | _BV(REFS1) | _BV(REFS0);
+    ADCSRA |= _BV(ADSC);
+    loop_until_bit_is_clear(ADCSRA, ADSC);
+    uint16_t res_internal = ADCL;
+    res_internal |= ADCH << 8;
+
+    float internal_volts = res_internal * (1.1 / 1024.0);
+
+    // 1mV/degree
+    int internal_temp = (internal_volts - 2.73) * 5000;
+    internal_measurements[n_measurements] = internal_temp;
+
+    printf_P("measure %d: external %d, internal %d, 1.1 %d\n",
+            n_measurements, temp, internal_temp, f_11);
+
+    n_measurements++;
+    PRR |= _BV(PRADC);
+}
+
 static void
 do_measurement()
 {
     need_measurement = 0;
+
+    do_adc_335();
 }
 
 static void
@@ -186,7 +259,7 @@
 	need_comms = 0;
 
 	// turn on bluetooth
-	// turn on serial (interrupts)
+    uart_on(UBRR);
 	
 	// write sd card here? same 3.3v regulator...
 	
@@ -197,18 +270,29 @@
 		{
 			break;
 		}
+
+        if (need_measurement)
+        {
+            do_measurement();
+        }
+
 		idle_sleep();
 	}
 
+    uart_off();
+
 	// turn off bluetooth
-	// turn off serial (interrupts)
 }
 
 int main(void)
 {
-    uart_init(UBRR);
+    stdout = &mystdout;
+    uart_on(UBRR);
+    fprintf_P(&mystdout, PSTR("hello %d\n"), 12);
+    uart_off();
 
-    fprintf(&mystdout, "hello %d\n", 12);
+    // turn off everything except timer2
+    PRR = _BV(PRTWI) | _BV(PRTIM0) | _BV(PRTIM1) | _BV(PRSPI) | _BV(PRUSART0) | _BV(PRADC);
 
     // set up counter2. 
     // COM21 COM20 Set OC2 on Compare Match (p116)
@@ -219,6 +303,12 @@
     // set async mode
     ASSR |= _BV(AS2);
 
+#ifdef TEST_MODE
+    for (;;)
+    {
+        do_comms()
+    }
+#else
     for(;;){
         /* insert your main loop code here */
         if (need_measurement)
@@ -235,5 +325,6 @@
 
 		deep_sleep();
     }
+#endif
     return 0;   /* never reached */
 }