logo elektroda
logo elektroda
X
logo elektroda
Adblock/uBlockOrigin/AdGuard mogą powodować znikanie niektórych postów z powodu nowej reguły.

[Atmega8l][C] Czujnik ultradźwiękowy- problem z timer1

marex85 10 Sty 2010 16:02 1515 3
  • #1 7514990
    marex85
    Poziom 11  
    Witam
    Mam problem z programem odmierzającym czas. Mikrokontroler współpracuje z czujnikami ultradźwiękowymi.
    Ogólne założenie programu jest takie że generuje paczkę 8 impulsów prostokątnych o częstotliwości 40KHz następnie 4ms na wyciszenie układu. Generowanie paczki wykonywane jest za pomocą Timera2 w trybie CTC.
    Następnie za pomocą Timera1 powinien być mierzony czas od momentu wygenerowania pierwszego impulsu przez Timer2 do momentu pojawienia się echa, które z czujników ultradźwiękowych przekazywane jest na wejśie ICP Atmegi. Na podstawie czasu wyznaczana jest odległość (ten fragment programu działa nieprawidłowo)
    Następnie otrzymany wynik wysyłany jest przez UART do komputera.

    Dodam iż jestem początkującym programistą wiec proszę o wyrozumiałość. Generacja paczki i transmisja UART były sprawdzane na oscyloskopie i przebiegi wyglądają prawidłowo jednak pomiar czasu to lepiej nie mówić.
    Z góry dziękuję za wszelaką pomoc

    Kod programu:

    #include <avr/io.h> // wejscia_wyjscia avr
    #include <avr/interrupt.h> // bibloteka obslugi przerwan
    #include <util/delay.h> // biblioteka opóźnieńs
    #include <stdlib.h>

    #define F_CPU 8000000UL // częstotliwość pracy procesora
    #define BAUD 9600 // prędkość transmisji
    #define dist 0.17

    /****************************USART*******************************/
    void InitUSART( void )
    {
    UBRRH = (unsigned char)(((F_CPU/(16UL*BAUD))-1)>>8); //Ustawiam predkosc USARTu
    UBRRL = (unsigned char)((F_CPU/(16UL*BAUD))-1);

    // Otwarcie kanalu odbioru i nadawania oraz przerwań od odbioru
    UCSRB = (1<<RXEN)|(1<<TXEN)|(1<<RXCIE);

    //URSEL=1 korzystanie z rejestru UCSC
    //USBS=0 1 bit stopu
    //UMP0=0 sprawdzanie parzystości wyłączone
    //UCSZ0=3 8 bitów danych
    //UMSEL=0 Asynchroniczne nadawanie
    UCSRC = (1<<URSEL)|(0<<USBS)|(3<<UCSZ0);
    }

    void TransmitCHAR( unsigned char data ) // funkcja wysłania bajtu po RS232
    {
    while (!( UCSRA & (1<<UDRE))); // oczekiwanie na pusty buror
    UDR = data; // wysyłanie danych
    }

    void TransmitSTRING(char *text) //funkcja wysłania danych po RS232
    {
    while(*text)
    {
    while (!( UCSRA & (1<<UDRE)));
    UDR = *text;
    text++;
    }
    }

    void TransmitINT(int number)
    {
    char buffer[7];
    itoa(number,buffer,10);
    TransmitSTRING(buffer);
    }


    /****************************TIMER2******************************/

    void InitCTC(void)
    {
    DDRB|=(1<<PB2)|(1<<PB3); //port B2, B3 jako wyjsciowe
    DDRB&=~(1<<PB0); //port B0 jako wejsciowy
    PORTB|=(1<<PB2); // Port B2 podciągnięty do zasilania
    DDRD|=(1<<PD5);
    PORTD|=(1<<PD5);

    //ustawienia timera2 generatora CTC
    //CS20=1 preskaler 1->1
    //WGM21=1 tryb CTC
    //COM20=1 zmiana stanu na przeciwny pinu OC2
    TCCR2=(1<<WGM21)|(1<<CS20);

    //czestotliwosc CTC 40kHz dla 99 działek
    OCR2=0x63;

    TIMSK|=(1<<OCIE2);
    }

    volatile uint8_t count;

    ISR(SIG_OUTPUT_COMPARE2)
    {
    if (count==0) TCNT1=0;

    count=count+1; //zwiększ licznik

    if (count>0 && count<16) //8 okresów f=40khz = 200us prostokąt
    {
    TCCR2|=(1<<COM20);
    TCCR2&=~(1<<COM21);
    }
    else if (count>=16 && count<336) //120 okresów o f=40khz =3ms 0
    {
    TCCR2|=(1<<COM21);
    TCCR2&=~(1<<COM20);
    }

    else if(count==336) //powrót do ustawień początkowych
    {
    count=0;
    TCCR2|=(1<<COM20);
    TCCR2&=~(1<<COM21);
    }

    }


    /****************************TIMER1******************************/
    void InitICP( void )
    {
    //ICNC1=1 włączenie eliminacji szumów
    //ICES1=1 wyzwolenie przechwytywania zboczem narastajacym
    //CS1n preskaler 001->1,010->8, 011->64, 100->256, 101->1024
    TCCR1B=(1<<ICNC1)|(1<<ICES1)|(1<<CS10);

    //TICIE1 przerwanie od ICP
    //TOIE1 przerwanie od przepełnienia licznika
    TIMSK|=(1<<TICIE1)|(1<<TOIE1);
    }

    volatile int sensor;
    volatile char flaga=0;

    ISR(SIG_INPUT_CAPTURE1)
    {
    sensor=TCNT1;
    flaga=1;
    }

    int main (void)
    {
    DDRD|=(1<<PD7)|(1<<PD6);
    PORTD|=(1<<PD7)|(1<<PD6);

    DDRB&=~(1<<PB1); // PORT PB1 jako wejściowy
    PORTB|=(1<<PB1); // podciągnięcie do stanu wysokiego

    InitUSART();
    InitCTC();
    InitICP();
    sei();

    while(1)
    {

    if (flaga==1)
    {

    flaga=0;
    count=0;
    sensor= sensor*dist;
    TransmitINT(sensor);
    TransmitCHAR(0x0A);

    }
    _delay_ms(50);
    }

    return(0);

    }
  • #2 7516158
    ktrot
    Poziom 20  
    count to zmienna 8 bitowa więc nie może przyjąć wartości 336.
    Ustawiasz przerwanie TOIE1 ale go nie obsługujesz.

    Ponadto zmienna count jest zwykłą zmienną globalną inkrementowaną jawnie, więc nie ma potrzeby deklarować ją jako volatile.
  • #3 7518210
    marex85
    Poziom 11  
    Po wprowadzeniu poprawek dalej mam bałagan w liczeniu czasu.Może jeszcze jakieś sugestie ??
  • #4 7518874
    OlekM
    Poziom 17  
    Być może to kolejne odbicia rejestrowane przez mikrofon zakłócają pomiar. Proponuję, po wykryciu przerwania SIG_INPUT_CAPTURE1 wyłączyć je - by kolejne paczki nie nadpisywały wartości 'sensor' aż do rozpoczęcia kolejnego pomiaru. Poza tym, odczyt chyba powinien nastąpić z rejestru ICR1 zamiast TCNT1.

    Proponuję także, przy wklejaniu kodu zamienić tabulatory na spacje - dzięki temu kod pokaże się z ładnymi wcięciami. Dzięki temu inni forumowicze chętniej go przeczytają.
REKLAMA