Ik ben van plan om een ​​periodiek systeem met Arduino's hulp te doen, maar ik heb een paar vragen

Ik doe dat voor mijn schoolproject, maar ik heb weinig vragen voordat ik de componenten koop.

Laat me eerst uitleggen hoe het werkt:

Er zal 4x20 LCD zijn, een Arduino en waarschijnlijk twee potentiometers (vanwege de gevoeligheid van de potentiometer). Wanneer de gebruiker de potentiometers draait, voegt het programma de waarde van de eerste potentiometer toe aan de waarde van de andere potentiometer, vanwege gevoeligheidsproblemen. Vervolgens controleert het programma welk element overeenkomt met de waarden van de twee potentiometers.

Daarna toont het programma de informatie van dat element op het LCD-scherm (zoals de naam, symbool, neutronummer, protonnummer, valentie-elektronen, ...).

vragen:

  • Er zijn ongeveer 118 elementen in het periodiek systeem. Ik ben geen expert met programmeren, maar dit betekent dat er 118 if ... else if ... -instructies zijn. Ik kan de binnenkant van de instructie if per functie inkorten, maar er zijn nog steeds 118 if -instructies. Ik ben bang dat het over de limiet van de geheugenlimiet van de Arduino zal gaan. Hoe kan ik de code verkorten?

  • Moet ik een Mega kopen of is een Uno genoeg?

  • Zullen er problemen zijn als ik een 5V Arduino-pin op beide potentiometers en 4x20-achtergrondverlichting aansluit? Zo nee, hoe kan ik dit oplossen? Ik wil geen andere stroombron gebruiken behalve Arduino.

1
U zou ongeveer 100 tot 150 bytes per element op een Uno kunnen opslaan als een PROGMEM-array. Dat is meer dan een volledige pagina van uw LCD. En misschien wilt u een roterende encoder gebruiken in plaats van uw twee potten.
toegevoegd de auteur Sprogz, de bron
@Gerben: voor deze gebruikssituatie lijkt een array veel geschikter dan een lange switch-case .
toegevoegd de auteur Sprogz, de bron
U definieert een struct die alle gegevens van een element bevat, waarna een array van 118 van dergelijke structuren alle gegevens kan bevatten die u nodig hebt. Uw programma bladert vervolgens door de array om de gegevens van het door de gebruiker gekozen element uit te pakken en af ​​te drukken. Ik kan proberen een basisvoorbeeld te maken van hoe je de gegevens zou kunnen ordenen, maar ik heb geen tijd vóór ~ 24h.
toegevoegd de auteur Sprogz, de bron
Zoek naar schakel-zaak in plaats van als s
toegevoegd de auteur Al., de bron
Leer hoe u arrays en PROGMEM kunt gebruiken. Het staat allemaal op de Arduino Playground als je ernaar googt.
toegevoegd de auteur Majenko, de bron
De aanwijzing zit in het woord "PROGMEM" ...
toegevoegd de auteur Majenko, de bron
@ EdgarBonet 10 draai 10kohm pot zou het naar mijn mening ook moeten doen. Kun je me een hint geven over waar ik arrays moet gebruiken? en slaat het progmem de gegevens van de array op in normaal geheugen (32kb) in plaats van ram?
toegevoegd de auteur iThek, de bron

4 antwoord

Een antwoord uit mijn commentaar op je vraag uitbreiden:

Het eerste is om een ​​struct te definiëren die alle gegevens bevat die je wilt opslaan en weergeven voor één element:

struct Element {
    char symbol[3];
    char name[16];
    float mass;
    char electronic_state[9];
   //etc...
};

Bewaar het atoomnummer niet, want dit wordt afgeleid van de index de array die je gaat bouwen. Elke tekenreeks in deze struct (symbool, naam ...) moet groot genoeg zijn om de langst mogelijke reeks op te slaan, inclusief de laatste NULL-terminator. De compiler helpt je hier: als je dat niet doet voldoende ruimte toewijzen, zal het later iets zeggen als " fout: initializer-string voor array van tekens is te lang ".

Het is natuurlijk enigszins inefficiënt om elke reeks het maximum toe te wijzen mogelijke lengte. Ik stel voor dat je dit doet omwille van de eenvoud, en omdat ik niet denk dat je een korte flits moet hebben, zelfs op een Uno. Als je hebt echt een tekort aan flash, dan raad ik je serieus aan Overweeg jwpat7's antwoord. Het is enigszins ingewikkeld, maar waarschijnlijk ook aanzienlijk efficiënter dan de mijne in termen van flitsgebruik.

Tweede stap is het periodiek systeem op te schrijven als een PROGMEM-array:

const Element periodic_table[] PROGMEM = {
   //symbol  name    mass      electronic state
    {"H",  "Hydrogen", 1.008,    "1s1"     },
    {"He", "Helium",   4.002602, "1s2"     },
    {"Li", "Lithium",  6.94,     "[He] 2s1"},
   //etc...
};
const size_t table_length = sizeof periodic_table/sizeof *periodic_table;

Uw programma hoeft dan alleen in volgorde door deze tabel te bladeren om de benodigde informatie te krijgen. Het enige lastige deel hier is dat jij zal de gegevens naar RAM moeten kopiëren voor gebruik, bijvoorbeeld met zoiets als:

Element elt; //element in RAM
memcpy_P(&elt, &periodic_table[i], sizeof elt);

Ik heb geen LCD-scherm, dus ik heb een testprogramma geschreven dat het tabel via de seriële poort:

void setup()
{
    Serial.begin(9600);
}

void loop()
{
    Serial.println(F("Z  Symbol  Name  Atomic mass  El. state"));
    Serial.println(F("---------------------------------------"));
    for (size_t i = 0; i < table_length; i++) {
        Element elt; //element in RAM
        memcpy_P(&elt, &periodic_table[i], sizeof elt);
        Serial.print(i+1); //Z = i+1
        Serial.print(F("    "));
        Serial.print(elt.symbol);
        Serial.print(F("     "));
        Serial.print(elt.name);
        Serial.print(F("  "));
        Serial.print(elt.mass);
        Serial.print(F("  "));
        Serial.println(elt.electronic_state);
    }
    Serial.println();
    delay(1000);
}

Dit programma neemt slechts 4480 bytes aan flitser. Dit betekent dat ik zou kunnen uitbreiden de tabel tot 118 elementen en meer dan 200 bytes aan gegevens per element eerder bijna geen flits meer op een Uno.

2
toegevoegd

In plaats van alle periodieke tabelgegevens handmatig in een programma in de juiste vorm te plaatsen (wat nogal vervelend zou zijn), zou u een programma op uw softwareontwikkelingscomputer kunnen gebruiken om periodiek-tabelgegevensbestanden te lezen en de bijbehorende C- te maken. programmagegevensstructuren.

Het hieronder getoonde pythonprogramma geeft een voorbeeld van die aanpak. (Het bevat een gegevenstabel in een lijst met tupels, dwz leest geen gegevens, maar gegevens zoals die in de tuples kunnen worden gelezen uit een bestand, of met een beetje programmeren, vanuit een < a href = "http://www.meta-synthesis.com/webbook/35_pt/pt_database.php?PT_id=194" rel = "nofollow"> spreadsheet van periodiek-tabelgegevens .)

Het python-programma opent bestand datatables.data.c voor uitvoer, dan schrijft het C-instructies in dat bestand, die vervolgens kunnen worden toegevoegd aan een schets, datatables.ino , als later getoond.

Python-programma, 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')

Let op de lijnen met de opmerkingen die niet zijn opgenomen

        #a, d, t, m = i
        #print '{:20} {:12} {:12} {:12}'.format(a, d, t, m)

zou een geschikte plaats zijn om het python-programma aan te passen, zodat het uitprint hoe de lijnen eruit zien op het 4x20 LCD-scherm. In plaats van het herhaaldelijk downloaden van bestanden naar uw Uno of Mega om alleen lijnen te corrigeren die een beetje te lang zijn, of niet goed zijn uitgelijnd, enz., Kunt u het Python-programma het uiterlijk van het display laten weergeven in dezelfde lus waarin het gegevensstructuren genereert die moeten worden opgenomen in de Arduino-schets.

Opmerking: als u niet bekend bent met het construct with , raadpleegt u het gedeelte Met verklaring van pythonforbeginners.com Lezen en schrijven van bestanden op Python pagina.

Wat het Python-programma genereert:

Sommige regels uit het bestand gegenereerd door densconmelt.py worden hieronder weergegeven, afgewisseld met opmerkingen over wat die regels doen. Later wordt het hele bestand datatables.data.c weergegeven.

#ifdef ADDTABLE //Disallows separate compile

Die regel is een preprocessor-instructie om te voorkomen dat datatables.data.c alleen wordt gecompileerd. Tijdens compilaties kopieert de Arduino IDE datatables.ino en datatables.data.c naar een tijdelijke werkdirectory en compileert ze allemaal. De body van datatables.data.c zal echter niet alleen correct compileren (buiten de schets), dus wordt bewaakt voor het veroorzaken van compileerfouten door het te omringen met # ifdef ... #endif regels.

const char datatext[] PROGMEM =

Die regel vertelt de C-compiler om de waarde van datatext [] op te slaan in het programmageheugen. Het zegt ook dat de waarde en inhoud van datatext constant zijn, en datatext een reeks tekens is.

  "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" 
  ;

Die lijnen geven elk de naam van een metaal of een legering, de dichtheid, de thermische geleidbaarheid en het smeltpunt. Waarden zijn tekenreeksen in plaats van getallen, dus bereiken en ontbrekende waarden kunnen worden verwerkt. Merk op dat bij regels van C, strings zonder operatoren daartussen aaneenschakelen. Bijvoorbeeld, de regel "Tin \ 0" "7280 \ 0" "63 \ 0" "232 \ 0" is gelijk aan de regel "Tin \ 07280 \ 063 \ 0232 \ 0 ". Let op, elke \ 0 is een nul karakter aan het einde van een subtekenreeks. Als de ruimte kort was, kon men alle \ 0 s weglaten en stringlengtes berekenen als verschillen van aangrenzende items in offsets [] .

const int offsets[] = { 0, 9, 14, ... 524, 528, 533, 538, 542, 546};

Die regel vertelt waar elke substring begint, in de grote string datatext . Deze methode voor het opslaan van offsets en substrings kost 12 bytes per item, dwz 4 · 2 bytes voor 4 int waarden plus 4 bytes voor null-tekens. Er zijn een vijftal manieren om de overhead te verminderen tot 5 tot 10 bytes per item, maar de meest effectieve eenvoudige wijziging zou zijn om offsets [] in PROGMEM te plaatsen. Bovendien kan een aantal velden van tekenreeksen in gehele getallen of drijvers worden gewijzigd, waarvoor geen nulscheidingstekens of verschuivingswaarden nodig zijn als deze worden geplaatst bij vaste verschuivingen aan de voorzijde van de record van een item.

enum { LONGSTR=38, ITEMS=19};
char buffy[LONGSTR];
#endif

Die lijnen maken twee constanten, LONGSTR en ITEMS, die de lengte van de langste subtekenreeks en het aantal items aangeven; toewijzen van een buffer, zolang de langste subtekenreeks; en sluit de bewaking # 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

Schets om itemgegevens uit het programmageheugen te halen en weer te geven:

We hebben densconmelt.py gebruikt om datatables.data.c te genereren zoals hierboven, en zal nu een schets laten zien die de gegevens van een item uit het programmageheugen haalt en deze toont, wanneer de schets een artikelnummer ontvangt via seriële invoer.

// 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 
// 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 << "   [email protected] " << buffy << " C" << endl << endl;
}

Opmerking: voor een beschrijving van strcpy_P() argumenten, zie nortnu.org's avr/pgmspace.h: Programma Space Utilities pagina.

Zie arduino.cc's PROGMEM -pagina voor een vluchtig overzicht van PROGMEM.

Zie avrfreaks.net's GCC en het PROGMEM-kenmerk pagina voor een gedetailleerde beschrijving van PROGMEM, en zie Nick Gammon's Constante gegevens in programmageheugen plaatsen (PROGMEM) pagina ook.

Voorbeeld van programma-uitvoer, zoals in het vak Seriële Monitor:

Hieronder ziet u een voorbeeld van de uitvoer van het programma zoals weergegeven in het vak Seriële monitor nadat ik verschillende nummers in de invoerregel heb getypt en na elk ingevoerd heb gedrukt. (Opmerking: onder in het vak Seriële monitor stelt u Regeluitgang in op Newline en gegevenssnelheid op 115200 bps.)

Please enter item number from 1 to 19: 18
Item #18, Tin
Density 7280   Thermal cond. 63   [email protected] 232 C

Please enter item number from 1 to 19: 19
Item #19, Zinc
Density 7135   Thermal cond. 115   [email protected] 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   [email protected] 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   [email protected] 930 C

Please enter item number from 1 to 19: 

De schets weergalmt het gebruikersinvoeritemnummer twee keer, dus het verschijnt aan het einde van elke invoeraanvraag en op regellabels zoals "Item # 5, Geel Koper".

1
toegevoegd
@ ÇayÖncesi, de sketch gebruikt Serial alleen ter illustratie - je zou een roterende encoder of een pot voor invoer vervangen, en een LCD voor output. Zelfs als je geen preprocessor van een ontwikkelingssysteem gebruikt (met een codegenerator geschreven in python, C, of ​​welke taal je maar wilt), kun je je Arduino-code organiseren op een manier die lijkt op de illustratie.
toegevoegd de auteur Martin C. Martin, de bron
Dat lijkt ingewikkeld. Ik kreeg het idee, maar ik weet niets over python-syntaxis, uitspraken ... en ik kan geen extern apparaat dragen behalve arduino. alleen de Arduino en elektrische componenten. Maar voor het idee
toegevoegd de auteur iThek, de bron

Je hebt waarschijnlijk geen Mega hiervoor nodig, maar beschouw het als een langetermijninvestering als je wilt blijven rommelen met de Arduino/doorgaan naar grotere projecten.

Helaas zal het typen van alle code behoorlijk vervelend zijn. Maar je kunt aparte arrays maken voor strings van alle elementnamen:

https://stackoverflow.com/questions/1088622/ how-do-i-create-een-rij-of-strings-in-c

En u kunt overeenkomstige arrays maken voor alle numerieke gegevens.

Dan neem je het signaal, doe wat wiskunde om erachter te komen hoe je het signaal kunt gebruiken om een ​​geheel getal van 1-118 te verkrijgen, schrijf dat in een geheel getal (zeg i), en schrijf dan naam [i], symbool [i], neutnum [i], enzovoort, op het LED-scherm.

Het moeilijkste deel zal wiskunde doen, zodat de overgang tussen twee elementen in termen van het draaien van de potentiometer natuurlijk aanvoelt.

Merk op dat als je wiskunde op de een of andere manier 200 genereert, dan zal naam [200] waarschijnlijk willekeurige waarden uit het geheugen naar je LED-scherm schrijven. I denk. Als je LED-scherm onzin laat zien, dan is dat waar je eerst naar moet kijken/debuggen.

1
toegevoegd
thx voor het antwoord, ik zal waarschijnlijk een incrementele encoder kopen. Maar als ik de R.E. niet kan instellen. ik ga met potten. Arrays kwam ik eerder niet te binnen, maar nu begrijp ik dat arrays beter zullen werken. Ik zal mega kopen, ik vond een goedkope (Non-Clone). Thx opnieuw
toegevoegd de auteur iThek, de bron

ik denk dat je misschien een mega moet kopen (waarschijnlijk duurder!)

i also fear someone putting countless nights into coding (preferably on pc for me, because 1: sketch is only available as an ancient version on raspberrypi. & 2: easier transfer of code.)

0
toegevoegd
Kun je alsjeblieft uitleggen waarom Mega een betere keuze zou zijn?
toegevoegd de auteur user67244, de bron
ik zal mega kopen, voor dit project en voor de toekomst
toegevoegd de auteur iThek, de bron