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   654 / 840
(#) Max26 válasza kapu48 hozzászólására (») Márc 12, 2015 /
 
Az égetőhöz való csatlakozáskor ez a kép fogad és nem csatlakozik az eszközhöz.
Bővebben: Link
(#) csabeszq válasza Max26 hozzászólására (») Márc 12, 2015 /
 
Ez azt jelenti, hogy nem megy. Nem sikerült belépnie programozó módba.

Új IC, vagy HVPP kell.
(#) TavIR-AVR válasza dbase hozzászólására (») Márc 12, 2015 /
 
ATMega8-16 (16 MHz, 5V)
Mega8L-8 (8MHz, 3V-on tesztelt, de 5Von 16MHz megy)
Mega8A (8 és 16 MHz-s chipet egyesíti, kisebb csíkszélesség, azonos a 2 chip). Az eltérés pár helyen van:
- belső ellenállások 20k-> 80...120k
- resetellenállás 20k -> 82k
- a Vcc és VccA közti belső ellenállás kikerült. Azaz be kell kötni a Vcc és a VccA lábat is, hogy a GND és a GNDA-t is

Bővebben: Link - A vagy Nem A
A hozzászólás módosítva: Márc 12, 2015
(#) k3gy3tl3n válasza Max26 hozzászólására (») Márc 12, 2015 /
 
Ez a kép nem azt mutatja, hogy a SPIEN kivan kapcsolva, hanem hogy nem tudtad kiolvasni a fuse biteket. Szóval nem tudhatod, hogy ki van e kapcsolva. Ha rádobsz egy külső kristályt ÍGY és úgy sem tudsz kapcsolódni akkor valszeg kikapcsoltad a SPIENT. A két kondi 22pF-os a kristály meg pár MHz (mondjuk 4).
(#) Kovidivi hozzászólása Márc 12, 2015 /
 
Sziasztok!
Szeretnék készíteni egy várakozó függvényt, ami úgy működik, hogy pl. szeretnék 100mS-ot várakozni, ilyenkor közbejöhet akár több interrupt is, a lényeg, hogy a 100mS 100mS legyen, ne pedig 100mS+interrupt hossza. Beállítottam az egyik timer-t, ami 1024uS-ként növel egy long változót, tehát majdnem 1mS-ként. Kezdetnek ez is megteszi, később lehet finomítani a pontosságot. Ez az Arduino-s millis() függvény egyszerűsített változata. Működik is, viszont néha rövidebb időt várakozik. 1000mS-nál a soros porton 1000-et küld vissza a főprogram általában, de kb. 15-ből 1x kisebb értéket kapok, 890-950-975 körülit. Nagyobbat soha. Ez a várakozó függvényem:

  1. void _delay_ms_my(unsigned int varakozas)       //ms-ban.
  2. {
  3.         cli();   // ez a 2 byte-os változó átadás miatt van itt.
  4.          // ha lehet, elhagynám szívesen.
  5.          // vele, és nélküle is néha hamarabb ér véget a várakozás
  6.         unsigned long kezdeti_ido=millis();
  7.         sei();
  8.         kezdeti_ido+=varakozas;
  9.         while (millis()<kezdeti_ido)
  10.                 {;}
  11. }


A főprogramban:
  1. unsigned long temp=millis();   
  2. _delay_ms_my(1000);
  3. soros_kuld_szam(millis()-temp);


Ha a normál _delay_ms(1000) függvényt használom, akkor mindig megfelelő az időzítés, viszont az interrupttal megnövelt értéket kapom vissza. 1035-1036-ot, amikor minden interrupt működik, és ha csak a millis()-t kiszolgáló megy, akkor 1031, ami 4ms eltérés. Nem sok, de ezt is szeretném kiküszöbölni. Mit gondoltok, mitől lehet ez a rövidebb várakozás? Én ezt a részt érzem hibásnak: "while (millis()<kezdeti_ido)" Ha igaz, hogy lehetne javítani?
Köszönöm!

szerk: Tettem egy gyors próbát, így jónak tűnik:
  1. void _delay_ms_my(unsigned int varakozas)       //ms-ban.
  2. {
  3.         //cli();
  4.         unsigned long kezdeti_ido=millis();
  5.         unsigned long kezdeti_ido2=millis();
  6.         unsigned long jelenlegi1=0,jelenlegi2=0;
  7.         if (kezdeti_ido!=kezdeti_ido2) kezdeti_ido=millis();
  8.         //sei();
  9.         kezdeti_ido+=varakozas;
  10.         while (1)
  11.                 {
  12.                         jelenlegi1=millis();
  13.                         jelenlegi2=millis();
  14.                         if (jelenlegi1!=jelenlegi2)
  15.                                 jelenlegi1=millis();
  16.                         if (jelenlegi1>kezdeti_ido) break;
  17.                 }
A hozzászólás módosítva: Márc 12, 2015
(#) killbill válasza Kovidivi hozzászólására (») Márc 13, 2015 /
 
Szia!
Nem ertek valamit. Miert kell letiltani a megszakitast a "kezdeti_ido = millis();" miatt? Ha a millis() nem igazi fuggveny, hanem egy makro, ami csak egy valtozot ad vissza, akkor a while()-ban is le kellene tiltani a megszakitast. Ha a millis() egy valodi fuggveny, akkor meg nem kell tiltani. Felteve, hogy a millis() fuggveny vigyaz arra, hogy ne tudjuon rossz erteket visszaadni. Azt a fuggvenyt lehetne latni?
(#) Kovidivi válasza killbill hozzászólására (») Márc 13, 2015 /
 
Szia.
A millis() kb. ennyi: void millis() {return millis_;}, ez unsigned long, a millis_ pedig az interruptban van növelve, 1mS-ként. Mostanában olvasgattam, hogy okozhat gondot 8bit-es AVR-en egy 32bit-es változó átvétele, ha közben az interrupt azt változtatni tudja, mert két részben történik a változó kezelése. A kódot, amit utoljára hozzáadtam még, ha megnézed, ott már nincs cli() és sei(). Ez a kód így jól működik, mert ha falsch értéket kapok a millis()-től, akkor harmadjára is megtörténik az értékadás, ami már 100%-osan jó lesz.
Próbálkoztam ugyanezt megoldani uS-ra, ez még kicsit problematikusabb, dolgozni kell rajta...
A problémáról itt találsz további infókat: Bővebben: Link. Volt korábban is hasonló probléma egy változóval ebben a topicban.
A hozzászólás módosítva: Márc 13, 2015
(#) killbill válasza Kovidivi hozzászólására (») Márc 13, 2015 /
 
A problemadra a kovetkezo az egyik megoldas:
  1. unsigned long millis(void)
  2. {
  3. unsigned long temp;
  4.  
  5.  cli();
  6.  temp = millis_;
  7.  sei();
  8.  return temp;
  9. }

De, ha nem akarod letiltani az interrupt-ot minden egyes lekerdezesnel, akkor csinalhatsz egy olyan timer interrupt-ot, ami a kert ido elteltevel beallit egy flag-et, es azt kell csak figyelned. Azt viszont figyelheted engedelyezett megszakitas mellett is.
(#) csabeszq válasza killbill hozzászólására (») Márc 13, 2015 /
 
  1. unsigned long millis(void)
  2. {
  3.   unsigned long temp1, temp2;
  4.  
  5.   do {
  6.     temp1 = millis_;
  7.     temp2 = millis_;
  8.   } while( temp1 != temp2 );
  9.   return temp1;
  10. }


Fölöslegesen az interruptot ne kapcsold le. Csak akkor kell, ha tényleg nem tudsz mást csinálni. Bevallom Arduino alatt állandóan agybajt kapok attól, hogy TIMER0 mindenbe bekavar.
(#) killbill válasza csabeszq hozzászólására (») Márc 13, 2015 /
 
Kinek a pap, kinek a papné. Errol mar beszeltunk itt par oldallal ezelott. En inkabb tiltom 5 utasitasnyi idore az IT-t, mint hasznaljak 8 byte stack-et, egy kazal kodot es meg lassitsak is a programon a 32 bites hasonlitgatassal. Ha egy rendszerben gondot okoz egy ilyen rovid ideju IT tiltas, akkor a te modszered jo, de amugy nem latom ertelmet.
A hozzászólás módosítva: Márc 13, 2015
(#) Kovidivi válasza killbill hozzászólására (») Márc 13, 2015 /
 
Mindkettőtöknek igaza van! Csabeszq kódja tetszik, köszi. Az ok, amiért nem lehet az interruptot kikapcsolni: LED-mátrix van multiplexálva interruptból. Ha megáll az interrupt, bevillan a kép, megáll egy pillanatra. Ha a LED-ek nem 20mA-rel vannak hajtva, hanem 100mA-rel (mivel úgy is csak 1/8-ad ideig van bekapcsolva), akkor egy interrupt tiltás egyben a LED-ek végét is jelenti!
Egyik órámban a fényerősség is interrupttal van szabályozva, ha kikapcsolom az interruptot, akkor felvillannak a LED-ek maximális fényerővel, mert be még bekapcsolódnak, de ki már nem, vagy nem akkor, amikor kellene. És minél később vannak kikapcsolva, annál nagyobb a fényerő.
Ezek az okok. Ez miatt kell megoldanom pl. a DS18b20 hőmérő szenzorral a kommunikációt is interrupt kikapcsolása nélkül. Az I2C egyáltalán nem kavar be, ott megvárom szép türelmesen, amíg beáll a megfelelő flag. A főprogram lehet lassú, az interrupt sajnos nem.
(#) Kovidivi válasza killbill hozzászólására (») Márc 13, 2015 /
 
Ez nagyon szimpatikus: " csinalhatsz egy olyan timer interrupt-ot, ami a kert ido elteltevel beallit egy flag-et, es azt kell csak figyelned", átgondolom hogyan lehetne megoldani szépen. Abból állna a delay függvény, hogy lenullázná a számlálót, és beállítaná az OCR értékét a megfelelő értékre. Ezután az interrupt beállítja a flag-et, és lenullázza a számlálót, meg kikapcsolja a megszakítását. A várakozó függvény vár, amíg a flag be nem lesz állítva, amikor ez megtörténik, egyből meg is vizsgálhatja, hogy a számláló azóta hol tart. Ugyanis ha egy másik interrupt miatt a várakozó függvény túl sokáig volt várakoztatva, akkor az eltelt idő több, mint ami kell. Ilyenkor újra kell kezdeni a kommunikációt, remélve, hogy most nem lesz pont rosszkor félbeszakítva. Esetleg a másik megszakításból lehetne figyelni az időzítő interruptot Még átgondolom, hogy minek van értelme. Köszönöm a tippeket mindkettőtöknek!
(#) killbill válasza Kovidivi hozzászólására (») Márc 13, 2015 /
 
5 utasitas idore az interruptot egesz nyugodtan le lehet tiltani, nem fog latszani a LED-en. Persze, ha ciklikusan hivogatod azt a fuggvenyt, ami letiltja, akkor igen. De normalisan ez teljesen elfogadott dolog, hogy par utasitasnyi idore letiltjuk a megszakitast. Amikor egy megszakitasi rutin fut, akkor az sokkal hosszabb idore tiltja. Igaz, ez csak akkor erdekes, ha tobb is van.
(#) Kovidivi válasza killbill hozzászólására (») Márc 14, 2015 /
 
Egy interrupt van, aminek mindig mennie kell, ez küldi az adatot a portoknak és a shift regisztereknek. 5 utasításidő valóban nem sok. A gond ott van, hogy így kommunikál a DS18b20: cli(); delay-us(48); sei();, na ez már bőven látszik.
A hozzászólás módosítva: Márc 14, 2015
(#) killbill válasza Kovidivi hozzászólására (») Márc 14, 2015 /
 
Idézet:
„Ha a LED-ek nem 20mA-rel vannak hajtva, hanem 100mA-rel (mivel úgy is csak 1/8-ad ideig van bekapcsolva), akkor egy interrupt tiltás egyben a LED-ek végét is jelenti!”
Ha felted a LED-eket, akkor megfelelo HW-rel meg kell vedeni oket. Pl. egy idozito (555 vagy akarmi), ami ha lejar, akkor lekapcsolja az egesz LED tapot, vagy hasonlo. Az idozitot meg valami olyan jel triggereli, ami a kijelzo meghajtasbol szarmazik. Ez eleg regi modszer a SW-es LED matrixok vedelmere. A SW-ed barmi mastol is megallhat, es akkor ugyanugy kinyirja a LED-eket, ha nincs hardware-es vedelem.
(#) killbill válasza Kovidivi hozzászólására (») Márc 14, 2015 /
 
Idézet:
„A gond ott van, hogy így kommunikál a DS18b20: cli(); delay-us(48); sei();, na ez már bőven látszik.”
Ez a DS18B20 egy problemas dolog, mert se nem gyors, se nem lassu. Ahhoz tul gyors, hogy egy jofele interrupt rutin elkezelje egy AVR-en (bar lehet, hogy lenne ertelme elgondolkodni rajta), viszont ahhoz lassu, hogy le lehessen tiltani a megszakitast egy bit idore.
(#) csabeszq válasza Kovidivi hozzászólására (») Márc 14, 2015 /
 
Mesélhetek még nyalánkságokat.

Például, hogy úgy kezded a hosszú interruptot, hogy kikapcsolod az IE flag-et, nehogy rekurzív legyen, utána sei(). Interruptból lehet másik interruptot meghívni.

Amikor jöttek befelé az SPI parancsok miközben software PWM-et futtattam, akkor volt erre szükségem. Se az SPI, se a PWM nem várt.

Az történt, hogy mentek az interruptok és ha SPI parancs érkezett be, akkor elindított egy szálat a főprogram helyett, ami mindaddig futott, amíg a bejövő SPI parancsok le nem lettek kezelve. Utána visszaadta a vezérlést a főprogramnak. Eközben ment a software PWM.

Ha éppen egy új SPI interrupt jött be, azt pufferbe raktam. Addig dolgoztam fel az SPI-t, ameddig volt még parancs, utána visszaadtam a vezérlést a főprogramnak.
A hozzászólás módosítva: Márc 14, 2015
(#) Istvanpisti válasza Kovidivi hozzászólására (») Márc 14, 2015 /
 
A 48us meglátszik a kijelzésen?
Milyen frekvenciával váltod a sorokat?
Nálam 800Hz-es timer küldi az adatot ki, tehát egy sorra 10ms jut, ilyenkor a 48us nekem nem tűnik kritikusnak.
(#) Istvanpisti válasza Istvanpisti hozzászólására (») Márc 14, 2015 /
 
Bocs, 1,25ms jut egy sorra.
(#) jocka0012 hozzászólása Márc 14, 2015 /
 
Üdv!
Van egy Atmega 328p xplained mini fejlesztői kártyám , és egy lcd-s ébresztőórát akarok csinálni ds1307 rtc áramkörrel.Kezdő vagyok még , és az i2c kommunikációt próbálom megoldani a mikrokontroller és az rtc között , de a programom mindig megakad egy bizonyos részen.Ezt a példaprogramot néztem ki: Bővebben: Link
Ebben a függvényben akad el mindig a while ciklusnál:
  1. unsigned char i2c_readNak(void)
  2. {
  3.         TWCR = (1<<TWINT) | (1<<TWEN);
  4.         while(!(TWCR & (1<<TWINT)));
  5.        
  6.     return TWDR;
  7.  
  8. }
Valaki tudna segíteni , hogy mi lehet a probléma?
(#) gabi20 válasza jocka0012 hozzászólására (») Márc 14, 2015 /
 
Szia esetleg próbáld ki ezzel, nekem bevállt. Ez egy példaprogram az RTC beolvasására, az adatok feldolgozása nincs benne.
Felhúzóellenállásokat ne felejtsd el!
  1. void I2C_start(unsigned char slave_adress){
  2.  
  3.                 TWCR = (1<<TWINT)|(1<<TWSTA)|(1<<TWEN);
  4.                 while(!(TWCR & (1<<TWINT)));            // Send START condition
  5.  
  6.                 TWDR = slave_adress;                            // Send slave adress + R/W
  7.                 TWCR = (1<<TWINT)|(1<<TWEN);
  8.                 while(!(TWCR & (1<<TWINT)));
  9. }
  10.  
  11. void I2C_stop(){
  12.  
  13.                 TWCR = (1<<TWINT)|(1<<TWEN)|(1<<TWSTO);
  14. }
  15.  
  16. void I2C_TX(unsigned char data){
  17.  
  18.                 TWDR = data;
  19.                 TWCR = (1<<TWINT)|(1<<TWEN);
  20.                 while(!(TWCR & (1<<TWINT)));
  21. }
  22.  
  23. unsigned char I2C_RX_ACK(){
  24.  
  25.                 TWCR = (1<<TWINT)|(1<<TWEN)|(1<<TWEA);
  26.                 while(!(TWCR & (1<<TWINT)));
  27.                 return TWDR;
  28. }
  29.  
  30. unsigned char I2C_RX_NACK(){
  31.  
  32.                 TWCR = (1<<TWINT)|(1<<TWEN);
  33.                 while(!(TWCR & (1<<TWINT)));
  34.                 return TWDR;
  35. }
  36.  
  37. int main(void){
  38.  
  39.                 TWCR = 0x04;                    // Enable TWI
  40.                 TWBR = 242;                     // Set TWI baud rate 32kbit/s
  41.  
  42.                 while(1){
  43.  
  44.                         I2C_start(0xD0);
  45.                         I2C_TX(0x00);
  46.                         I2C_start(0xD1);
  47.               for(unsigned char i = 0; i < 8; i++) timekeeper[i] = I2C_RX_ACK();
  48.                         I2C_RX_NACK();
  49.                         I2C_stop();
  50.  
  51.                                
  52.                 }
  53. }
A hozzászólás módosítva: Márc 14, 2015
(#) jocka0012 hozzászólása Márc 14, 2015 /
 
Ennél is valamiért ugyanott , amikor először belép a for ciklusba a főprogramban akkor meg akad.Felhúzó ellenállások vannak , és az áramkörnek jónak kéne lennie , mert arduinoval kipróbáltam , és ott kitudtam olvasni az rtc-ből az időt.
(#) jocka0012 hozzászólása Márc 14, 2015 /
 
Na sikerült megoldani a problémát!A fejlesztői panelen egyel elcsúsztam és nem az 5V tápfeszt adtam az ic-nek . hanem a 3,3 V-ot.
(#) killbill válasza jocka0012 hozzászólására (») Márc 14, 2015 2 /
 
eggyel
(#) Kovidivi válasza Istvanpisti hozzászólására (») Márc 14, 2015 1 /
 
Szia. Nem csak csak 1x 48uS, hanem sokkal többször. 1bithez kell ennyi idő, én is küldök utasításokat, DS is küld vissza. Egy DuoLED-es matrixomnál 3x250uS-ig világít egy sor, amikor 3xtúlcsordul a timer, jön a következő sor, összesen 8. Azért 3x255uS, mert így 3+1 féle színárnyalatom van (kikapcsolva, halvány, közepes, max), így tudok színeket kikeverni. Ehhez jön hozzá a fényerőszabályzás, amit pedig az OCR szabályoz. Ha OCR 10, akkor 0-10ig világít a sor, 10-255ig nem, tehát sötét lesz az a sor.
(#) zombee válasza Kovidivi hozzászólására (») Márc 14, 2015 /
 
Esetleg egy másik időzítőt használhatnál az 1-Wire kezelésére, ami meg is szakíthatja a mátrixot kezelő interruptot. Ezt azért lehet megcsinálni mert a mátrixoknál az interrupt legelején megcsinálod az "átkapcsolást" a következő sorra vagy színárnyalatra, a többi részében meg a számításokat végzed el, és ha shift regisztered(74HC595) van akkor kiküldöd de nem csinálsz STORE-t (azt majd a következő megszakítás legelején). Tehát ezen interrupt LEGELEJÉN megcsinálod az átkapcsolást, ami kb. annyit tesz egy 8MHz-es IC esetében hogy kb. 1-1.5 us alatt megvan a dolog. Ezután (és csak ezután!) beraksz egy "sei"-t hogy a "számolós-kiküldős" részt az 1-Wire időzítő lejárta bármikor meg tudja szakítani.

Bármilyen hihetetlen, de az 1-Wire időzítőjének megszakítását is csinálhatod ugyanígy: az időzítéskritikus részeket(port beolvasás, port átbillentés) a megszakítás legelső néhány utasítására teszed, majd kiadsz egy "sei"-t hogy az 1-Wire számolós-shiftelgetős részeit a mátrix meg tudja szakítani, hiszen sort/árnyalatot kell váltania. Azért a mátrixod nem annyira ördöngős hogy 5-10us-nél tovább tartson a következő sor konverziója. Persze nem Arduino-ban...
(#) zombee válasza zombee hozzászólására (») Márc 14, 2015 /
 
Igazából azt olvastam ki a DS18B20 adatlapjából, hogy egy "time slot"-ot el lehet nyújtani, tehát nem kell feltétlenül 60us-nek lennie, akár 255us is lehet mivel minden bit átvitelét a master kezdeményezi. Persze ha a DS tolerálja a többszörösére nyújtott timeslot-ot.

Ekkor a kezelés a következő: a mátrix megszakításában egy flag-et beállítasz, amit a főprogramban figyelsz. Utóbbi törli a flag-et és belefog a következő timeslot kezelésébe. Mivel éppen le lett kezelve a legutóbbi megszakítás a mátrixon, a következő 60us-ban biztosan nem fog jönni egy újabb hogy elrontsa a delay függvényt. Innentől tiszta sor.

Mondani persze könnyű. Én úgy próbálnám ki hogy fogok valami "semleges" áramkört, az egyes timeslotok közé teszek valami hosszabb várakozást a delay függvénnyel és megnézem mi az eredmény. A DS adatlapja szerint elvileg végtelen is lehet ez a várakozás...
A hozzászólás módosítva: Márc 14, 2015
(#) Kovidivi válasza zombee hozzászólására (») Márc 15, 2015 /
 
Köszi a tippeket! Ezt még meg kell emésztenem... Most már legalább van többféle irány, csak ki kell választani, hogy melyik lenne a legjobb megoldás.
(#) Anthym hozzászólása Márc 18, 2015 /
 
Sziasztok! Tegnap próbáltam ki először avr programozóm (kezdő vagyok még, ezért kérem a segítségetek). USBasp-t használok, atmel studio 6.2-ben. Atmega8-as processzort használok, sikerült rátölteni a programot, teszteltem is, működik. A probléma viszont az, hogy én 16Mhz-en akarom üzemeltetni, de a processzor 1Mhzen jár. A cikkek közt találtam egy bekezdést, hogy másnak is volt már ez problémája, hogy elvileg a CLKDIV8 fuse leosztja az órajelet 1Mhz-re. Tudnátok segíteni, hogyan állíthatom át, hogy 16Mhzen működjön? Előre is nagyon köszönöm a segítséget.
(#) rolandgw válasza Anthym hozzászólására (») Márc 18, 2015 /
 
Szia! Miért nem használsz inkább egy GUI szoftvert,mint a studioban external tools-ként vacakolni?Például ezt.
Itt mindenképpen nézz körül!
Következő: »»   654 / 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