I made this little project and wanted to share it. The code is mostly from "Half Duplex Software UART on the LaunchPad" by NJC, I just added the ADC parts I needed. The Processing application send first a "X" and the LP answer with the value from one of the axes, then send a "Y" and you get the value from the other axis. After that the soft update the snake position and repeat the process. In order to start the game you have to click on the START button (pretty obvious), you lose if the snake touchs any of the sides, also the length and speed increase as you eat the little boxes.
The codes are far from perfect and can be improved. I'm making a little video (that actually took me almost the same amount of time I spent programming) and I'll upload it in a while.
TI has some sample code for the internal temperature sensor, but it does not explain how to scale the ADC reading to useful units of degrees. Here is a step-by-step explanation of how to do the scaling with integer math for degrees C, K and F. There is also sample code to display the temperature on a Nokia 5110 LCD.
The data sheet (SLAU144) has this formula for converting temperature in degrees Celsius to voltage.
V = 0.00355 * C + 0.986
What we need is a formula for converting voltage to temperature.
Rewrite the data sheet fomula with temperature on the left
0.00355 * C + 0.986 = V
Divide both sides by 0.00355
C + 277.75 = V / 0.00355
Subtract 277.75 from both sides
C = V / 0.00355 - 277.75
Now we have a formula for converting voltage to temperature.
The data sheet has this formula for converting voltage to ADC value, once again the opposite of what we neeed.
For Vref- == 0
A = 1023 * V / Vref
Swap sides
1023 * V / Vref = A
Multiply by Vref
1023 * V = A * Vref
Divide by 1023
V = A * Vref / 1023
For a 1.5V reference
V = A * 1.5 / 1023
Simplify
V = A * 0.0014663
Substitute ADC conversion forumula for voltage in the temperature conversion formula.
C = A * 0.0014663 / 0.00355 - 277.75
Simplify
C = A * 0.413 - 277.75
Now we have a formula to convert ADC reading to temperature.
It uses real numbers, so floating point math is required for good precision.
Floating point is slow and requires more flash, so let's use integer math instead.
Multiply by 65536 (2^16) and then divide by the same.
C = (A * 27069 - 18202393) / 65536
Use a right shift instead of divide. This will become a move of high word to low word.
C = (A * 27069 - 18202393) >> 16
Add 0.5 * 65536 to impove rounding.
C = (A * 27069 - 18202393 + 32768) >> 16
Simplify.
C = (A * 27069 - 18169625) >> 16
So that is how to go from ADC to degrees Celsius.
To convert degrees C to degees K.
K = C + 273.15
Applied to ADC to degrees C conversion formula.
K = (A * 27069 - 18169625) >> 16 - 273.15
Implement with integer math by multiplying by 65536
K = (A * 27069 - 18169625 - 17,901,158) >> 16
Simplify.
K = (A * 27069 - 268467) >> 16
To convert degrees C to degrees F.
F = C * 9 / 5 + 32
Applied to voltage to degrees C conversion forumula
F = (V / 0.00355 - 277.75) * 9 / 5 + 32
Multiply by 9
F = (V / 0.0003944 - 2499.75) / 5 + 32
Divide by 5
F = (V / 0.0019722 - 499.95) + 32
Add 32
F = V / 0.0019722 - 467.95
Substitute ADC to voltage forumula
F = A * 0.0014663 / 0.0019722 - 467.95
Simplifiy
F = A * 0.7435 - 467.95
Convert to integer
F = (A * 48724 - 30667156) >> 16
Improve rounding
F = (A * 48724 - 30667156 + 32768) >> 16
Simplify
F = (A * 48724 - 30634388) >> 16
So now we have three formulas to convert ADC reading to degrees C, K and F using fast and compact integer math.
C = (A * 27069 - 18169625) >> 16
K = (A * 27069 - 268467) >> 16
F = (A * 48724 - 30634388) >> 16
Using the ADC value, rather than a different temperature scale, will ensure greatest precision for each temperature scale.
main.c
#include
#include
#include "lcd.h"
#define ADC_SLEEP // Sleep during ADC conversion
//#define SHOW_ADC // Show ADC raw and ADC millivolts
// Print integer from -999 to 9999 using 12 x 16 font
void print_int(int i, const unsigned y)
{
if(i < -999 || i > 9999) return;
const unsigned neg = i < 0;
if(neg) i = -i;
div_t d; d.quot = i;
unsigned x = 48;
do {
d = div(d.quot, 10);
pd12(d.rem, x -= 12, y);
} while(d.quot);
if(neg) pd12(14, x -= 12, y);
while(x) pd12(10, x -= 12, y);
}
// Print integer from 0 to 9999 vertically using 6 x 8 font
void print_v(int i, unsigned x)
{
unsigned y = 4;
unsigned c;
if(i < 0 || i > 9999) return;
div_t d; d.quot = i;
do {
d = div(d.quot, 10);
c = d.rem + '0';
lcd_print((char *)&c, x, --y);
} while(d.quot);
c = ' ';
while(y) lcd_print((char *)&c, x, --y);
}
void main(void)
{
unsigned adc; // ADC value
int c, k, f; // Temperature in degrees C, K, and F
unsigned mv; // ADC reading in millivolts
//
WDTCTL = WDTPW | WDTHOLD; // Disable watchdog reset
//
lcd_init(); // Initialize LCD
lcd_clear(0); //
pd12(15, 48, 0); // Degrees
pd12(17, 59, 0); // F
pd12(15, 48, 2); // Degrees
pd12(16, 58, 2); // C
pd12(15, 48, 4); // Degrees
pd12(18, 59, 4); // K
#ifdef SHOW_ADC //
lcd_print("Am", 72, 4); // AD / mV
lcd_print("DV", 72, 5); //
#endif //
//
ADC10CTL0 = 0; // Configure ADC
ADC10CTL1 = INCH_10 | ADC10DIV_3; //
ADC10CTL0 = SREF_1 | ADC10SHT_3 | REFON | ADC10ON | ADC10IE;
//ADC10CTL0 = SREF_1 | ADC10SHT_3 | REFON | ADC10ON | ADC10IE | REF2_5V;
#ifdef ADC_SLEEP //
ADC10CTL0 |= ADC10IE; // Enable ADC conversion complete interrupt
#endif //
//
for(; { // for-ever
#ifdef ADC_SLEEP //
ADC10CTL0 |= (ENC | ADC10SC); // Begin ADC conversion
__bis_SR_register(LPM0_bits + GIE); // Sleep until conversion complete
#else //
ADC10CTL0 &= ~ADC10IFG; // Clear conversion complete flag
ADC10CTL0 |= (ENC | ADC10SC); // Begin ADC conversion
while(!(ADC10CTL0 & ADC10IFG)); // Wait for conversion to complete
#endif //
//
adc = ADC10MEM; // Read ADC
//
// Convert to temperature
c = ((27069L * adc) - 18169625L) >> 16; // Vref = 1.5V
//c = ((45115L * adc) - 18169625L) >> 16; // Vref = 2.5V
//
k = ((27069L * adc) - 268467L) >> 16; // Vref = 1.5V
//k = ((45115L * adc) - 268467L) >> 16; // Vref = 2.5V
//
f = ((48724L * adc) - 30634388L) >> 16; // Vref = 1.5V
//f = ((81206L * adc) - 30634388L) >> 16; // Vref = 2.5V
//
// Convert to millivolts
mv = (96094L * adc + 32768) >> 16; // Vref = 1.5V
//mv = (160156L * adc + 32768) >> 16; // Vref = 2.5V
//
// Display on LCD
print_int(f, 0); // Degrees F
print_int(c, 2); // Degrees C
print_int(k, 4); // Degrees K
//
#ifdef SHOW_ADC //
print_v(adc, 72); // ADC
print_v(mv, 78); // ADC millivolts
#endif //
//
//__delay_cycles(100000); //
} //
}
#pragma vector = ADC10_VECTOR // ADC conversion complete interrupt
__interrupt void ADC10_ISR(void) //
{ //
__bic_SR_register_on_exit(LPM0_bits); // Wakeup main code
} //
lcd.h
typedef enum {
lcd_command = 0, // Array of one or more commands
lcd_data = 1, // Array of one or more bytes of data
lcd_data_repeat = 2 // One byte of data repeated
} lcd_cmd_type;
void lcd_send(const unsigned char *cmd, unsigned len, const lcd_cmd_type type);
void lcd_home(void);
void lcd_pos(unsigned char x, unsigned char y);
void lcd_clear(unsigned char x);
void lcd_init(void);
void lcd_print(char *s, unsigned x, unsigned y);
void pd12(unsigned n, unsigned x, unsigned y);