Instantly share code, notes, and snippets.

Embed
What would you like to do?
diff --git a/t400/buttons.h b/t400/buttons.h
index 14c4827..744e55f 100644
--- a/t400/buttons.h
+++ b/t400/buttons.h
@@ -3,9 +3,8 @@
#include <Arduino.h>
-namespace Buttons {
- // Button names
- enum Button {
+// Button names
+enum Button {
BUTTON_A,
BUTTON_B,
BUTTON_C,
@@ -13,7 +12,9 @@ namespace Buttons {
BUTTON_E,
BUTTON_POWER,
BUTTON_COUNT
- };
+};
+
+namespace Buttons {
void setup();
bool pending();
diff --git a/t400/functions.cpp b/t400/functions.cpp
index c340613..7237ef4 100644
--- a/t400/functions.cpp
+++ b/t400/functions.cpp
@@ -1,4 +1,5 @@
#define __STDC_LIMIT_MACROS
+
#include <stdint.h>
#include <avr/io.h>
@@ -10,21 +11,35 @@
namespace Display {
+#define TEMP_MAX_VALUE_F (3276.0)
+#define TEMP_MAX_VALUE_I (32760)
+#define TEMP_MIN_VALUE_F (-3276.0)
+#define TEMP_MIN_VALUE_I (-32760)
+
+#define LINE_COUNT 4
+
+const uint8_t lines[LINE_COUNT][4] = {
+ { 0, 7, 132, 7}, // hline between temperatures and status bar
+ {31, 0, 31, 7}, // vline between TC1 and TC2
+ {65, 0, 65, 7}, // vline between TC2 and TC3
+ {99, 0, 99, 7}, // vline between TC3 and TC4
+};
+
// Graphical LCD
U8GLIB_PI13264 u8g(LCD_CS, LCD_A0, LCD_RST); // Use HW-SPI
-//// Graph data
-int8_t graph[SENSOR_COUNT][MAXIMUM_GRAPH_POINTS]={}; // Array to hold graph data, in pixels
+// Graph data
+int16_t graph[SENSOR_COUNT][MAXIMUM_GRAPH_POINTS]={}; // Array to hold graph data, in temperature values
+
uint8_t graphCurrentPoint; // Index of latest point added to the graph (0,MAXIMUM_GRAPH_POINTS]
uint8_t graphPoints; // Number of valid points to graph
-double graphMin; // Value of the minimum tick mark, in degrees
uint32_t graphScale; // Number of degrees per pixel in the graph[] array.
-uint8_t axisDigits; // Number of digits to display in the axis labels (ex: '80' -> 2, '1000' -> 4, '-999' -> 4)
+uint8_t axisDigits; // Number of digits to display in the axis labels (ex: '80' -> 2, '1000' -> 4, '-999' -> 4)
-double maxTemp = -99999; // highest temperature ever seen (for setting the scale)
-double minTemp = 99999; // lowest temperature ever seen (for setting the scale)
+float maxTemp = TEMP_MIN_VALUE_F;
+float minTemp = TEMP_MAX_VALUE_F;
// Get a reference to the graph point at the specified
// uint8_t& graphPoint(uint8_t sensor, uint8_t point)
@@ -41,111 +56,124 @@ double minTemp = 99999; // lowest temperature ever seen (for setting the scale
// @param min Minimum temperature value, in temperature
// @return representation of the temperature in graph space
#define temperatureToGraphPoint(temperature, scale, min) (DISPLAY_HEIGHT - 3 - (temperature-min)/scale*10)
-#define graphPointToTemperature(point, scale, min) (((double)(DISPLAY_HEIGHT - 3 - point))*scale/10.0 + min)
//#define rescaleGraphPoint(point, originalScale, originalMin, newScale, newMin) ((point - ))
+// Helper macros to go between int and float
+#define float_to_int(D) ((int16_t)((D)*10))
+#define int_to_float(D) (((float)(D))/10.0)
-void resetGraph() {
+
+void resetGraph()
+{
graphCurrentPoint = 0;
graphPoints = 0;
- graphMin = 25; // TODO: sliding scale?
- graphScale = 1; // in 10ths
-
- maxTemp = 29;
- minTemp = 25;
-}
-
-void updateGraph(double* temperatures) {
-
- // Increment the current graph point (it wraps around)
- if(graphCurrentPoint == 0) {
- graphCurrentPoint = MAXIMUM_GRAPH_POINTS - 1;
- }
- else {
- graphCurrentPoint -= 1;
- }
-
- // Increment the number of stored graph points
- if(graphPoints < MAXIMUM_GRAPH_POINTS) {
- graphPoints++;
+ graphScale = 1;
+
+ // Blank the array
+ for(uint8_t x = 0; x < SENSOR_COUNT; x++)
+ {
+ for(uint8_t y=0; y < MAXIMUM_GRAPH_POINTS; y++)
+ {
+ graph[x][y] = OUT_OF_RANGE_INT;
+ }
}
- // Test if any of the new temperatures are out of range, and adjust the graph appropriately.
+ return;
+}
- for(uint8_t sensor = 0; sensor < SENSOR_COUNT; sensor++) {
- if(temperatures[sensor] == OUT_OF_RANGE) {
- continue;
+// Update the graph using temperatures[NUM_SENSORS]
+void updateGraphData(float* temperatures)
+{
+ int16_t temp_int;
+
+ // Increment the current graph point (it wraps around)
+ if(graphCurrentPoint == 0)
+ {
+ graphCurrentPoint = MAXIMUM_GRAPH_POINTS - 1;
+ }else{
+ graphCurrentPoint -= 1;
}
- if(temperatures[sensor] > maxTemp) {
- maxTemp = temperatures[sensor];
+ // Increment the number of stored graph points
+ if(graphPoints < MAXIMUM_GRAPH_POINTS) {
+ graphPoints++;
}
-
- if(temperatures[sensor] < minTemp) {
- minTemp = temperatures[sensor];
+
+ // Stick the new temperature in the array
+ // This converts the temperature to a int16_t which is in 1/10ths of
+ // a degree
+ for(uint8_t sensor = 0; sensor < SENSOR_COUNT; sensor++)
+ {
+ temp_int = float_to_int(temperatures[sensor]);
+ graph[sensor][(graphCurrentPoint%MAXIMUM_GRAPH_POINTS)] = temp_int;
}
- }
- double graphMinLast = graphMin;
- uint32_t graphScaleLast = graphScale;
+ return;
+}
- // Shift the minimum value based on the lowest reading
- if(minTemp < graphMin) {
- graphMin = minTemp;
+void updateGraphScaling()
+{
+ uint16_t delta;
+ int16_t max=TEMP_MIN_VALUE_I;
+ int16_t min=TEMP_MAX_VALUE_I;
+ int16_t * ptr;
+ int16_t p;
+
+ // Itterate over all the data and get the max & min
+ for(uint8_t x = 0; x < SENSOR_COUNT; x++)
+ {
+ ptr = (int16_t*)&graph[x][0];
+ for(uint8_t y=0; y < MAXIMUM_GRAPH_POINTS; y++)
+ {
+ p = *ptr;
+ if(p!=OUT_OF_RANGE_INT)
+ {
+ if(p>max) max = p;
+ if(p<min) min = p;
+ }
+ ptr++;
+ }
}
- // Expand the graph scale based on the current measurements
- if(maxTemp - graphMin > graphScale * 4) {
- graphScale = (maxTemp - graphMin + 3.999) / 4; // TODO: better rounding strategy
- }
+ if(max==TEMP_MIN_VALUE_I) max=0;
+ if(min==TEMP_MAX_VALUE_I) min=0;
- // TODO: Contract these later
-
- // If we need to scale or shift the graph, modify the existing readings first
- // TODO: Fix me!
- if(graphMinLast != graphMin || graphScaleLast != graphScale) {
- for(uint8_t sensor = 0; sensor < SENSOR_COUNT; sensor++) {
- for(uint8_t point = 0; point < MAXIMUM_GRAPH_POINTS; point++) {
- if(graph[sensor][point] != GRAPH_INVALID) {
- graph[sensor][point] = temperatureToGraphPoint(
- graphPointToTemperature(graph[sensor][point],graphScaleLast,graphMinLast),
- graphScale,
- graphMin);
- }
- }
- }
- }
+ minTemp = int_to_float(min);
+ maxTemp = int_to_float(max);
+ delta = max - min;
+ if(delta<4) maxTemp=minTemp+4.0;
- // Record the current readings in the graph
- for(uint8_t sensor = 0; sensor < SENSOR_COUNT; sensor++) {
- graphPoint(sensor, 0) = (temperatures[sensor] ==
- OUT_OF_RANGE) ? GRAPH_INVALID : temperatureToGraphPoint(temperatures[sensor],graphScale,graphMin);
- }
+ graphScale = (uint32_t)((delta + 39) / 40); // TODO: better rounding strategy
+ if(graphScale<=0) graphScale = 1;
+
+ // graphScale is an int multiplier. Normally we display 4 temperatures.
+ // maxTemp is the highest temp in the dataset
+ // minTemp is the lowest temp in the dataset
// Calculate the number of axes digits to display
- if(graphMin + graphScale*4 > 999 || graphMin < -99) {
+ axisDigits = 2;
+ if((min + (graphScale*4)) > 9999 || min < -999) {
axisDigits = 4;
}
- else if(graphMin + graphScale*4 > 99 || graphMin < -9) {
+ else if((min + (graphScale*4)) > 999 || min < -99) {
axisDigits = 3;
}
- else {
- axisDigits = 2;
- }
+
+ return;
}
-void setup() {
+void setup()
+{
u8g.setContrast(LCD_CONTRAST); // Set contrast level
-
u8g.setRot180(); // Rotate screen
u8g.setColorIndex(1); // Set color mode to binary
u8g.setFont(u8g_font_5x8r); // Select font. See https://code.google.com/p/u8glib/wiki/fontsize
}
+
void draw(
- double* temperatures,
-// double ambient,
+ float* temperatures,
uint8_t graphChannel,
uint8_t temperatureUnit,
char* fileName,
@@ -155,93 +183,107 @@ void draw(
) {
// Graphic commands to redraw the complete screen should be placed here
- static char buf[8];
-
+ char buf[8];
uint8_t page = 0;
- u8g.firstPage(); // Update the screen
+ uint8_t x;
+ uint8_t lastPoint;
+ uint8_t battX = 128;
+ uint8_t battY = 9;
+
+ // Update the screen
+ u8g.firstPage();
do {
- //// Draw temperature graph
- if (page < 6) {
- if(page == 5) {
+
+ // Draw temperature graph
+ switch(page){
+ case 5:
u8g.drawLine( 0, 16, 132, 16); // hline between status bar and graph
- }
+ // no break
+ default:
// Draw the separator line between axes labels and legend
u8g.drawLine(CHARACTER_SPACING*axisDigits + 2, DISPLAY_HEIGHT,
CHARACTER_SPACING*axisDigits + 2, 18);
// Draw axis labels and marks
- for(uint8_t interval = 0; interval < GRAPH_INTERVALS; interval++) {
+ for(uint8_t interval = 0; interval < GRAPH_INTERVALS; interval++)
+ {
u8g.drawPixel(CHARACTER_SPACING*axisDigits + 1, 61 - interval*10);
- u8g.drawStr(0, DISPLAY_HEIGHT - interval*10, dtostrf(graphMin + graphScale*interval,axisDigits,0,buf));
+ u8g.drawStr(0, DISPLAY_HEIGHT - interval*10, dtostrf(minTemp + graphScale*interval,axisDigits,0,buf));
}
-
- // Draw labels on the right side of graph
- // TODO:scale these correctly?
- for(uint8_t sensor=0; sensor<4; sensor++){
- if(temperatures[sensor] == OUT_OF_RANGE || sensor != graphChannel && graphChannel < 4) {
- continue;
- }
- u8g.drawStr(113+5*sensor, 3 + graphPoint(sensor, 0), dtostrf(sensor+1,1,0,buf));
- };
// Calculate how many graph points to display.
- uint8_t lastPoint = graphPoints;
+ lastPoint = graphPoints;
// If the axis indicies are >2 character length, scale back the graph.
- if(lastPoint > MAXIMUM_GRAPH_POINTS - (axisDigits - 2)*5) {
- lastPoint = MAXIMUM_GRAPH_POINTS - (axisDigits - 2)*5;
- }
+ x = MAXIMUM_GRAPH_POINTS - (axisDigits - 2)*5;
+ if(lastPoint > x) lastPoint = x;
// Draw the temperature graph for each sensor
- for(uint8_t sensor = 0; sensor < 4; sensor++) {
+ for(uint8_t sensor = 0; sensor < 4; sensor++)
+ {
+ int8_t p;
+ float p_float;
+ int16_t* starting_point;
+ int16_t* wrap_point;
+
// if the sensor is out of range, don't show it
- if(temperatures[sensor] == OUT_OF_RANGE || sensor != graphChannel && graphChannel < 4) {
+ if(temperatures[sensor] == OUT_OF_RANGE || (sensor != graphChannel && graphChannel < 4) )
continue;
- }
-
- int8_t* starting_point = &graph[sensor][graphCurrentPoint]; // Starting address of the graph data
- int8_t* wrap_point = &graph[sensor][MAXIMUM_GRAPH_POINTS]; // If the address pointer reaches this, reset it to graph[sensor][0]
- for(uint8_t point = 0; point < lastPoint; point++) {
-
- u8g.drawPixel(MAXIMUM_GRAPH_POINTS+12-point,
- *(starting_point++));
-
+ // Get the latest point from the array
+ p_float = ((float)(graphPoint(sensor, 0)))/10.0;
+ p = temperatureToGraphPoint(p_float,graphScale,minTemp);
+ // Draw a string the the latest point
+ u8g.drawStr(113+5*sensor, 3 + p, dtostrf(sensor+1,1,0,buf));
+
+ // Now, draw all the points
+ starting_point = &graph[sensor][graphCurrentPoint]; // Starting address of the graph data
+ wrap_point = &graph[sensor][MAXIMUM_GRAPH_POINTS]; // If the address pointer reaches this, reset it to graph[sensor][0]
+ for(uint8_t point = 0; point < lastPoint; point++)
+ {
+ p_float = ((float)(*(starting_point++)))/10.0;
+ p = temperatureToGraphPoint(p_float,graphScale,minTemp);
+ u8g.drawPixel(MAXIMUM_GRAPH_POINTS+12-point,p);
if(starting_point == wrap_point) {
starting_point = &graph[sensor][0];
}
- }
- }
- }
+ } // end for point
+
+ }// end for sensor
+
- //// Draw status bar
- else if(page == 6) {
+ break;
+
+ case 6:
+ // Draw status bar
//u8g.drawStr(0, 15, dtostrf(ambient,5,1,buf)); // Ambient temperature
u8g.drawStr(0, 15, "TypK");
-
u8g.drawStr(25, 13, "o");
- if(temperatureUnit == TEMPERATURE_UNITS_C) {
+ switch(temperatureUnit){
+ case TEMPERATURE_UNITS_C:
u8g.drawStr(30, 15, "C");
- }
- else if(temperatureUnit == TEMPERATURE_UNITS_F) {
+ break;
+ case TEMPERATURE_UNITS_F:
u8g.drawStr(30, 15, "F");
- }
- else {
+ break;
+ default:
u8g.drawStr(30, 15, "K");
+ break;
}
- u8g.drawStr(40, 15,fileName); // File name
-
+ if(fileName==NULL)
+ u8g.drawStr(40, 15,"Not logging");
+ else
+ u8g.drawStr(40, 15,fileName);
u8g.drawStr( 100, 15, dtostrf(logInterval,2,0,buf)); // Interval
u8g.drawStr(110, 15, "s");
-
+
// Draw battery
- const uint8_t battX = 128;
- const uint8_t battY = 9;
- if(bStatus == ChargeStatus::DISCHARGING) {
+ switch(bStatus){
+ case ChargeStatus::DISCHARGING:
u8g.drawLine(battX, 14, battX+3, 14);
u8g.drawLine(battX, 14, battX, 10);
u8g.drawLine(battX+3, 14, battX+3, 10);
@@ -251,15 +293,15 @@ void draw(
for(uint8_t i = 0; i < batteryLevel; i++) {
u8g.drawLine(battX, 13-i, battX+3, 13-i);
}
- }
- else if(bStatus == ChargeStatus::NO_BATTERY) {
+ break;
+ case ChargeStatus::NO_BATTERY:
u8g.drawLine(battX, battY, battX, battY+5);
u8g.drawLine(battX, battY, battX+3, battY);
u8g.drawLine(battX, battY+2, battX+2, battY+2);
u8g.drawLine(battX, battY+5, battX+3, battY+5);
- }
- else if(bStatus == ChargeStatus::CHARGING) {
+ break;
+ case ChargeStatus::CHARGING:
u8g.drawLine(battX, 14, battX+3, 14);
u8g.drawLine(battX, 14, battX, 10);
u8g.drawLine(battX+3, 14, battX+3, 10);
@@ -270,31 +312,27 @@ void draw(
for(uint8_t i = 0; i < batteryState; i++) {
u8g.drawLine(battX, 13-i, battX+3, 13-i);
}
- }
- else { // CHARGED
+ break;
+ default:
+ // CHARGED
u8g.drawLine(battX, battY+1, battX, battY+5);
u8g.drawLine(battX+1, battY, battX+1, battY+5);
u8g.drawLine(battX+2, battY, battX+2, battY+5);
u8g.drawLine(battX+3, battY+1, battX+3, battY+5);
+ break;
}
- }
-
- //// Draw thermocouple readings
- else if (page == 7) {
- #define LINE_COUNT 4
- const uint8_t lines[LINE_COUNT][4] = {
- { 0, 7, 132, 7}, // hline between temperatures and status bar
- {31, 0, 31, 7}, // vline between TC1 and TC2
- {65, 0, 65, 7}, // vline between TC2 and TC3
- {99, 0, 99, 7}, // vline between TC3 and TC4
- };
-
- for (uint8_t i = 0; i < LINE_COUNT; i++) {
+ break;
+
+ case 7:
+ // Draw thermocouple readings
+ for (uint8_t i = 0; i < LINE_COUNT; i++)
+ {
const uint8_t* pos = lines[i];
u8g.drawLine(pos[0], pos[1], pos[2], pos[3]);
}
// Display temperature readings
+ #if 1
for(uint8_t sensor = 0; sensor < SENSOR_COUNT; sensor++) {
if(temperatures[sensor] == OUT_OF_RANGE) {
u8g.drawStr(sensor*34, 6, " ----");
@@ -303,24 +341,43 @@ void draw(
u8g.drawStr(sensor*34, 6, dtostrf(temperatures[sensor], 5, 1, buf));
}
}
- }
+ #elif 0
+ // DEBUG: Write variable values to the spaces rather than the current temp
+ u8g.drawStr(0*34, 6, dtostrf(temperatures[0], 5, 1, buf));
+ u8g.drawStr(1*34, 6, dtostrf(temperatures[1], 5, 1, buf));
+ u8g.drawStr(2*34, 6, dtostrf(temperatures[2], 5, 1, buf));
+ u8g.drawStr(3*34, 6, dtostrf(temperatures[3], 5, 1, buf));
+ #else
+ // DEBUG: Write variable values to the spaces rather than the current temp
+ u8g.drawStr(0*34, 6, dtostrf(maxTemp, 5, 1, buf));
+ u8g.drawStr(1*34, 6, dtostrf(minTemp, 5, 1, buf));
+ u8g.drawStr(2*34, 6, dtostrf(graphScale, 5, 1, buf));
+ u8g.drawStr(3*34, 6, " ----");
+ #endif
+ break;
+
+ } // End of select(page)
+ // Go to next page
page++;
- }
+
+ }while( u8g.nextPage() );
- while( u8g.nextPage() );
+ return;
}
void clear() {
// Clear the screen
u8g.firstPage();
- do {
- } while( u8g.nextPage() );
+ while( u8g.nextPage() );
}
-}
+} // End namespace Display
+
-int32_t GetJunctionVoltage(double* jTemp) {
+// TODO: What namespace is this then?
+int32_t GetJunctionVoltage(double* jTemp)
+{
int32_t jVoltage = 0;
uint8_t i = 0;
@@ -336,27 +393,33 @@ int32_t GetJunctionVoltage(double* jTemp) {
return jVoltage;
}
-double GetTypKTemp(int32_t microVolts) {
+float GetTypKTemp(int32_t microVolts)
+{
+ float LookedupValue;
+
// Input the junction temperature compensated voltage such that the junction
// temperature is compensated to 0°C
microVolts += TK_OFFSET; //Add an offset for the adjusted lookup table.
// Check if it's in range
- if(microVolts > TEMP_TYPE_K_MAX_CONVERSION || microVolts < TEMP_TYPE_K_MIN_CONVERSION){
+ if(microVolts > TEMP_TYPE_K_MAX_CONVERSION || microVolts < TEMP_TYPE_K_MIN_CONVERSION)
+ {
return OUT_OF_RANGE;
}
- double LookedupValue;
-
// TODO: Binary search here to decrease lookup time
- for(uint16_t i = 0; i<TEMP_TYPE_K_LENGTH; i++){
+ for(uint16_t i = 0; i<TEMP_TYPE_K_LENGTH; i++)
+ {
uint16_t valueLow = lookupThermocouleData(i);
uint16_t valueHigh = lookupThermocouleData(i + 1);
- if(microVolts >= valueLow && microVolts <= valueHigh){
- LookedupValue = ((double)-270 + (i)*10) + ((10 *(double)(microVolts - valueLow)) / ((double)(valueHigh - valueLow)));
+ if(microVolts >= valueLow && microVolts <= valueHigh)
+ {
+ LookedupValue = ((float)-270 + (i)*10) + ((10 *(float)(microVolts - valueLow)) / ((float)(valueHigh - valueLow)));
break;
}
+
}
+
return LookedupValue;
}
diff --git a/t400/functions.h b/t400/functions.h
index 6ac63a7..489a7cb 100644
--- a/t400/functions.h
+++ b/t400/functions.h
@@ -47,12 +47,13 @@ namespace Backlight {
namespace Display {
void resetGraph();
- void updateGraph(double* temperatures);
+ void updateGraphData(float* temperatures);
+ void updateGraphScaling();
void setup();
void draw(
- double* temperatures,
+ float* temperatures,
// double ambient,
uint8_t graphChannel,
uint8_t temperatureUnit,
@@ -73,7 +74,7 @@ int32_t GetJunctionVoltage(double* jTemp);
// Converts the thermocouple µV reading into some usable °C
// @param microVolt reading from the ADC
// @return Temperature, in ???
-double GetTypKTemp(int32_t microVolts);
+float GetTypKTemp(int32_t microVolts);
#endif
diff --git a/t400/t400.h b/t400/t400.h
index 46ea0ef..33f9db2 100644
--- a/t400/t400.h
+++ b/t400/t400.h
@@ -1,41 +1,42 @@
// Hardware definitions for the t400
-#define __AVR_ATmega32U4__ 1
+#define __AVR_ATmega32U4__ 1
// Feature settings
-#define SD_LOGGING_ENABLED 1 // Enable/disable all SD card functionality. Saves 8,696 bytes
-#define SERIAL_OUTPUT_ENABLED 1 // Enable/disable serial output functionality. Saves 192 bytes
+#define SD_LOGGING_ENABLED 1 // Enable/disable all SD card functionality. Saves 8,696 bytes
+#define SERIAL_OUTPUT_ENABLED 1 // Enable/disable serial output functionality. Saves 192 bytes
// Calibration values
-#define MCP3424_CALIBRATION_MULTIPLY 1.00713
-#define MCP3424_CALIBRATION_ADD 5.826
-#define LCD_CONTRAST 0x018*7 // Sets the LCD contrast
+#define MCP3424_CALIBRATION_MULTIPLY 1.00713
+#define MCP3424_CALIBRATION_ADD 5.826
+#define LCD_CONTRAST 0x018*7 // Sets the LCD contrast
// Debugging
-#define DEBUG_JUNCTION_TEMPERATURE 0
+#define DEBUG_JUNCTION_TEMPERATURE 0
// Compile-time settings. Some of these should be set by the user during operation.
-#define SYNC_INTERVAL 1000 // millis between calls to sync()
-#define SENSOR_COUNT 4 // Number of sensors on the board (fixed)
-#define OUT_OF_RANGE 99999.9 // Double value representing an invalid temp. measurement
-#define GRAPH_INVALID -127 // Invalid graph point
+#define SYNC_INTERVAL 1000 // millis between calls to sync()
+#define SENSOR_COUNT 4 // Number of sensors on the board (fixed)
+#define OUT_OF_RANGE_INT 9999 // Int value representing an invalid temp. measurement
+#define OUT_OF_RANGE 999.9 // Double value representing an invalid temp. measurement
// Graph display settings
#define MAXIMUM_GRAPH_POINTS 100
-#define DISPLAY_HEIGHT 64 // Height of the display
-#define CHARACTER_SPACING 5 // Width of a character+space to next character
+#define DISPLAY_HEIGHT 64 // Height of the display
+#define CHARACTER_SPACING 5 // Width of a character+space to next character
-#define TEMPERATURE_UNITS_C 0
-#define TEMPERATURE_UNITS_F 1
-#define TEMPERATURE_UNITS_K 2
+#define TEMPERATURE_UNITS_C 0
+#define TEMPERATURE_UNITS_F 1
+#define TEMPERATURE_UNITS_K 2
#define TEMPERATURE_UNITS_COUNT 3
-#define GRAPH_CHANNELS_COUNT 5
+
+#define GRAPH_CHANNELS_COUNT 5
/// I2C addresses
-#define MCP3424_ADDR 0x69
+#define MCP3424_ADDR 0x69
// Pin definitions for Electronics version 0.13
-#define pcbVersion ".13" // Electronics version 0.12 milestone.
-#define FIRMWARE_VERSION "0.15"
+#define pcbVersion ".13" // Electronics version 0.12 milestone.
+#define FIRMWARE_VERSION "0.15"
// Pin definitions
#define BUTTON_B_PIN 1 // 0.12-mod 7, 0.13 1
diff --git a/t400/t400.ino b/t400/t400.ino
index 3b19fd2..039a5ea 100644
--- a/t400/t400.ino
+++ b/t400/t400.ino
@@ -24,49 +24,56 @@ Firmware for the Pax Instruments T400 temperature datalogger
// Import libraries
#include "t400.h" // Board definitions
-#include <Wire.h> // i2c
+#include <Wire.h> // I2C
#include <SPI.h>
-#include "PaxInstruments-U8glib.h" // LCD
-#include <MCP3424.h> // ADC
-#include <MCP980X.h> // Ambient/junction temperature sensor
-#include <ds3231.h> // RTC
-
+#include "PaxInstruments-U8glib.h" // LCD
+#include <MCP3424.h> // ADC
+#include <MCP980X.h> // Ambient/junction temperature sensor
+#include <ds3231.h> // RTC
#include "power.h" // Manage board power
#include "buttons.h" // User buttons
#include "typek_constant.h" // Thermocouple calibration table
#include "functions.h" // Misc. functions
#include "sd_log.h" // SD card utilities
+
#define BUFF_MAX 80 // Size of the character buffer
char fileName[] = "LD0001.CSV";
// MCP3424 for thermocouple measurements
-MCP3424 thermocoupleAdc(MCP3424_ADDR, MCP342X_GAIN_X8, MCP342X_16_BIT); // address, gain, resolution
+MCP3424 thermocoupleAdc(MCP3424_ADDR, MCP342X_GAIN_X8, MCP342X_16_BIT); // address, gain, resolution
MCP980X ambientSensor(0); // Ambient temperature sensor
+// Map of ADC inputs to thermocouple channels
+const uint8_t temperatureChannels[SENSOR_COUNT] = {1, 0, 3, 2};
-const uint8_t temperatureChannels[SENSOR_COUNT] = {1, 0, 3, 2}; // Map of ADC inputs to thermocouple channels
-double temperatures[SENSOR_COUNT]; // Current temperature of each thermocouple input
-double ambient = 0; // Ambient temperature
+// Current temperature of each thermocouple input
+float temperatures[SENSOR_COUNT] = {OUT_OF_RANGE,OUT_OF_RANGE,OUT_OF_RANGE,OUT_OF_RANGE};
+
+// Ambient temperature
+double ambient = 0;
boolean backlightEnabled = true;
+// Available log intervals, in seconds
#define LOG_INTERVAL_COUNT 6
-const uint8_t logIntervals[LOG_INTERVAL_COUNT] = {1, 2, 5, 10, 30, 60}; // Available log intervals, in seconds
-uint8_t logInterval = 0; // currently selected log interval
-boolean logging = false; // True if we are currently logging to a file
+const uint8_t logIntervals[LOG_INTERVAL_COUNT] = {1, 2, 5, 10, 30, 60};
+
+uint8_t logInterval = 0; // currently selected log interval
+boolean logging = false; // True if we are currently logging to a file
-bool timeToSample = false; // If true, the display should be redrawn
-uint8_t isrTick = 0; // Number of 1-second tics that have elapsed since the last sample
-uint8_t lastIsrTick = 0; // Last tick that we redrew the screen
-uint32_t logTimeSeconds; // Number of seconds that have elapsed since logging began
-struct ts rtcTime; // Buffer to read RTC time into
+bool timeToSample = false; // If true, the display should be redrawn
+uint8_t isrTick = 0; // Number of 1-second tics that have elapsed since the last sample
+uint8_t lastIsrTick = 0; // Last tick that we redrew the screen
+uint32_t logTimeSeconds; // Number of seconds that have elapsed since logging began
-uint8_t temperatureUnit; // Measurement unit for temperature
+struct ts rtcTime; // Buffer to read RTC time into
+
+uint8_t temperatureUnit; // Measurement unit for temperature
uint8_t graphChannel = 4;
@@ -96,6 +103,8 @@ double convertTemperature(double Celcius) {
// This function runs once. Use it for setting up the program state.
void setup(void) {
+ uint8_t x;
+
Power::setup();
ChargeStatus::setup();
#if SERIAL_OUTPUT_ENABLED
@@ -110,6 +119,10 @@ void setup(void) {
Display::setup();
Display::resetGraph();
+ // Clear the temperature array
+ //for(x=0;x<SENSOR_COUNT;x++)
+ // temperatures[x] = OUT_OF_RANGE;
+
thermocoupleAdc.begin();
ambientSensor.begin();
@@ -153,7 +166,9 @@ static void readTemperatures() {
ambient = ambientSensor.readTempC16(AMBIENT) / 16.0; // Read ambient temperature in C
// ADC read loop: Start a measurement, wait until it is finished, then record it
- for(uint8_t channel = 0; channel < SENSOR_COUNT; channel++) {
+ for(uint8_t channel = 0; channel < SENSOR_COUNT; channel++)
+ {
+
thermocoupleAdc.startMeasurement(temperatureChannels[channel]);
do {
// Delay a while. At 16-bit resolution, the ADC can do a speed of 1/15 = .066seconds/cycle
@@ -161,24 +176,41 @@ static void readTemperatures() {
delay(70);
} while(!thermocoupleAdc.measurementReady());
+
+ // This gets a float value. We do a y = mx+b for calibration
measuredVoltageUv = thermocoupleAdc.getMeasurementUv() * MCP3424_CALIBRATION_MULTIPLY + MCP3424_CALIBRATION_ADD; // Calibration value: MCP3424_OFFSET_CALIBRATION
compensatedVoltage = measuredVoltageUv + GetJunctionVoltage(&ambient);
temperature = GetTypKTemp(compensatedVoltage);
+ #if 0
+ // TODO: Get the real value in a float, then convert it to a fixed point int, that
+ // way we can get rid of floating point math
+ temperature_int = float_to_int(temperature);
+ #endif
if(temperature == OUT_OF_RANGE) {
temperatures[channel] = OUT_OF_RANGE;
}
else {
- // temperatures[channel] = convertTemperature(temperature + ambient);
+ //temperatures[channel] = convertTemperature(temperature + ambient);
temperatures[channel] = convertTemperature(temperature);
}
-// This is some debugging code. Use it to display various values to the LCD.
-#if DEBUG_JUNCTION_TEMPERATURE
+ // DEBUG: Fake some data
+ #if 0
+ temperatures[0] = 22.0;
+ temperatures[1] = OUT_OF_RANGE;
+ temperatures[2] = OUT_OF_RANGE;
+ temperatures[3] = OUT_OF_RANGE;
+ #endif
+
+
+ // This is some debugging code. Use it to display various values to the LCD.
+ #if DEBUG_JUNCTION_TEMPERATURE
if(channel == 2 ){// != OUT_OF_RANGE){
temperatures[channel] = (double)measuredVoltageUv; // Display measured voltage across thermocouple. Everything looks good here.
}
-#endif
+ #endif
+
}
}
@@ -224,25 +256,30 @@ void loop() {
readTemperatures();
-// DS3231_get(&rtcTime);
+ //DS3231_get(&rtcTime);
writeOutputs();
- Display::updateGraph(temperatures);
+ Display::updateGraphData(temperatures);
+ Display::updateGraphScaling();
needsRefresh = true;
}
+ // Check for button presses
if(Buttons::pending()) {
uint8_t button = Buttons::getPending();
- if(button == Buttons::BUTTON_POWER) { // Disable power
+ switch(button){
+ case BUTTON_POWER:
+ // Disable power
if(!logging) {
Display::clear();
Backlight::set(0);
Power::shutdown();
}
- }
- else if(button == Buttons::BUTTON_A) { // Start/stop logging
+ break;
+ case BUTTON_A:
+ // Start/stop logging
#if SD_LOGGING_ENABLED
if(!logging) {
startLogging();
@@ -253,8 +290,9 @@ void loop() {
resetTicks();
needsRefresh = true;
#endif
- }
- else if(button == Buttons::BUTTON_B) { // Cycle log interval
+ break;
+ case BUTTON_B:
+ // Cycle log interval
if(!logging) {
logInterval = (logInterval + 1) % LOG_INTERVAL_COUNT;
resetTicks();
@@ -263,26 +301,33 @@ void loop() {
resetTicks();
needsRefresh = true;
}
- }
- else if(button == Buttons::BUTTON_C) { // Cycle temperature units
+ break;
+ case BUTTON_C:
+ // Cycle temperature units
if(!logging) {
rotateTemperatureUnit();
resetTicks();
needsRefresh = true;
}
- }
- else if(button == Buttons::BUTTON_D) { // Sensor display mode
+ break;
+ case BUTTON_D:
+ // Sensor display mode
graphChannel = (graphChannel + 1) % GRAPH_CHANNELS_COUNT;
while(graphChannel < 4 & temperatures[graphChannel] == OUT_OF_RANGE) {
graphChannel = (graphChannel + 1) % GRAPH_CHANNELS_COUNT;
}
needsRefresh = true;
- }
- else if(button == Buttons::BUTTON_E) { // Toggle backlight
+ break;
+ case BUTTON_E:
+ // Toggle backlight
backlightEnabled = !backlightEnabled;
Backlight::set(backlightEnabled);
- }
- }
+ break;
+
+ default: break;
+ } // end button select
+
+ } // end if button pending
// If we are charging, refresh the display every second to make the charging animation
if(ChargeStatus::get() == ChargeStatus::CHARGING) {
@@ -292,31 +337,22 @@ void loop() {
}
}
- if(needsRefresh) {
- if(logging) {
- Display::draw(
- temperatures,
- // ambient,
- graphChannel,
- temperatureUnit,
- fileName,
- logIntervals[logInterval],
- ChargeStatus::get(),
- ChargeStatus::getBatteryLevel()
- );
- }
- else {
- Display::draw(
- temperatures,
- // ambient,
- graphChannel,
- temperatureUnit,
- "Not logging",
- logIntervals[logInterval],
- ChargeStatus::get(),
- ChargeStatus::getBatteryLevel()
- );
- }
+ // Draw the display
+ if(needsRefresh)
+ {
+ char * ptr = NULL;
+ if(logging) ptr = fileName;
+
+ Display::draw(
+ temperatures,
+ graphChannel,
+ temperatureUnit,
+ ptr,
+ logIntervals[logInterval],
+ ChargeStatus::get(),
+ ChargeStatus::getBatteryLevel()
+ );
+
}
// Sleep if we are on battery power
@@ -324,6 +360,8 @@ void loop() {
if(ChargeStatus::get() == ChargeStatus::DISCHARGING) {
Power::sleep();
}
+
+ return;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment