Rather than manually putting all of the periodic-table data into a program in just the right form (which would be quite tedious), you could use a program on your software development computer to read periodic-table data files and create the corresponding C-program data structures.
The python program shown below gives an example of that approach. (It contains a data table in a list of tuples, ie doesn't read data; but data like that in the tuples can be read from a file, or with a bit of programming, from a spreadsheet of periodic-table data.)
The python program opens file datatables.data.c
for output, then it writes C statements into that file, which subsequently can be added into a sketch, datatables.ino
, as shown later.
Python program, densconmelt.py
:
#!/usr/bin/python
# From data as shown in slide 19 of 39 at
# http://www.slideshare.net/bravetiger1964/lecture-11-metals-and-its-alloys-their-crystalline-structure-and-properties
# Physical Properties of several Metals and Alloys.
# Metal or Alloy
# Density (kg/m3)
# Thermal conductivity W/(m*K) (t=20 C)
# Melting point (Tm) (C)
adtm = [
('Aluminum', '2712', '204', '659'),
('Aluminum alloys', '7700-8700', '120-180', '462-671'),
('Brass-casting', '8400-8700', '', '990-1025'),
('Red Brass', '8746', '159', '1027'),
('Yellow Brass', '8470', '115', '930'),
('Bronze - lead', '7700-8700', '', '850-1000'),
('Copper', '8930', '385', '1083'),
('Gold', '19320', '318', '1063'),
('Pure iron', '6800-7800', '72', '1530'),
('Cast Iron', '7850', '', 'Gray 1370, Malleable 1360, White 1370'),
('Wrought Iron', '7750', '58', '1450'),
('Lead', '11340', '35.3', '327'),
('Nickel', '8800', '89', '1453'),
('Silver', '10490', '406', '961'),
('Solder 50/50 Pb/Sn', '8885', '', ''),
('Non-alloyed and low-alloy steel', '7850', '53.6', '1480'),
('Stainless Steel', '7480-8000', '12.11-45.0', '1430-1500'),
('Tin', '7280', '63', '232'),
('Zinc', '7135', '115', '419')
]
locs = []
# To track current offset into datatext, and longest single string part
used = longy = 0
with open('datatables.data.c', 'w') as fo:
fo.write('#ifdef ADDTABLE // Disallows separate compile\n')
fo.write('const char datatext[] PROGMEM = \n ')
for i in adtm:
#a, d, t, m = i
#print '{:20} {:12} {:12} {:12}'.format(a, d, t, m)
for x in i:
locs.append(used)
used += len(x)+1
longy = max(longy, len(x)+1)
fo.write('"{}\\0" '.format(x))
fo.write('\n ')
fo.write(';\nconst int offsets[] = {')
for o in locs:
fo.write(' {},'.format(o))
fo.write(' {}{};\n'.format(used, '}'))
fo.write('enum {} LONGSTR={}, ITEMS={}{};\n'.format('{', longy, len(adtm), '}'))
fo.write('char buffy[LONGSTR];\n')
fo.write('#endif\n')
Note, the out-commented lines
#a, d, t, m = i
#print '{:20} {:12} {:12} {:12}'.format(a, d, t, m)
would be an appropriate place to modify the python program so it prints out how the lines will look when displayed on the 4x20 LCD. Rather than repeatedly downloading files to your Uno or Mega just to fix lines that are a little too long, or misaligned, etc., you could make the python program show the display appearance in the same loop where it generates data structures to be included in the Arduino sketch.
Note, if you aren't familiar with the with
construct, see the With Statement section of pythonforbeginners.com's Reading and Writing Files in Python page.
What the Python program generates:
Some lines from the file generated by densconmelt.py
are shown below, interspersed with comments about what those lines do. Later, the whole of the file datatables.data.c
is shown.
#ifdef ADDTABLE // Disallows separate compile
That line is a preprocessor statement to keep datatables.data.c
from being compiled alone. During compilations, the Arduino IDE will copy datatables.ino
and datatables.data.c
into a temporary work directory and will compile each of them. However, the body of datatables.data.c
won't compile correctly alone (outside the sketch), so is guarded from causing compile errors by surrounding it with #ifdef ... #endif
lines.
const char datatext[] PROGMEM =
That line tells the C compiler to store the value of datatext[]
into program memory. It also says the value and content of datatext
are constant, and datatext
is an array of characters.
"Aluminum\0" "2712\0" "204\0" "659\0"
"Aluminum alloys\0" "7700-8700\0" "120-180\0" "462-671\0"
"Brass-casting\0" "8400-8700\0" "\0" "990-1025\0"
...
"Tin\0" "7280\0" "63\0" "232\0"
"Zinc\0" "7135\0" "115\0" "419\0"
;
Those lines each give the name of a metal or alloy, its density, its thermal conductivity, and its melting point. Values are strings instead of numbers, so ranges and missing values can be handled. Note that by rules of C, strings with no operators between them concatenate together. For example, the line "Tin\0" "7280\0" "63\0" "232\0"
is equivalent to the line "Tin\07280\063\0232\0"
. Note, each \0
is a null character at the end of a substring. If space were short, one could leave out all the \0
s and compute string lengths as differences of adjacent entries in offsets[]
.
const int offsets[] = { 0, 9, 14, ... 524, 528, 533, 538, 542, 546};
That line tells where each substring begins, within the big string datatext
. This method of storing offsets and substrings takes 12 bytes per item, ie 4·2 bytes for 4 int
values plus 4 bytes for null characters. There are half a dozen ways to reduce the overhead to 5 to 10 bytes per item, but the most effective simple change would be to put offsets[]
in PROGMEM. In addition, one might change some fields from strings to integers or floats, which would not need null separators or offset values if placed at fixed offsets at the front of an item's record.
enum { LONGSTR=38, ITEMS=19};
char buffy[LONGSTR];
#endif
Those lines create two constants, LONGSTR and ITEMS, telling the length of the longest substring and the number of items; allocate a buffer, as long as the longest substring; and close the guarding #ifdef ... #endif
.
datatables.data.c
, shown whole:
#ifdef ADDTABLE // Disallows separate compile
const char datatext[] PROGMEM =
"Aluminum\0" "2712\0" "204\0" "659\0"
"Aluminum alloys\0" "7700-8700\0" "120-180\0" "462-671\0"
"Brass-casting\0" "8400-8700\0" "\0" "990-1025\0"
"Red Brass\0" "8746\0" "159\0" "1027\0"
"Yellow Brass\0" "8470\0" "115\0" "930\0"
"Bronze - lead\0" "7700-8700\0" "\0" "850-1000\0"
"Copper\0" "8930\0" "385\0" "1083\0"
"Gold\0" "19320\0" "318\0" "1063\0"
"Pure iron\0" "6800-7800\0" "72\0" "1530\0"
"Cast Iron\0" "7850\0" "\0" "Gray 1370, Malleable 1360, White 1370\0"
"Wrought Iron\0" "7750\0" "58\0" "1450\0"
"Lead\0" "11340\0" "35.3\0" "327\0"
"Nickel\0" "8800\0" "89\0" "1453\0"
"Silver\0" "10490\0" "406\0" "961\0"
"Solder 50/50 Pb/Sn\0" "8885\0" "\0" "\0"
"Non-alloyed and low-alloy steel\0" "7850\0" "53.6\0" "1480\0"
"Stainless Steel\0" "7480-8000\0" "12.11-45.0\0" "1430-1500\0"
"Tin\0" "7280\0" "63\0" "232\0"
"Zinc\0" "7135\0" "115\0" "419\0"
;
const int offsets[] = { 0, 9, 14, 18, 22, 38, 48, 56, 64, 78, 88, 89, 98, 108, 113, 117, 122, 135, 140, 144, 148, 162, 172, 173, 182, 189, 194, 198, 203, 208, 214, 218, 223, 233, 243, 246, 251, 261, 266, 267, 305, 318, 323, 326, 331, 336, 342, 347, 351, 358, 363, 366, 371, 378, 384, 388, 392, 411, 416, 417, 418, 450, 455, 460, 465, 481, 491, 502, 512, 516, 521, 524, 528, 533, 538, 542, 546};
enum { LONGSTR=38, ITEMS=19};
char buffy[LONGSTR];
#endif
Sketch to get item data from program memory and display it:
We've used densconmelt.py
to generate datatables.data.c
as above, and now will show a sketch that gets an item's data out of program memory and displays it, whenever the sketch receives an item number via Serial input.
// Sketch that accepts a number via serial input, and responds with
// two lines of data via serial output. The reply-data consists of an
// Alloy name on the first line, and Density, Thermal conductivity,
// and Melting point on the next line.
// See http://arduiniana.org/libraries/streaming/ for Streaming library
#include <Streaming.h>
// This sets up datatext in PROGMEM; offsets[]; buffy; LONGSTR; ITEMS
#define ADDTABLE
#include "./datatables.data.c"
void setup() {
Serial.begin(115200); // init serial port
}
void loop() {
Serial << "Please enter item number from 1 to " << _DEC(ITEMS) << ": ";
int item = 0;
while (1) {
while (!Serial.available()) {}; // Wait for a character
int c = Serial.read();
if (c == '\n') break;
item = 10*item + c - '0';
}
if (item < 1 || item > ITEMS) {
Serial << item << endl << item << " is out of range -- try again.\n";
return;
}
// Display specified item's title on first line
strcpy_P(buffy, datatext + offsets[item*4-4]);
Serial << item << endl << "Item #" << item << ", " << buffy << endl;
// Show other data items on next line
strcpy_P(buffy, datatext + offsets[item*4-3]);
Serial << "Density " << buffy;
strcpy_P(buffy, datatext + offsets[item*4-2]);
Serial << " Thermal cond. " << buffy;
strcpy_P(buffy, datatext + offsets[item*4-1]);
Serial << " Melt@ " << buffy << " C" << endl << endl;
}
Note, for a description of strcpy_P()
arguments, see nongnu.org's avr/pgmspace.h : Program Space Utilities page.
See arduino.cc's PROGMEM page for a cursory overview of PROGMEM.
See avrfreaks.net's GCC and the PROGMEM Attribute page for detailed coverage of PROGMEM, and see Nick Gammon's Putting constant data into program memory (PROGMEM) page as well.
Example of program output, as in Serial Monitor box:
Following is an example of program output as shown in the Serial Monitor box after I typed several numbers into the input line and pressed enter after each. (Note, at the bottom of the Serial Monitor box, set Line Ending to Newline
and data rate to 115200 bps.)
Please enter item number from 1 to 19: 18
Item #18, Tin
Density 7280 Thermal cond. 63 Melt@ 232 C
Please enter item number from 1 to 19: 19
Item #19, Zinc
Density 7135 Thermal cond. 115 Melt@ 419 C
Please enter item number from 1 to 19: 20
20 is out of range -- try again.
Please enter item number from 1 to 19: -2220
-2220 is out of range -- try again.
Please enter item number from 1 to 19: 2
Item #2, Aluminum alloys
Density 7700-8700 Thermal cond. 120-180 Melt@ 462-671 C
Please enter item number from 1 to 19: 0
0 is out of range -- try again.
Please enter item number from 1 to 19: 5
Item #5, Yellow Brass
Density 8470 Thermal cond. 115 Melt@ 930 C
Please enter item number from 1 to 19:
The sketch echoes the user-input item number twice, so it appears at the end of each input solicitation as well as in line labels like “Item #5, Yellow Brass”.
switch-case
instead ofif
sswitch-case
.