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   663 / 837
(#) krisztianAMG válasza Kovidivi hozzászólására (») Máj 3, 2015 /
 
Tudom, C-ben szeretek is programozni, de most assemblert követel meg a feladat.
(#) Gj hozzászólása Máj 3, 2015 /
 
Üdv!
ATMega8-on hogyan lehet kódvédelmet bekapcsolni?
Én még szeretnék írni bele, csak a kiolvasást akarom letiltani.
Ez ISP-n megoldható?
(#) Kovidivi válasza Gj hozzászólására (») Máj 3, 2015 /
 
A Lock biteket kell bekapcsolni. Ezzel a visszaolvasást tudod letiltani. Ha ki szeretnéd kapcsolni a Lock biteket, akkor egy teljes törlést kell végrehajtanod (ezután már nincs mit kiolvasni...), ezután tudod írni újra a program memóriát, majd újra beállítod (0-t kell beírni, hogy be legyen állítva) a lock biteket, és kész.
(#) rolandgw válasza krisztianAMG hozzászólására (») Máj 3, 2015 /
 
Nem Mega16,de az Avr242 app. note segíthet,ha járatos vagy az asm-ben.
(#) zombee válasza krisztianAMG hozzászólására (») Máj 3, 2015 / 1
 
Tartok tőle hogy ezt senki nem fogja megírni neked.

Ott kellene elindulni hogy a kijelzőt multiplexálod, amihez egy időzítő megszakítást használsz. Az időzítőt úgy állítsd be hogy 1-5 ms - enként megszakítást generál. A megszakításrutinban egyrészt kezeled a multiplexálást, utána növeled az óra számlálóját és feltételes láncban (pl. "ha eléri a 60-at a másodperc akkor...") végigmész a kijelzendő értékek számlálóin is. Igazából a "főprogram" nem fog semmit sem csinálni, mindent a megszakításrutin kezel le. Esetleg nyomógomb kezelést beletehetsz amivel az óra beállítható.
(#) csatti2 válasza zombee hozzászólására (») Máj 3, 2015 /
 
Én inkább kihasználnám, hogy ez a uC is támogatja az asszinkron módot az egyik időzítőnél (timer 2) egy külső kristállyal. Ha a programhoz a belső oszcillátort használja és ráköt egy külső 32.768kHz-es kristályt akkor egy jól kezelhető és pontos órát kap. Annyi dolga van csak, hogy asszinkron módra kapcsolja a T2-t, majd úgy állítja be a regisztereket, hogy minden másodpercben hívja meg a megszakítást (esetleg fél másodpercenként vagy hasonló módon, hogy a pontokat is villogtathassa a hétszegmenses kijelzőn). A program többi részén így már időzítenie sem kell, alárendelhet minden mást az idő beállításának (gombok, PCINT megszakítással) és kijelzőn megjelenítésének.
Továbbfejlesztési lehetősége, ha betesz egy plusz 3V-os gombelemet és figyeli, hogy leesik-e a betáp fesz. Ha igen, akkor leáll a kijelző meghajtással és energiatakarékos módra kapcsol, ahol csak a külső kristály meghajtása a fontos (meg az idő követése).
(#) kapu48 válasza krisztianAMG hozzászólására (») Máj 3, 2015 /
 
Lásd, milyen jó vagyok hozzád!
Elvezetlek a megoldáshoz!

Bővebben: Link
Alul jobbra: avr-source

Digital clock with ATmega16 and 7-segment displays
Bővebben: Link
(#) killbill válasza krisztianAMG hozzászólására (») Máj 4, 2015 /
 
Az assembler az a fordito program maga, ami az assembly nyelven irt forrast forditja. Szoval nem assembrelben, hanem assembly-ben lehet programot irni.
(#) zombee válasza csatti2 hozzászólására (») Máj 4, 2015 /
 
Ennek az a szépséghibája hogy fél-egymásodperces megszakítással a kijelzőt nem fogja multiplexálni. Mindenképp kell egy gyorsabb időzítő megszakítása is, de ez akár a T2 is lehet aszinkron módban kisebb előosztóval.
(#) kapu48 válasza zombee hozzászólására (») Máj 4, 2015 /
 
Rajta javítsátok ki!
(#) csatti2 válasza zombee hozzászólására (») Máj 4, 2015 /
 
Nem feledkeztem meg róla. Egyszerűen mivel csak ennyi a program a kijelző frissithető úgy, ahogy csak a csövön kifér, nincs szükség külön időzítőre.
(#) csabeszq válasza wbt hozzászólására (») Máj 4, 2015 /
 
Az I2C az sosem egyszerű, pláne kezdő szinten.

Nekem is napjaim mentek ez azzal, hogy megpróbáljam kitalálni, hogy mi a fene baj van.
Azóta vettem 2000 pénzért az Ebay-en logikai jelanalizátort és a fejlesztési idő drámaian lecsökkent.

Az 1-2-3 hónap idő kezdőként reális. Ennél gyorsabb, ha veszel egy Arduino-t és a kész könyvtárakat használod hozzá.

A hálózati kommunikáció mindig macerás, pláne ha eszközeid sincsenek hozzá.
A hozzászólás módosítva: Máj 4, 2015
(#) zombee válasza csabeszq hozzászólására (») Máj 4, 2015 /
 
Idézet:
„Az I2C az sosem egyszerű”

Ezzel vitatkoznék. Kezdőként, aláírom hogy az I2C bonyolult. Hiába tanultam meg pár éve bitről bitre, újra elő kellett vennem a cuccost hogy mi és miért meg hogyan. Most sem tudnám fejből elmondani, mikor lehet STOP feltételt kiadni az UC-vel és mikor nem, meg hogyan lehet elkerülni a végtelen ciklust ha épp nem válaszol a cucc, de kis gyakorlattal a hátam mögött már nem kell analizátor(eredetileg sem volt), meg többnapos kutakodás hogy meg tudjak szólaltatni egy IC-t. Meg ha kéznél van egy épkézláb I2C könyvtár(saját gyártmány!!!) akkor azt a 20 perces guglizást és doksiolvasást is meg tudom spórolni. A szoftver I2C csak annyival nehezebb hogy az órajelet és a mintavételezést neked kell megoldani, a START/STOP feltételt pedig "jókor" kiadni. Slave esetén talán egyszerűbb, csak figyelni kell a START feltételt, az első 7 biten azonosítani a saját cimet, ha van akkor ACK-ot kiadni, majd az órajel alapján adni/venni, (master felőli) olvasáskor nemutolsó bájtnál ACK-ot, utolsó bájtnál NACK-ot adni, (master felőli) íráskor meg minden bájtnál ACK-al válaszolni és figyelni a STOP feltételt...
A hozzászólás módosítva: Máj 4, 2015
(#) Szabi1 hozzászólása Máj 4, 2015 /
 
Sziasztok! Valaki átnézné a következő kódom?
Tehát adott az Atmega 8 mikrovezérlő és két PWM kimenet OC1A és OC1B. Az ADC olvassa be a két poti állását, eszerint csinálja a PWM kitöltési tényezőjét.
INT0-n van egy kapcsoló, ami megszakítja a programot, és az egyik PWM kitöltési tényezőjét 100%-ra állítsa, mikor újra megnyomódik, akkor a neki megfelelő poti alapján készíti a kitöltési tényezőt. A PWM frekvenciák körülbelül 500Hz-en kellene működjenek.
  1. #define F_CPU 8000000UL
  2. #include <avr/io.h>
  3. #include <avr/interrupt.h>
  4.  
  5. int pressed;
  6.  
  7. unsigned char Beolvas8bitADC(unsigned char csatorna)
  8. {
  9. ADMUX = (ADMUX & 0b11110000) | csatorna;   // ADC csatorna kivalasztasa
  10. ADCSRA |= (1<<ADSC);    // ADC konverzio elinditasa
  11. while (ADCSRA & (1<<ADSC));    // varas az atalakitasra
  12. ADCSRA |= (1<<ADSC);         // konverzió elindítás
  13. while (ADCSRA & (1<<ADSC));    // varas az atalakitasra
  14. return (ADCH);     // ADC ertek visszaadasa (csak a felso 8 bit (ADCH), az also 2 zajos bit elhagyasa)
  15. }
  16.  
  17. ISR (INT0_vect)
  18. {
  19.     if(pressed==0)
  20.     {
  21.         pressed=1;
  22.     }
  23.     else
  24.     {
  25.         pressed=1;
  26.     }
  27. }
  28.  
  29. int main (void)
  30. {
  31.     GICR |= (1<<INT0);
  32.       MCUCR = (1<<ISC01) ;
  33.       TCCR1A |= (1<<WGM10);     /*8 bites fazishelyes PWM*/
  34.       TCCR1B |= (1<<CS10);         /*elooszto = FCPU/1*/
  35.       TCCR1B |= (1<<CS11);         /*elooszto = FCPU/1*/
  36.       TCCR1A |= _BV(COM1A1);     /*** nem-invertalt PWM, A csatorna*/
  37.       DDRB |= _BV(PB1);          /*** PORTB PB1 lab kimenet*/
  38.       TCCR1A |= _BV(COM1B1);      /***nem-invertalt PWM, B csatorna*/
  39.       DDRB |= _BV(PB2);          /*** PORTB PB2 lab kimenet*/
  40.       DDRB |= _BV(PB0);          /*** PORTB PB2 lab kimenet*/
  41.  
  42.  
  43.         ADMUX |= (1<<REFS0)|(1<<ADLAR);    // Vcc mint referencia, balra rendezett ADC eredmeny
  44.     ADCSRA = (1<<ADEN) | (1<<ADPS1) | (1<<ADPS0);
  45.         pressed=0;
  46.       //OCR1A = _duty;         /***motor1 pwm kitoltesi tenyezo*/
  47.       //OCR1B = _duty;
  48.       sei();
  49.       while(1)
  50.       {
  51.           if(pressed==0)
  52.           {
  53.               OCR1A =Beolvas8bitADC(0);
  54.           }
  55.           else
  56.           {
  57.               ORR1A=255;
  58.           }
  59.           OCR1B =Beolvas8bitADC(1);
  60.       }
  61.  
  62.  
  63. }
A hozzászólás módosítva: Máj 4, 2015
(#) csatti2 válasza Szabi1 hozzászólására (») Máj 4, 2015 / 1
 
Az else után szerintem pressed=0; kellene. Prellezést is kéne kezelned (kapcsoláskor könnyen ide oda csapkodhat majd a mód). PWM rész ránézésre jónak tűnik (nagyon látszik a copy-paste azonban, (1<<WGM10) az ugyanaz, mint _BV(WGM10) ).

500Hz-es PWM-ben biztos vagy? Cincogni fognak a motorok.
(#) Jaedong válasza Szabi1 hozzászólására (») Máj 4, 2015 / 1
 
Nagyon hulla vagyok most este már ahhoz hogy belenézzek a kódba még ha nem is hosszú , viszont az kiszúrja a szemem, hogy a pressed az nem volatile.
(#) csabeszq válasza zombee hozzászólására (») Máj 4, 2015 /
 
Ha már van tapasztalat, akkor oké, nem olyan bonyolult.

Nekem sikerült egy felhúzó ellenállást a CLK mögül rossz helyre kötni (föld) és minden megakadt. Egy óra elment vele, míg rájöttem, hogy miért vár mindenki. A jelanalizátorral látod, hogy az adó mit ad ki és a vevő mit fogad. Ez roppant nagy előny, mert tudod, hogy egy bonyolult folyamatban ki a hibás.

Arról nem is beszélve, hogy ha a vevő 1 MHz-en megy, az adó meg 16 MHz-en, azért érhetnek meglepetések.

AVR alatt egyébként azért TWI-nek hívják a protokolt, mert nem tartják az I2C szabványt.
A legrondább ugye a STOP kezelése slave módban (0xA0):

- master küld egy STOP jelet
- a slave STOP után már nem tudja tartani a vonalat, mert nincs busy wait (CLK-val)
- közben a master új kérést küld a slave-nek
- a slave az előző STOP-ot még nem dolgozta fel, ezért az új kérésre automatikus NACK-ot küld
- a slave végre feldolgozza a 0xA0 státuszt, engedélyezi újra magát a buszon
- a master új kérését már kész fogadni

Amikor olyan implementációt látsz AVR alatt, hogy az első NACK után még kétszer újra megkérdezi a slave-et, az ezért van. Vagy amikor az interrupt első 10 órajelében lekezelik az 0xA0-t, az is ugyanilyen okból történik. Gondolom az I2C minősítést nem kapták volna meg ezzel a megoldással.
A hozzászólás módosítva: Máj 4, 2015
(#) zombee válasza csabeszq hozzászólására (») Máj 4, 2015 /
 
Mi úgy tanultuk, szabadalmi oka van annak hogy TWI-nek hívják, mert az "I2C" a Philips szabadalma.
A másik ok hogy TWI-n másfajta kommunikáció is megvalósítható, a harmadik amit mondasz az az
hogy az AVR master módban egyáltalán nem érzékeli ha a slave lehúzva tartja az SCK vonalat.
(#) Szabi1 válasza csatti2 hozzászólására (») Máj 4, 2015 /
 
Köszönöm szépen a segítséget, kijavítottam a hibákat:
  1. #define F_CPU 6528000UL
  2. #include <avr/io.h>
  3. #include <avr/interrupt.h>
  4. #include <util/delay.h>
  5. volatile pressed;
  6.  
  7. unsigned char Beolvas8bitADC(unsigned char csatorna)
  8. {
  9. ADMUX = (ADMUX & 0b11110000) | csatorna;   // ADC csatorna kivalasztasa
  10. ADCSRA |= (1<<ADSC);    // ADC konverzio elinditasa
  11. while (ADCSRA & (1<<ADSC));    // varas az atalakitasra
  12. ADCSRA |= (1<<ADSC);         // konverzió elindítás
  13. while (ADCSRA & (1<<ADSC));    // varas az atalakitasra
  14. return (ADCH);     // ADC ertek visszaadasa (csak a felso 8 bit (ADCH), az also 2 zajos bit elhagyasa)
  15. }
  16.  
  17. ISR (INT0_vect)
  18. {
  19.     if(pressed==0)
  20.     {
  21.         pressed=1;
  22.     }
  23.     else
  24.     {
  25.         pressed=1;
  26.     }
  27.     GICR &= ~(1<<INT0);
  28. }
  29.  
  30. int main (void)
  31. {
  32.     GICR |= (1<<INT0);
  33.       MCUCR = (1<<ISC01) ;
  34.       TCCR1A |= (1<<WGM10);     /*8 bites fazishelyes PWM*/
  35.       //TCCR1B |= (1<<CS10);         /*elooszto = FCPU/1*/
  36.       TCCR1B |= (1<<CS12);         /*elooszto = FCPU/1*/
  37.       TCCR1A |= _BV(COM1A1);     /*** nem-invertalt PWM, A csatorna*/
  38.       DDRB |= _BV(PB1);          /*** PORTB PB1 lab kimenet*/
  39.       TCCR1A |= _BV(COM1B1);      /***nem-invertalt PWM, B csatorna*/
  40.       DDRB |= _BV(PB2);          /*** PORTB PB2 lab kimenet*/
  41.       DDRB |= _BV(PB0);          /*** PORTB PB2 lab kimenet*/
  42.  
  43.  
  44.         ADMUX |= (1<<REFS0)|(1<<ADLAR);    // Vcc mint referencia, balra rendezett ADC eredmeny
  45.     ADCSRA = (1<<ADEN) | (1<<ADPS1) | (1<<ADPS0);  // ADC engedelyezese, ADC eloosztas = 8 (125 KHz)
  46.         pressed=0;
  47.       //OCR1A = _duty;         /***motor1 pwm kitoltesi tenyezo*/
  48.       //OCR1B = _duty;
  49.       sei();
  50.       while(1)
  51.       {
  52.            if((GICR & (1<<INT0)) == 0)
  53.             {
  54.  
  55.             _delay_ms(400);
  56.  
  57.             GIFR |= (1<<INTF0);
  58.             GICR |= (1<<INT0);
  59.             }
  60.        
  61.           if(pressed==0)
  62.           {
  63.               OCR1A =(Beolvas8bitADC(0)/2);
  64.           }
  65.           else
  66.           {
  67.               ORR1A=127;
  68.           }
  69.           OCR1B =(Beolvas8bitADC(1)/2);
  70.       }
  71.  
  72.  
  73. }

Az MCU órajelét módosítanom kell 6528000Hz-re, a prescallert meg 256-ra, mivel 50Hz-es marad a PWM, és a kitöltési tényező max 127 lehet, ezért az ADC értékeket mielőtt OCR megkapja 2-vel osztom.
Csak most nemtudom biztosan, hogy ehez az "ULKA szivattyuhoz" milyen frekijű PWM kell.
A hozzászólás módosítva: Máj 4, 2015
(#) Szabi1 válasza Szabi1 hozzászólására (») Máj 4, 2015 /
 
Maradok a B tervnél, és kb 290Hz-es PWM-t csinálok, mert ha csak 50 Hz-est csinálok akkor a pompa vagy elkapja a pozitív részét a szinusznak, vagy nem és akkor egyáltalán nem megy.
(#) Jaedong válasza Szabi1 hozzászólására (») Máj 5, 2015 / 2
 
Szia!
A pressed még mindig nem jó. A volatile nem helyettesíti a típust, mivel az egy módosító kulcsszó, ami lényegében annyit csinálsz, hogy jelzi a fordítónak, hogy a vele kapcsolatos dolgokat ne optimalizálja ki. Ez olyan hibákat okozhat, a te kódodban például (nem tudom mennyire okos ez a gcc), hogy főciklusod előtt a pressed értékét alaphelyzetbe állítottad nulla és utána sehol se kap új értéket a fordítód szerint (mert ő azt honnan tudja szegénykém, hogy te interruptban változtatod az értékét?), tehát a továbbiakban a pressed-et abban a környezetben úgy tekinti mint ha egy konstans 0 lenne. Ezért kiszedi az elágazást is, mert annak nincs értelme, hogy folyton megnézd, hogy a "0==0 ?" + ennek a feltételnek sose lesz else ága .
  1. //ezt hellyettesíteni fogja
  2.  ...
  3.  if(pressed==0)
  4.           {
  5.               OCR1A =(Beolvas8bitADC(0)/2);
  6.           }
  7.           else
  8.           {
  9.               ORR1A=127;
  10.           }...
  11.  //erre
  12.    OCR1A =(Beolvas8bitADC(0)/2);

Ezért kell a változód volatile ként deklarálni, és akkor nem fogja piszkálni az optimalizációs része a fordítódnak.
  1. volatile int pressed;
  2. //vagy int volatile pressed;



Szerk: + ha az interruptban mindenképpen 1 re állítod a változót, akkor miért van elágazás?
A hozzászólás módosítva: Máj 5, 2015
(#) killbill válasza Jaedong hozzászólására (») Máj 5, 2015 /
 
Idézet:
„A volatile nem helyettesíti a típust,”
Bizony nem, bár default-bol int lesz, ahogy a fuggvenyeknel, és szól is érte a gcc, hogy "type defaults to int". Persze, aki -Wall -Werror opciókkal fordít, annak ez rögtön ki is derül.
(#) Szabi1 válasza Jaedong hozzászólására (») Máj 5, 2015 /
 
Igen a fordítóm kiirta, warningnak, hogy
Idézet:
„type defaults to int”
. Szóval azt akartam volna interrupt-al elérni, hogy a főciklusban állandóan adc szerint csinálja a PWM kitöltési tényezőjét, de ha megnyomom az interruptot, akkor a következő interrupt lenyomásáig 50% os kitöltési tényezővel menjen. Akkor a főciklus előtt ne nullázzam le a pressed értékét?
(#) kapu48 válasza Szabi1 hozzászólására (») Máj 5, 2015 /
 
  1. 1.       if(pressed==0)
  2. 2.                {
  3. 3.                    OCR1A =(Beolvas8bitADC(0)/2);
  4. 4.                }
  5. 5.                else
  6. 6.                {
  7. 7.                    ORR1A=127;  ?? Most nincs előttem az adatlap, de ilyen regiszterre nem emlékszem!
  8. 8.     
  9. 9.                }...
(#) vzoole válasza kapu48 hozzászólására (») Máj 5, 2015 /
 
Csak gépelési hibának tűnik... leírt működés szerint OCR1A=127; lesz az.
(#) Szabi1 válasza kapu48 hozzászólására (») Máj 5, 2015 /
 
Igen, mert OCR1A nem ORR sajnos elírtam.
Valaki átnézné ezt is?
Atmega8 relé késleltetés, PD2-n GND-re bekapcsol az a funkció, hogyha PD5-on megvaltozik a kapcsolo allapota akkor delayal be és kikapcsol egy relét.
Itt nem használhatnák NOT, vagyis ! jelet az első if-nél?
  1. if(!PIND & _BV(PD2))
  2.       {
  3. ...
  4. }

  1. void do_action_1(void)
  2. {
  3.     PORTB |=  (1 << PB0); //rele be
  4.     _delay_ms(20000);
  5.     PORTB |=  (1 << PB0); //rele ki
  6. }
  7.  
  8.  
  9.  
  10.     int main(void) // Foprogram
  11.     {
  12.         unsigned int prew_state=0;
  13.         DDRB = 0b11111111; /*B port kimenet*/
  14. while(1)
  15. {
  16.     /*rele 1*/
  17.       if(PIND & _BV(PD2))
  18.       {
  19.             //nem aktiv
  20.             _delay_ms(2);
  21.       }
  22.       else
  23.       {
  24.            if(PIND & _BV(PD5))
  25.             {
  26.                 if(prew_state==0)
  27.                 {
  28.                     prew_state=1;
  29.                     do_action_1();
  30.                 }
  31.             }
  32.             else
  33.             {
  34.                 if(prew_state==1)
  35.                 {
  36.                     prew_state=0;
  37.                     do_action_1();
  38.                 }
  39.             }
  40.       }
  41.  
  42.  
  43.     }
  44. }
A hozzászólás módosítva: Máj 5, 2015
(#) Gj hozzászólása Máj 5, 2015 /
 
Üdv!
ATMega8-on WatchDog-ot használt már valaki?
Adatlapját néztem, a beállításhoz kellő regiszterek meg is vannak, de nem tudom, hogy melyik bitet kéne mindig törölni/beállítani, hogy a házőrző újrakezdje a számolást.

Melyik az a bit?
A hozzászólás módosítva: Máj 5, 2015
(#) Jaedong válasza Gj hozzászólására (») Máj 6, 2015 / 1
 
Szia!
Elég trükkös, mert adatlapban nem tudom, hogy hol írják. A watchdog újraindítására egy külön asm parancs van: WDR. Esetleg az adatlapban található példakódból lehetett rájönni, ha jól emlékszem.
1., __asm__ __volatile__ ("wdr");
2., #include <avr/wdt.h> és használód a wdt_reset()-et // ugyanazt csinálja mint a fenti kód
(#) Gj válasza Jaedong hozzászólására (») Máj 6, 2015 /
 
Örök hálám!
(#) csabeszq válasza zombee hozzászólására (») Máj 6, 2015 /
 
Igazából mester-szolga módban az TWI remekül megy.

Egyszer próbáltam multimesteres módot kialakítani Atmel IC-vel, de befürdés lett a vége.
Azt kell, hogy mondjam, hogy a multimesteres mód AVR alatt csak papíron létezik.

Annyi hardver hibába futottam bele, hogy letettem az egészről.
Következő: »»   663 / 837
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