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   544 / 840
(#) csabeszq válasza johny999 hozzászólására (») Jún 26, 2013 /
 
Az OCRA = 4.12 vicces, a fordító egyébként visszakerekíti 4-re, ne aggódj (a tömböd 4,4,4,4,4,4,4,5 lesz)

Menet közben is változtathatod az értékét az OCR-eknek, szoktam is, amikor zenét játszom.

Két lehetőséged van: vagy definiálsz egy interruptot és minden 20,000. alkalom után váltasz (1s), vagy indítasz egy másik, lassabb timert, arra definiálsz interruptot.

Az első hátulütője, hogy 20kHz-en két megszakítás között 400 órajelciklus telik el. Ebbe kell az interruptodnak beleférni, ez relatíve kevés, de megoldható vele, viszont érezhetően belassít minden mást, amit csinálnál.
A hozzászólás módosítva: Jún 26, 2013
(#) johny999 válasza csabeszq hozzászólására (») Jún 26, 2013 /
 
Jó tudni. Akkor te hogyan oldanád meg azt a freki változtatást?

Ez az interruptozás nekem kicsit magas
A hozzászólás módosítva: Jún 26, 2013
(#) blackdog hozzászólása Jún 26, 2013 /
 
Sziasztok!

Vízhőfokot kellene állanó 16 °C-on tartanom. Ezt egy keverőszeleppel kell megoldanom.
Abban vagyok bizonytalan, hogy milyen hőérzékelőt válasszak.
A szelep motorja max. 15mm-t mozog. Sebessége 15s/mm. Szerintetek erre elég lenne egy NTC érzékelő is vagy jobb egy DS1820 ?
(#) zombee válasza aszika hozzászólására (») Jún 26, 2013 /
 
Szerintem nem annyira OFF, másokat is érdekelhet a megoldás.

A1: Az ATMega128 külső megszakításait kezelő lábak a PD0-PD3 (INT0-INT3) illetve a PE4-PE7 (INT4-INT7) portlábakon találhatók. Engedélyezni ill. tiltani az EIMSK regiszterrel lehet őket egyesével, a megszakítás feltételét(lefutó/felfutó él, bármilyen élátmenet - toggle mód, és szintvezérlés - LOW állapot) az EICRA és EICRB regiszterekben lehet beállítani.

A2: rajz nem lesz, csak program.
  1. //csak inicializálás és a cilkus:
  2. DDRA = 0b00010000;  //LED: kimenet
  3. PORTA = 0; //LED:kikapcsol, a nyomógombra a lehúzó ellenállás miatt nem kell felhúzó ell.
  4. uint8_t prev_button = PINA&(1<<7);
  5. while(1)
  6. {
  7.   if(PINA&(1<<7) && !prev_button)  //gomb lenyomás...
  8.   {
  9.     PORTA ^= (1<<4);  //LED állapotváltás
  10.     while(1)  //pergésmentesítés
  11.     {
  12.       while(PINA&(1<<7));  //várakozik az elengedésre...
  13.       uint8_t timer = 0;
  14.       for(timer=0; timer<250; timer++)  //elengedés után számlálás
  15.       {
  16.         if(!PINA&(1<<7)) break;
  17.         _delay_us(100);
  18.       }
  19.       if(timer==250) break;  //az elengedés akkor érvényes ha legalább 25ms ideig tart
  20.     }
  21.   }
  22.   prev_button = PINA&(1<<7);  //átmeneti tároló visszaállítás
  23. }


A3: A tisztán hardveres megoldás csak 16 bites időzítővel lehetséges, 8 biteshez túl nagy a CPU frekvencia: 8000000/1024=7812.5 - a legnagyobb előosztóval is nagyobb lesz mint 255. 16 bites időzítők: Timer1 és Timer3, bármelyikkel megoldható. 8 bites időzítők: timer0 és timer2.
Pontosan 1s időzítéshez kell egy 8 bites segédváltozó is - szoftveres rásegítés miatt.
1024-es előosztó nem jó, mert nem ad egész értéket. Ezért 256-osat használnuk.
8000000/256=31250 - ekkora frekvenciával fog a TCNT0 lépkedni.
CTC módban a komparátor regiszterbe (OCR0A) 249-et kell tölteni, ekkor a számláló 31250/250=125-ször fog körbefordulni másodpercenként. Minden körbefordulásnál növeljük a segédváltozót, ha eléri a 125-öt akkor le kell nullázni és lefuttatni azt a programrészt ami 1s-es időzítést igényel.

B1: Az ATMega128 2 darab, teljesen azonos funkcionalitással és önálló regiszterkészlettel rendelkező USART egységet tartalmaz: USART0 és USART1. Az egység sorszámát ezek után "n"-el jelölöm, mivel mindkettőre érvényesek az alábbiak:
- aszinkron működési mód 5-9 biten, beállítható paritásbit ill. 1 vagy 2 stopbit
- szinkron működés, azonos az aszinkronnal, csak kiegészül az XCKn szinkron vezetékkel.
Adó vezeték: TxDn; vevő vezeték: RxDn; szinkron vezeték(XCKn) - csak szinkron módban
Aszinkron átvitel: start bittel indul, a bitek visszaállítása belső számlálóval történik - előre meg kell beszélni a sebességet - BAUD RATE. Ezt az UBRRn 16 bites regiszterben lehet beállítani: UBRRn = (F_CPU/16/BAUD_RATE)-1.
Vezérlő regiszterek - nem részletezem a szerepüket: UCSRnA, UCSRnB, UCSRnC;
A 3 féle megszakítás kezeléséhez(küldés kész, fogadás kész, adó buffer üres) engedélyező és a flag bitek állnak rendelkezésre, amelyek az UCSRnB, UCSRnA regiszterekben találhatók.

B2: a példa az A2-ben, különbség hogy 2 gombra kell ugyanazt megoldani!

B3: Az eleje ugyanaz mint A3, tehát kell a segédváltozó. Előosztó: 128; ekkor a számláló 4000000/128=31250--szer lépked másodpercenként(TCNT0). Fontos hogy 10-el osztható legyen! A komparátor regiszterbe 124-et töltünk, ekkor 31250/125=250 körbefordulás történik másodpercenként. 100ms-onként 25, tehát 300ms-onként 75. Tehát a segédváltozót minden körbefordulásnál 1-el növeljük, ha eléri a 75-öt akkor le kell nullázni és futtatni a 300ms-os programrészt.

C1: Az ATMega128 8 darab ADC csatornát használ, melyek az F porton találhatóak.
A konverzió a szukcesszív approximáció elvén működik. Ehhez tartozik egy számláló(minden konverziós lépéshez 13 ADC órajel szükséges), egy komparátor és egy DAC. Utóbbi a szukcesszív approximációs eljárás jellegzetessége, a konverzió alatti visszacsatolás miatt szükséges.
Tulajdonságok: 10 bites felbontás, egyetlen csatorna esetén max. 15kSPs mintavételi sebesség, többféle feszültségreferencia(2.56V, AVCC, külső), differenciális bemenetválasztás, utóbbi esetén 20 és 200-szoros analóg előerősítés választható.
Egyszerre csak egyetlen csatornán(differenciális bemenetnél csatornapáron) végezhető a konverzió.
ADC regiszter: 16 bites, konverzió után ide kerül az eredmény
ADMUX regiszter: kiválasztható vele a referenciafeszültség(REFS1 és REFS0 bitek), a bitek eltolása a 16 bites ADC regiszterben - alsó vagy fölső 10 bit használata(ADLAR bit), csatorna vagy csatornapár(differenciális bemenetnél), utúbbi esetben az erősítés is - ezek a MUX4:MUX0 biteken.
ADCSRA regiszter: vezérlő-és státusz. konverzió indítás, konverzió befejezés detektálás, megszakítás engedélyezés, ADC órajel osztója(F_CPU/2^n - ahol n=1..7).

C2: nagyon épít az A2 és B2 feladatra, ha azokat érted akkor nem lesz gond. Az időzítés lehet szoftveres, mivel nem adtak meg CPU sebességet.

C3: UGYANAZ MINT A B3 feladat, a 100ms-es időzítésig. Mivel az órajel negyede, az előosztó is lehet negyede: 128->32. Komparátor regisztert 124-re kell állítani, ekkor a számláló 1000000/32/125=250-szer fordul körbe másodpercenként, ilyenkor a segédváltozót 1-el növeljük. Ha a segédváltozó eléri a 25-öt, le kell nullázni és tudod mi lesz...

Nem biztos hogy minden hibátlan, de a gondolatmenet az már több mint értékelhető. Ha felém jársz valamikor, meghívhatsz egy sörre.
A hozzászólás módosítva: Jún 26, 2013
(#) zombee válasza csabeszq hozzászólására (») Jún 26, 2013 /
 
Vegyél vissza az előosztóból, és akkor beállíthatsz nagyobb értéket is az OCRA-ba!
Még így sem biztos hogy egész, de legalább pontosabb lesz!
A hozzászólás módosítva: Jún 26, 2013
(#) johny999 válasza zombee hozzászólására (») Jún 26, 2013 /
 
Levettem az F_CPU-t 1MHz-re, prescalert 1024-en hagytam így az excel táblázatom szerint az OCRA 40-122-között változik és nincs ismétlődés.

Már csak a frekvencia változásra kell valamit kitalálni.
A hozzászólás módosítva: Jún 26, 2013

ocra.PNG
    
(#) zombee válasza johny999 hozzászólására (») Jún 27, 2013 /
 
CTC módot használsz? Azzal nem fog menni. Bocs, nem olvastam végig mindenki hozzászólását!
(#) csabeszq válasza johny999 hozzászólására (») Jún 27, 2013 /
 
Ne haragudj, de ennek így semmi értelme. Nem 20 kHz-es jelet kellene előállítanod? Ennek a felállásnak az elméleti maximális sebessége 1 kHz.

Azt javaslom, hogy telepíts egy AVR Studio-t és alatta szimuláld végig, hogy mit csinál a timer és hogyan változtatja a kimeneteit.

Miután tisztázódott, hogy mi az a prescaler, hogyan lehet a kimenetekre rákapcsolni a timert, hogyan tudsz az órajel ismeretében adott frekvenciát beállítani, akkor kérdezz.
(#) johny999 válasza zombee hozzászólására (») Jún 27, 2013 /
 
Miért nem jó a CTC mód?

@csabeszq

Úgy néz ki fáradtan nem jó ilyenekkel szórakozni.
Na még egyszer akkor.

8MHz, no prescaling, CTC mód, ORCA 200, freki 19,9kHz.
8000000/(2*(1+200)) = 19900.49Hz

Remélem most már nem számoltam el semmit.

  1. int main(void)
  2. {
  3.         DDRB |= 1 << PINB0;             //Set pin PB0 as output
  4.        
  5.         TCCR0A |= (1 << COM0A0) | (0 << WGM02) | (1 << WGM01) | (0 << WGM00);   //CTC Mode
  6.         TCCR0B |= (0 << CS02) | (0 << CS01) | (1 << CS00);      //No prescaling
  7.        
  8.         TCNT0 = 0x00;
  9.        
  10.         OCR0A = 0xC8;   //0xC8 = 200 dec -> 19,9kHz
  11.         OCR0B = 0x00;
  12. }
(#) csabeszq válasza johny999 hozzászólására (») Jún 27, 2013 /
 
Akkor már csak egy árnyalatnyit tennék hozzá, ami igazából szépség kérdése, a működést nem befolyásolja.

A TCCR0A-nak nincs WGM02 bitje. A WGM02 a TCCR0B-hez tartozik. Az |= helyett meg az = biztonságosabb.

  1. TCCR0A = (1 << COM0A0) | (1 << WGM01) | (0 << WGM00);   //CTC Mode
  2. TCCR0B = (0 << WGM02) |  (0 << CS02) | (0 << CS01) | (1 << CS00);


Később, ha változtatsz valamit a kódon, az ilyen apróságokkal szokott fél nap elmenni.
A hozzászólás módosítva: Jún 27, 2013
(#) zombee válasza johny999 hozzászólására (») Jún 27, 2013 /
 
Azért nem jó a CTC, mert nincs szinkronizálás. Ha menet közben változtatod a kitöltést,
az a kimenetre is hatással van ami nem kívánatos. PWM módban a változtatás a számláló
körbeérése után érvényesül. És CTC módban az OCRnA-t nem használhatod a kitöltés beállítására.
A hozzászólás módosítva: Jún 27, 2013
(#) johny999 válasza zombee hozzászólására (») Jún 27, 2013 /
 
Azért választottam a CTC-t mert itt fix az 50%-os kitöltési tényező, ami nekem megfelel, egy tranzisztort akarok vele kapcsolgatni. Csak a frekvencia fog változni, amit még egyelőre nem tudom hogyan oldjak meg.

@csabeszq
Igazad van, köszi.
(#) johny999 válasza csabeszq hozzászólására (») Jún 27, 2013 /
 
Definiáltam egy másik timert, TCCR1 1024-es prescalerrel. (CS13,CS11,CS10 ->1)
TCNT1-be beírtam 57723 értéket.
TIMSK-ba beállítottam a TOIE1 bitet

Még valami global interrupt bitet kell beállítani valami SREGbe, tovább nem tudom :/
(#) csabeszq válasza johny999 hozzászólására (») Jún 28, 2013 /
 
  1. #include <avr/interrupt.h>
  2.  
  3. main()
  4. {
  5.   sei();  // interrupt engedélyezése
  6.   cli();  // tiltás
  7. }
(#) Massawa hozzászólása Jún 28, 2013 /
 
Egy kérdés:

Mi a legjobb eljárás C ill ASM- ben irt részprogramok összeolvasztására?

Kösz!
(#) csabeszq válasza Massawa hozzászólására (») Jún 28, 2013 /
 
  1. uint8_t j;
  2. for( j=0; j < 10; j++ )
  3. {
  4.   asm volatile (
  5.      "in r30, %[port]  \n\t"
  6.      "add r30, %[j]    \n\t"
  7.      "out %[port], r30 \n\t"
  8.        :
  9.        : [j]     "r" (j),
  10.          [port]  "I" (_SFR_IO_ADDR(PORTD)),
  11.    );
  12. }


Nem triviális megérteni az asm volatile-t, olvass utána, hogy hogyan működik.
A hozzászólás módosítva: Jún 28, 2013
(#) Massawa hozzászólása Jún 28, 2013 /
 
Kösz, majd átrágom magam, vagy maradok az ASM-nél.
(#) johny999 válasza csabeszq hozzászólására (») Jún 28, 2013 /
 
Kösz.

Ez így szerinted jó?

  1. #define F_CPU 8000000
  2.  
  3. #include <avr/io.h>
  4. #include <avr/interrupt.h>
  5.  
  6. int freq = 200;
  7.  
  8. int main(void)
  9. {
  10.         //Set pin PB0 as output
  11.         DDRB |= 1 << PINB0;            
  12.        
  13.         //Set up timer0 for generating freq with 50% duty
  14.         TCCR0A = (1 << COM0A0) | (1 << WGM01) | (0 << WGM00);                                           //CTC Mode
  15.         TCCR0B = (0 << WGM02)  | (0 << CS02)  | (0 << CS01) | (1 << CS00);              //No prescaling
  16.        
  17.         TCNT0 = 0x00;
  18.        
  19.         OCR0A = freq;   ////200 -> 19,9kHz; 66 -> 59,7kHz
  20.         OCR0B = 0x00;
  21.        
  22.         //Set up timer1 to generate interrupt after 1sec
  23.         TCCR1 = (1 << CS13) | (1 << CS11) | (1 << CS10);       
  24.         TIMSK = (1 << TOIE1);
  25.         sei();
  26.         TCNT1 = 57723;          //65536-7813 = 57723  1 second
  27.                
  28.         for(;;) {
  29.        
  30.         }
  31. }
  32.  
  33. ISR(TIMER1_OVF_vect) {
  34.        
  35.         if (freq >= 66) {
  36.                 freq--;
  37.         }
  38.        
  39.         if (freq == 65) {
  40.                 freq = 200;
  41.         }
  42. }
(#) csabeszq válasza johny999 hozzászólására (») Jún 28, 2013 /
 
Fejben elég nehéz futtatni, de
- a timer1 szerintem nem fog menni, ott is definiálni kell a WGM-et, különben áll
- OCR0A-t nem állítod be az ISR végén
- a TCNT1 = 57723 beállítja a timert, majd 0xFFFF-nél megszakít, utána 0-ról újrakezdi. Gondolom nem ezt akarod, ott is az OCR1A-val kellene trükközni, ahogy a timer0-nál
- még megjegyzéskét: a freq változó jelenleg jó úgy ahogy van, de amint a főprogramból is elkezdenéd írni/olvasni "volatile int freq" deklaráció kell. A volatile akkor kell, amikor a főszál / interrupt egyszerre kezel egy változót. Nálad nem ez van, csak a teljesség kedvéért írtam le, hogy később ne lepődj meg, ha az interrupt módosít, de a fő szál a régi értéket használná, akkor az a volatile hiánya.
A hozzászólás módosítva: Jún 28, 2013
(#) johny999 válasza csabeszq hozzászólására (») Jún 28, 2013 /
 
TCCR1-nél nem láttam WGM bitet az adatlapban.

Az OCR0A = freq; -t bedobtam az ISR-be ugyanúgy a TCNT1 = 57723; -t is.

  1. #define F_CPU 8000000
  2.  
  3. #include <avr/io.h>
  4. #include <avr/interrupt.h>
  5.  
  6. // ATtiny45/85 Pin map
  7. //                       +-\/-+
  8. // Reset/Ain0 (D5) PB5  1|o   |8  Vcc
  9. //       Ain3 (D3) PB3  2|    |7  PB2 (D2) Ain1
  10. //       Ain2 (D4) PB4  3|    |6  PB1 (D1) pwm1
  11. //                 GND  4|    |5  PB0 (D0) pwm0
  12. //                       +----+
  13.  
  14. volatile int freq = 200;
  15.  
  16. int main(void)
  17. {
  18.         //Set pin PB0 as output
  19.         DDRB |= 1 << PINB0;            
  20.        
  21.         //Set up timer0 for generating freq with 50% duty
  22.         TCCR0A = (1 << COM0A0) | (1 << WGM01) | (0 << WGM00);                                           //CTC Mode
  23.         TCCR0B = (0 << WGM02)  | (0 << CS02)  | (0 << CS01) | (1 << CS00);              //No prescaling
  24.        
  25.         TCNT0 = 0x00;
  26.        
  27.         OCR0A = freq;   //200 -> 19,9kHz; 66 -> 59,7kHz
  28.         OCR0B = 0x00;
  29.        
  30.         //Set up timer1 to generate interrupt after 1sec
  31.         TCCR1 = (1 << CS13) | (1 << CS11) | (1 << CS10);       
  32.         TIMSK = (1 << TOIE1);
  33.         sei();
  34.         TCNT1 = 57723;          //65536-7813 = 57723  1 second
  35.                
  36.         for(;;) {
  37.        
  38.         }
  39. }
  40.  
  41. ISR(TIMER1_OVF_vect) {
  42.        
  43.         if (freq >= 66) {
  44.                 freq--;
  45.         }
  46.        
  47.         if (freq == 65) {
  48.                 freq = 200;
  49.         }
  50.        
  51.         OCR0A = freq;
  52.         TCNT1 = 57723;
  53. }


Sajna nincs oszcilloszkópom amivel le tudnám ellenőrizni hogy jó e a kimenet.

Ha szerinted így jó akkor megpróbálok csinálni egy módosított verziót ami 1Hz-től 50Hz-ig változik, azt egy leddel le tudom ellenőrizni.
(#) csabeszq válasza johny999 hozzászólására (») Jún 28, 2013 /
 
Az Attiny45-nek nincs 16 bites timere, a Timer1 a mega IC-ken 16 bites. A TCNT1 0 és 255 közötti egész szám lehet.

Bővebben: Doksi

89. oldaltól a 94. oldalig van minden leírva.
A hozzászólás módosítva: Jún 28, 2013
(#) Suncorgo hozzászólása Jún 28, 2013 /
 
Sziasztok

Lehet valamit nem tudok ami ti igen de ez a kód miért nem működik úgy ahogy kellene neki? Egy frekvencia generátort szeretnék belőle. Van egy függvény aminek beadom a kívánt frekit és az F_CPU előosztás értékét.

  1. void FreqGen(uint16_t freq,uint16_t pre) //freq=1000hz, pre=64 -> a pre az órajel leosztás
  2. {
  3.         InitTimer1(pre); //ez elindítja a timer countert Fcpu/64 órajellel
  4.         double freq_period_time = 1/freq; //0,001 -> 1ms
  5.         uint32_t counting_freq = 16000000/pre; //64 -> 250000hz
  6.         double counting_period_time = 1/counting_freq; //0,000004s -> 4us
  7.         OCR1A = (freq_period_time/counting_period_time)/2;//OCR1A érték számolás ((0,001/0,000004)/2=125)
  8.        
  9.         if(pre==64){lcd_cls();lcd_putstr("pre ok",0);d1ms(1000);} //ez jó
  10.         if(freq_period_time==0,001){lcd_cls();lcd_putstr("freq_period_time ok",0);d1ms(1000);} //ez is jó
  11.         if(counting_freq==250000){lcd_cls();lcd_putstr("counting_freq ok",0);d1ms(1000);} //ez is jó
  12.         if(counting_period_time==0,000004){lcd_cls();lcd_putstr("counting_period_time ok",0);d1ms(1000);} //ez is jó
  13.         if(OCR1A==125){lcd_cls();lcd_putstr("OCR1A ok",0);d1ms(1000);} //ezt pedig már nem írja ki, miért nem szmolja ki?
  14.        
  15.  
  16. }


így viszont működik:

  1. void FreqGen(uint16_t freq,uint16_t pre) //freq=1000hz, pre=64 -> a pre az órajel leosztás
  2. {
  3.         InitTimer1(pre); //ez elindítja a timer countert Fcpu/64 órajellel
  4.         double freq_period_time = 1/freq; //0,001 -> 1ms
  5.         uint32_t counting_freq = 16000000/pre; //64 -> 250000hz
  6.         double counting_period_time = 1/counting_freq; //0,000004s -> 4us
  7.         //OCR1A = (freq_period_time/counting_period_time)/2;//OCR1A érték számolás ((0,001/0,000004)/2=125)
  8.         OCR1A = (0.001/0.000004)/2;// <- változás
  9.        
  10.         if(pre==64){lcd_cls();lcd_putstr("pre ok",0);d1ms(1000);} //ez jó
  11.         if(freq_period_time==0,001){lcd_cls();lcd_putstr("freq_period_time ok",0);d1ms(1000);} //ez is jó
  12.         if(counting_freq==250000){lcd_cls();lcd_putstr("counting_freq ok",0);d1ms(1000);} //ez is jó
  13.         if(counting_period_time==0,000004){lcd_cls();lcd_putstr("counting_period_time ok",0);d1ms(1000);} //ez is jó
  14.         if(OCR1A==125){lcd_cls();lcd_putstr("OCR1A ok",0);d1ms(1000);} //és most ez is jó!!!
  15.        
  16.  
  17. }


így is próbáltam, nem jó:
  1. void FreqGen(uint16_t freq,uint16_t pre) //freq=1000hz, pre=64 -> a pre az órajel leosztás
  2. {
  3.         InitTimer1(pre); //ez elindítja a timer countert Fcpu/64 órajellel
  4.         double freq_period_time = 1/freq; //0,001 -> 1ms
  5.         uint32_t counting_freq = 16000000/pre; //64 -> 250000hz
  6.         double counting_period_time = 1/counting_freq; //0,000004s -> 4us
  7.         OCR1A = (uint16_t) (freq_period_time/counting_period_time)/2;//OCR1A érték számolás ((0,001/0,000004)/2=125)
  8.        
  9.         if(pre==64){lcd_cls();lcd_putstr("pre ok",0);d1ms(1000);} //ez jó
  10.         if(freq_period_time==0,001){lcd_cls();lcd_putstr("freq_period_time ok",0);d1ms(1000);} //ez is jó
  11.         if(counting_freq==250000){lcd_cls();lcd_putstr("counting_freq ok",0);d1ms(1000);} //ez is jó
  12.         if(counting_period_time==0,000004){lcd_cls();lcd_putstr("counting_period_time ok",0);d1ms(1000);} //ez is jó
  13.         if(OCR1A==125){lcd_cls();lcd_putstr("OCR1A ok",0);d1ms(1000);} //ez most sem jó
  14.        
  15.  
  16. }


mind 2 esetben OCR1A értéke 0 (nulla).

Van valami ötletetek hogy mi okozza ezt?
(Fejlesztő környezet: AtmelStudio6)

Üdv: Suncorgo
A hozzászólás módosítva: Jún 28, 2013
(#) johny999 válasza csabeszq hozzászólására (») Jún 28, 2013 /
 
Vagyis akkor a timer1-et be se lehet állítani 1sec-re? (Ha 8MHz az F_CPU)
A hozzászólás módosítva: Jún 28, 2013
(#) csabeszq válasza Suncorgo hozzászólására (») Jún 29, 2013 /
 
@Suncorgo

1. - ez egy mikrokontroller, inkább használj egész számokat, kevesebb bajod lesz vele
2. - a te esetedben egyértelműen kerekítési hibáról beszélünk.

Az 1/3-ad végeredménye 10-es számrendszerben: 0.3333333333333333....
Az 1/5-öd végeredménye 16-os számrendszerben: 0.3333333333333333.... hexadecimálisan

Egyértelmű, hogy a 0,000004 az végtelen tizedestört 16-os számrendszerben az 1/5-ös osztás miatt.

Értelemszerűen az
  1. if( val == 0.1)

programozási hiba, mert mi van ha a végeredmény 0.09999999999. Akkor már nem egyenlő?

Térjünk vissza a te esetedre:
  1. OCR1A = (0.001/0.000004)/2

A fordító ezt neked fordításnál kiszámolja a PC-n alkalmazott alapértelmezett 8 byte-os double-lel. Ennek pontossága 1/10^15-en.

  1. OCR1A = (freq_period_time/counting_period_time)/2;


Ezt bizony már az AVR számolja ki, ahol a double 4 byte-os, a pontossága 1/10^7-en.
Nyilván a 16-os számrendszerben a végtelen tizedestörted egy kissé bezavar, ezért lehet a végeredmény más, mondjuk 124.9999, ami egészre kerekítés után 124 lesz.
A hozzászólás módosítva: Jún 29, 2013
(#) rolandgw hozzászólása Jún 29, 2013 /
 
Sziasztok ! Van egy kis problémám egy avr-re kötött pillanat kapcsolóval.Start/stop funkciót lát el,engedélyezi ill.tiltja a timer megszakítást.Prell mentesítést tettem be 60ms-os újraolvasással,port beolvasás van a ciklusban,felhúzó ellenállás bekapcsolva.Viszont elég rövid a loop ciklusom,gondolom ezért bizonytalan a működés,sokszor nem vált funkciót,valószínűleg rádupláz.Hogy lehetne ezt megoldani ? Kösz !
(#) Suncorgo válasza csabeszq hozzászólására (») Jún 29, 2013 /
 
Oké

Köszi a kimeritő választ, szép napot
(#) vzoole válasza rolandgw hozzászólására (») Jún 29, 2013 /
 
Gomb lenyomáskor tegyél be egy gomb tiltó fleget.
Ezt csak felengedett állapotban tudd törölni.
(#) johny999 válasza csabeszq hozzászólására (») Jún 29, 2013 /
 
  1. ISR(TIMER1_OVF_vect) {
  2.        
  3.         timer1_ovf_count++;
  4.        
  5.         if (timer1_ovf_count > 30) { //8Mhz/1024presc/2^8 = 30.5
  6.        
  7.                 if (freq >= 66) {
  8.                         freq--;
  9.                 }
  10.                
  11.                 if (freq == 65) {
  12.                         freq = 200;
  13.                 }
  14.                
  15.                 OCR0A = freq;
  16.                
  17.                 timer1_ovf_count = 0;
  18.         }
  19.        
  20. }


Ez így jó lehet?
A hozzászólás módosítva: Jún 29, 2013
(#) rolandgw válasza vzoole hozzászólására (») Jún 30, 2013 /
 
  1. LOOP:
  2. .
  3. .
  4. SBIS    BUTTON_PIN,BUTTON_PIN_START
  5. RCALL   START_STOP
  6. .
  7. RJMP     LOOP
  8. .
  9. START_STOP:
  10.        
  11.         RCALL   DELAY_60MS
  12.         SBIC    BUTTON_PIN,BUTTON_PIN_START
  13.         RJMP    NOT_0
  14.         LDS     TEMP2,TIMSK1
  15.         LDI     TEMP1,1<<OCF1A
  16.         EOR     TEMP1,TEMP2
  17.         STS     TIMSK1,TEMP1
  18. NOT_0:
  19.         RET

Ez a kód,ha beteszek egy tiltó fleget, a loop-ban újra engedélyeznem kell,szerintem akkor ismét rá tud futni a ciklus hosszabb gombnyomás esetén...de lehet,hogy rosszul értem amit írtál.
(#) csabeszq válasza johny999 hozzászólására (») Jún 30, 2013 /
 
Igen, én is így szoktam a ritka interruptokat kezelni.

Egyébként szúnyogriasztót építesz?
Következő: »»   544 / 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