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   812 / 837
(#) Istvanpisti válasza Milligram hozzászólására (») Feb 11, 2020 / 1
 
Szia!
Te a TIMER1/COUNTER1 8-as PWM módját választottad, ahol a TOP értéket (ameddig felfelé számol a számláló) az ICR1 regiszter határozza meg, egyszerűbben mondva ez fogja meghatározni a PWM frekvenciát, az OCR1A, és OCR1B pedig a két output compare unit kimenetén a kitöltési tényezőt.
Adjál értéket az ICR1 regiszternek.
(#) Milligram válasza Istvanpisti hozzászólására (») Feb 11, 2020 /
 
Ha ICR1 regiszternek értéket adok akkor még a PB1 se kapcsol.
Próbáltam változtatni a WGM de a PB2 akkor se akar változni . :/
(#) Istvanpisti válasza Milligram hozzászólására (») Feb 11, 2020 /
 
A kérdés, mekkora értéket adtál?
(#) Milligram válasza Istvanpisti hozzászólására (») Feb 11, 2020 /
 
Próbáltam több értéket 0-tól 65535-ig.
(#) Milligram hozzászólása Feb 11, 2020 /
 
Sikerült egy attiny85 amit akartam.
Ha egy bement ADC ként szolgál és ezt az értéket beírom a pwm jeléhez ez szépen változik is de csak akkor ha a függvény lefutott.
Egy megszakítást szeretnék a main függvénybe meghívtam a sei() parancsot és azon kívül pedig a ISR(ADC_vect),de nem változik a kimenet amíg le nem fut az összes függvény.
Vagy esetleg meg lehet oldani másként is?
(#) Istvanpisti válasza Milligram hozzászólására (») Feb 11, 2020 /
 
Ha kódot mutatnál, talán könnyebb lenni megpróbálni segíteni.
(#) Milligram válasza Istvanpisti hozzászólására (») Feb 11, 2020 /
 
Kiszedtem a megszakítást de szeretném hogy csak akkor legyen a kimenet aktiv (PB1-OC0B) ha PB0 -ra rákapcsolom a mínuszt.
Ugyan igy a PB3(Bemenet) és PB4(Kimenet).
Ha a PB0 megkapja a jelet akkor fel is kapcsol arra a PWM jelre ami épp be van állítva az ADC bemeneten de úgy marad sajnos :/ .

  1. #include <avr/io.h>
  2. #include <util/delay.h>
  3. #include <avr/interrupt.h>
  4.  
  5.  
  6.  
  7. void adc_setup (void){
  8.  
  9.         ADMUX |= (1 << MUX0);
  10.         ADMUX |= (1 << ADLAR);
  11.  
  12.  
  13.         ADCSRA |= (1 << ADPS1) | (1 << ADPS0) | (1 << ADEN) | (1<<ADIF) ;
  14. }
  15.  
  16. int adc_read (void){
  17.  
  18.         ADCSRA |= (1 << ADSC);
  19.  
  20.         while (ADCSRA & (1 << ADSC));
  21.  
  22.         return ADCH;
  23. }
  24.  
  25. void pwm_writeL (int val)
  26. {
  27.         OCR0B = val;
  28.         OCR1B = 255;
  29.        
  30.         }
  31.        
  32. void pwm_writeR (int val){
  33.        
  34.         OCR1B = val;
  35.         OCR0B = 255;
  36.        
  37.        
  38. }
  39.  
  40. void pwm_setup(){
  41.        
  42.         TCCR0B |= (1 << CS01) | (1 << CS00);
  43.         TCCR0A |= (1 << WGM00)|(1 << WGM01);
  44.         TCCR0A |= (1 << COM0B1);
  45.        
  46.         TCCR1 |= (1<<CS12);
  47.         GTCCR |= (1<<COM1B1)|(1<<PWM1B);
  48.  
  49.        
  50. }
  51.  
  52. int main (void){
  53.         int val;
  54.         int b;
  55.         b=0;
  56.  
  57.        
  58.         DDRB &= ~((1<<PB0)|(1<<PB3));
  59.         PORTB |= (1<<PB0)|(1<<PB3);
  60.        
  61.        
  62.        
  63.        
  64.         adc_setup();
  65.         pwm_setup();
  66.  
  67.        
  68.         while (1) {
  69.                
  70.                 val = adc_read();
  71.                
  72.                
  73.                
  74.                                
  75.         if (((PINB &(1<<PINB0))==0) && (b==0)){
  76.                        
  77.                         DDRB |= (1<<PB1);
  78.                         b=1;
  79.                 }
  80.                                                                
  81.                         if((PINB &(1<<PINB0))==0){
  82.                         _delay_ms(5);
  83.                         pwm_writeL(val);                       
  84.                         }
  85.                
  86.                                
  87.        
  88.         if (((PINB &(1<<PINB3))==0) && (b==1)){
  89.                
  90.                 DDRB |= (1<<PB4);
  91.                 b=2;
  92.         }
  93.        
  94.                  if((PINB &(1<<PINB3))==0){
  95.                                 _delay_ms(5);
  96.                                 pwm_writeR(val);       
  97.                                
  98.                         }
  99.                        
  100.                
  101.                
  102.                
  103.         }
  104. }



Köszönöm a segítséget.
(#) Milligram hozzászólása Feb 11, 2020 /
 
Át írtam a kódot egy kicsit .

  1. int main (void){
  2.         int val;
  3.         int b;
  4.         b=0;
  5.  
  6.        
  7.         DDRB &= ~((1<<PB0)|(1<<PB3));
  8.         PORTB |= (1<<PB0)|(1<<PB3);
  9.        
  10.         DDRB |= (1<<PB1)|(1<<PB4);
  11.        
  12.        
  13.        
  14.         adc_setup();
  15.         pwm_setup();
  16.        
  17. pwm_writeL(255);
  18. pwm_writeR(255);
  19.        
  20.         while (1) {
  21.                
  22.                 val = adc_read();
  23.                        
  24.                                                                
  25.                         if((PINB &(1<<PINB0))==0){
  26.                         _delay_ms(5);
  27.                         pwm_writeL(val);                       
  28.                         }
  29.                         if(PINB &(1<<PINB0)==1){
  30.                                 pwm_writeL(255);
  31.                         }
  32.        
  33.                        
  34.                  if((PINB &(1<<PINB3))==0){
  35.                                 _delay_ms(5);
  36.                                 pwm_writeR(val);       
  37.                                
  38.                         }
  39.                         if(PINB &(1<<PINB3)==1){
  40.                                 pwm_writeR(255);
  41.                         }
  42.                
  43.                
  44.                
  45.         }
  46. }


De ilyenkor a PB4 csak villog ha a PB3 aktiv.
(#) Milligram hozzászólása Feb 11, 2020 /
 
Sikerült megoldani az alábbi módon.

  1. while (1) {
  2.                
  3.                 val = adc_read();
  4.                        
  5.                                                                
  6.                         if((PINB &(1<<PINB0))==0){
  7.                         _delay_ms(5);
  8.                         pwm_writeL(val);                       
  9.                         }
  10.                         if((PINB &(1<<PINB0))==1){
  11.                                 _delay_ms(5);
  12.                                 pwm_writeL(255);
  13.                         }
  14.        
  15.                        
  16.                  if((PINB &(1<<PINB3))==0){
  17.                                 _delay_ms(5);
  18.                                 pwm_writeR(val);       
  19.                                
  20.                         }
  21.                         if((PINB &(1<<PINB3))==1){
  22.                                 _delay_ms(5);
  23.                                 pwm_writeR(255);
  24.                         }
  25.                
  26.                
  27.                
  28.         }


Beraktam egy delay-t és így nem villog a PB4 és csak akkor aktív ha van bemenet .
(#) jacoka hozzászólása Feb 20, 2020 / 1
 
Tiny13-hoz remek forrásanyag 100+ projekt attiny13-hoz.

UART library tiny13-hoz, viszont egy minimális korrekcióval remekül használható 25/45/85-nél is a klasszikus 1000000/8000000/16000000 órajeleken.
  1. #if defined F_CPU
  2. #define UART_BAUDRATE (9600 * (F_CPU / 1000000))
  3. #endif


Természetesen putty-ban ennek megfelelően kell beállítani a baud rate-et.
A hozzászólás módosítva: Feb 20, 2020
(#) jacoka válasza jacoka hozzászólására (») Feb 20, 2020 / 1
 
Az általam kicsit módosított UART library (header-ként).
Tiny 13/25/45/85 WinAVR és AvrDude környezet (windows/linux/valamint raspberry pi raspbian környezetben használva)

  1. #ifndef __serial_h
  2. #define __serial_h
  3.  
  4. #define UART_RX_ENABLED (0)
  5. #define UART_TX_ENABLED (1)
  6.  
  7. #ifndef F_CPU
  8. # define F_CPU (1000000UL)
  9. #endif
  10.  
  11. #if defined(UART_TX_ENABLED) && !defined(UART_TX)
  12. # define UART_TX PB3
  13. #endif
  14.  
  15. #if defined(UART_RX_ENABLED) && !defined(UART_RX)
  16. # define UART_RX PB4
  17. #endif
  18.  
  19. #if (defined(UART_TX_ENABLED) || defined(UART_RX_ENABLED)) && !defined(UART_BAUDRATE)
  20. # define UART_BAUDRATE (9600)
  21. #endif
  22.  
  23. #define TXDELAY   (int)(((F_CPU / UART_BAUDRATE) - 7 + 1.5) / 3)
  24. #define RXDELAY   (int)(((F_CPU / UART_BAUDRATE) - 5 + 1.5) / 3)
  25. #define RXDELAY2  (int)((RXDELAY * 1.5) - 2.5)
  26. #define RXROUNDED (((F_CPU/UART_BAUDRATE)- 5 + 2) / 3)
  27.  
  28. #if RXROUNDED > 127
  29. # error Low baud rates are not supported - use higher, UART_BAUDRATE
  30. #endif
  31.  
  32. #define MAXCHAR (10)
  33.  
  34. #include <avr/interrupt.h>
  35.  
  36. uint8_t uart_getc(void) {
  37. #ifdef  UART_RX_ENABLED
  38.         char    c;
  39.         uint8_t sreg;
  40.  
  41.         sreg = SREG;
  42.         cli( );
  43.         PORTB &= ~(1 << UART_RX);
  44.         DDRB  &= ~(1 << UART_RX);
  45.        
  46.         __asm volatile(
  47.                 " ldi r18, %[rxdelay2] \n\t"
  48.                 " ldi %0, 0x80 \n\t"
  49.                 "WaitStart: \n\t"
  50.                 " sbic %[uart_port]-2, %[uart_pin] \n\t"
  51.                 " rjmp WaitStart \n\t"
  52.                 "RxBit: \n\t"
  53.                 " subi r18, 1 \n\t"
  54.                 " brne RxBit \n\t"
  55.                 " ldi r18, %[rxdelay] \n\t"
  56.                 " sbic %[uart_port]-2, %[uart_pin] \n\t"
  57.                 " sec \n\t"
  58.                 " ror %0 \n\t"
  59.                 " brcc RxBit \n\t"
  60.                 "StopBit: \n\t"
  61.                 " dec r18 \n\t"
  62.                 " brne StopBit \n\t"
  63.                 : "=r" (c)
  64.                 : [uart_port] "I" (_SFR_IO_ADDR(PORTB)),
  65.                 [uart_pin] "I" (UART_RX),
  66.                 [rxdelay ] "I" (RXDELAY),
  67.                 [rxdelay2] "I" (RXDELAY2)
  68.                 : "r0","r18","r19"
  69.         );
  70.         SREG = sreg;
  71.         return c;
  72. #else
  73.         return (-1);
  74. #endif
  75. }
  76.  
  77. void uart_putc(uint8_t c) {
  78. #ifdef  UART_TX_ENABLED
  79.         uint8_t sreg;
  80.  
  81.         sreg = SREG;
  82.         cli( );
  83.         PORTB |= 1 << UART_TX;
  84.         DDRB  |= 1 << UART_TX;
  85.        
  86.         __asm volatile(
  87.                 " cbi %[uart_port], %[uart_pin] \n\t"
  88.                 " in r0, %[uart_port] \n\t"
  89.                 " ldi r30, 3 \n\t"
  90.                 " ldi r28, %[txdelay] \n\t"
  91.                 "TxLoop: \n\t"
  92.                 " mov r29, r28 \n\t"
  93.                 "TxDelay: \n\t"
  94.                 " dec r29 \n\t"
  95.                 " brne TxDelay \n\t"
  96.                 " bst %[ch], 0 \n\t"
  97.                 " bld r0, %[uart_pin] \n\t"
  98.                 " lsr r30 \n\t"
  99.                 " ror %[ch] \n\t"
  100.                 " out %[uart_port], r0 \n\t"
  101.                 " brne TxLoop \n\t"
  102.                 :
  103.                 : [uart_port] "I" (_SFR_IO_ADDR(PORTB)),
  104.                 [uart_pin] "I" (UART_TX),
  105.                 [txdelay ] "I" (TXDELAY),
  106.                 [ch] "r" (c)
  107.                 : "r0","r28","r29","r30"
  108.         );
  109.         SREG = sreg;
  110. #endif
  111. }
  112.  
  113. void serial_printc(const uint8_t c) {
  114.         uart_putc(c);
  115. }
  116.  
  117. void serial_prints(const char *s) {
  118.         while(*s) uart_putc(*(s++));
  119. }
  120. /*
  121.  *
  122.  *      print integer number
  123.  *      1 param : integer
  124.  *      2 param : clear digit (param length) if param greater than zero
  125.  *
  126.  */
  127. void serial_printi(int i, uint8_t d) {
  128.         int  j;
  129.         char s[MAXCHAR] = {0x00};
  130.  
  131.         if(i < 0) {
  132.                 uart_putc('-');
  133.                 i = -i;
  134.         }
  135.  
  136.         if(i == 0) {
  137.                 uart_putc('0');
  138.                 if(d) d--;
  139.                 while(d && d--) uart_putc(' ');
  140.         }
  141.         else {
  142.                 for(j = 0; i > 0 && j < MAXCHAR; i /= 10, j++) {
  143.                         s[j] = (i % 10) + '0';
  144.                 }
  145.        
  146.                 j -= 1;
  147.        
  148.                 for(; j >= 0; j--) {
  149.                         uart_putc(s[j]);
  150.                         if(d) d--;
  151.                 }
  152.  
  153.                 while(d && d--) uart_putc(' ');
  154.         }
  155. }
  156.  
  157. #endif  /* __serial_h */
A hozzászólás módosítva: Feb 20, 2020
(#) jacoka hozzászólása Feb 20, 2020 /
 
Attiny 13/25/45/85 családhoz használható HD44780/KS7066 kompatibilis 4/8bites parallel kijelzőhöz 2x16 LCD készítettem shiftregiszteres meghajtót + saját library-t (2 vezetékes, nem i2c és nem SPI). Ha valakit komolyabban érdekelne megosztom a nyák illetve a library forrásokat.
A hozzászólás módosítva: Feb 20, 2020
(#) zombee hozzászólása Feb 27, 2020 /
 
Sziasztok!
T0,T1,T2 (időzítő bemenetek) beállíthatók-e közvetlen interrupt generáláshoz fel-VAGY lefutó élre úgy, mint az INT lábak? Időzítő CTC mód, OCRn(A)=1, órajel forrás Tn fel-vagy lefutó élen, megszakítás engedélyezve komparálásra. A többi alternatíva (ICP1, AIN1) már foglalt, hasonló célra.
Fontos, hogy csak az egyik élen generálhat megszakítást, így a PCINT ki van zárva.
(#) exup74 hozzászólása Feb 27, 2020 /
 
Sziasztok.

Nem kezdtem az elejétől olvasgatni a topic-ot, lehet nem is ide kéne kérdeznem ez ügyben. Nagyon kezdő vagyok a programozásban, igazából meglévő példákat alakítgatok és módosítok a saját feladatomhoz. Gondolom volt is ilyenről szó, valószínűleg beállítási gondjaim vannak. A lényeg, hogy atmega8, de 328-al is ez van. Modbus kommunikációm csak akkor üzemel, ha belső 1MHZ óra van használva. Ha belső 8 vagy külső 12, 16, akkor eldobálja a kommunikációt. bootloaderben kiválasztom a "megfelelőt" az arduino ide progiban is a megfelelő board-ot. Mégis csak default belső 1MHZ beállítással üzemel a modbus.

Előre is köszi minden okosságot
(#) asch válasza zombee hozzászólására (») Feb 28, 2020 /
 
Melyik csipről van szó? Nekem ezek a T0, T1, T2 bemenetek nem rémlenek így fejből, hogy mik, azért kérdezem.
(#) asch válasza exup74 hozzászólására (») Feb 28, 2020 /
 
A Modbus UART-ra épül, ha jól tudom. Tippjeim:

* Nem jó az UART-serial órajel. Ennek két alfaja lehetséges:
** Egyáltalán nem jó az órajel. A kód 1MHz-hez állítja be jól, más CPU órajelet használva ezért nem működik. (Pl 8MHz-en használva a CPU-t 8-szor gyorsabb lesz a serial jele)
** Nem elég pontos a serial órajele. Ahhoz, hogy a serial ne hibázzon a kommunikációban részt vevők órája kb 8%-os hibán belül együtt kell hogy járjon. A belső órajelek (az általam ismert AVR-ek esetén) kalibráció nélkül nem alkalmasak serial kommunikációhoz. A belső órajel hőmérséklet függő is: kompenzáció nélkül előfordulhat, hogy extrém melegben vagy hidegben "elromlik" az UART kommunikáció. Megoldási lehetőségek:
*** Külső kvarc használata pontos és stabil órajel előállításhoz.
*** Kalibráció és hőmérséklet kompenzáció. (A csipek belső órajelét tudtommal 3.3V-ra kalibrálják gyárilag. Ha 5V-on használjuk, akkor egy OSCCAL += 3; parancs korrigálja a kalibrációt az internetes néphagyomány szerint. Lásd: http://becomingmaker.com/tuning-attiny-oscillator/ Játszásból ez is elégséges megoldás, de komoly gépet ne így vezéreljünk!)
*** Órajel mérése a slave oldalon, és az UART hozzáigazítása. Ilyenkor a kommunikáció első bájtját méréshez használjuk. Ez csak Slave oldalon működik és eléggé komplex megcsinálni. A Series0 és Series1 csipek adatlap szerint már hardveresen tudni fogják ezt a funkciót (még sajnos nem próbáltam). Modbus esetén mivel nincs mérőbájt a protokoll elején, ezért pláne nehézkes volna megcsinálni.

Nem teljesen világos a leírásban egyébként, hogy hogyan váltogatod a CPU órajeleket? Tudtommal: A belső és a külső óra között a FUSE bitekkel lehet váltani programozót használva. Ha már elindult a csip, akkor már nem lehet órajelet váltani, ezért a bootloadernek ehhez már nincs köze. Az Arduino IDE pedig board típusonként 1-1 fix órajellel számol, nincs felkészítve a CPU órajel változtatására. Szóval érdemi segítséghez jobban körül kellene írnod, hogy pontosan mit csinálsz.

Ha próbálgatással nem jön össze, akkor mérni kellene a serial órajelét. Ennek mikéntjéhez egy másik topikban csináltam egy leírást: https://www.hobbielektronika.hu/forum/topic_post_2331885.html#2331885
A hozzászólás módosítva: Feb 28, 2020
(#) Sick-Bastard válasza exup74 hozzászólására (») Feb 28, 2020 /
 
Üdv!

Hibakeresési kérdések:
Hogy állítottad be a külső órajeleket? Milyen Fuse Bit konfigurációval?
A Fuse bitekben ki van kapcsolva a DIV8? Ez az oszcillátor 8-as osztója, így kapsz belső oszcillátorral 8Mhz helyett 1Mhz-et, vagy külső 16Mhzes kristállyal 2Mhz-et.
Milyen F_CPU definíció van beállítva? Ez két helyen lehet. A Make file-ban, vagy magában a kódban.

Ha az F_CPU definíciója nem azonos a valód órajellel, akkor történhet ilyesmi történhet, amit leírtál.

Hozzátenném, hogy sem Modbust, sem Arduinot nem használok. Utóbbival is csak felületesen találkoztam.
(#) exup74 válasza asch hozzászólására (») Feb 28, 2020 /
 
Tehát, atmega8 külső 16mhz kvarccal. Arduino IDE progiba kivállasztom a csippet, külső kvarc-ot 16mhz-el. Itt beletöltök bootloadert. Ellenőrzöm avrdudess-el, fuse biteket átírta. Beletöltöm a modbus példa progit, nem működik, eldobálja a kommunikációt. Ha annyit változtatok, hogy belső 1mhz-ra állítom, akkor tökéletes. Mivel teljesen kezdő vagyok, ezért magamtól nem tudom min kell változtassak. Majd megmérem szkóppal a leírásod alapján.
(#) Sick-Bastard válasza zombee hozzászólására (») Feb 28, 2020 /
 
Üdv!

Ha nem kritikus az időzítése/sebessége a megszakítónak akkor a PCINT-ba egy if() else() beiktatásával szerintem majdnem ugyan azt kapod, mint egy élen generált megszakítással.

  1. ISR(PCINT1_vect)
  2. {
  3.         if((PCINT1_PIN & (1<<PCINT1_PIN1)))             // if pin == high
  4.         {
  5.                 foo();                                         
  6.         }
  7.         else                                                                    // else pin ==low
  8.         {
  9.                 // do nothing
  10.         }
  11. }


Ez persze akkor nem megy, ha csak egy rövid impulzus kap a megszakító bemenete. Talán ezért keresel egy élgeneráltat?
(#) exup74 válasza Sick-Bastard hozzászólására (») Feb 28, 2020 /
 
Szia.

A te elképzelésed lehet a megoldásom, de nem tudok most mindenre válaszolni, mert nem vagyok otthon. A példa kódban nincs F_CPU beállítás. Gondolom ezt az átfordításnál beírja a kódba maga a program(Arduino IDE)amit abban kiválasztottam(16mhz external). És bootloadert is éget bele, ha rányomok. A fuse biteket is így írja át. Én csak ellenőrizni szoktam, hogy változtatta-e. A div8-at majd otthon megnézem.
(#) asch válasza exup74 hozzászólására (») Feb 28, 2020 /
 
Nálam ilyen opciók nincsenek az Arduino IDE-ben. (1.8.9-est használok, mert eddig nem láttam értelmét 1.8.12-re frissíteni.)

A boards manager részből elérhetően online forrásokból lehet telepíteni plusz boardokat az Arduino alá, lehetséges, hogy onnan telepítettél valami plusz board supportokat? És nálam ez nincs telepítve, azért nem látszik nálam hasonló beállítás?

Sick-Bastard-dal egyetértek, a programban más CPU frekvencia lesz beállítva, mint amin a csip valójában fut.
(#) exup74 válasza asch hozzászólására (») Feb 28, 2020 /
 
Igen, találtam leírást atmega8-328 boardhoz amit külön kellett leszedni és olyankor kiválaszthatod melyik mc és mhzt meg, hogy intern vagy extern.
Atmega
(#) exup74 válasza Sick-Bastard hozzászólására (») Feb 28, 2020 /
 
Az atmega328 viszont a belső 8mhz beállítással is jól működik, míg az atmega8 nem. Csak mint érdekesség. Igazából valószínüleg ezt a mikrokontrollert fogom használni. Csak jó lenne tudni a külső 16mhz-vel miért nem jó nekem egyik se.
Atmega8-nál nincs fuse bitek között DIV8 atmega328-nál van, ott nincs bepipálva(Low:E2)
(#) zombee válasza Sick-Bastard hozzászólására (») Feb 29, 2020 /
 
Már próbáltam. Mechanikus enkóder (PEC11R) megy rá, és kétélű megszakítással a ciklusok kb. 3-5%-át elveszíti. Egyélű megszakítással ennek tizede, vagy még kisebb a hibaarány. Jelenleg ATMega16 van, ami elvisz két enkódert az INT0-2 illetve ICP1 lábakon. Ezen próbáltam ki hogyan viselkedik, ha az INTn bemeneteken kétélű megszakítás van. Jól működik a cucc, de át akarom rakni ATMega48-ra. Azon megvan az INT0-1 és ICP1, a negyediket akarom T0 vagy T1 lábbal kiváltani ha lehet. Analóg komparátor egyelőre kiesik, mivel azon nincs schmitt-triggeres szűrés és nem akarom még egy IC-vel (pl. 74HCT1G00) bonyolítani.
(#) zombee válasza asch hozzászólására (») Feb 29, 2020 /
 
ATMega48 lenne. T2 kiesik (konkrétan:nincs), csak az adatlap tévesen utal rá. Marad T0 és T1.
(#) asch válasza zombee hozzászólására (») Feb 29, 2020 /
 
Jé, ezt már el is felejtettem, hogy van ilyen funkciója is. Pedig az ATMega328 adatlappal fekszek és kelek...

Szerintem ha úgy állítod be a számlálót, hogy 1-nél átforduljon, akkor az overflow interrupt lényegében pin change interruptként fog működni. De nem bogarásztam végig az adatlapot.

Egyébként milyen gyakoriak a jelek? Mármint mi a megengedett legynagyobb sebessége a jeladónak, és ebből milyen periódusidő, vagy jelváltás idő jön ki?

Mozoghatnak-e egyszerre a jeladók és hányféle interruptot használsz? Ha az ISR kiszolgálási időkre is adsz becslést, akkor ki lehet számolgatni, hogy lesz-e és mennyi lesz a jelvesztés.

Pont mostanában csináltam ilyet, és végül úgy valósítottam meg, hogy minden jelet egy külön ATTiny25 számol, és SPI-n küldi a mester ATMega-nak. A program garantálja, hogy 12 órajelenként jöhet 1 jelváltás, azt még fel tudja dolgozni. És 16MHz belső óráról jár. Itt van a kódja: https://github.com/rizsi/Arduino-IR-decoder/blob/quadrature_counter...er.asm és a hozzá tartozó ugrótábla is: https://github.com/rizsi/Arduino-IR-decoder/blob/quadrature_counter...le.inc

Ha worst-case-re kell tervezni, akkor az interrupt kezelés overhead-je miatt és a kiszámíthatóság miatt lehet, hogy jobban jársz, ha egyetlen fix periódusú időzítővel mintavételezed az összes bemenetet és ugrótábla segítségével számolsz az ISR-en belül. Ezzel a megoldással lehet szerintem a legtöbb kvadratúra jeladót egyszerre feldolgozni egyetlen csipen. És ha jó a megvalósítás, akkor több jeladó egyszerre adott jele nem zavarja meg egymást. Tehát ha beméred, hogy X frekvenciával jövő jelek még fel vannak dolgozva, akkor azok fel lesznek dolgozva akkor is, ha közben a másik csatornán is jönnek a jelek.

Illetve ha semmi mást nem csinál a csip, akkor fix periódusú ASM-et lehet még írni, ahogy a fentebb linkelt megoldásom is működik. Egyetlen ISR futtatása kb 50 órajelet is elvisz feldolgozással együtt (számolgattam, mert eredetileg úgy akartam megoldani a számlálást), fix periódussal pedig sikerült 36 CPU ciklusnyi periódusokkal 3 jelet egyszerre feldolgozni. Nekem úgy tűnik, hogy ez a minimum. Talán 11, vagy esetleg 10 CPU órajelre még le lehetne vinni.
(#) zombee válasza asch hozzászólására (») Feb 29, 2020 /
 
Igen, én is 1-re állítanám a komparátort, csak most nincs időm kipróbálni, működik-e vagy sem.
Az áramkörterv előbb kell, utána jöhet a szoftveres próba, csak nehogy koppanás legyen a vége.
A cuccos a két PEC mellett a forgókarok lenyomását is érzékeli, 2 db. 4 digites kijelzőt vezérel, I2C-n keresztül 2-2 ADC és DAC-vel kommunikál, és közben erőteljesen konvertálja
az ADC és DAC értékeket is. Profik már kitalálták: labortáp vezérlőmodulja.

Ezeknek az enkódereknek nem kell bika proci. A nehézséget egyedül az okozza, hogy a mechanikus kivitel erőteljes pergést okoz, valószínű, ez miatt nem jött be a kétélű megszakítás.
A bekötés se mindegy: 10k felhúzó ellenállás kell (nálam 4k7), és 100nF kerámia a földre.
Ha ez utóbbi nincs, még zavarosabb lesz a jel, vagyis inkább: kezelhetetlen.

A megszakításban beolvasom a másik oldali enkóderkimenet állapotát (feltételezi, hogy váltáskor a másik oldalon stabil), majd összevetve egy állapotváltozóval (lastevent) eldönti hogy léptessen-e vagy sem. Léptetni az "enc" változóval, amit egy 2ms-enként futó időzítő megszakítás figyel. Ugyanez az időzítő figyeli és pergésmentesíti az enkóderkar lenyomását is.
  1. //S2A:
  2. ISR(INT1_vect)
  3. {
  4.         if(PIND&(1<<6))
  5.         {
  6.                 if(lastevent2==1) enc2--;
  7.                 lastevent2=0;
  8.         }
  9.         else lastevent2 = 2;
  10.        
  11. }
  12.  
  13. //S2B:
  14. ISR(TIMER1_CAPT_vect)
  15. {
  16.         if(PIND&(1<<3))
  17.         {
  18.                 if(lastevent2==2) enc2++;
  19.                 lastevent2=0;
  20.         }
  21.         else lastevent2 = 1;
  22. }
(#) asch válasza zombee hozzászólására (») Feb 29, 2020 /
 
A pergésmentesítést szerintem "természetes úton" megoldaná, ha élvezérelt helyett idő alapon kérdezgetnéd a kvadratúra jelek értékeit. Csak úgy kell belőni a periódusidőt, hogy elbírja a proci, és ne vesszen el hasznos jel. Ha kiszámolod a futásidőt, simán kijöhet, hogy 10kHz-vel simán tudod futtatni ezt az interruptot (800 órajelenként egyszer 8MHz CPU órajel mellett), és az már elég lehet mindennek a dekódolására. Csak egy interruptod van, és ezért sokkal egyszerűbb és kiszámíthatóbb lesz minden.

Gondolom akkor a beállító gombok lesznek ilyen digitális enkoderrel megvalósítva: ezek nem fognak túl gyorsan pörögni sosem.

Én így csinálnám a mostani eszemmel - miután hetek óta kvadratúra dekódert optimalizálok magam sem tudom minek:

  1. static uint8_t prevValue;
  2. ISR(TIMER2_OVF_vect)  // Kb. 10kHz periódussal fusson le
  3. {
  4.     uint8_t pind=PIND; // PIND beolvasása regiszterbe.
  5.     uint8_t value=pind&MASK; // Hasznos bitek kiválasztása
  6.     uint8_t selector=(prevValue<<1)+value; // Az elozo es a mostani ertek kombinalasa. Ha a 0. és a 2. pint használjuk a porton, akkor ez a művelet az alsó 4 biten adja ki a hasznos értékeket
  7.     switch(selector)
  8.     {
  9.       case 0b0000:  break; // 00 -> 00
  10.       case 0b0001:  counter++; // 00 -> 01
  11.       case 0b0100:  counter--; // 00 -> 10
  12.       case 0b0101:  error(); // 00 -> 11 - ha kell kezelünk hibát, ha nem kell ignoráljuk
  13.       ... // a többi átmenetre is ki kell tölteni a reakciót értelemszerűen
  14.     }
  15.     prevValue=value;
  16.  
  17.    ... gombok kezelése, többi enkóder kezelése, stb
  18. }
(#) rolandgw válasza asch hozzászólására (») Márc 2, 2020 /
 
Ezt használtam anno, STM32-nél már nem kell ezzel foglalkozni, van interfész.
(#) asch válasza rolandgw hozzászólására (») Márc 2, 2020 /
 
Igen, valójában egyszerű a számlálás, akár diszkrét logikával is meg lehetne valósítani. De nagy sebességgel hibázás nélkül implementálni 8 bites AVR mikrovezérlőn mégis kihívás.

A linkelt oldalon a javaslatomhoz hasonlóan periódikus timerrel veszik a mintákat: egyetértek, szerintem is ez a legjobb. Pláne ha több jeladót kell egyszerre kezelni, ahogy zombee tervezi.
Következő: »»   812 / 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