Fórum témák

» Több friss téma
Fórum » AVR - Miértek hogyanok
WinAVR / GCC alapszabályok:
1. Ha ISR-ben használsz globális változót, az legyen "volatile"
2. Soha ne érjen véget a main() függvény
3. UART/USART hibák 99,9% a rossz órajel miatt van
4. Kerüld el a -O0 optimalizációs beállítást minden áron
5. Ha nem jó a _delay időzítése, akkor túllépted a 65ms-et, vagy rossz az optimalizációs beállítás
6. Ha a PORTC-n nem működik valami, kapcsold ki a JTAG-et
Bővebben: AVR-libc FAQ
Lapozás: OK   617 / 617
(#) fecus hozzászólása Aug 13, 2014 /
 
Van egy nixie órám. Ha mp-ként futtatom az interrupt-ot akkor szépen dolgozik.
Szeretném 0,5 mp-ként meghívni az IT-t és csak minden 2. alkalommal elvégezni az óra kiszámítását. Ha így teszek egyszerűen, véletlenszerűen megbolondul és csak 9-ig számol. Utána sem állítani nem lehet, sem a normál lépését sem végzi el. Néha csak az óra néha csak a perc, néha mindkettő. Néha elmegy 19-ig és ott áll meg.
A különbség csak a kommentel tiltott (//) if utasítás és a vált növelése. Ha van if akkor bolond, ha nincs működik.
A kód:
  1. ISR(TIM1_COMPA_vect )
  2. {
  3.         cli();
  4.  
  5.         int but1 = 0x00;
  6.         int but2 = 0x00;
  7.         int LIGHT = 0x00;
  8.        
  9.         // két gomb beolvasása + óra beállító léptetése:
  10.         but1 = ~PINA & 0x03;                    // look at two buttons, invert
  11.         _delay_ms(20);
  12.         but2 = ~PINA & 0x03;                    // look at two buttons, invert
  13.        
  14.         if (but1 == but2)
  15.         {
  16.                 switch (but1)
  17.                 {
  18.                         case 0x01:
  19.                                 perc_egyes++;         // +1 perc
  20.                                 mp_egyes = 0x00;                // mp újraindul
  21.                                 mp_tizes = 0x00;                // mp újraindul
  22.                         break;
  23.                         case 0x02:
  24.                                 ora_egyes++;            // +1 óra
  25.                                 mp_egyes = 0x00;                // mp újraindul
  26.                                 mp_tizes = 0x00;                // mp újraindul
  27.                         break;
  28.                 }
  29.         }
  30.        
  31.         //Fénymérő beolvasása + kettőspont flag ki- bekapcsolása:
  32.         LIGHT=Average();
  33.        
  34.         switch (LIGHT)
  35.         {
  36.                 case 0 ... 240:
  37.                 light_on = 0xF0;                                //villogás be
  38.                 break;
  39.                 case 246 ... 255:
  40.                 light_on = 0x00;                                //villogás ki (sötét van)
  41.                 break;
  42.         }
  43.        
  44.         // kijelző fényerő szabályzása:
  45.         // (255-LIGHT)*2,5 +55
  46.         temp = 255 - LIGHT;
  47.         temp *= 25;
  48.         temp /= 10;
  49.        
  50.         temp += 55;
  51.  
  52.         if (temp < 0x37)
  53.         {
  54.                 temp = 0x37;
  55.         }
  56.        
  57.         if (temp > 0xFE)
  58.         {
  59.                 temp = 0xFF;
  60.         }
  61.        
  62.         OCR0A = temp;
  63.  
  64.         BYTE4 |= 0b00100000;                // kettőspont ki
  65.        
  66. //      if (valt & 0b00000001)
  67. //      {
  68.                 // idő kiszámolása és léptetése:
  69.                 mp_egyes++;                         //+1 másodperc
  70.                
  71.                 if (mp_egyes == 10)
  72.                 {
  73.                         mp_tizes++;
  74.                         mp_egyes = 0x00;
  75.                 }
  76.                
  77.                 if (mp_tizes == 6)
  78.                 {
  79.                         perc_egyes++;
  80.                         mp_tizes = 0x00;
  81.                 }
  82.                
  83.                 if (perc_egyes == 10)
  84.                 {
  85.                         perc_tizes++;
  86.                         perc_egyes = 0x00;
  87.                 }
  88.                
  89.                 if (perc_tizes == 6)
  90.                 {
  91.                         ora_egyes++;
  92.                         perc_tizes = 0x00;
  93.                 }
  94.        
  95.                 if (ora_egyes == 4 && ora_tizes == 2)
  96.                 {
  97.                         ora_tizes = 0x00;
  98.                         ora_egyes = 0x00;
  99.                 }
  100.        
  101.                 if (ora_egyes == 10)
  102.                 {
  103.                         ora_tizes++;
  104.                         ora_egyes = 0x00;
  105.                 }
  106.                
  107.         writeout_all();
  108.         _delay_ms(450);
  109.                
  110.                 if (light_on == 0xF0)
  111.                 {
  112.                         BYTE4 &= 0b11011111;            // kettőspont be ha világos van
  113.                 }
  114.                
  115. //      }
  116.        
  117.         writeout_all();
  118. //      valt ++;                        // váltás a mp másik felére az utolsó bittel (páros/páratlan)
  119.         sei();
  120. }

Létezik, hogy több if egymásban vagy több if az IT rutinban bizonytalanságot okoz? Veremhiba?
A hozzászólás módosítva: Aug 13, 2014
(#) Lpi válasza fecus hozzászólására (») Aug 13, 2014 /
 
Hali,
Csak ránéztem a kódra, de szemet szúrt, hogy van egy delay az ISR-ben. Az ilyen megoldás kerülendő, mert kevés idő marad a főprogramra, vagy más megszakításokra.
Esetedben valószínűleg éppen ez okozza a hibát, mert 450ms-ig áll a program, és ha 500ms-enként akarod meghívni az ISR-t a többi műveletre nem elég az 50msec, és mivel a függvény végén nullázod a flag-et, a következő megszakítás kimarad.
Ha én írnám a kódot, a timer-t 100msec-re állítanám be, és minden 10. futásra állítanék egy flag-et, amit a főprogram vizsgálna, és ott lenne az óra beállítása, flag törlése, kettőspont (ez szintén flag, csak 5-ös osztással) és a többi.
(#) fecus válasza Lpi hozzászólására (») Aug 14, 2014 /
 
Elnézést, de a kódban benne maradt a workaround. Az eredeti kódban nincs 450ms delay csak a 20ms prellmentesítő. Ezt kéretik nem figyelembe venni:
  1. writeout_all();
  2.         _delay_ms(450);

Azért hívtam meg 500ms-re mert így villogtatnám a kettőspontot. Mellesleg az működik, úgyhogy az IT meghívása rendben zajlik.
Workaround: kínomban 1mp-enként hívom a rutint és 480ms-t várok majd frissítem a kijelzést. Ettől villog a jel. De így 480ms-t elbukom mert nem megy le idle állapotba.

Pontosan erről kérdeztem a program megírása előtt itt a fórumon és ha visszanézed nem volt határozott álláspont.
Nem sokból tart átírni. A hétvégén megcsinálom.
Így még a beállítás sebességét is pontosítani tudom 10 lépésben.
Köszönöm.
(#) csabeszq válasza fecus hozzászólására (») Aug 14, 2014 /
 
Hogy csinálsz veremhibát a fenti kódban?

1) az interruptban szöszmötölsz delay_ms-sel, meg minden mással
2) az interrupt végén meghívod a sei-t

Ez a kettő garantált veremhibát eredményez. Interruptban se a cli-t, se a sei-t nem kell meghívni.
Meghívódik a timer interrupt, elkezdesz benne időthúzni, mégegyszer lejár a timer, de ez még nem lenne baj, mert amint kilép az interrupt, azonnal újrameghívódna, nem lenne veremhiba.

De te elengeded az interruptot sei()-vel az interrupt befejezése előtt, ami azt eredményezi, hogy ahelyett, hogy kitakarítaná a vermet, azonnal újra meghívódik az interrupt és néhány ciklus után túlcsordul.

Ha nem lenne sei, az MCU másodpercenként 2-3 utasítást végrehajtana.

Két hiba összege, amit látsz. Interruptban a delay_ms(1) is brutális késleltetés, mondjuk 16 MHz alatt 16000 ciklust zabál el értelmetlenül. Delay-t nem raksz interruptba, se kicsit, se nagyot.
A hozzászólás módosítva: Aug 14, 2014
(#) fecus válasza csabeszq hozzászólására (») Aug 15, 2014 /
 
Köszönöm. Értettem.
Akkor megy ki a cucc a main-be. Ahogy Lpi írta szaporán It-zek, flag-ezek aztán számolgatok mikor ki fusson le a szükséges rutinok közül.
Akkor az valószínű, hogy nem az egymásba ágyazott if-ek okoznak gondot, ugye? Azt továbbra is használhatom a főprogramban?
A főprogram végén maradhat az idle, hogy a fölös időben ne egyen olyan sokat?
(#) KDavid753 hozzászólása Aug 15, 2014 /
 
Sziasztok, lehet hogy ez nem ebbe a témába tartozik, de az lenne a kérdésem, hogy az ATTINY13-20PU többször felprogramozható? (kezdő vagyok)
(#) kala1982a válasza KDavid753 hozzászólására (») Aug 15, 2014 /
 
10000-szer, adatlapjában benne van.

attiny13.jpg
    
(#) fecus válasza fecus hozzászólására (») Aug 15, 2014 /
 
Hát nem megy. Valami más a baj és nem tudok rájönni. Most az alábbi kód is megállt 19:49-nél és sehova tovább:
  1. ISR(TIM1_COMPA_vect )
  2. {
  3.         IT_count ++;                // +1 IT
  4. }
  5.  
  6. int main(void)
  7. {
  8.         initmaster();
  9.         InitADC();
  10.         InitPWM();
  11.         Init_Timer1();
  12.         set_sleep_mode(SLEEP_MODE_IDLE);
  13.         sei();              // enable global interrupts
  14.        
  15.         while(1)
  16.         {
  17.         cli();
  18.        
  19.         int but1 = 0x00;
  20.         int but2 = 0x00;
  21.         int LIGHT = 0x00;
  22.        
  23.         // két gomb beolvasása + óra beállító léptetése:
  24.         if ( IT_count == 4 || IT_count == 9 )
  25.         {
  26.                 but1 = ~PINA & 0x03;        // look at two buttons, invert
  27.                 _delay_ms(20);        // prellmentesítés
  28.                 but2 = ~PINA & 0x03;        // look at two buttons, invert
  29.                
  30.                 if (but1 == but2)
  31.                 {
  32.                         switch (but1)
  33.                         {
  34.                                 case 0x01:
  35.                                         perc_egyes++;      // +1 perc
  36.                                         mp_egyes = 0x00;        // mp újraindul
  37.                                         mp_tizes = 0x00;        // mp újraindul
  38.                                 break;
  39.                                 case 0x02:
  40.                                         ora_egyes++;        // +1 óra
  41.                                         mp_egyes = 0x00;        // mp újraindul
  42.                                         mp_tizes = 0x00;        // mp újraindul
  43.                                 break;
  44.                         }
  45.                 }
  46.  
  47.                 if (light_on == 0xF0)
  48.                 {
  49.                         BYTE4 &= 0b11011111;    // kettőspont be ha világos van
  50.                 }
  51.         }
  52.        
  53.         //Fénymérő beolvasása + kettőspont flag ki- bekapcsolása:
  54.         if ( IT_count == 9 )
  55.         {       
  56.                 LIGHT=Average();
  57.        
  58.                 switch (LIGHT)
  59.                 {
  60.                         case 0 ... 240:
  61.                                 light_on = 0xF0;        //villogás be
  62.                         break;
  63.                         case 246 ... 255:
  64.                                 light_on = 0x00;        //villogás ki (sötét van)
  65.                         break;
  66.                 }
  67.  
  68.                 // kijelző fényerő szabályzása (255-LIGHT)*2,5 +55:
  69.                 temp = 255 - LIGHT;
  70.                 temp *= 25;
  71.                 temp /= 10;
  72.                
  73.                 temp += 55;     
  74.        
  75.                 if (temp < 0x37)
  76.                 {
  77.                         temp = 0x37;
  78.                 }
  79.                
  80.                 if (temp > 0xFE)
  81.                 {
  82.                         temp = 0xFF;
  83.                 }
  84.                
  85.                 OCR0A = temp;
  86.  
  87.                 BYTE4 |= 0b00100000;            // kettőspont ki
  88.                
  89.                 // idő kiszámolása és léptetése:
  90.                 mp_egyes++;                         //+1 másodperc
  91.  
  92.                 if (mp_egyes == 10)
  93.                 {
  94.                         mp_tizes++;
  95.                         mp_egyes = 0x00;
  96.                 }
  97.  
  98.                 if (mp_tizes == 6)
  99.                 {
  100.                         perc_egyes++;
  101.                         mp_tizes = 0x00;
  102.                 }
  103.  
  104.                 if (perc_egyes == 10)
  105.                 {
  106.                         perc_tizes++;
  107.                         perc_egyes = 0x00;
  108.                 }
  109.  
  110.                 if (perc_tizes == 6)
  111.                 {
  112.                         ora_egyes++;
  113.                         perc_tizes = 0x00;
  114.                 }
  115.  
  116.                 if (ora_egyes == 4 && ora_tizes == 2)
  117.                 {
  118.                         ora_tizes = 0x00;
  119.                         ora_egyes = 0x00;
  120.                 }
  121.  
  122.                 if (ora_egyes == 10)
  123.                 {
  124.                         ora_tizes++;
  125.                         ora_egyes = 0x00;
  126.                 }
  127.         }
  128.        
  129.         writeout_all();
  130.        
  131.         if ( IT_count == 9 )
  132.         {
  133.                 IT_count = 0;
  134.         }
  135.         sei();
  136.         sleep_mode();
  137.         }
  138. }

Most nincs több ötletem. Valami mégiscsak az if-ekkel lesz. A következő indulás után a 09:19-nél akadt ki amikor be akartam állítani. Ez nem a kód logikájában lesz
(#) gtk válasza fecus hozzászólására (») Aug 15, 2014 /
 
A fejlesztes folyaman erdemes bizonyos program reszeket kulon kulon tesztelni es utanna osszerakni egy nagyobb programot belole es igy tovabb. Az extrak maradnak a vegere (esetedben sleep, stb) A konstansokat nevezd el (C-ben #define nev ertek), ugyanigy a gombokat es maszkjait is. Nincs az a pihent ember aki bitenkent vegignezi a kodot manapsag a forumon, mert sok ido es energia. Ha mar IT-zel, ne hasznalj delayt. A delay csak anyit csinal hogy megeszi adott ideig a proci idot, semmi szukseg ra, kezdo, tudatlan programozo hasznalja csak. (Inicializalasoknal hasznalhato, mert az csak egyszer fut le)
(#) fecus válasza fecus hozzászólására (») Aug 15, 2014 /
 
Mindenkinek köszi. Megvan a hiba. Akkor akadt ki amikor felgyorsítottam a beállításkor a számlálást olyan állapotba került, amit a számláló programrészlet nem tudott kezelni (9-ről 11-re ugrott egy mp alatt). Ettől szétesett. Nem az if vagy az IT tette hanem ha 1mp-cel futott a beállítás akkor jó volt ha pörgettem nem.
Kicseréltem a feltételeket = helyett > -ra és láss csodát megy.
Úgy jártam mint a tudós és a bolha. Rossz következtetést vontam le a kísérletekből.
(#) fecus válasza gtk hozzászólására (») Aug 15, 2014 /
 
Majd szétnézek a Neten más prellmentesítő algoritmus után. Minden más delay-t töröltem.
(#) zombee válasza fecus hozzászólására (») Aug 15, 2014 /
 
zombee féle hiszterézises prellmentesítés - az algoritmus:

- csinálj egy időzítő interruptot, abban vizsgáld a nyomógombokat(akár többet is)
- minden nyomógombhoz tartozzék egy számláló (elég 8 bites)
- ha egy gomb le van nyomva, a hozzá tartozó számlálót növeled 1-el ha nem érte el a "maximumot"
- ha egy gomb nincs lenyomva, csökkented a számlálóját (kivéve akkor ha nulla)
- ha egy gomb számlálója ÉPPEN elérte a "maximumot", egy jelzőbitet 1-esre állítasz(LENYOMVA)
- ha egy gomb számlálója ÉPPEN kisebb lesz mint a "minimum", 0-ra állítod (FELENGEDVE)

A jelzőbitek lehetőleg "volatile" változókban legyenek, a számlálók lehetnek "sima" globális
változók mivel csak az interruptból lesznek használva. Pár paraméter:
- az interruptot 1-2 ms közé érdemes beállítani
- MAXIMUM = 25
- MINIMUM = 19
(#) rolandgw válasza fecus hozzászólására (») Szo, 11:06 /
 
Itt találsz párat, a Dannegger féle hasonló,mint amit zombee javasolt.
(#) gtk válasza fecus hozzászólására (») Szo, 18:50 /
 
Nem kell bonyolult dolgokra gondolni. Ha mar van egy megszakitas beallitva, ami eleg gyorsan fut be ahhoz hogy egy gombot be tudj olvasni mar meg is van oldva a problema egy resze. Nehan 10ms-onkent kell megnezni hogy az adott gomb milyen allapotban van. Ha az IT-d gyorsabb, akkor novelsz a megszakitasban egy szamlalot. A main()-ben pedig vizsgalod, hogy a szamlalod elert-e egy bizonyos erteket (ez az ertek elore kiszamolhato az IT idobol), ha elerte kinullazod azt es beolvasod a gomb(ok) allapotat.
(#) rolandgw hozzászólása Vas, 8:05 /
 
Üdv ! A Studio4-ben használható a legfrissebb Toolchain ,vagy csak nálam fagy a szimulációban ?
(#) rolandgw válasza rolandgw hozzászólására (») Hé, 10:33 /
 
Csak a 3.3.1-ig megy,telepíthetem újra a 6-ost. Miért pont visual studio ?
(#) Vfr72 hozzászólása Sze, 21:52 /
 
üdv. Mindenkinek!
Nem készülő projekttel kapcsolatban, csak gondolati síkon érdekel a válasz.
Ha nem tudom beállítani a megszakítások prioritását, akkor hogy kezelem le azt az esetet, amikor egy megszakítást kiszolgáló rutin éppen fut, de számomra éppen beérkező más típusú megszakítás fontosabb?

üdv. VFR72.
(#) zombee válasza Vfr72 hozzászólására (») Sze, 22:47 /
 
A "nem fontosabb" megszakításrutin elejére teszel egy "sei();"-t.
(#) Vfr72 válasza zombee hozzászólására (») Sze, 23:15 /
 
A sei(); nem a globális megszakítás engedélyezése?
(#) TavIR-AVR válasza Vfr72 hozzászólására (») Csü, 6:23 /
 
Figyeled a megszakításban a számodra fontosabb megszakítás jelzőbitjét. És
- átugrasz és végrehajtod és nullázod,
- a futó megszakításodat lezárod, az alacsonyabb prioritású végrehajtódik és a végén az abbahagyott jelzőbitjét újra bebillented.


Melyik INTekről van szó? Hátha van más megoldás...
A hozzászólás módosítva: Csü, 6:23
(#) Vfr72 válasza TavIR-AVR hozzászólására (») Csü, 11:20 /
 
Szervusz!

Általánosságban érdekel a dolog, de nézzünk egy konkrét esetet:
RS232 porton megszakítással fogadom a karaktereket, ez a megszakítás fontos, mert nem dobhatok el egy karaktert sem, de mindeközben fut egy időzítő is, ami alárendelt szerepet játszik a történetben.
A kérdés az, hogy megszakításon belül tudok-e tiltani egy másikat?

Azaz:
- jön a karakter
- megszakítási rutinra ugrok
- tiltom a timert
- elvégzem a megszakításban a feladatot (karakter ment, számláló inkrementál)
- engedélyezem a timert
(#) TavIR-AVR válasza Vfr72 hozzászólására (») Csü, 12:29 /
 
A soros buffer 3 byte + a vételi buffer. Mindez HW-ből.
Nem.

Megszakítas jon, timerre ugrasz. Végrehajtod. A rutin max ideje 1-2 karakter vétele.
A timer lefutott, akkor kilépés után azonnal a soros INT-re ugrik.
(#) steelgoofy hozzászólása Csü, 15:03 /
 
Sziasztok,
Egy projektben, egyszerre több nMOSFET-et kell vezérelnem, PWM jellel. Ehhez egy arduino és 74HC126-típusú IC-k vannak, mindegyik Mosfethez ugyan az a PWM jel kell, a probléma a kapcsolgatással van. Az IC elég egyszerű, minden 'A' bemenethez megy ugyan az a PWM jel az Arduinoból, és mindegyik PWM jelet egy digitális jellel engedélyezek, hogy mehet e ez a jel a Mosfetre, a baj az, hogy amikor a PWM jelet nem engedélyezem, az IC nem tökéletessége miatt a kimenetén ilyenkor is megjelenik egy kb 0,5 V feszültség ami a Mosfetet már nyitja, holott éppen ilyenkor zárt állásban kellene lennie. Ebben szeretnék segítséget kérni, hogyan lehetne, hogy nem engedélyezett jel mellett a Mosfet Gatjére ne kerüljön feszültség, 0V-on legyen, egyébként pedig 0-5 V-ig vezérelhető a gate a PWM jelnek megfelelően.

LDL.png
    
(#) csabeszq válasza Vfr72 hozzászólására (») Csü, 15:18 /
 
Nem mindig tudod megcsinálni.

I2C alatt használtam ilyet, ott hellyel-közzel be lehet rakni a sei()-t, mert amíg le nem kezeled, addig a a TWINT 1-ben van és fogja a buszt (a STOP jelet külön kellett kezelni, ott nem jó a sei).

Baromi veszélyes, mert könnyen stack túlcsorduláshoz vezet.

Timer esetén sei szintén megy, de előtte tiltsd a timer interruptot. Egy cli után meg interruptból visszakapcsolhatod a timer interruptot.
A hozzászólás módosítva: Csü, 15:20
(#) TavIR-AVR válasza steelgoofy hozzászólására (») Csü, 15:19 /
 
A PWM _NEM_ 0...5V folyamatos jel. Vagy 0V vagy 5V és ezek aránya változik!
Diódával lehúzni még 0.5V-ot?
(#) Vfr72 válasza TavIR-AVR hozzászólására (») Csü, 21:12 /
 
Részleteznéd, hogy mire gondoltál?
Következő: »»   617 / 617
Bejelentkezés

Belépés

Hirdetés
Frissek
2014. Aug, 22. Pé
1:58:52
Jelenleg 60 fő olvassa az oldalt
Online tagok:
Lapoda.hu     XDT.hu     HEStore.hu