• Witaj na Forum Arduino Polska! Zapraszamy do rejestracji!
  • Znajdziesz tutaj wiele informacji na temat hardware / software.
Witaj! Logowanie Rejestracja


Ocena wątku:
  • 0 głosów - średnia: 0
  • 1
  • 2
  • 3
  • 4
  • 5
Sterowanie urządzeniem, zmiana kilku zmiennych pod danym warunkiem
#1
Witam wszystkich. Przepraszam, ale nie miałem innego pomysłu na temat, napiszę o co mi chodzi.
Mam urządzenie, które na podstawie odczytanej przez serial danej (dokładnie częstotliwości) nadaje wartości kilku innym zmiennym. Częstotliwość z przedziału. Poniżej przykład:
if ( freq  > 1000 && freq < 1100) {
a = 1;
b = 0;
c = 1;
d = 240;
e = 11230;
f = 20;
g = 1;
h = 0;
i = 1
}
if ( freq  > 1000 && freq < 1100) {
a = 0;
b = 0;
c = 1;
d = 40;
e = 12230;
f = 20;
g = 0;
h = 0;
i = 1
} ................. i tak np 70 razy.


freq to unsigned int, d, e, f to int, a, b, c i g, h, i to boolean. 
Zmienne od a do i mają wartości zadane przeze mnie dla każdego zakresu freq. Tych zakresów będzie dużo, powiedzmy 70.
Jak napisać program. Jak stworzyć tablicę, którą można by było w łatwy sposób edytować w przypadku zmiany którejś wartości. Pisanie 70 raz warunku jak powyżej jest raczej kiepskim pomysłem. 
Atmega na podstawie odczytanej częstotliwości przełączy 6 przekaźników i nastawi trzy serwa.
Potrzebuję pomocy w ty temacie.
Pozdrawiam. Robert
Robert, sp8sn
 
Odpowiedź
#2
Poczytaj o strukturach, one służą do robienia zestawów danych https://plociennik.info/index.php/struktury-cpp. Potem robisz sobie tablicę takich zmiennych i umieszczasz w flash. Poczytaj jak umieszczać tablice we flash AVR by nie zajmowały RAM. Jedną zmienną tego typu używasz by ją napełniać danym z wybranej pozycji tablicy struktur.
Miło być decenianym https://buycoffee.to/kaczakat
 
Odpowiedź
#3
(14-08-2019, 00:23)kaczakat napisał(a): Poczytaj o strukturach, one służą do robienia zestawów danych https://plociennik.info/index.php/struktury-cpp. Potem robisz sobie tablicę takich zmiennych i umieszczasz w flash. Poczytaj jak umieszczać tablice we flash AVR by nie zajmowały RAM. Jedną zmienną tego typu używasz by ją napełniać danym z wybranej pozycji tablicy struktur.

Dziękuję poczytałem ten i kilka innych artykułów i niestety jestem za cienki, żeby to zrobić. Nie do końca rozumiem, może nie tyle samych struktur, ale jak je zaimplementować do moich potrzeb. Jeszcze na spokojnie przeanalizuje przykłady.
Robert, sp8sn
 
Odpowiedź
#4
Robisz sobie po prostu nowy typ zmiennej, która ma w sobie X różnych zmiennych. Taką zmienną możesz przypisać jak zmienne int a,b; i potem w programie możesz użyć a=b.

Kod:
struct pakiet{
int a=0;
float b=0;
bajt c=0;
char d=0; 
} struktura;

pakiet struktura2;
void setup() {
  Serial.begin(115200);
 

  struktura.a=12;
  struktura.b=13;
  struktura.c=14;
  struktura.d=15;

struktura2= struktura;
  Serial.println(struktura2.a);
  Serial.println(struktura2.b);
  Serial.println(struktura2.c);
  Serial.println(struktura2.d);
}
void loop() {}

Wszystkie wartości przypisane wewnątrz zmiennej "struktura" zostaną przekopiowane do zmiennej struktura2 i to zobaczysz na wydruku. Do poszczególnych zmiennych odwołujesz się używając operatora '.' i nazwy elementu.
Możesz sobie zrobić np. 1000 tak zdefiniowanych zmiennych, w kodzie programu używasz zawsze do np. wydruku Serial.println(strukturaaktualna.b);, a gdy chcesz zmienić zestaw danych na ten o numerze 678 to wystarczy strukturaaktualna=struktura678 i dopóki znowu tego nie zmienisz będzie brał wszystkie zmienne .a .b .c .d z zestawu 678.
Żeby było łatwiej to nie robisz sobie 1000 zmiennych o różnych nazwach, skoro jest to 1000 tych samych zmiennych (tego samego typu - pakiet) to robisz sobie ich tablicę. Typem zmiennej jest dalej "pakiet".
pakiet tabstr[1000];
Oczywiście 1000 takich zmiennych zjadło by kilka razy RAM w UNO, więc umieść je we flash.
Dla powiedzmy 10 jak nic ciekawego nie robisz to może być RAM, wystarczy go, i wtedy jest prosto:

Kod:
pakiet tabstr[10]; 
  tabstr[5]=struktura;
  Serial.println(tabstr[5].a);
  Serial.println(tabstr[5].b);
  Serial.println(tabstr[5].c);
  Serial.println(tabstr[5].d);
 

W Arduino, czy tam C++ (to właściwie to samo) są obiekty. To rozwinięcie struktur. W obiektach mogą być również funkcje specjalnie przypisane do obsługi danych obiektu.

Choć oczywiście tu użyjesz odwrotnie, strukturaaktualna=tabstr[5], czy tam któryś i-ty element tablicy. 
Tylko wtedy definiując tablicę od razu przypisujesz wartości wszystkim 10 zestawom. Tu się zaciąłem, bo oczywiście nigdy tego nie robiłem, a choć logicznie byłoby robić tak jak z wszystkimi innymi zmiennymi to jednak z tablicami to nie działa. Można zmienne definiować już w czasie działania programu, ale przypisanie zmiennych globalnych od razu trzeba robić w definicji struktury.

A teraz patrz uważnie, bo tego w książkach nie znajdziesz:

Kod:
uint32_t czasTeraz,czasPoprzedni,tik=10; //tik musi byc mniejszy niz 1000 i dzielic 1000ms na rowne czesci
uint8_t nTik,sekundy,minuty,godziny,dni; //liczniki tikow, sekund, itd.
bool fnTik,fsekundy,fminuty,fgodziny,fdni; //flagi zdarzen nowy tik, nowa sekunda,minuta, godzina, dzien
char napis[32];





   struct  pakiet  {  //definicja struktury RAM
int a;
int b;
int c;
int d; 
} tabstr[]={ //tablica struktur w RAM z inicjalizacja, mozna dodawac i odejmowac pola (linia to zestaw danych) by sprawdzic jak to wplywa na RAM
  {1,2,3,4},
  {11,12,13,1},
  {21,22,23,24},
  {31,32,33,34},
  {41,42,43,44},
  {51,52,53,54}
};

const pakiet tablicaPROGMEM[] PROGMEM= // a to definicja tablicy struktur we FLASH
{
  {311,312,313,31},
  {321,322,323,324},
  {331,332,333,334},
  {341,342,343,344}, //mozna dodawac i odejmowac pola by sprawdzic jak to wplywa na RAM
  {351,352,353,354},

};
 

pakiet struktura;
pakiet struktura2;


void setup() {
  Serial.begin(115200);

  struktura2={21,22,23,24};
  struktura.a=12;
  struktura.b=13;
  struktura.c=14;
  struktura.d=15;

struktura2= struktura;
  Serial.println(struktura2.a);
  Serial.println(struktura2.b);
  Serial.println(struktura2.c);
  Serial.println(struktura2.d);
  tabstr[4]=struktura;
  Serial.println(tabstr[4].a);
  Serial.println(tabstr[4].b);
  Serial.println(tabstr[4].c);
  Serial.println(tabstr[4].d);

  for (int i =0; i<6;i++)
  {
  Serial.println(tabstr[i].a);
  Serial.println(tabstr[i].b);
  Serial.println(tabstr[i].c);
  Serial.println(tabstr[i].d);
  Serial.println();
  }

memcpy_P( &struktura2, &tablicaPROGMEM[3], sizeof( pakiet)); //przepisanie danych z FLASH do RAM, ze struktury we FLASH do struktury w RAM,
// i wydruk tych wartosci

  Serial.println(struktura2.a);
  Serial.println(struktura2.b);
  Serial.println(struktura2.c);
  Serial.println(struktura2.d);
 
 
}
void loop() {
  czas();
  static int zmienna=0;

  if (fsekundy)
  {
// a teraz zabawa z roznymi zestawami danych w zaleznosci od wartosci zmiennej "zmienna"
 
     memcpy_P( &struktura2, &tablicaPROGMEM[zmienna], sizeof( pakiet));
    sprintf(napis,"%02d:%02d:%02d:%02d ",struktura2.a,struktura2.b,struktura2.c,struktura2.d);
    Serial.print("Wydruk wartosci aktualnych wartosci struktura2: ");
    Serial.println(napis);
   
    if(++zmienna>4) zmienna=0;
  }
}




void czas()
{
czasTeraz=millis();
fnTik=fsekundy=fminuty=fgodziny=fdni=0;
if((uint32_t)(czasTeraz-czasPoprzedni)>=tik) //tan napisany warunek jest odporny na "klątwe 50 dni millis()"
{
  czasPoprzedni=czasTeraz;
  fnTik=1;
  nTik++;
  if(nTik>=(1000/tik))
  {
    nTik=0;
    sekundy++;
    fsekundy=1;
     if (sekundy>=60)
    {
      sekundy=0;
      minuty++;
      fminuty=1;
      if (minuty>=60)
      {
        minuty=0;
        godziny++;
        fgodziny=1;
        if (godziny>=24)
        {
          godziny=0;
          fdni=1;
          dni++;
   
        }
      }
    }
  }
}
}
No część może tak, nie widziałem nigdzie wszystkiego razem. 
Gdy pobawisz się ilością zestawów danych w tych dwóch rodzajach tablic to zauważysz, że ta w RAM zjada flash i RAM, a ta z const PROGMEM tylko flash. Znaczki '&' pobierają adres w pamięci zmiennych za nimi, dzięki niemu przepisujesz funkcją memcpy_P dane ze zmiennej we flash do zmiennej w RAM (zmiennej zawierającej całą strukturę). O robaczkach typu & * -> możesz poczytać w książkach.
Może uda Ci się ściągnąć książki o C stąd (darmowe i bez punktów): https://www.elektroda.pl/rtvforum/viewto...6#18012536.
 
Miło być decenianym https://buycoffee.to/kaczakat
 
Odpowiedź
#5
Bardzo dziękuję za obszerny materiał. Muszę nad tym posiedzieć. Na pierwszy rzut oka mam wątpliwość jak wyciągnąć tzn. przypisać wartości zmiennej na podstawie wartości pierwszej zmiennej w tablicy, albo na podstawie innej zmiennej, a dokładnie przedziału w jakim się znajduje. Ale tak jak mówię, muszę posiedzieć. Dzięki.
Robert, sp8sn
 
Odpowiedź
#6
Ostatecznie ta część dalej może być:

Kod:
if ( freq  > 1000 && freq < 1100) {
zestawAktualny= zestaw1;
}
if ( freq  > 1100 && freq < 1200) {
zestawAktualny= zestaw2;
} ................. i tak np 70 razy.


Choć też jest konstrukcja if  else, else if i wtedy wystarczy:

Kod:
if ( freq  < 1100) {
zestawAktualny= zestaw1;
}
else if ( freq  < 1200) {
zestawAktualny= zestaw2;
} ................. i tak np 70 razy. - wykona się tylko pierwsza pasująca, to co wcześniej nie spełnia, to co później jest wycięte else.

I pewnie coś tu można jeszcze inne użyć z C, wystarczy poczytać, może case? Na pewno wtedy jeśli powyżej ustalisz tylko numer zestawu do wczytania, czyli przypiszesz wartość porządkową "i" i potem wybierzesz i-ty element z tablicy flesz o numerze zmienna.

Kod:
if ( freq  < 1100) {
i=0;
}
else if ( freq  < 1200) {
i=1;
} ................. i tak np 70 razy.

Jeśli częstotliwości są rozmieszczone równomiernie wystarczy int i=freq/100 i będziesz dostawał 11,12,13 itd., można też odjąć 11 od każdego i mieć 0,1,2,3... to już łatwo powiązać z indeksem tablicy.
W strukturze dobrze jest też umieszczać dane bajtami, a konkretnie parami. Niektóre kompilatory zajmują pamięć słowami, czyli tymi parami bajtów. Ta sama struktura może zajmować inny rozmiar dla UNO, a inny dla ESP. Dodatkowo int w ESP to 32bity, a w UNO 16bitów. Jak chcesz mieć to samo w obu to możesz użyć int16_t w obu i w obu będzie to liczba 16bitowa ze znakiem.
No i oczywiście struktury można zagnieżdżać. Pierwszy raz jak zobaczyłem strukturę to była użyta do pol bitowych - wartości bool. Taką strukturę można wrzucić w inną strukturę. Ale po użyciu PROGMEM raczej bym się w to nie bawił, nawet po użyciu 1000 zestawów i tak w pamięci RAM zajmie to 1x10xbajt (tylko aktualny zestaw  wczytany do RAM) a nie 1001x10xbajt.
Im więcej zostaje w głowie po przeczytaniu książek, napisaniu setek prostych programów samodzielnie tym potem łatwiej.
Miło być decenianym https://buycoffee.to/kaczakat
 
Odpowiedź
#7
Dzięki,czeka mnie sporo pracy nad sobą.
Mam jednak pewną wątpliwość. Jaki jest sens wszystkiego jeśli i tak muszę pisać wszystkie warunku.
Chodzi mi o to, że myślałem (nie wiem czy jest to możliwe) zrobić to jednym warunkiem
if ( freq  > x && freq < y) {
.....
}
zmienne x i y byłyby w tablicy
x,y,a,b,c,d,e,f,g,h
[1000,1100,12,1,0,121,345,110,1,0]
czyli jeśli warunek zmiennych x i y jest spełniony, zmiennym a b c d e f g h przypisywane są wartości z tablicy w danym wierszu

Edit: wymyśliłem sobie coś takiego:
Kod:
#include <LiquidCrystal.h>
LiquidCrystal lcd(8, 9, 10, 11, 12, 13);
int itab;
int rawread;
int znak1;
int znak2;
int znak3;
int znak4;

int tab[5][5]={
  {1,6,3,5,7},
  {2,4,2,8,5},
  {3,5,3,2,2},
  {4,1,2,1,1},
  {5,3,2,6,7}
};


void setup()
{
  pinMode(A0, INPUT);
  lcd.begin(16, 2);
}

void loop()
{
rawread = analogRead(A0);
itab = map(rawread,0,1020,0,4);
  znak1 = tab[itab][1];
  znak2 = tab[itab][2];
  znak3 = tab[itab][3];
  znak4 = tab[itab][4];
lcd.print(znak1);
lcd.print(".");
lcd.print(znak2);
lcd.print(".");
lcd.print(znak3);
lcd.print(".");
lcd.print(znak4);
lcd.print(".");
delay(50);
lcd.clear();
}

Czyli w zależności od napięcia na A0 -> mapowane od 0 do 4 po pierwszej wartości w każdym wierszu, ustala cztery pozostałe wartości w wierszu i wyświetla sobie. Działa tylko czy zmieści mi się tabela int tab[70][11] bo tyle mi trzeba.
Robert, sp8sn
 
Odpowiedź
#8
Tablice danych też można wstawiać do flash, jeśli jest to procek z RAM >4kb i program w pozostałej część już z nim nie szaleje to można nawet zostawić jak jest. Jednak zasada będzie ta sama, a ilość zajętej pamięci większa, bo tablica musi mieć wszystkie komórki tej samej wielkości. Po to jest struktura by obejść ten problem i zmniejszyć ilość danych w programie i w RAM. Dane we flash dotyczy ta sama zasada, by ich użyć trzeba je skopiować do RAM.
Mnie chodziło o to, że jeśli umieścisz 1500 bajtów we flesh to bez sensu je wszystkie odczytywać i sprawdzać, które pasują. Można wyliczyć, lub z ifa wziąć informację po który zestaw sięgnąć bezpośrednio.
Jeśli zakresy częstotliwości nie są kompletnie losowe, ale można podczepić pod nie jakieś równanie to zamiast 70 ifów masz to równanie, najprostsze to właśnie i=freq/100, potem odczyt i-tego zestawu.
Miło być decenianym https://buycoffee.to/kaczakat
 
Odpowiedź
#9
Nie bardzo da się w prosty sposób wyliczyć z częstotliwości. Częstotliwości będą z pasm amatorskich KF, czyli ogólnie 1.8MHz, 3.5MHz, 7MHz, 10MHz, 14MHz, 18MHz, 21MHz i 28MHz. Są to pasma o różnych szerokościach więc w każdym z nich będzie nieco inna ilość odczytywanych zakresów. W jednym będzie wymagany skok o 20kHz a w drugim 50kHz. Nie jestem nawet w stanie teraz tego w 100% określić więc proste wyliczanie nie wchodzi w grę. Można jedynie np pobierać paczkę w zależności od zakresu, czyli 8 paczek.
Robert, sp8sn
 
Odpowiedź
#10
Można połączyć switch case dla 8 przypadków + 8 prostych wzorów. Pewnie też nie znam wszystkich możliwości, uczę się programowania od niedawna.
Miło być decenianym https://buycoffee.to/kaczakat
 
Odpowiedź
  


Skocz do:


Przeglądający: 1 gości