Fórum témák

» Több friss téma
Cikkek » SRF-04 Ultrahangos távolságmérő szenzor használata Arduino-val és AVR-rel
SRF-04 Ultrahangos távolságmérő szenzor használata Arduino-val és AVR-rel
Szerző: Fizikus, idő: Dec 7, 2011, Olvasva: 28736, Oldal olvasási idő: kb. 5 perc
Lapozás: OK   4 / 7

Távolságmérés AVR-rel (Timer1 Normál működési mód)

Nincs mese, ahhoz hogy megértsük, hogy hogyan működik az AVR-GCC-ben írt ultrahangos távolságmérő kód, az AVR timer-einek működését kell alap szinten megismerni.
Röviden, a Timer egy olyan regiszter, ami egy megadott időnként növeli az értékét anélkül hogy a mikrovezérlőnek foglalkozni kellene vele. A mai modern mikrovezérlők timerei sokféle működési módra állíthatóak be, amik különféle célokra használhatóak. Korábbi cikkjeimben már ezek közül röviden tárgyaltam néhányat (amelyekre most nem térek ki részletesen):

  • Normál működési mód: megadott időközönként előállított megszakítások létrehozására alkalmas (a Timer0-t a soros LCD panelt vezérlő a szoftveres UART rutin pontos időzítésére használtam - Link)
  • Output Compare mód: különböző frekvenciájú és szimmetriáju jelek előállítására alkalmas (a Timer1-et a robotjaimat meghajtó áttételes DC motorok sebességének PWM jellel történő szabályozására használtam - Link)

Az AVR-es példákban az Echo lábon lévő jel hosszát kétféle módszerrel fogom megmérni. Először pollingolással a Timer Normál módjának használatával, másodszor pedig megszakításokkal az Input Capture mód használatával.

ATMega8 Timerek
A példámban egy ATMega8-ast használok, aminek két 8 bites és egy 16 bites Timere van. A 16 bites Timer sokkal több funkcióval rendelkezik mint a 8 bites, és a 16 bites felbontásnak köszönhetően sokkal pontosabb jelgenerálásra és időzítésre használható (amíg a 8 bites timerek számlálója max. 255-ig tud számolni, addig a 16 bites Timer számlálóregisztere maximálisan 65535-ig). Az ATMega8-as esetén a Timer1 a 16 bites, aminek igen sokféle működési módja van (a részletekért lásd az ATMega8 adatlapját). Rendelekezik két 16 bites output compare regiszterrel (OCR1A és OCR1B), amivel pl PWM jel állítható elő. Továbbá rendelkezik egy 16 bites Input Capture regiszterrel is (ICR1). A Timer1 beállításait és a működési módjait a hozzá tartozó TCCR1A és TCCR1B kontrol regiszterrel vezérelhetjük. (A Timerekhez tartozó regiszterek neve Timer-enként és AVR típusonként eltérő lehet, ezért másmilyen típusú AVR használata esetén mindenki nézze meg az adott AVR adatlapjában az eltéréseket).

A TCCR1A regiszter az Output Compare működési módok beállítására szolgál, amivel PWM jelet állíthatunk elő a Timerhez tartozó megfelelő kimeneti lábakon. Később a példákban a Timer1-et normál módban és input capture módban fogom használni, ezért a TCCR1A regiszter bitjeit 0-nak állítom be.

A TCCR1B regiszter a Timer-t meghajtó órajelimpulzusok és az Input Capture működési mód beállítására szolgál.
 

AVR példa 1
Először pollingolással a Timer Normál módjának használatával fogom megmérni az Echo lábon lévő jel hosszát. A soros LCD modulról szóló cikkemben a Timer0 normál módjának a használatával már részletesen foglalkoztam, ami nagyon hasonló a Timer1-hez, ezért erre most nem térek ki.

Az AVR-es példákban az SRF04 szenzor Trigger lábát az ATMega8 PD7-es lábára, az Echo lábat pedig a PB0 lábára kötöttem.

  1. /*
  2. Szoftveres idomeres + polling
  3. SRF04 + AVR + soros LCD
  4. Hardware: ATmega8 @ 7.372800MHz
  5. PC Software:Hyper terminal @ 9600 baud, Nincs Paritas Bit, 1 Stop Bit, Flow Control = NONE
  6. */
  7. #define F_CPU 7372800UL // rendszer orajel: 7.3728 MHz
  8. #define USART_BAUDRATE 9600  // soros kommunikacio sebessege: 9600 bps
  9. #define UBRR_ERTEK ((F_CPU / (USART_BAUDRATE * 16UL)) - 1) // UBRR
  10.  
  11. #include <avr/io.h>
  12. #include <inttypes.h>
  13. #include <util/delay.h>
  14. #define Trigger_PORT PORTD
  15. #define Trigger_PIN PIND
  16. #define Trigger_DDR DDRD
  17. #define Trigger_Lab PD7    //SRF04 Trigger laba PORTD7-re kotve
  18. #define Echo_PORT PORTB
  19. #define Echo_PIN PINB
  20. #define Echo_DDR DDRB
  21. #define Echo_Lab PB0    //SRF04 Echo laba PORTB0-re kotve
  22. void KonfigUART() // UART beallitasa
  23. {
  24.    // 9600 bps soros kommunikacio sebesseg beallitasa
  25.    UBRRL = UBRR_ERTEK;    // UBRR_ERTEK also 8 bitjenek betoltese az UBRRL regiszterbe
  26.    UBRRH = (UBRR_ERTEK>>8);   // UBRR_ERTEK felso 8 bitjenek betoltese az UBRRH regiszterbe
  27.    // Aszinkron mod, 8 Adat Bit, Nincs Paritas Bit, 1 Stop Bit
  28.    UCSRC |= (1 << URSEL) | (1 << UCSZ0) | (1 << UCSZ1);
  29.    //Ado es Vevo aramkorok bekapcsolasa
  30.    UCSRB |= (1 << RXEN) | (1 << TXEN);   //
  31. }
  32. char UARTAdatFogad() // Ez a fuggveny a beerkezo adatokat kiolvassa az UDR regiszter bejovo pufferebol
  33. {
  34.    while(!(UCSRA & (1<<RXC)))  // Varakozas amig nincs uj bejovo adat
  35.    {
  36.       //Varakozas
  37.    }
  38.    //Most mar van beerkezett adat, amit kiolvasunk a pufferbol
  39.    return UDR;
  40. }
  41.  
  42. void UARTAdatKuld(char data) // Ez a fuggveny a kuldendo adatot beirja az UDR regiszter kimeno pufferjebe
  43. {
  44.    while(!(UCSRA & (1<<UDRE)))  // Varakozas amig az Ado kesz nem lesz az adatkuldesre
  45.    {
  46.       //Varakozas
  47.    }
  48.    // Az Ado mar kesz az adatkuldesre, a kuldendo adatot a kimeno pufferjebe irjuk
  49.    UDR=data;
  50. }
  51. void UARTSzovegKuld( char *p)
  52. {
  53.  while(*p)
  54.  {
  55.    UARTAdatKuld( *p++);
  56.  }
  57. }
  58.  
  59. uint16_t JelSzelesseg()
  60. {
  61.        uint16_t result;
  62.          //az SRF04 Trigger labara 15us-os, magas allapotu impulzus adasa
  63.          Trigger_PORT |= (1<<Trigger_Lab);   //magas allapot
  64.          _delay_us(15);  // varakozas 15 mikroszekundumig
  65.          Trigger_PORT &= (~(1<<Trigger_Lab)); //alacsony allapot
  66.         // _delay_us(20);
  67.        //varakozas az Echo labon megjeleno felfuto elre (polling)
  68.        while(!(Echo_PIN & (1<<Echo_Lab)));
  69.        //Timer1 beallitasa es nullazasa
  70.        TCCR1A=0X00;
  71.        TCCR1B=(1<<CS11); //eloosztas = Fcpu/8
  72.        TCNT1=0x00;       //Timer szamlalo nullazasa
  73.        //varakozas az Echo labon megjeleno lefuto elre (polling)
  74.   while(Echo_PIN & (1<<Echo_Lab));
  75.        result=TCNT1;
  76.        //Timer leallitasa
  77.        TCCR1B=0x00;
  78.        if(result > 60000) //ha az impulzus hosszabb mint 60ms,nincs celtargy a szenzor elott
  79.           return 0x0000; //0 ertek visszaadasa eredmenyul
  80.        else
  81.           return (result);
  82. }
  83. int main(void)  // Foprogram
  84. {
  85.   uint16_t Time = 0;
  86.   KonfigUART();   // UART Konfiguralasa
  87.         //Trigger pin kimenet
  88.         Trigger_DDR |= (1<<Trigger_Lab);
  89.         //Echo pin bemenet
  90.         Echo_DDR &= (~(1<<Echo_Lab));
  91.  while(1)
  92.     {
  93.   //az Echo labon levo impulzus szelessegenek merese
  94.   Time = JelSzelesseg();
  95.   UARTSzovegKuld("?f");  // ?f soros LCD parancs: LCD torlese
  96.   UARTAdatKuld('0'+(Time/10000) % 10);  // Tizezresek kiirasa
  97.   UARTAdatKuld('0'+(Time/1000) % 10);   // Ezresek ertekenek kiirasa
  98.   UARTAdatKuld('0'+(Time/100) % 10);  // Szazasok ertekenek kiirasa
  99.   UARTAdatKuld('0'+(Time/10) % 10);   // Tizesek ertekenek kiirasa
  100.   UARTAdatKuld('0'+Time % 10);    // Egyesek ertekenek kiirasa
  101.   UARTSzovegKuld(" us");     //
  102.   UARTSzovegKuld("?m");     // ?m soros LCD parancs: ugras a sor elejere
  103.   _delay_ms(50);         // várakozás
  104.    }
  105. }

A program elején a Trigger lábat kimenetnek állítom be, az Echo lábat pedig bemenetnek. A Trigger lábat alacsony állapotra kapcsolom (ez lesz az alapértelmezett állapot)

Létrehozok egy JelSzelesseg() függvényt, ami az Echo lábon lévő impulzus hosszát méri meg. A függvény a távolságmérés minden lépését végrehajtja: előállítja a Trigger jelet, elindítja a Timert és megméri a visszhang jel hosszát:

  1. A Trigger lábat magas állapotra kapcsolja
  2. Vár 15us-ig
  3. A Trigger lábat alacsony állapotra kapcsolja
  4. Vár az Echo láb magas állapotára
  5. Amikor az Echo láb magas állapotra kapcsol, nullázza és elindítja a Timert normál módban.
  6. Vár amíg az Echo láb alacsony állapotra nem kapcsol, ekkor a Timer értékét kiolvassa egy változóba és kikapcsolja a Timert.


A fenti függvénynél a Trigger láb és az Echo láb szabadon választható, ezért a szenzor az AVR bármelyik szabad I/O lábára ráköthető. Az Arduino-s példához hasonlóan, a fenti függvény is teljesen lefoglalja a mikrovezérlőt, amíg a távolságmérés be nem fejeződik. A mikrovezérlő folyamatosan figyeli az Echo lábat. A függvény maximum 36ms-ig vár a céltárgyról visszaérkező visszhangra, ha eddig nem érkezik visszhang (nincs a szenzor előtt semmi, vagy a tárgy túl messze van), akkor a függvény 0 értéket ad vissza. Fontos, hogy legalább 10ms legyen a mérések között, hogy az előző mérés alatt generált ultrahang impulzusok elhaljanak és az új mérésbe ne zavarjanak be.

A példában az AVR rendszerórajele 7.3728 MHz, ezért 8-as leosztást használva egy 1.085 mikroszekundumonként számláló Timert tudunk csak létrehozni. Ez az időalap különbözik az Arduino-nál használt 1 us-os időalaptól, ezért a céltárgy távolságát megadó képlet is változni fog. De először egy mérőszalag segítségével felvettem a szenzor impulzushossz - céltárgytávolság függvényét.

Az 1.085 mikroszekundum alatt az ultrahang impulzus 0.37 mm-nyi utat tesz meg. Ez 0.185mm-es távolságnak felel meg, ami jó közelítéssel 10/54-el egyenlő. A 7.3728 MHz-es AVR órajel esetén  a JelSzelesseg() függvénnyel a céltárgy távolsága az alábbi módosított képlettel számolható:
Távolság (mm-ben) = JelSzelesség()*10/54

A fenti példában láthattuk, hogy a Timer1 normál módjának felhasználásával csak pollingolva mérhető meg az Echo lábon lévő jel hossza. Ez a mikrovezérlőt a mérés idejére teljesen lefoglalja. Ezzel a módszerrel ugyanazt az eredményt értük el mint az Arduino-val, de az AVR-GCC kód bonyolultabb és lényegesebben nagyobb méretű.

Most nézzük meg hogyan lehet a jel hosszának mérését elegánsan, pollingolás nélkül, megszakítások használatával, a Timer1 Input Capture működési módjának a segítségével megoldani.


A cikk még nem ért véget, lapozz!
Következő: »»   4 / 7
Értékeléshez bejelentkezés szükséges!
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