Arduino schéma - arduino.sk

Prvky pola

Programovanie arduina
Obrázok užívateľa
Príspevky: 43
Registrovaný: Str 25. Feb 2015 22:19:54
Bydlisko: Fintice

Prvky pola

Poslaťod dzooky » Ned 03. Jan 2016 1:41:53

Pani mam problem s prvkami pola.
Cele sa to sprava velmi zvlastne.
Mam zadefinovane 10 prvkove pole

Kód: Vybrať všetko
char *check_numbers1[10]={};


A ked dam vypisat prvky pola napr cez cyklus for

Kód: Vybrať všetko
    for (byte i = 0; i < (sizeof(check_numbers)/2); i++)
      {
        Serial.println(check_numbers[i]);
      }


Tak nieco ine mi vypise ked to dam vypisat v loop a nieco ine ked ten vypis je z nejakej funkcie. WTF?

Takto to vyzera

Kód: Vybrať všetko
Cislo bolo uspesne pridane do zoznamu
0910836055
0910836055
0910836055
0910836055
0910836055
0910836055
0910836055
0910836055
0910836055
0910836055
Ziaden prichadzajuci hovor
0910836055
0910836055
0910836055
0910� 
0910
0910
0910
0910
0910
0910


Cele to pouzivam pre GSM shield a ked zavolam na neho kompletne premaze pole a uz je prazdne.
Co neviem preco urobi lebo nemalo by to na to sahat.

Obrázok užívateľa
Príspevky: 133
Registrovaný: Štv 06. Nov 2014 12:06:09

Re: Prvky pola

Poslaťod budvar10 » Ned 03. Jan 2016 11:34:08

No z toho, čo si poslal, sa dá niečo ťažko usúdiť. Premenná je 10 nedefinovaných pointrov na string. Odkiaľ sa tam zobrali tie čísla?

Len malá poznámka. Myslím, že lepšie by bolo:
Kód: Vybrať všetko
#define CHECK_NUMBER_SIZE  10

char *check_numbers1[CHECK_NUMBER_SIZE]={};

for (byte i = 0; i < CHECK_NUMBER_SIZE; i++)
{
    Serial.println(check_numbers[i]);
}

pretože tvoja verzia funguje správne len za predpokladu, že prvky poľa sú 2 byte veľké.

Príspevky: 174
Registrovaný: Ned 16. Mar 2014 23:22:00

Re: Prvky pola

Poslaťod posjirka » Ned 03. Jan 2016 15:23:07

souhlas s budvar10.
Podle výsledku je pole pouze 10 čísel. Je zbytečné mu tedy dávat typ "char". Typ "byte" by bylo asi rozumnější.
Právě ti pak může haprovat hodnota výsledku "sizeof" a dávat ti rozdílné výsledky.
Je třeba si uvědomit, že i když nám Arduino dává volbu několika typů proměnných jedná se o 8-bitový procesor a tudíž s touto a nižší bitovou hloubkou pracuje nejlépe.
Navíc, když víš jak veliké je pole , tak asi není třeba se na tu velikost pořád do kola ptát. Zbytečně se združuje procesor a narůstá ti velikost programu....

Zkrátka nezjištuj předem známé věci. Vše se ti zjednodušší a zmenší....

Obrázok užívateľa
Príspevky: 43
Registrovaný: Str 25. Feb 2015 22:19:54
Bydlisko: Fintice

Re: Prvky pola

Poslaťod dzooky » Ned 03. Jan 2016 23:31:43

No pre ujasnenie robim novu verziu Otvaranie brany cez GSM
Nova funkcia ma byt ze SMSkou pridam cislo ktore bude vediet otvorit branu.

Premenna check_numbers je char lebo aj kniznice pre GSM shield pouzivaju telefonne cislo ako char a porovnavam ich ci je to povolene cislo na ovladanie.
Taktiez som urcil rozmer toho pola kedze mi bolo povedane rozmer pola je pevny resp nezarucuje arduino potom jeho spravne pouzitie.

Premennu som skusal od zaciatku nechat prazdnu a potom dopisat cislo alebo od zaciatku ju naplnit nejakym vymyslenym a potom jednu hodnotu zmenit ale vzdy to bolo rovnake.

Obrázok užívateľa
Príspevky: 133
Registrovaný: Štv 06. Nov 2014 12:06:09

Re: Prvky pola

Poslaťod budvar10 » Pon 04. Jan 2016 9:31:30

Pozor, hlavne posjirka, ja som netvrdil, že to má byť byte. Prečítajte si to pozorne. Char je v poriadku, len som narážal na toto:
sizeof(check_numbers)/2.
Čo to znamená? Premenná check_numbers1 je jednorozmerné pole 10 smerníkov na znakové reťazce zatiaľ neznáme. Jeho veľkosť je 'veľkosť každého pointra (t.j adresa v RAM)' * 10. Makro sizeof nám vráti 20 ale len za predpokladu, že pracujeme so systémom, ktorý má adresy v RAM veľkosti 2 byte. Napr. Arduino UNO resp. ATmega328P je OK, ale Mega už nemusí byť. Takže ja navrhujem tam proste dať konštantu pomocou #define, aby si to v prípade potreby menil len na jednom mieste. Z hľadiska kompilácie je to jedno, kompilátor nahradí sizeof(check_numbers)/2 ale aj CHECK_NUMBER_SIZE konštantou.

Program nemám čas teraz pozerať, ale ešte ma napadá jedna vec. Niekde musíš mať alokovanie RAM pre tie reťazce tel. čísel, ale ich dĺžka sa asi nebude meniť. Mobil 0910836055 v takejto forme bude vždy 11 znakov (10+1 pre NULL). Preto navrhujem radšej dať pevnú veľkosť poľa, radšej ako alokovať. Dosť ti to ušetrí kód. Avšak, ešte lepšie by bolo použitie EEPROM, aby si to pamätalo tie čísla, čo tam zadáš, aj po výpadku napájania, teda ak nie sú natrvalo. Potom by som to dal do flashky.

Obrázok užívateľa
Príspevky: 43
Registrovaný: Str 25. Feb 2015 22:19:54
Bydlisko: Fintice

Re: Prvky pola

Poslaťod dzooky » Pon 04. Jan 2016 11:28:50

Ahojte.
Pozeram ze som to tam zle dal. Asi som to pozuil z inej casti kodu.
Bolo to tam na to ze pocitalo pocet premenny ale pred tym som tam mal int co je dvojbajtovy kde char je zase jedno bajtovy. Ale o to nejde,, ide mi o to ze v inej casty programu ukazuje inu hodnotu tej istej premenej.
Program vyzera asi takto (obrazne)


void loop
{
funkcia jedna();
funkcia dva();
for {vypis premennej}
}

void funkcia dva()
{
kod funkcie;
for {vypis premennej}
}

a ako som vyssie uviedol
nad eeprom som rozmyslal ale dajak nemam na to velmi cast pri detoch a sviatkoch a taktiez som s eeprom nerobil. zatial arduino len skusam :D

Príspevky: 33
Registrovaný: Pia 26. Jún 2015 21:17:41

Re: Prvky pola

Poslaťod barado » Uto 05. Jan 2016 0:04:39

Ahoj.
Chalani tu su na pre mna dost vysokej urovni programovania a vela som sa tu naucil.
Pre dobru radu by si mal najskor uviest, co chces dosiahnut, aby si dostal viacero moznosti riesenia Tvojho problemu. To si aj neskor urobil.

Kedze chces otvarat branu cez GSM - co je mimochodom genialny napad, spravne si rozhodol, ze viac ako 10 cisiel asi nema vyznam. A to je tiez celkom dost, teda ako to nie je niekde vo firme.
Dalej by bolo mozno vhodne v SMS aj presne urcit, do ktoreho pola sa ma dane cislo zapisat. Na druhu stranu sa to da spravit aj tak, ze budu pole zapisovane od prveho indexu pola a budes zvysovat index pri kazdom novom cisle az po maximalny index pola, potom dalej ignorujes, alebo si das reset indexu a zacinas odznova.
EEPROM sa asi nevyhnes. Nie je dovod po kazdom vypadku napajania znovu predsa plnit pole cisiel novymi SMS-kami.

Posielam kod, od ktoreho by si sa mozno mohol odrazit.
Kod precita 10 miestne cislo na serial porte a ulozi ho do buffera. Buffer prehodi do 0-teho indexu pola, ulozi do eeprom a precita z eeprom do 1-veho indexu pola. Nic svetoborneho to nie je a chlapci to tuna mozu kludne zrevidovat. Nie som bohvieaky programator.

Jo a este nieco som zabudol.
Nie su tu osetrene nespravne zadane cisla/znaky. To si budes musiet uz osetrit sam, lebo toto nie je kod, ktory budes asi pouzivat. Je to iba mozny navod.

Kód: Vybrať všetko
#include <EEPROM.h>

// premenne
int index=0;             //index precitaneho cisla zo serial.read

char serialString[10];   //buffer pre nacitavanie zo serial

char *number[] = {       //vytvorenie 10 poli, ktore obsahuju 10 cisiel plus terminating null a ich inicializacia
"0999999999",            //char su ulozene v eprom ako ascii
"1999999999",            // "0"=48
"2999999999",            // "1"=49
"3999999999",            // "2"=50
"4999999999",            // "3"=51
"5999999999",            // "4"=52
"6999999999",            // "5"=53
"7999999999",            // "6"=54   ...
"8999999999",
"9999999999",
};

void setup()
{
  Serial.begin(9600);                                              //start serial
}

void loop()


if (Serial.available())               //Test na prichod stringov
{
  char ch=Serial.read();              //ulozenie jedneho stringu do premennej
  if(index<10 && ch>='0' && ch<='9')  //test na to ci to je cislo
  {
    serialString[index]=ch;           //ulozim string do buffera s prislusnym indexom
    index++;                          //zvysenie indexu
  }
  else                                //ak nie je cislo alebo je zadanych viac ako 10 cisel
  {
    serialString[index]=0;            //terminating null
    index=0;                          //reset indexu
    Serial.print("Precital som ");    //vypis na serial
    Serial.println(serialString);     //vypis co som nacital zo serial portu
    number[0]=serialString;           //ulozenie do prveho pola cisiel
    Serial.println(number[0]);        //vypis prveho pola cisiel
    Serial.println(number[1]);        //vypis druheho pola cisiel
    eepromSaveAdress();               //ulozenie do eeprom
    eepromReadAdress();               //nacitanie do eeprom
    Serial.println(number[1]);        //vypis druheho pola cisiel uz nacitaneho z eeprom
  }

}
//    eepromReadAdress();              //pozor pri odkomentovani tychto troch dojde k spomaleniu
//    Serial.println(number[1]);       //nacitavania zo serial, treba iba pockat 
//    delay(1000);                     //je to sposobene tymto delay, inak by to ficalooooo
}

void eepromReadAdress(void)              //nacitanie adries z eeprom
{
  static int eepromAdress;
  static int pom;
  eepromAdress=0;
  for(int i=0;i<10; i++)
  {
    number[1][i]=EEPROM.read(eepromAdress); 
//    Serial.println(i);
    eepromAdress++;
  }
  eepromAdress=0;
  number[1][10]=0;
//  pom=EEPROM.read(0);
//    Serial.print("read from eeprom:");
//    Serial.println(pom);     
}

void eepromSaveAdress(void)
{
  static int eepromAdress;
  static int pom;
  eepromAdress=0;
  for(int i=0;i<11; i++)
  {
//    Serial.print("eepromAdress:");
//    Serial.print(eepromAdress);
//    Serial.print("i:");
//    Serial.print(i); 
//    Serial.print("data:");
//    Serial.println(number[0][i]);   
    EEPROM.update(eepromAdress,number[0][i]);
    eepromAdress++;
  }
//  pom=EEPROM.read(0);
//    Serial.print("read from eeprom:");
//    Serial.println(pom);   
//  delay(2000);
}




Obrázok užívateľa
Príspevky: 133
Registrovaný: Štv 06. Nov 2014 12:06:09

Re: Prvky pola

Poslaťod budvar10 » Uto 05. Jan 2016 9:45:36

@barado
V tvojom programe je myslím pár chýb. Len som ho tak prebehol očami ale:
1. number[] je pole naplnené konštantným znakovým reťazcom a potom ho chceš prepísať, to nedáva zmysel
2. serialString[10] má desať prvkov, tel číslo "0999999999" má 10 číslic/znakov + 1 znak pre NULL, to je 11 dokopy, t.j. zapíšeš NULL do pamäti niečomu inému
3. toto number[0]=serialString; //ulozenie do prveho pola cisiel určite nefunguje tak ako si myslíš, ak chceš nahradiť reťazec nejakým iným, musíš to robiť po znakoch alebo je nato napr. funkcia strcpy.

Obrázok užívateľa
Príspevky: 43
Registrovaný: Str 25. Feb 2015 22:19:54
Bydlisko: Fintice

Re: Prvky pola

Poslaťod dzooky » Uto 05. Jan 2016 11:00:42

To nepochybujem ze su tu riadny manici :D

Prva verzia bola urobena tak, ze mala natvrdo zadane cisla, ktore vedeli branu otvorit.
Tak som zacal uvazovat na verzii 2.0, ktora by vedela aj pridavat ci uberat telefonne cisla.
Prva idea bola taka, ze pridam tlacidlo, ktore ked stlacis a prezvonis z nejakeho cisla prida ho do zoznamu.
Druha idea je teraz co riesim cez SMS vies pridat ci odobrat cislo.
To ze sa cisla pri vypadku zmazu to ma zatial netrapilo.

aktualne to vyzera takto s premenymi

master_number - master cislo, len toto vie pridat/odobrat cisla a na neho sa mozu poslat info SMS, uvazoval som take ze pri vypadku/restarte brana prezvoni, ze sa restartlo a pridane cisla ktore boli cez sms sa zmazali
slave_numbers - dalsie cisla ktore mozu otvarat branu, tie su surovo zadane cisla
check_numbers - premenna na ukladanie cisel cez sms,ja som si dal zatial fixne 10 cisel

No, ked takuvazujem nepotrebujem ukladat 10 miestne cislo resp 11 so znakom null
Staci mi 8 resp 9 kedze lokalne kazde (mobilne) cislo ma na zaciatku 09 a to si tam viem dosadit.
Jedine keby ten moj program siel do sveta a trebalo by aj cislo krajiny v tvare napr 421 atd.
Lenze problem su kniznice, tie su urobene tak ze pri volani vracaju cislo vo formate 09XX... len pri SMSke to davaju s krajinou. To by trebalo prekopat tie. No mozno nakoniec skusim pouzit tu eeprom.

No zatial uvazujem preco tie moje sa v priebehu programu menia co do nich saha, resp preco ich inak v ypisuje v inych castiach programu.

Obrázok užívateľa
Príspevky: 133
Registrovaný: Štv 06. Nov 2014 12:06:09

Re: Prvky pola

Poslaťod budvar10 » Uto 05. Jan 2016 12:43:16

Pošli zdroják, čo ti nefunguje. Ten kód v odkaze zo včera to asi nie je, nie je tam volanie z funkcie. Mimochodom, number[10] je krátke a spôsobí nekonzistentnosť dát v pamäti. Toto je určite vážny problém.

Príspevky: 33
Registrovaný: Pia 26. Jún 2015 21:17:41

Re: Prvky pola

Poslaťod barado » Uto 05. Jan 2016 14:03:50

budvar10 píše:@barado
V tvojom programe je myslím pár chýb. Len som ho tak prebehol očami ale:
1. number[] je pole naplnené konštantným znakovým reťazcom a potom ho chceš prepísať, to nedáva zmysel
2. serialString[10] má desať prvkov, tel číslo "0999999999" má 10 číslic/znakov + 1 znak pre NULL, to je 11 dokopy, t.j. zapíšeš NULL do pamäti niečomu inému
3. toto number[0]=serialString; //ulozenie do prveho pola cisiel určite nefunguje tak ako si myslíš, ak chceš nahradiť reťazec nejakým iným, musíš to robiť po znakoch alebo je nato napr. funkcia strcpy.


Ahoj.
Dakujem za reakcie. Neviem ako, ale funguje to. Odskusane na arduino UNO R3. Software Arduino IDE 1.6.3. A teraz aj virtualne v Proteus8
edit: iba som si myslel, ze to funguje. Dakujem budvar10.

1. ano number[] je premenna inicializovana preto, aby si vytvorila miesto a mala potrebnu velkost. Aspon preto som to tak urobil a myslel som, ze je to treba. Preto mozem k number[] pristupovat sposobom napr: number[0][0], number[1][5] ...
2. ano serialString ma desat prvkov, tam som asi urobil chybu, ale jedenaste miesto nahradzam NULL v kode kde index ma hodnotu 11
Kód: Vybrať všetko
  serialString[index]=0;            //terminating null

kazdopadne je mozne zvysit velkost stringu, kod po 10 cisle ostatne ignoruje. Viem, ze sa to musi este osetrit, no takto to funguje.
3. tu prosim o vysvetlenie. to nemozem len tak hodit string do stringu? Lebo momentalne to funguje bez problemov a ak sa to ma robit inak, tak neviem ako. ..

Este raz dakujem
Naposledy upravil barado dňa Str 06. Jan 2016 12:30:32, celkovo upravené 1

Obrázok užívateľa
Príspevky: 133
Registrovaný: Štv 06. Nov 2014 12:06:09

Re: Prvky pola

Poslaťod budvar10 » Uto 05. Jan 2016 15:10:09

Barado je to trochu veľa písania na mňa ale pokúsim sa.
1. Áno premenná vytvorí miesto, ale tie stringy budú zaberať miesto vo flash aj v RAM. Je to konštanta a každý pokus o jej zmenu je "memory access violation", samozrejme na Atmege sa dá aj to. Ale toto súvisí aj s bodom 3. Dá sa predsa zadefinovať dvojrozmerné pole number[10][11] a máš pole pre 10 mobilných čísel. Globálna premenná bude automatický inicializovaná nulami.
2. NULL proste zapíšeš do pamäťového miesta, ktoré môže patriť inej premennej, je to fatálna chyba. Znakové reťazce nemajú info o max. dĺžke, končia nulou a programátor musí ustriehnuť aby nikde v programe sa nepresiahla max dĺžka. RAM je usporiadaná ako reťaz bajtov a premenné v nej sú ukladané jedna za druhou. Dá sa aj zistiť toolom (napr. avr-objdump), čo nasleduje za serialString.
3. Ty chceš uložiť serialString do number[0] ale to sa nestane, resp. inak než si myslíš. number[0], rovnako aj ostatné, je pointer na pamäťové miesto, kde je uložený reťazec "0999999999" - konštanta. Ty ale neprepíšeš tento reťazec, len zmeníš pointer na identický so serialString. Od tej chvíle čo je v jednom, je aj v druhom, keďže obidva ukazujú na to isté miesto v RAM. Céčko je low level jazyk a reťazce typu char * sa nepresúvajú takto. Proste sa to musí robiť bajt po bajte alebo je na to funkcia strcpy, memcpy....
Existuje class String a tam to samozrejme funguje cez =, ale to je objektová úroveň a ak by si šiel do podrobností, tiež je za tým kopírovanie bajt po bajte.

Ešte pre vysvetlenie:
1. number je smerník na pole smerníkov = adresa v RAM kde začína number[0], number[1]....
2. number[0] je smerník na reťazec = adresa v RAM, kde sa nachádza 0999999999 a NULL; takto to je aj s number[1] atď
3. serialString je smerník/adresa na reťazec desiatich bajtov v RAM.
Jednoduchým pokusom zistíš, že ak po tomto príkaze number[0]=serialString; zmeníš obsah serialString, zmení sa aj number[0].

Obrázok užívateľa
Príspevky: 43
Registrovaný: Str 25. Feb 2015 22:19:54
Bydlisko: Fintice

Re: Prvky pola

Poslaťod dzooky » Uto 05. Jan 2016 15:28:40

budvar10 píše:Pošli zdroják, čo ti nefunguje. Ten kód v odkaze zo včera to asi nie je, nie je tam volanie z funkcie. Mimochodom, number[10] je krátke a spôsobí nekonzistentnosť dát v pamäti. Toto je určite vážny problém.


Prave som si uvedomli, ze mozno viem, kde bude chyba.
Asi to co popisujes v svojom dalsom prispevku v bode 10.

Ja som si cisla ukladal cisla do premennej check_numbers, ktoru som si zadefinoval rovnako ako barado a teda check_numbers[10] co je 10 prvkove pole teda asi tam neviem ulozit dasat desatprvkovych cisel. :D
Teda ono sa to tam aj podari nejako zapisat ale ci to tam bude bavit uz asi nie.
Asi bude lepsie urobit dvojrozmerne pole check_numbers[10][10]

idem na to spravne?

Obrázok užívateľa
Príspevky: 133
Registrovaný: Štv 06. Nov 2014 12:06:09

Re: Prvky pola

Poslaťod budvar10 » Uto 05. Jan 2016 15:33:41

Na telefónne číslo v požadovanej forme pre 10 číslic potrebuješ 11 bajtov!!!

check_numbers[10][11]

Príspevky: 174
Registrovaný: Ned 16. Mar 2014 23:22:00

Re: Prvky pola

Poslaťod posjirka » Uto 05. Jan 2016 17:03:26

souhlas s budvar10. potřebuješ 2 rozměrné pole o 10 "řádcích" (počet telefonních čísel) a 11 "sloupcích" (jednotlivá čísla + null).
Podle toho co píšeš je to super nápad: otevírání brány přes GSM. Rozhodně bezpečnější než nějáký přenos po 433MHz.


Já bych k tomu přitupoval asi takto:
použil bych GSM modul
Arduino
relé + tranzistor, ...
LED indikaci stavu (zelená vše ok, oranžová přijmám data, rudá chyba)

Do EEPROM bych zapisoval čísla po 20.
0, pozice bude kontrolní, když bude zapsáno tel. číslo zapiš tak "10" jinak zapiš "0"
1, pozice bude 1 znak tel. čísla
2, pozice bude 2 znak tel. čísla
...
20, kontrolní pozice
21, pozice bude 1 znak tel. čísla
.....

Určitě pak časem budeš chtít něco upravit a nebudeš mít volné místo, nebo to budeš muset znovu vše nastavovat.
Navíc nevím jak se ti bude zobrzovat tel. číslo ale mě na mobilu jdou některá čísla i s předčíslím státu (+420) v tu chvíli máš už 13 znaků + null
Každopádně máš místo pro 50 tel. čísel.

pole znaku bych dal radši větší (15 zn.) na začátku s přednastveným textem (-,-,-,-,-,-,-,-,-,-,-,-,-,-,-)

Do paměti si zadáš 4 hesla pro SMS:
když pošleš z nějákého telefonu ze seznamu SMS ve tvaru "1.heslo + tel. číslo" smaže se toto číslo z EEPROM a přeskládá EEPROM aby nebyli mezery mezi záznamy.
když pošleš z jiného SMS ve tvaru "2.heslo", tak ti přidá toto telefonní číslo do seznamu a prvnímu tel. číslu pošle SMS o přidání čísla do seznamu.
když pošleš z jakéhokoliv tel. čísla ze seznamu SMS ve tvaru "3.heslo" pošle ti zpět SMS se seznamem tel. čísel .
když pošleš z jakéhokoliv tel. čísla ze seznamu SMS ve tvaru "4.heslo" vymaže se paměť SMS zpráv.

v programu č.1 celou vymazat EEPROM a od pozice 0 tam zapiš 10 a svoje telefonní číslo

V druhém (tom hlavním programu):
1, volání knihoven + definice proměnných
2, setup ... vstupy, výstup, kontrola GSM modulu,
3, loop ... čekat na telefonní číslo
když zavolá, projít eeprom a najít si zda se shoduje
pokud ano otevři bránu
když ti příjde SMS
porovnej text ze seznamem hesel
switch case .... podle tvaru hesla.

Ďalší

Späť na Software