PWM w C. Kompletny brak reakcji

To forum jest dla wszystkich pasjonatów mikrokontrolerów AVR Atmela. Wymiana doświadczeń i pomoc dla początkujących w pisaniu programów zarówno w C, Asemblerze jak i BASCOM. Zapraszam znawców tematu, aby pomogli wszystkim początkującym!
ODPOWIEDZ
hagop
-
Posty: 16
Rejestracja: 15 maja 2009, 18:53
Lokalizacja: Słupsk

PWM w C. Kompletny brak reakcji

Post autor: hagop » 16 mar 2010, 21:28

Witam

Oto kod:

plik konfiguracji portow

Kod: Zaznacz cały

/*==============================================================================================*/
/*																								*/
/*		 			PLIK CIAL KONFIGURACYJNY TIMEROW											*/
/*				  				PROCESOROW 														*/
/*																								*/
/*==============================================================================================*/
#include 	"timers_config.h"

#define		SET_BIT(r,x)		r|=_BV(x);
#define		CLR_BIT(r,x)		r&=~_BV(x);
#define		TOG_BIT(r,x)		r^=_BV(x);

void init_AVR_timers(void)
{
								//TIMER 0
//	SET_BIT(TCCR0,CS00);
//	SET_BIT(TCCR0,CS01);
//	SET_BIT(TCCR0,CS02);
								//CS02 CS01 CS00 Description
								//	0 	0 	0 	No clock source (Timer/Counter stopped).
								//	0 	0 	1 	clkI/O/(No prescaling)
								//	0 	1 	0 	clkI/O/8 (From prescaler)
								//	0 	1 	1 	clkI/O/64 (From prescaler)
								//	1 	0 	0 	clkI/O/256 (From prescaler)
								//	1 	0 	1 	clkI/O/1024 (From prescaler)
								//	1 	1 	0 	External clock source on T0 pin. Clock on falling edge.
								//	1	1 	1 	External clock source on T0 pin. Clock on rising edge.

								// TIMER 1
//	SET_BIT(TCCR1B,ICNC1);			//Input Capture Noise Canceler
//	SET_BIT(TCCR1B,ICES1);		 	//Input Capture Edge Select
									//0-opadajace
									//1-narastajace


	SET_BIT(TCCR1B,CS10);		//CS12 CS11 CS10 Description
//	SET_BIT(TCCR1B,CS11);		//0 	0 	0 	No clock source. (Timer/Counter stopped)
//	SET_BIT(TCCR1B,CS12);		//0 	0 	1 	clkI/O/1 (No prescaling)
								//0 	1 	0 	clkI/O/8 (From prescaler)
								//0 	1 	1 	clkI/O/64 (From prescaler)
								//1 	0 	0 	clkI/O/256 (From prescaler)
								//1 	0 	1 	clkI/O/1024 (From prescaler)
								//1 	1 	0 	External clock source on T1 pin. Clock on falling edge.
								//1 	1 	1 	External clock source on T1 pin. Clock on rising edge.

//	SET_BIT(TIMSK,TOIE0);		// Timer/Counter0 Overflow Interrupt Enable
//	SET_BIT(TIMSK,TICIE1);		// Timer/Counter1, Input Capture Interrupt Enable
//	SET_BIT(TIMSK,OCIE1A);		// Timer/Counter1, Output Compare A Match Interrupt Enable
//	SET_BIT(TIMSK,OCIE1B);		// Timer/Counter1, Output Compare B Match Interrupt Enable
//	SET_BIT(TIMSK,TOIE1);		// Timer/Counter1, Overflow Interrupt Enable
//	SET_BIT(TIMSK,OCIE2);		// Timer/Counter2  Output Compare Match Interrupt Enable
//	SET_BIT(TIMSK,TOIE2);		// Timer/Counter2 Overflow Interrupt Enable
								//Waveform Generation Mode Bit Description

								//WGM13 WGM12 WMG11 WMG10
								//	0	  0		0	  0		NORMAL
	SET_BIT(TCCR1A,WGM10)		//	0	  0		0	  1		PWM, Phase Correct, 8-bit
	SET_BIT(TCCR1A,WGM11)		//	0	  0		1	  0		PWM, Phase Correct, 9-bit
//	SET_BIT(TCCR1B,WGM12)		//	0	  0		1	  1		PWM, Phase Correct, 10-bit
//	SET_BIT(TCCR1B,WGM13)		//	0	  1		0	  0		CTC
								//	0	  1		0	  1		Fast PWM, 8-bit
								//	0	  1		1	  0		Fast PWM, 9-bit
								//	0	  1		1	  1		Fast PWM, 10-bit
								//	1	  0     0	  0		PWM, Phase and Frequency Correct ICR1
								//	1	  0		0	  1		PWM, Phase and Frequency Correct OCR1A
								//	1	  0		1	  0		PWM, Phase Correct ICR1
								//	1	  0		1	  1		PWM, Phase Correct OCR1A
								//	1	  1		0	  0		CTC
								//	1	  1		0	  1		(Reserved)
								//	1	  1		1	  0		Fast PWM ICR1
								//	1	  1		1	  1		Fast PWM OCR1A

	SET_BIT(TCCR1A,COM1A0)		// COM1A1 COM1A0
	SET_BIT(TCCR1A,COM1A1)		//  1	    1       //Wyzerowany przy zrównaniu, liczy w dół, ustawiony przy zrównaniu, liczy w górę
								//  1	    0		//Wyzerowany przy zrównaniu, liczy w górę, ustawiony przy zrównaniu, liczy w dół




}

plik główny

Kod: Zaznacz cały

#include <avr/io.h>                
#include<avr/iom8.h>
#include <avr/interrupt.h>      


#include "timers_config\timers_config.h"
#define PWM_out(value)        OCR1A=value

#define cbi(sfr, b) (sfr &= ~(1<<b))
#define sbi(sfr, b) (sfr |= (1<<b))
#define DDR(x) _SFR_IO8(_SFR_IO_ADDR(x)-1) // adr. rej. kier. PORTx
#define PIN(x) _SFR_IO8(_SFR_IO_ADDR(x)-2) // adr. rej. wej. PORTx

#define LED_PORT        PORTB                // port diody LED
#define LED_BIT                1                // bit diody LED
#define LED_PORT_O        LED_PORT             // rejestr wyjściowy
#define LED_PORT_D        DDR(LED_PORT)   // rejestr kierunkowy
#define LED_PORT_I        PIN(LED_PORT)   // rejestr wejściowy

#define KEY1_PORT        PORTB             // port przycisku
#define KEY1_BIT                2                // bit przycisku
#define KEY1_PORT_O        KEY1_PORT             // rejestr wyjściowy
#define KEY1_PORT_D        DDR(KEY1_PORT)   // rejestr kierunkowy
#define KEY1_PORT_I        PIN(KEY1_PORT)   // rejestr wejściowy

#define KEY2_PORT        PORTB             // port przycisku
#define KEY2_BIT                3                // bit przycisku
#define KEY2_PORT_O        KEY2_PORT             // rejestr wyjściowy
#define KEY2_PORT_D        DDR(KEY2_PORT)   // rejestr kierunkowy
#define KEY2_PORT_I        PIN(KEY2_PORT)   // rejestr wejściowy


uint16_t pwm=512;

void delay(void)     
{
  unsigned int i;
  for(i=0;i<50000;i++);
}

int main(void)                        // program główny
{

	  sbi(LED_PORT_D,LED_BIT);

	  cbi(KEY1_PORT_D,KEY1_BIT);
	  sbi(KEY1_PORT_I,KEY1_BIT);

	  cbi(KEY2_PORT_D,KEY2_BIT);
	  sbi(KEY2_PORT_I,KEY2_BIT);




//  TCCR1A = _BV(COM1A1)|_BV(COM1A0)|_BV(PWM10)|_BV(PWM11);
                                  // czasomierz 1 w trybie 10 bitowego PWM
//  TCCR1B = _BV(CS00);                 // czasomierz 1 taktowany F_CPU

// to wyżej nie działa

  pwm=0;                        

  while(1)                       
  {
    PWM_out(pwm);               

    if (bit_is_clear(PINB,PB2))
    {
      delay();                        
      if (++pwm==1024) pwm=1023;
    }

    if (bit_is_clear(PINB,PB3))
    {
      delay();                        
      if (--pwm==0xFFFF) pwm=0;      
    }
	//pwm=pwm+1; (to dodałem żeby sprawdzić w debugerze co się dzieje)
  }
}

Zrobiłem symulacje w avr studio i zauważyłem ze:
1. Licznik się kręci.
2. Gdy ściągnę PB2 lub PB3 do 0 to nie wskakuje w funkcje warunkowe
3. Na końcu pętli dodałem inkrementacje pwm i na to też nie reaguje. Gdy zmieniam na sztywno przypisaniem to wtedy pwm zmienia wartość.
4. PB1 nigdy się nie załącza...

Ten PWM się uparł i nie ma ochoty współpracować.

PS jak zmienić w AVR-Studio w debugerze prędkość atmegi? Mam ciągle 4MHz a atmega chodzi na 8MHz

snow
Użytkownik
Posty: 794
Rejestracja: 16 sty 2007, 3:44
Lokalizacja: lubelskie
Kontakt:

Post autor: snow » 16 mar 2010, 23:04

Strasznie skomplikowałeś sobie sprawę. Ten program zająłby góra 10-15 linijek ;) No ale tak to bywa jak się kopiuje jakieś kody.

Na pierwszy rzut oka linia:

Kod: Zaznacz cały

#define KEY1_PORT_D        DDR(KEY1_PORT)   // rejestr kierunkowy 
wydaje mi się dość dziwna. Rejestr kierunku to DDRx a nie DDR(x)

Do funkcji opóźnienia jest gotowa biblioteka delay.h i nie ma potrzeby robić własnych opóźnień. Poza tym rozumiem że korzystasz ze starego WinAvr i przy kompilacji nie dostajesz żadnych błędów z cbi,sbi.

No i nie zauważyłem abyś gdzieś zwiększał zmienną pwm albo zmniejszał a jedynie sprawdzasz sobie warunki na jej wartość.

hagop
-
Posty: 16
Rejestracja: 15 maja 2009, 18:53
Lokalizacja: Słupsk

Post autor: hagop » 16 mar 2010, 23:58

WINAVR jest nowy. zobacz na początek mam w makrze zdefiniowane sbi cbi. Wcześniej uzywalem do ustawiania i usuwania bitu tego

Kod: Zaznacz cały

#define        SET_BIT(r,x)        r|=_BV(x); 
#define        CLR_BIT(r,x)        r&=~_BV(x); 
#define        TOG_BIT(r,x)        r^=_BV(x);
ale coś sie popsuło wraz z nowa wersją winavr'a i nie moge odowływać sie do definicji

np: CLR_BIT(MOTOR_DDR,MOTOR_BIT) musze CLR_BIT(DDRB,PB2) a tu jest problem z dopasowywaniem kodu do innych urzadzen.


Wiem ze jest biblioteka delay ale ja chciałem porostu uruchomić tego pwm'a i zobaczyć jak to działa (wersja sprzętowa) bo wersje programowa sam sobie napisałem.

Jak będę wiedział o co w tym chodzi tez mi pewnie zajmie 15 linijek.

inkrementacja zmiennej pwm jest (na końcu pętli while jako comment tutaj) sprawdzałem czy ta zmienna w ogle się zmienia (i sie nie zmienia).

do zmiany rejestrów DDRB=0xFF itd nie potrafię się przyzwyczaić (za dożo czasu to mi zajmuje przeliczanie kodu 16stkowego na binarny)

źródełko gotowca:
http://avr.elektroda.eu/?q=node/39

PS
plik konfiguracji timerow powinien być wyżej oczywiście a nie portów :)

snow
Użytkownik
Posty: 794
Rejestracja: 16 sty 2007, 3:44
Lokalizacja: lubelskie
Kontakt:

Post autor: snow » 17 mar 2010, 7:37

hagop pisze:do zmiany rejestrów DDRB=0xFF itd nie potrafię się przyzwyczaić (za dożo czasu to mi zajmuje przeliczanie kodu 16stkowego na binarny)
Ależ nie ma potrzeby zapisywać jako szesnastkowy, można jako binarny:

Kod: Zaznacz cały

DDRB=0b00001000; 
lub na pojedynczych bitach:

Kod: Zaznacz cały

DDRB|=(1<<PB3);

Zauważ że u siebie odwołujesz się do bitu CS00 w rejestrze TCCR1B. Jakbyś spojrzał do dokumentacji procesora to zauważyłbyś że w tym rejestrze nie ma bitu CS00, natomiast jest CS10. Bit CS00 odnosi się do timera0 a nie timera1;)


A teraz twój program w kilku linijkach:

Kod: Zaznacz cały

#include <avr/io.h>
#include <util/delay.h>

#define plus bit_is_clear(PINB,PB2)
#define minus bit_is_clear(PINB,PB3)

unsigned int pwm;

int main (void)
{

DDRB=0b11110011;
PORTB=0b00001100;

TCCR1A|= _BV(COM1A1)|_BV(COM1A0)|_BV(PWM10)|_BV(PWM11);
                                
TCCR1B| = _BV(CS10);                  

while(1)
{
   OCR1A=pwm;
   delay_ms(100);


   if(plus)  pwm++;
   if(minus)  pwm--;
   if(pwm>1023) pwm=1023;
   
}

return 0;
}
Pisane z głowy i bez sprawdzenia ale powinno działać.

Ps. Co do AVRStudio to ja mam mieszane uczucia, jakoś zawsze mi programy skompilowane pod nim nie działają jak potrzeba, więc jak ustawić coś w nim to nie mam pojęcia.

hagop
-
Posty: 16
Rejestracja: 15 maja 2009, 18:53
Lokalizacja: Słupsk

Post autor: hagop » 17 mar 2010, 14:56

Znalazłem błąd u siebie. Jest w pliku konfiguracji timerów (Musze to poprawić bo to całkiem wygodny sposób konfiguracji :)).

Jeżeli nie AVR-Studio to w czym sprawdzać w którym miejscu jest błąd?
W chwili obecnej czekam na Atmege1280 i elementy do zbudowanie JTAGA ICE więc będę miał możliwość sprzętowego debugowania.

ODPOWIEDZ