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

[Mega8][C] Problem z SPI i Timer2

serafim 30 Paź 2008 16:26 1479 3
REKLAMA
  • #1 5683688
    serafim
    Poziom 2  
    Witam Wszystkich,
    To mój pierwszy post na forum, jakoś jak do tej pory wszystkie odpowiedzi udawało się znaleźć.
    Ale pojawił się następujący problem: Wykorzystuje ATmega8 do sterowania trzema serwami (jeden timer-jedno serwo). Z samym sterowaniem na przyciskach wszystko jest ok i nie to jest problemem. Nie wiem jak sobie poradzić z transmisją danych na SPI skoro Timer2 ma wyjście na wejściu MOSI a ATmega8 ma być ustawiona jako slave. Jeśli ma ktoś jakiś pomysł będę bardzo wdzięczny za pomoc.

    Próbowałem zrobić to w taki sposób żeby DDRB timera ustawiać w przerwaniu jako wyjście, a przez pozostały czas mogło by służyć jako wejście dla SPI, ale niestety się nie sprawdza, symulacja w AVRStudio działa ale po wrzuceniu na uC niestety nie. Poniżej zamieszczam kod:
    
    #include <avr/io.h>
    #include <avr/interrupt.h>
    #include <util/delay.h>
    
    #define SetBit(x,y) x |= (1<<y)
    #define ClrBit(x,y) x &= ~(1<<y)
    #define NegBit(x,y) x ^= (1<<y)
    
    unsigned char a;
    
    volatile unsigned char x;
    
    //ustawienia inicjujące porty
    void port_init(void)  
    {
    
    //DDRB=0B000001011; //#
    
    DDRD=0x00;
    PORTD=0x03;
    
    }
    
    //ustawienia inicjujące timery
    void timer_init(void)
    {
    
    //Timer 0
    TCCR0=0x04;		//Prescaler /256
    TCNT0=0xE8;
    
    //Timer 1
    TCCR1A=0x00;
    TCCR1B=0x04;	//Prescaler /256
    TCNT1H=0xFF;
    TCNT1L=0xE8;
    
    //Timer 2
    TCCR2=0x06;		//Prescaler /256
    TCNT2=0xE8;
    
    //Zezwolenie na przerwania od T1,T2,T3
    TIMSK|=_BV(TOIE0)|_BV(TOIE1)|_BV(TOIE2);
    
    }
    
    //funkcje przerwań
    
    SIGNAL (SIG_OVERFLOW0) 
    
    {
      
    
    	if(!(a & 0x01) )
    
    		{	DDRB|=(1<<0); //#
    
    			TCCR0=0x00;
      			
    			SetBit(PORTB,0);
    		
      			TCNT0=x;
    			
    			TCCR0=0x04;
    
      			a=PORTB;
    
     		}
    		
    
    	else if((a & 0x01))
    
    		{	
    			TCCR0=0x00;
    
    			ClrBit(PORTB,0);
    			
      			TCNT0=x;
    			
    			TCCR0=0x04;
    
      			a=PORTB;
    
    			DDRB&=~(1<<0);//#	
    		}
    
    }
    
    
    
    SIGNAL (SIG_OVERFLOW1) 
    
    {
      
    	if(!(a & 0x02) )
    		{	
    			DDRB|=(1<<1);//#
    
    			TCCR1A=0x00;
      			TCCR1B=0x00;
    			
    			SetBit(PORTB,1);
    			
    			TCNT1H=0xFF;
      			TCNT1L=x;
    			
    			TCCR1A=0x00;
    			TCCR1B=0x04;
    
      			a=PORTB;
     		}
    		
    
    	else if((a & 0x02))
    
    		{
    			
    
    			TCCR1A=0x00;
    			TCCR1B=0x00;
    			
    			ClrBit(PORTB,1);
    			
    
    			TCNT1H=0xFF;
      			TCNT1L=x;
    			
    			TCCR1A=0x00;
    			TCCR1B=0x04;
    
      			a=PORTB;
    			
    			DDRB&=~(1<<1); //#	
    		}
    
    }
    
    SIGNAL (SIG_OVERFLOW2) 
    
    {
      
    
    	if(!(a & 0x08) )
    
    		{	
    			DDRB|=(1<<3);//#
    
    			TCCR2=0x00;
      			
    			SetBit(PORTB,3);
    		
      			TCNT2=x;
    			
    			TCCR2=0x06;
    
      			a=PORTB;
     		}
    		
    
    	else if((a & 0x08))
    
    		{	
    			
    			TCCR2=0x00;
    
    			ClrBit(PORTB,3);
    		
    
      			TCNT2=x;
    			
    			TCCR2=0x06;
    
      			a=PORTB;	
    			
    			DDRB&=~(1<<3);//#
    		}
    
    }
    
    //funkcja inicjująca
    void init_devices(void)
    {
    
     //zatrzymanie przerwań na czas uruchomienia
     cli(); //wyłączenie przerwań
     
     //inicjacja f-cji
     port_init();
     timer_init();
     
     //inicjacja rejestrów
     MCUCR = 0x00;
     GICR  = 0x00;
    
     //zezwolenie na przerwania
     sei(); 
    
    }
    
    int main (void)
    {
    	a=0;
    	
    	x=0xBA; //Położenie środkowe
    
    
    //funkcja inicjująca
      init_devices();
    
      while(1)
      {
    
    
    ///Ustawienia przycisku///
    
    	if(!(PIND & 0x01))
    	{
    	
    		_delay_ms(10);
    
    		if(!(PIND & 0x01))
    		{
    		x++;
    		}
    		if(x>0xE9)
    		{
    			x=0xE9; 
    		}	
    	
    
    	}	
    
     	if(!(PIND & 0x02))
    	{
    
    		_delay_ms(10);
    	
    		if(!(PIND & 0x02))
    		{
    		x--;
    		}
    		
    		if(x<0x8B)
    		{
    			x=0x8B; 
    		}	
    	
    	}
    	
      }
    
    return(1);
    }
    

    Program jeszcze bez SPI, ponieważ Timery w takim ustawieniu nie działają, ale jeśli zmienić odpowiednio miejsca oznaczone przez //# tzn. usunąć komentaż przy DDRB w port_init() a pozostałe elementy usunąć wszystko działa bez zarzutów.
  • REKLAMA
  • #2 5683739
    szelus
    Poziom 34  
    Jeżeli mega ma działać jako SPI slave, to nie uda Ci się współdzielić pinów od SPI z inną funkcją, niestety, bo nie masz kontroli kiedy zewnetrzny host wystawi coś na SPI.
    Nie wiem z jaka częstotliwością chodzą te serwa, ale może dałoby się PWM przenieść programowo na inny pin. Tzn. sprzętowy PWM wyłączasz dla timera 2, natomiast w jego przerwaniu OC sterujesz odpowiednio innym pinem.

    P.S.DDR nie załatwia sprawy, bo sygnały wymuszajace funkcję sprzętową na pinie maja wyższy priorytet. Zobacz sobie schemat logiczny pinu (rys. 25 w DS) i tabelkę 24.
    PS2. Twojego programu nie analizowałem...
  • REKLAMA
  • #3 5685705
    Dr.Vee
    VIP Zasłużony dla elektroda
    Ja również nie analizowałem głębiej Twojego programu, bo masz w nim niezły bajzel ;)

    Proponuję wykorzystać przerwania OC1A i OC1B do ustawiania, a TOV1 do zerowania wyjść (jak w PWM). W trybie CTC możesz użyć rejestru ICR1 do wyznaczenia maksymalnej wartości timera1 (praca w trybie 12, por. tab. 39 w datasheecie atmega8). W ten sposób uwolnisz timer2.

    Alternatywnie mógłbyś użyć sprzętowego podwójnego PWM na timerze 1, ale niestety pin OC1B jest współdzielony z pinem /SS, więc to nie zadziała.

    PS. Jakoś dziwnie testujesz warunki w przerwaniach, skoro najpierw masz if (a & 0xXX), to poźniej już nie potrzebujesz else if (!(a & 0xXX)), bo ten warunek jest automatycznie spełniony.
    Poza tym można "wyrzucić" wspólny kod poza warunki.

    Pozdrawiam,
    Dr.Vee
  • #4 5686241
    serafim
    Poziom 2  
    Połączyłem wszystko co napisaliście, dołożyłem coś od siebie i wszystko działa pięknie :D Bałagan w kodzie już jest a to dopiero początek :D

    Dzięki za pomoc :) Pozdrawiam!!!
REKLAMA