Fórum témák

» Több friss téma
Fórum » Arduino
A klónok CH340 Soros-USB illesztőjének drivere (Letöltés)
Lapozás: OK   706 / 838
(#) vargham válasza kriszrap hozzászólására (») Okt 19, 2021 /
 
Arduino kód lassú. A digitalWrite különösen. A shiftOut pedig digitalWrite-ot hívja ciklusból.
Közvetlen port regiszter írással lehetne rajta gyorsítani.
(#) kriszrap válasza vargham hozzászólására (») Okt 19, 2021 /
 
Köszönöm a gyors választ .
Akkor lenne egy bit es kérdésem Megpróbálom igy lerajzolni.
led[y][z]=BIN X;
tömb a formációja.
Azt szeretném 1. lévő értéket elkezdem balra shiftelni és amikor elérte a 8 bitet akkor át töltse
2. 8 bitjébe
aztán azt az értéket
3. 8bitjébe
........

Vagy is vizuális ha z irány is ezzel az elvel megcsinálom akkor körbe futt a pl szám az egész ledkockán.

  1. 8.00000000
  2. 7.00000000
  3. 6.00000000
  4. 5.00000000
  5. 4.00000000
  6. 3.00000000
  7. 2.00000000
  8. 1.11001100
  9.  
  10.  
  11. 8.00000000
  12. 7.00000000
  13. 6.00000000
  14. 5.00000000
  15. 4.00000000
  16. 3.00000000
  17. 2.10000000
  18. 1.10110000


Erre van valami frappáns megoldás? Hogy lehetne shiftelést áttölteni egy másik tömbbe?
(#) majkimester válasza kriszrap hozzászólására (») Okt 19, 2021 / 2
 
Ilyen alapból nincs, de megoldható:

- shifteled a legutolsó byte-ot
- teszteled az előtte lévő byte legfelső bitjét, ha az 1 akkor növeled a legutolsó byte-ot 1-gyel
- shifteled az előtte lévő byte-ot
- így tovább az összes byte-ra

Valami ilyesmi egydimenziós tömbbel:

  1. byte led[8];
  2.       for(i=7;i>=0;i--)
  3.       {
  4.          led[i] = led[i] << 1;
  5.          if (i>0 && (led[i-1] & 0x80)!=0) led[i]++;
  6.       }
A hozzászólás módosítva: Okt 19, 2021
(#) kapu48 válasza kriszrap hozzászólására (») Okt 19, 2021 /
 
A char x,y,z; értéke csak pozitív egész szám lehet 0...255-ig!
A -1 feltétel nem jó! for(z=7;z>-1;z--)...
(#) kriszrap válasza kapu48 hozzászólására (») Okt 19, 2021 /
 
Majkimester köszönöm.

Kapu48 -1 re nem igy megy az érték.
(#) majkimester válasza kapu48 hozzászólására (») Okt 19, 2021 /
 
Sajnos az Ardiuno leirás egyértelműen nem mondja ki, hogy a char előjel nélküli vagy előjeles típus, méretre is csak annyit mond hogy minimum 8 bit. Továbbá létezik az unsigned char, ami meg azt sugallja, hogy a sima char előjeles. Igazából a háttérben lévő gcc forditó a char típust alapból előjelesen kezeli, de megadható neki a -funsigned-char command line paraméter amivel meg előjel nélküli lesz. Nem tudom az Arduino használja-e ezt a paramétert. Ugyan a doksiban nincs benne, de leírhatod a char helyett azt is hogy signed char, és akkor egyértelműen előjeles. De én például mindig typedef-fel használom:

  1. typedef unsigned char u08;
  2. typedef signed char s08;
  3.  
  4. ...
  5.  
  6. u08 u = 0;
  7. s08 s = -1;
(#) kapu48 válasza kriszrap hozzászólására (») Okt 19, 2021 /
 
A feltétel z>-1 = z nagyobb mint -1! Mindig igaz marad.
Ezért sosem lesz vége a for ciklusnak!
Bővebben: char Link
The size of the char datatype is at least 8 bits. It’s recommended to only use char for storing characters. For an unsigned, one-byte (8 bit) data type, use the byte data type.
(#) kapu48 válasza majkimester hozzászólására (») Okt 19, 2021 /
 
A char típust karakter kódok tárolására találták ki.
Akkor a 128-nál nagyobb grafikus vagy ékezetes karaktereket mínusz előjelesként, hogyan tudná értelmezni a fordító?
A hozzászólás módosítva: Okt 19, 2021
(#) majkimester válasza kapu48 hozzászólására (») Okt 19, 2021 /
 
Az, hogy előjeles vagy nem a karakter tárolása szempontjából mindegy. Legyen 8 bit egymás után, és kész. Egy karakter kód esetében semmi értelme az előjelességet vizsgálni.

A előjelesség csak akkor jön képbe, ha műveletet akarsz végezni az adott változóval. Ezt nyilván karakterrel is lehet, pl. char c = 'a' + 15; Ha egyértelműsíteni akarod mi is történik, akkor mindig eléírod hogy unsigned vagy signed, vagy használod a fent említett typedef-et.

Ami inkább érdekes, hogy azt írja az arduino leírásban, hogy minimum 8 bit, azaz bizonyos platformokon, lehet, hogy UTF-16 karaktert értenek alatta?
(#) kapu48 válasza majkimester hozzászólására (») Okt 19, 2021 /
 
Éppen ezért kifogásoltam a for ciklusokban alkalmazott char z<-1 feltétel használatát!
Bővebben: Link a hsz.-re

Akkor ide teszem lefordítva az ajánlást amit szintén idéztem:
A char adattípus mérete legalább 8 bit. Javasoljuk, hogy a karaktereket csak karakterek tárolására használja. előjel nélkül, egybájtos (8 bites) adattípus esetén használja a bájtos adattípust.
A hozzászólás módosítva: Okt 19, 2021
(#) kriszrap hozzászólása Okt 19, 2021 /
 
Rendben.
Akkor kijavítom >=0 re akkor gondolom jó lesz.
char azért használom mert amikor 1...8 kell for ciklust csinálni elég rá bőven és ram ot nem pazarlom annyira.
(#) tbarath válasza kriszrap hozzászólására (») Okt 19, 2021 /
 
Idézet:
„char azért használom mert amikor 1...8 kell for ciklust csinálni elég rá bőven és ram ot nem pazarlom annyira.”

Akkor használj byte-ot: Bővebben: Link
Vagy unsigned char-t (ami ugyanaz, mint a byte).
(#) zosza18 hozzászólása Okt 19, 2021 /
 
Sziasztok!

Kérdésem a következő lenne...
Mérnem kellene egy rakodógép motorjának a fordulatát, majd a későbbiekben tovább foglalkozni vele, de jelenleg a fordulat mérés a lényeg.
PNP-s jeladó van gyárilag benne, amit ISR-el figyelek. Ez részben működik is, viszont 20x4 I2C lcd-re is ki kellene írni közben, hogy látható is legyen.
Mivel delay-t nem lehet használni, így a kijelzés konkrétan csak van, de nem látható. Ötletet várnék arra, hogyan kellene a kijelzés frissítési idejét kb 1-2mp-re kitolni, míg maga a megszakítás rész nyugodtan fut?
Előre is Köszönöm a segítséget!
Mellékletben a példaprogram.
  1. #include <Wire.h>
  2. #include <LiquidCrystal_I2C.h>
  3. LiquidCrystal_I2C lcd(0x27,20, 4);
  4.  
  5. float value=0;
  6. float rev=0;
  7. int rpm;
  8. int oldtime=0;
  9. int time;
  10. int kijelzes = 0;
  11.  
  12. void isr() //interrupt service routine
  13. {
  14. rev++;
  15. }
  16.  
  17. void setup()
  18. {
  19. lcd.init();
  20. lcd.backlight();
  21. lcd.clear();
  22. lcd.setCursor(2,0);
  23. lcd.print("- Fordulatszam - ");
  24. lcd.setCursor(9,2);
  25. lcd.print(" RPM");  
  26. attachInterrupt(0,isr,FALLING);  //attaching the interrupt
  27. }
  28.  
  29. void loop()
  30. {
  31. detachInterrupt(0);           //detaches the interrupt
  32. time=millis()-oldtime;        //finds the time
  33. rpm=(rev/time)*60000;         //calculates rpm
  34. oldtime=millis();             //saves the current time
  35. rev=0;
  36. attachInterrupt(0,isr,FALLING);
  37. lcd.setCursor(4,2);
  38. lcd.print("     ");
  39. lcd.setCursor(4,2);
  40. lcd.print(rpm);
  41. }
(#) kapu48 válasza zosza18 hozzászólására (») Okt 19, 2021 / 1
 
Itt javasoltam tanfolyamot a multitaskingra:
Bővebben: Link
22. oldal Időzítés – késleltetés nélkül
23. multitasking.ino

És fontos a time változók legyenek:
  1. unsigned long oldtime=0;
  2. unsigned long time;
A hozzászólás módosítva: Okt 19, 2021
(#) zosza18 válasza kapu48 hozzászólására (») Okt 19, 2021 /
 
Szia!
Köszönöm szépen!
Holnap átnézem a linkelt infót!
(#) Dragonmax válasza KBal76 hozzászólására (») Okt 20, 2021 /
 
Bocsánat léptetőmotorom van, elírtam , de nem ilyen segítséget kértem.
(#) Massawa válasza Dragonmax hozzászólására (») Okt 20, 2021 /
 
Hogyan vársz segitséget, ha még a feladatot sem tudod megfoglamazni?

Mi fontos számodra az idö vagy a léptetés?

Ha az idö, akkor csinálj egy megszakitásos idözitöt, ami adja az idöimpulzusokat ( másodpercenként stb). Ezeket számold a poti állásátol függöen, és amig el nem éred az impulzusszámot a motor forog a ráengedett impulzusok szerint.
Ha meg a motorba menö impulzusok fontosak. ( mennyit fordul el a motor), akkor meg azokat az impulzusokat számold valamelyik számolo eljárással.
(#) KoblogPerGyok válasza zosza18 hozzászólására (») Okt 20, 2021 /
 
Elsőként a rev változó mindenképpen Volatile float!!

Azok a változók, amik az ISR-ben kapnak értéket, azok elejére mindenképpen kell a Volatile!

Aztán kellene kisebb érték esetleg a float helyett. Kell ekkora szám neked mindenképpen?

A Setup-ban:

volatile float rev=0;

volatile
A hozzászólás módosítva: Okt 20, 2021
(#) asch válasza zosza18 hozzászólására (») Okt 20, 2021 /
 
Unortodox választ fogok adni egy ki nem mondott implicit kérdésre:

> Mivel delay-t nem lehet használni, így a kijelzés konkrétan csak van, de nem látható.

Miért ne lehetne delay-t használni? Azt hiszem tényleg van ilyen ajánlás, hogy ne használjunk delayt a main loopban, de valójában semmi akadálya nincsen, simán működik. Én pont így csinálnám, tennék egy
  1. delay(2000);
-et a loop-ba legelső sornak, aztán viszontlátás. A lényeg, hogy akkor várakozzon, amikor az interrupt kezelő be van állítva, a loop első sora ésszerű helye volna a delay-nek.

Ezen kívül hiba még, hogy az rpm változód float típusú, az lcd.print viszont nem kezeli a floatot, ezért először egész értékké kell alakítani, például long-gá. Így:

  1. lcd.print((long)rpm);


Létezik szebb megoldás - amiket a többiek javasoltak, azokat mind érdemes megfontolni - de ez így szerintem már működőképes volna.


(A delay nem csak a kijelzés ideje miatt fontos - hogy ne írjuk folyton felül, hanem azért is, mert enélkül a mérési idő nagyon rövid lesz, és többnyire egyetlen rev sem lesz a mérésben, így hibásan 0-t mérünk. Mennél nagyobb a mérés ideje, annál kisebb lesz ez a fajta "alignment" hiba. De mindenképpen ugrálni fog a mért érték ezzel a módszerrel, ha nincsen szinkronban az Arduino periódusa (pl kb 2 másodperc) és a motor fordulatszáma. Stabil kijelzést úgy lehet csinálni, ha a tickek között eltelt időt mérjük, vagy ha a mért tartományon belül az első tick előtti és az utolsó tick utáni időt levonjuk az osztás előtt. Így nem lesz szisztematikus alignment hiba a mérésben, de ez már egy következő verziónak a témája...)
(#) KoblogPerGyok válasza asch hozzászólására (») Okt 20, 2021 /
 
Ha delay()-t nem akar használni, akkor is van még egy halom megoldás. Timer-interrupt túlcsordulásakor hívja meg a kiírást pl.

Vagy a loop-ban mér még egy másik időt is. Ha az nem telik le, akkor nem ír ki semmit. A loop is fut, az ISR() is megy, és akkor ír az LCD-re amikor akar. Kell ugyan bele egy if, de hát na...

Bár már régen használtam Arduino-t, PIC-el kell játszanom.
(#) Josi777 válasza zosza18 hozzászólására (») Okt 20, 2021 / 2
 
Az egyik probléma a kódoddal, hogy teljesen felesleges minden egyes loop ciklusban frissíteni a kijelzőt, célszerű bizonyos időközönként kiírni az értékeket. Erre itt van egy példa (a kijelző kezelő függvény neve disp):
  1. currentMillis = millis();
  2.   if (currentMillis - previousMillis >= 500) {   // Minden 500. ms-ban meghívja a disp() függvényt
  3.     previousMillis = currentMillis;
  4.     disp();
  5.   }

A másik probléma, hogy amit te fordulatszámnak mérsz, az nem az, legfeljebb hasonlít hozzá, mert a fordulatszámmal arányosan változik az értéke. A fordulatszám a percenkénti impulzusok száma, amennyiben fordulatonként 1 impulzus érkezik. Kétféleképpen lehet a fordulatszámot mérni. Ha magasabb fordulatszámról van szó, akkor egy konstans idő alatt érkezett impulzusok számából lehet kiszámítani a fordulatszámot. A másik lehetőség, alacsonyabb fordulatszám esetén, amikor az impulzusok közötti időt mérjük. A te megoldásodban elvileg az elsőt alkalmaznád, csakhogy az az időtartam, ami alatt méred a beérkező impulzusokat, nincs benne a számítási képletben, márpedig a nélkül nem lesz jó az érték. Ráadásul ez az időtartam a loop hossza mínusz a 33. sor. Azaz ha módosítod a loop tartalmát, akkor ez az időtartam is módosul.
Miután már van egy megszakítás kezelőd, ezért annak a kiegészítésére mutatok egy példát, ahol a fordulatszámjelet egy tacho jeladó szolgáltatja:
  1. attachInterrupt(0, tacho, FALLING);   // a tacho jeléhez megszakítás beállítása, 2-es kivezetés
  2.  
  3. void tacho() {                 // tacho impulzus megszakítás. fordulatszám kiszámítása
  4.   unsigned long tachotime = micros() - lasttachotime;   // két impulzus közötti idő
  5.   float time_in_sec  = ((float)tachotime + rpmcorrection) / 1000000;  // átszámítás másodpercre
  6.   float prerpm = 60 / time_in_sec;                      // átszámítás percre
  7.   RPM = prerpm / TACHOPULSES;                           // és elosztva a fordulatonkénti tacho impulzusok számával
  8.   lasttachotime = micros();                             // időpont tárolása
  9. }

Az rpmcorrection Atmel processzornál és 16 MHz-es órajelnél 86
Mind a 2 kódrészlet le van tesztelve (ezt használom a motor fordulatszám szabályozómban).
(#) Skori válasza Josi777 hozzászólására (») Okt 20, 2021 / 1
 
Ha a micros() értékét nem kétszer olvasnád ki a függvényben, hanem rögtön az elején betennéd egy változóba, és utána mindenhol ezt a változót használnád a függvényben, akkor két kiolvasás között mindig ugyanannyi időeltolódással lehetne számolni, azaz szerintem akkor nem lenne szükség az rpmcorrection-ra.
A hozzászólás módosítva: Okt 20, 2021
(#) majkimester válasza Josi777 hozzászólására (») Okt 20, 2021 / 2
 
Annyit azért hozzátennék, hogy az ISR-ből száműzni kellene az egész számítást, az tárolja csak a tachotime-ot a global volatile unsigned long-ban, majd a főprogram meg kiszámolja belőle az RPM-et sokkal ritkában, mondjuk csak akkor amikor tényleg letelt az első kódrészletben az 500mS és ki akarod jelezni.

És maga a tachotime -> RPM számítás meg a float használatával is ágyúval verébre ha nem akarsz tizedes jegyeket kijelezni a fordulatszámnál. Ez simán fixpontos aritmetikával számítható 1 sorban.

  1. unsigned long rpm = 60000000L / (tachotime * TACHOPULSES);


(még akár 1 tizedesjeggyel együtt is, ha nagyon kellene, csak akkor 60 millió helyett 600 milliót kell osztani és az eredmény RPM*10 lesz, megfelelő helyre kirakott tizedesponttal kell megjeleníteni).

rpmcorrection meg szerintem nem is kellene, ha az ISR-ben a micros()-t nem 2x hívnád fel. Ez a 86uS gondolom az 5-7 sorok lefutási ideje, ami eltelik a két micros() között.
(#) majkimester válasza majkimester hozzászólására (») Okt 20, 2021 / 5
 
És ami szintén kimaradt, hogy az ISR-ben beállított unsigned long tachotime-ot a főprogramból ne használd direktben, hanem egy atomic blockban másold le, és a másolattal számolj tovább.

  1. #include <util/atomic.h>
  2. volatile unsigned long isr_tachotime;
  3.  
  4. // a főprogramban pedig
  5.   unsigned long tachotime;
  6.   ATOMIC_BLOCK(ATOMIC_RESTORESTATE) {
  7.     tachotime = isr_tachotime;
  8.   }
  9.   unsigned long rpm = 60000000L / (tachotime * TACHOPULSES);
  10.   disp(rpm);


Ez azért kell, mert a unsigned long 4 byte hosszú, és simán előfordulhat, hogy a főprogramban éppen számolsz vele, de bejön egy megszakítás ami meg éppen új értékre állítja. Így a főprogramban a számításod félig a régi félig az új értékkel számol. HA nem így teszel. akkor a fordulatszám kijelzésedbe néha néha bevillan egy hibás érték és nem érted miért.

Az atomic block tulajdonképpen a benne lévő kód futtatási idejére letíltja a megszakításokat, ezzel megakadályozva, hogy hibás értéket másolj.
(#) Skori válasza majkimester hozzászólására (») Okt 21, 2021 / 1
 
Pont ezért (is) tetszett meg az STM32, mert egy ilyen szorzás vagy osztás egy lépésben megvan (14nsec) , tehát gyakorlatilag a fenti probléma fel sem merülhet. Sőt 2x 14nanosec akár a megszakításban is ottmaradhatna

Amúgy azt, hogy az rpmcerrection nem szükséges, előtted fél órával én is leírtam.

Azt csak zárójelben jegyzem meg, hogy ha a ArduinoNano estében 85usec körüli idő eltelik azzal a pár utasítással, akkor irgalmatlanul nagy a sebességkülönbség az STM32/BluePill javára...
(#) sdrlab válasza Skori hozzászólására (») Okt 21, 2021 / 1
 
A hardveres osztás támogatás az STM32-nél(sem) azt jelenti, hogy 1 ciklus alatt oszt el bármit is, hanem hogy célhardver van rá benne, ami relatíve kevés ciklus szám alatt végzi azt el! Nem tévesztendő össze a szorzással, ami tényleg működhet 1 ciklus alatt is...
A hozzászólás módosítva: Okt 21, 2021
(#) Skori válasza sdrlab hozzászólására (») Okt 21, 2021 /
 
Idézek az STM32F103 adatlapjáról (legelső oldal):
Features
• ARM® 32-bit Cortex®-M3 CPU Core
– 72 MHz maximum frequency, 1.25 DMIPS/MHz (Dhrystone 2.1) performance at 0 wait state memory access
Single-cycle multiplication and hardware division

Nekem ez azt jelenti, hogy 1 órajel (single-cycle) ciklus (tehát kb. 14nanosec) ideig tart a szorzás és az osztás is. De fejtsd ki nyugodtan, hogyha szerinted ez mást jelent.

Véleményem szerint ha az osztás több ciklus lenne akkor külön kellett volna írni, valahogy így:
– Single-cycle multiplication
- Hardware division
A hozzászólás módosítva: Okt 21, 2021
(#) sdrlab válasza Skori hozzászólására (») Okt 21, 2021 / 1
 
Idézet:
„Single-cycle multiplication and hardware division”

Ezt kellene jobban értelmezni! Ez annyit jelent, hogy 1 ciklus alatt szoroz, de nem 1 ciklus alatt oszt, hanem erre ugyan van benne hardver, de az nem 1 ciklus alatt végez vele....
(#) majkimester válasza Skori hozzászólására (») Okt 21, 2021 / 2
 
Ne feledd, hogy másodpercenként 2x-5x akarod megjeleníteni az adatot, azaz 200..500mS-onként kell egy 85usec-es számolás float-tal, de én fixpontos szorzás osztást használnék ami meg még gyorsabb. Ez az egész az AVR-nek is gyerekjáték. Az STM32 egy 32 bites kontroller, egész más kategória, de ez a feladat még az AVR-nek is bőven az egyszerű dolgok közé tartozik.

Az rpmcerrection-ös hozzászólásodat már csak utána láttam, de emiatt már nem módosítottam.

Az AVR-ben is van egyébként hardver szorzó, 2 órajel a 8 bitre. Osztás viszont nincs. Ezért is írtam így: 60000000L / (tachotime * TACHOPULSES) ahelyett, hogy: 60000000L / tachotime / TACHOPULSES, hogy csak 1 osztás legyen, ami általában lassabb művelet mint a szorzás.

Az STM32-ben Cortex M3 mag van ami elvileg az alábbi órajel alatt oszt és szoroz:

Multiply 32 1 or 2
MUL, MLA, and MLS. MUL is one cycle and MLA and MLS are two cycles.

Multiply with 64-bit result 32 3-7[]
UMULL, SMULL, UMLAL, and SMLAL. Cycle count based on input sizes. That is, ABS(inputs) < 64K terminates early.

Divide 32 2-12[]
SDIV and UDIV. 32/32 divides both signed and unsigned with 32-bit quotient result (no remainder, it can be derived by subtraction). This earlies out when dividend and divisor are close in size.

azaz a Single-cycle multiplication and hardware division azt jelenti, hogy 1 órajel alatt szoroz, és van hardware osztás, ami nem 1 órajel. Ez fix pontos szorzás és osztás, lebegőpontos ott is tovább tart.
A hozzászólás módosítva: Okt 21, 2021
(#) djusee válasza sdrlab hozzászólására (») Okt 21, 2021 / 1
 
Sziasztok, ha jól értelmezem az ARM leírást akkor 2 től 12 órajelet vesz igénybe az osztás, a szorzás 1 től 7 órajelet.

Úgy tünik Majkimester gyorsabb volt
A hozzászólás módosítva: Okt 21, 2021
Következő: »»   706 / 838
Bejelentkezés

Belépés

Hirdetés
Lapoda.hu     XDT.hu     HEStore.hu
Az oldalon sütiket használunk a helyes működéshez. Bővebb információt az adatvédelmi szabályzatban olvashatsz. Megértettem