Fórum témák

» Több friss téma
Fórum » AVR - Miértek hogyanok
 
Témaindító: pakibec, idő: Márc 11, 2006
Témakörök:
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   467 / 840
(#) blackdog válasza mzozo95 hozzászólására (») Aug 11, 2012 /
 
Melyik cikkre gondolsz mert nem találom.
Tettem bele késleltetést, de lehet rossz helyre mert nem jó a dolog.

  1. .....
  2. #define LED_ON  PORTC |=  (1<<PINC0)
  3. #define LED_OFF PORTC &= ~(1<<PINC0)
  4. #define LED_STAT (PINC & _BV(PC0))
  5. #define BTN1  !(PIND & _BV(PD5))
  6. ....
  7.  
  8. if (BTN1) {
  9. _delay_ms(500);
  10.  
  11.     if (!LED_STAT)  { LED_ON; }
  12.  
  13.     else if( LED_STAT) { LED_OFF; }
  14. }
(#) zombee válasza blackdog hozzászólására (») Aug 11, 2012 /
 
Hello!

A késleltetéssel - legtöbb esetben - csak baj van, egyedül a legegyszerűbb eseteknél nem gond.

Nagyon rossz minőségű gomboknál előfordul hogy nyomva tartás közben is pereg.
Ezeket olcsóbb cserélni mint kódot írni rá!

Szűrő: a legegyszerűbb ha teszel egy pár száz nF-os kondit a kapcsoló két kontaktja közé. Sajna most nincs előttem az a logaritmusos képlet amivel meghatározható a töltődés ideje, ezért próbálgatni kell!

Alulmintavételezés: a késleltetős megoldáson alapul, tehát a mintavétel ritkábban történik
mint a pergés ideje lenyomáskor/felengedéskor. Ezt időzítő interrupttal lehet hatékonyan megoldani.

Hogy ne engedjelek el üres kézzel, adok egy kódot amiben késleltetés van. A késleltetés ideje 750us,
de a while ciklus maga is eszi a CPU-t, így egy ciklus kb. 1ms. Ez ugye nem elég, ezért figyelem
a nyomvatartási időt is. Ha eléri a BTIME_MIN (20ms) értéket csak akkor fogadjuk el a lenyomást.
Kis apróság, hogy ha eléri a BTIME_MAX értéket(2 sec) akkor az áramkör lekapcsolja magát...
  1. #define F_CPU 1000000
  2. #include<avr/io.h>
  3. #include<util/delay.h>
  4.  
  5. #define DYNAMO (1<<1)
  6. #define BUTTON (1<<3)
  7. #define DRIVER (1<<4)
  8.  
  9. #define DYNAMO_ON (PINB & DYNAMO)
  10. #define BUTTON_ON (PINB & BUTTON)
  11. #define DRIVER_ON  PORTB|=DRIVER
  12. #define DRIVER_OFF PORTB&=~DRIVER
  13.  
  14. #define DYNAMO_TIME 60000
  15. #define EXTRA_TIME 60000
  16. #define BTIME_MAX   2000
  17. #define BTIME_MIN   20
  18.  
  19. uint32_t timer = 0;
  20. uint8_t  button = 0;
  21. uint16_t btimer = 0;
  22.  
  23.  
  24. int main(void)
  25. {
  26.  
  27. //főciklus:
  28. while(1)
  29. {
  30.  
  31. if(timer)//ha megy az időzítő, meghajtás aktív!
  32. {
  33. timer--;
  34. DRIVER_ON;
  35. }
  36. else//ha lejárt az időzítő: alapállapot!
  37. {
  38. DRIVER_OFF;
  39. DDRB  = DRIVER;
  40. PORTB = 0;
  41. }
  42.  
  43. if(BUTTON_ON && !button)//gomb lenyomásakor
  44. {
  45. button = 1;
  46. btimer = 0;
  47. }
  48.  
  49. if(BUTTON_ON && btimer<BTIME_MAX)//gomb lenyomva tartásakor
  50. {
  51. btimer++;
  52. if(btimer==BTIME_MIN) timer+=EXTRA_TIME;//ha elérte az minimális időt, hozzáadja az időzítőhöz!
  53. }
  54.  
  55. if(!BUTTON_ON && button)//gomb felengedésekor...
  56. {
  57. button = 0;
  58. if(btimer==BTIME_MAX) timer=0;//hosszú nyomvatartáskor lekapcsol!
  59. }
  60.  
  61.  
  62. if(DYNAMO_ON && timer<DYNAMO_TIME)//töltés után is működik
  63. {
  64. timer = DYNAMO_TIME;
  65. }
  66.  
  67. _delay_us(750);//várakozási rész - kiegyenlített időzítés: ~1ms
  68.  
  69. }
  70. }
(#) trudnai válasza blackdog hozzászólására (») Aug 11, 2012 /
 
A "nem jo a dolog" helyett irdd mar le legyszi mit csinal vagy mit nem, mert igy nehez kitalalnunk mi nm stimmel

Ez nagyjabol jo, csakhogy figyelned kellene a gomb felengedeset, vagy pedig eltarolnod az elozo allapotot (hacsak nem vagy eleg gyors, es el nem engeded fel masodpercen belul). Amugy elegendo ugy 20-50 ms varakozas a legtobb gomb eseteben.
(#) zombee válasza trudnai hozzászólására (») Aug 11, 2012 /
 
Megerősítem! Késleltetős és számlálós módszernél is a gomb állapotát el kell tárolni,
másképp nem detektálható egy "lenyomás" vagy "felengedés".
Csak "le van nyomva" vagy "fel van engedve" állapotot lehet így lekérdezni!
(#) trudnai válasza zombee hozzászólására (») Aug 11, 2012 /
 
Lehet azt, csak akkor a felengedesig ott varakozol a felteltelen belul:

Bővebben: Link
(#) zombee válasza trudnai hozzászólására (») Aug 11, 2012 /
 
Csak akkor a rendszerben lesz egy kis késleltetés, engem speciel idegesítene ha csak felengedés után
történik meg az, amiért a gombot lenyomtam. Ha meg lenyomásra vár akkor szintén blokkolva van.
Ez csak akkor lehet jó, ha a programnak nincs semmi hasznos teendője a gomb lenyomásáig/felengedéséig.
(#) sikolymester válasza mzozo95 hozzászólására (») Aug 12, 2012 /
 
Az adatlapja donti el a minoseget. Minel alacsonyabb a ppm erteke, annal jobb.
(#) trudnai válasza zombee hozzászólására (») Aug 12, 2012 /
 
Pontosan! Nem a leg optimalisabb megoldas, hogy finom legyek. De hat tanulgatni jo ez is, meg hat vannak nagyon egyszeru alkalmazasok amibe teljesen mindegy hogyan oldjak meg a billentyu kezelest -- beallitasokhoz pl ahol nem szukseges hogy kozben tovabbra is menjen az alap funkcio, vagy be-ki kapcsolashoz, karaconyfa villogtatoba, stopper oraba stb elmegy igy is.
(#) zombee válasza trudnai hozzászólására (») Aug 12, 2012 /
 
Stopper órába?
Gondolom sütő-órára vagy bomba-visszaszámlálóra gondolsz és nem sportesemények segédeszközeire...
(#) blackdog válasza zombee hozzászólására (») Aug 12, 2012 /
 
Köszönöm a segítséget. Látom pár napja is ezzel bénázott valaki. Bővebben: Link
Ezekből is szemezgetek egy kicsit.
(#) blackdog válasza blackdog hozzászólására (») Aug 12, 2012 /
 
Nos, hogy teljes legyen. Itt jól kivesézi a srác a kérdést:Bővebben: Link
(#) blackdog válasza blackdog hozzászólására (») Aug 12, 2012 /
 
Az olvasottak alapján a következőt hoztam össze szoftveres pergésmentesítésre:
  1. #ifndef F_CPU
  2. #define F_CPU 1600000UL
  3. #endif
  4.  
  5. #include <avr/io.h>
  6. #include <util/delay.h>
  7.  
  8. int button_is_pressed();
  9. int Pressed = 0;
  10. int Pressed_Confidence_Level = 0;
  11. int Released_Confidence_Level = 0;
  12.  
  13. int button_is_pressed(int BTN_PIN, int BTN_BIT) {
  14.  
  15. if (bit_is_clear(BTN_PIN, BTN_BIT)) {
  16.   Pressed_Confidence_Level ++;
  17.  
  18.   if (Pressed_Confidence_Level >500) {
  19.     if (Pressed == 0) {
  20.         Pressed = 1;
  21.         Pressed_Confidence_Level = 0;
  22.         return 1;
  23.     }
  24.    Pressed_Confidence_Level = 0;
  25.   }
  26. } else {
  27.   Released_Confidence_Level ++;
  28.   if (Released_Confidence_Level >500) {
  29.     Pressed = 0;
  30.     Released_Confidence_Level = 0;
  31.   }
  32.  }
  33. return 0;
  34. }
  35.  
  36. int main(void) {
  37.  
  38.     DDRC= (1<<PINC0);
  39.     PORTC = (1<<PINC0);
  40.  
  41.     DDRD = (1<<PIND5);
  42.     PORTD = (1<<PIND5);
  43.  
  44.     while(1) {
  45.  
  46.        if (button_is_pressed(PIND, PD5)) {
  47.           PORTC ^= _BV(PC0);
  48.        }
  49.  
  50.    }
  51. }


Létrehoztam a button_is_pressed() függvényt így csak ezt kell paraméterezni és kész. A programban bárhol használható.
Tesztk alapján tökéletesen működik. Atmega168 az MCU 16MHz órajellel.
Mi a véleményetek? Esetleg programozástechnikai hiba? Még csak most szokom a C-t.
(#) sikolymester válasza blackdog hozzászólására (») Aug 12, 2012 /
 
Amúgy itt meglelhetők egész jó források pergésmentesítésre: Debounce Code - one post to rule them all
(#) mzozo95 válasza blackdog hozzászólására (») Aug 12, 2012 /
 
Pergésmentesítéshez olvasmány: Bővebben: Link
(#) blackdog válasza mzozo95 hozzászólására (») Aug 12, 2012 /
 
Olvastam, de én megszakítás nélkül szeretném. A mellékelt dolgot hogyan használod, ha PD2 (INT0) lábad már foglalt?
(#) zombee válasza blackdog hozzászólására (») Aug 12, 2012 /
 
Kérdés, milyen IC-d van, pl. van-e rajta INT1, INT2, stb.
Ezen kívül még van a PCINT, ha erre csak 1 kimenetet állítasz be akkor olyan mint ha egy INT lenne.
Még van az ICP1 is, erre is beállíthatsz interruptot. Illetve van az analóg komparátor, de ehhez 2 láb kell)...
(#) blackdog válasza zombee hozzászólására (») Aug 12, 2012 /
 
atmega168 és a gombok 11, 12, 13, 14 lábakon vannak. De ez csak próba panel tehát általános megoldást keresek. Amit készítettem az is bugos kicsit.
(#) trudnai válasza blackdog hozzászólására (») Aug 12, 2012 /
 
Ez mukodhet, es jo lehet, csak azt a magabiztossagi valtozot kell beloni jol minden alkalmazashoz. Nyilvan a gomb lekerdezgetese fog attol is fuggeni, hogy a fo ciklusodban a tobbi elem mennyit idozik -- jelen esetben ez elhanyagolhato. De ha oda bekerul egy par-tiz ezredmasodperces kesleltetes (pl LCD-re kiiras de lehet az barmi mas is), akkor mar jelentosen none a lekerdezesek kozott eltelt ido. Tehat ha csak minden 10ms-ben kerdezgeted le, akkor 10ms * 500 = 5s ami kicsit sok lenne

Egy hibat azonban felfedeztem: Mindket Confidence Levelt torolnod kellene megnyomaskor ill felengedeskor! Pl a gombot nem nyomod meg, akkor ugye a Release_Confidence_Level elkezd novekedni, es minden 500. alkalommal torlodik. De ha pl a 250. alkalomnal magnyomtad a gombot, akkor felengedeskor mar csak 250-et var, magyarul lehet meg a perges elott ugy dontesz minden rendben van...
(#) tamas 88 hozzászólása Aug 13, 2012 /
 
Sziasztok!
Puli122 AVR-es tesztpaneljét építettem meg és az lenne a kérdésem, hogy milyen típusú kijelző kell hozzá, mert csak annyi van megadva, hogy olyan kivitelű, amin oldalt vannak a kivezetések, úgy meg nem kérhetek.
Előre is köszönöm!
(#) sikolymester válasza blackdog hozzászólására (») Aug 13, 2012 /
 
Én a következő megoldást használom:

~50 ms késletetéssel hívok meg egy függvényt. Ez a gombok állapotát vizsgálja. Amennyiben egy gomb egymás után ugyanazt az állapotot adja, tehát 100ms eltéréssel, akkor le van nyomva. A felengedést hasonlóan vizsgálja.

De végeredményben a logikája teljesen mindegy, a fontos az, hogy mindez valamelyik timer interruptjából hívódik meg fix időközönként. A kódom természetesen nagyon gyorsan lefut. Ha nem tudsz olyan hatékony kódot írni és félsz, hogy sokat időzöl egy nagy prioritású interruptban, akkor csak egy flaget bökjél meg, aztán a main ciklusban vizsgáld az állapotokat.
(#) blackdog hozzászólása Aug 13, 2012 /
 
Sziasztok!

Most inkább ez talán programozás technikai kérdés. Kezdő vagyok még C-ben is.
Építettem egy teszt panelt, hogy kipróbáljam az ötleteim. Ezen van egy atmega168. Amit csinálok:
SPI-n keresztül vezérlek egy Shift regisztert 74HC595 ami vezérel egy tranzisztor mezőt ULN2804 ami reléket kapcsol ki-be a hozzájuk tartozó nyomógombok segítségével. Ezt az egészet még megfűszereztem egy RS232 vezérléssel majd C#-ban is készítettem neki kezelőfelületet. Most szeretném gatyába rázni a kódot az AVR-en. A relék vezérlésénél bizonytalanodtam el.
Létrehoztam egy változót:
  1. unsigned char releal;

Alap értéket is kapott:
  1. releal = 0x00;

Mikor lenyomom a reléhez tartozó gombot akkor beállítom a szükséges bit-et
  1. releal ^= (1<<0)

Itt pont az első reléhez tartozó módosítás látható.
Kérdésem, hogy jó ez így, hogy a releal változó az unsigned char ? Nekem az a fontos, hogy egy 8 bit-es vagyis 1 byte-os változóban tudjam tárolni az összes relé állapotát és innen kezelni. Remélem érthetően fogalmaztam. Új még nekem a C világa és kicsit fáradt is vagyok.

sikolymester
Még csiszolgatok a pergésmentesítésen mert nem az igazi, ha több gombot kezelek és nem csak egy ledet kapcsolok. Most az IF feltételek végére beszúrtam egy _delay_ms(250); sort és így egyenlőre jó, de javítanom kell még rajta.
(#) trudnai válasza blackdog hozzászólására (») Aug 13, 2012 /
 
Igen, jo az ugy. De hasznalhatsz uint8_t -t is akar, illetve definialhatsz magdnak tipust:

  1. #typedef uint8_t byte;
  2.  
  3. byte releal = 0;


Nezd meg, hogy a deklaracios sorban is lehet inicializalni a valtozot - ez amiatt jo, mert igy azonnal latod, hogy nem felejtetted el ezt megtenni... Azonkivul a foditok az ilyen inicializalgatasokat optimalizalva vegzik el, igy gyorsabb, mintha egyesevel tenned meg ugyanezt.
(#) sgt válasza Robi98 hozzászólására (») Aug 14, 2012 /
 
De komolyan. Rossz nézni ahogy szenvedsz. Használd már azt az átkozott timert és tegyél alá egy state machinet.
Az ilyenek:
  1. while(!(PINB & (PB6)))
  2. {
  3. DDRB|=(1<<PB6);
  4. _delay_ms(25);
  5. DDRB&=~(1<<PB6);

meg az ilyenek:
  1. _delay_ms(500);
  2. _delay_ms(500);
  3. _delay_ms(500);
  4. _delay_ms(500);

elkerülése végett, mert frászt kapok ha ránézek.

Itt egy állapot gépre egy példa. Ez egy forgalmi lámpa megvalósítása:
  1. volatile unsigned char count = 0;
  2. volatile bool start = false;
  3.  
  4. ISR(INT0_vect)
  5. {
  6. start = true;
  7. }
  8.  
  9. ISR(TIMER0_OVF_vect)
  10. {
  11. count++;
  12. TCNT0 = 100;
  13. }
  14.  
  15. int main(void)
  16. {
  17. init();
  18.  
  19. unsigned char limit = 4;
  20. bool event = false;
  21. enum STATES {stop, get_ready, ready, attention, idle} state;
  22.  
  23. state = idle;
  24.  
  25. while(1)
  26. {
  27. if(start)
  28. {
  29. state = attention;
  30. start = false;
  31. limit = 0;
  32. }
  33.  
  34. if(limit <= count)
  35. {
  36. event = true;
  37. count = 0;
  38. }
  39.  
  40. if(event)
  41. {
  42. switch(state)
  43. {
  44. case idle:
  45. PORTC ^= (1<<YELLOW);
  46. break;
  47.  
  48. case stop:
  49. PORTC = (1<<RED);
  50. state = get_ready;
  51. limit = 10;
  52. break;
  53.  
  54. case get_ready:
  55. PORTC = (1<<RED)|(1<<YELLOW);
  56. state = ready;
  57. limit = 4;
  58. break;
  59.  
  60. case ready:
  61. PORTC = (1<<GREEN);
  62. state = attention;
  63. limit = 3;
  64. break;
  65.  
  66. case attention:
  67. PORTC = (1<<YELLOW);
  68. state = stop;
  69. limit = 3;
  70. break;
  71. }
  72. event = false;
  73. }
  74. }
  75. }

Nyomógombbal mindennel együtt, és frankón működik.
(#) blackdog válasza (Felhasználó 15355) hozzászólására (») Aug 15, 2012 /
 
Szia!

Én atmega168-at használok gyakorláshoz. Próbapanelen csináltam egy teszt áramkört és ez van benne DIP28 tokkal.

[off] Sikerült összehozni a programozást?
(#) blackdog hozzászólása Aug 15, 2012 /
 
Sziasztok!

Gondom támadt az SPI-vel. MCU: Atmega168 Freq.: 16 MHz
Az SPI-n keresztül vezérlem a 74hc595 shift regisztert ami egy uln2804 tranzisztormezőt vezérel. Szépen működik is a dolog. Hibát akkor észleltem mikor használni szerettem volna a maradék B portot. Konkrétan PB0 és PB1.
PB0-ra egy nyomógombot kötöttem, PB1-re egy LED-et.
Nos az utóbbi nem működik.
SPI init:
  1. SPI_DDR = (1<<PB3)|(1<<PB5)|(1<<PB2);
  2. SPCR = (1<<SPE)|(1<<MSTR)|(1<<SPR0);
  3. SPI_PORT |= (1<<SPI_74HC595_CS);
  4.  
  5. SPI_74HC595_Write(0);


A LED init:
  1. DDRB = (1<<PINB1);
  2. PORTB = (1<<PINB1);


Ha LED init az SPI init elé kerül akkor működik, de nagyon halványan. Ha viszont az SPI init után teszem akkor a működés teljesen összezavarodik. Mi lehet a gond?

Másik kérdés:
Bővebben: Link Itt azt írják a 6.oldalon, hogy SPI/ISP közös használatakor használjunk soros védőellenállást. Én 10k tettem be.
A gond az, hogy mikor programozom akkor kapcsolgatnak a kimeneti relék amit az SPI vezérel.
Ezt hogyan lehetne kiküszöbölni úgy, hogy programozás előtt ne kelljen kapcsolókat állítgatni?
(#) sgt válasza blackdog hozzászólására (») Aug 15, 2012 /
 
  1. DDRB = (1<<PINB1);
  2.     PORTB = (1<<PINB1);


A fentebbi két sor, teljesen törli az SPI beállításait, ezért szoktuk használni a | operátort, ami nem fogja bántani .

Másik kérdésedre a válasz. Mivel CMOS IC-t használsz, ezért ha ujjadat húzod végig, akkor is befognak húzni a relék, mert elég egy apró tüske is a CMOS-nak. Első körben TTL-t használnék, vagy tegyél kondikat a CMOS lábaira.

Ui. nekem még a 8 bites shift regiszterrel egyáltalán nem sikerült kapcsolatot létesítenem SPI-al. Egyelőre sima port billegetéssel csinálom, de nekem is rá kéne feküdni, hogy mi lehet a baja.
(#) TavIR-AVR válasza (Felhasználó 15355) hozzászólására (») Aug 15, 2012 /
 
Mega328.

Memória, szolgáltatások és ár alapján...
M48-at hamar kinövöd....
(#) sgt válasza sgt hozzászólására (») Aug 15, 2012 /
 
A 10k és a shiftregiszter közé tegyél be fel/lehúzó ellenállásokat, mert ugye az a baj, hogy amíg te programozol addig legtöbb láb HiZ állapotban, és ezekkel az ellenállásokkal statikus szinten tudod tartani.
(#) Fizikus válasza (Felhasználó 15355) hozzászólására (») Aug 15, 2012 /
 
Az ATMega168 es 328 azert is jo valasztas, mert az Arduino is erre epul, amire rengeteg tutorialt es projektet lehet talalni a neten...
(#) blackdog válasza sgt hozzászólására (») Aug 15, 2012 /
 
Bakker. Igazad van
Módosítottam a kódot most már tökéletes:
  1. DDRB |= (1<<PINB1);
  2. PORTB |= (1<<PINB1);
  3.  
  4. SPI_DDR |= (1<<PB3)|(1<<PB5)|(1<<PB2);
  5. SPCR = (1<<SPE)|(1<<MSTR)|(1<<SPR0);
  6. SPI_PORT |= (1<<SPI_74HC595_CS);
Következő: »»   467 / 840
Bejelentkezés

Belépés

Hirdetés
XDT.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