Strerowanie diodą PWM

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
Awatar użytkownika
Dawid2379
Użytkownik
Posty: 318
Rejestracja: 17 lis 2010, 19:42
Lokalizacja: Kluczbork
Kontakt:

Strerowanie diodą PWM

Post autor: Dawid2379 » 29 gru 2011, 20:57

Przepisałem kod z książki M. Kardasia, skompilowałem i działał. Dopisałem tylko polecenie aby dioda wygasła na chwile (kod przy komentarzu), ale delikatnie się świeci chyba tak być nie powinno? Mam Mege16, fusy ustawione na 4MHz.

Kod: Zaznacz cały

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

int main(void)
 {


DDRB = (1 << PB3);

TCCR0 |= (1 << WGM01) | (1 << WGM00);
TCCR0 |= (1 << COM01) | (1 << COM00);
TCCR0 |= (1 << CS00);

uint8_t i;
while(1)
{
    for(i=0;i<255;i++)
      {
	    OCR0 = i;
		_delay_ms(30);
      }
    for(i=255;i>0;i--)
	   
      {	    
		OCR0 = i;
		_delay_ms(30);
      }
	  OCR0 = 0;
	  _delay_ms(2000); //wygaszenie diody na ok, 0,5 sek.
   }
}

Awatar użytkownika
kayron
Użytkownik
Posty: 2088
Rejestracja: 21 wrz 2008, 12:53
Lokalizacja: Poland
Kontakt:

Post autor: kayron » 30 gru 2011, 9:01

A nie trzeba gdzieś zdefiniować kompilatorowi FCPU aby Delay działał prawidłowo.
U mnie w C na PICi dodaje przeważnie taka wiązkę poleceń.
#ifndef _XTAL_FREQ
#define _XTAL_FREQ 4000000
#endif
Ale podkreślam to kompilator C na procesory Microchip PIC a nie AVRGCC.
EDIT.
A.. bo ty wpisując do OCR0 wartość 0, nie wyłączasz tak naprawdę Timera, tylko generujesz sygnał o minimalnym wypełnieniu (ok 1%), aby zgasić całkowicie diodę przed Deleyem musisz odciąć PWM od pinu portu (odpowiedni rejestr Timera), wstawić tam 0 (normalna operacja na porcie), odmierzyć te 2000ms i ponownie dołączyć sygnał PWM.
Nie podam ci szczegółów, bo teraz studiuję PICi i nie chcę sobie mieszać w głowie różnymi rodzajami procesorów (na razie AVRy posłałem na emeryturę), ale na pewno wszystko się rozbiega o odcięcie sygnału PWM od portu.
Też akurat wczoraj walczyłem z podobnym programem na PICa, z tą różnicą ze tam PWM to trochę inna historia.

Awatar użytkownika
Dawid2379
Użytkownik
Posty: 318
Rejestracja: 17 lis 2010, 19:42
Lokalizacja: Kluczbork
Kontakt:

Post autor: Dawid2379 » 30 gru 2011, 22:37

A można tak:

Kod: Zaznacz cały

for(i=255;i>0;i--)
	   
      {	    
		OCR0 = i;
		_delay_ms(50);
      }
	  DDRB &= ~(1<<PB3);
	  _delay_ms(1000); //wygaszenie diody na ok, 0,5 sek.
         DDRB |= (1<<PB3);
działa jak chciałem:)

Awatar użytkownika
Dawid2379
Użytkownik
Posty: 318
Rejestracja: 17 lis 2010, 19:42
Lokalizacja: Kluczbork
Kontakt:

Post autor: Dawid2379 » 03 sty 2012, 21:45

Pomoże mi ktoś zrozumieć jedna linijkę kodu: if(cnt>=pwm1) PORTC |= (1<<PC0); else PORTC &= ~(1<<PC0); Nie wiem po co tu zerowanie bądź ustawianie portów jeśli cnt większe bądź równe pwm1. Przykład pochodzi z książki m. Kardasia, jest to sterowanie PWM sześcioma ledami, powoli ściemniające się i rozjaśniające. Będę wdzięczny za pomoc dlaczego tak to jest rozwiązane,
nie kpw:/

Kod: Zaznacz cały

#include <avr/io.h>
#include <util/delay.h>
#include <avr/interrupt.h>
 
volatile uint8_t pwm1,pwm2,pwm,3,pwm4,pwm5,pwm6;

int main(void)
{
        DDRB = (1<<PB3);   //koncowka OC0 jako wyjscie PWM

    TCCR0  |= (1<<WGM01)  |  (1<<WGM00);   //fast PWM
    TCCR0  |= (1<<COM01);                            // clear at top
    TCCR0  |= (1<<CS00);                              //preskaler 1
    OCR0=255;                                               //wygaszenie diody w kanale PWM

	DDRC |= (1<<PC0) | (1<<PC1) | (1<<PC2) ;
	DDRD |= (1<<PD7) | (1<<PD6) | (1<<PD2) ;
 
        PORTC |= (1<<PC0) | (1<<PC1) | (1<<PC2) ;
	PORTD |= (1<<PD7) | (1<<PD6) | (1<<PD2) ;
 
	
   TCCR2 |= (1<<WGM21);   //tryb CTC
   TCCR2 |= (1<<CS20);      //preskaler1
   OCR2 = 200;                    //dodatkowy podział cześtotliowści przez 200
   TIMSK |= (1<<OCIE2);    // zewolenie na przeranie CompareMatch
 
   sei();
   uint8_t i; // definicja zmiennej i na potrzeby pętli for

 
	
       while(1)
	   {
       		for(i=0;i<255;i++)
	  	    {
		    pwm1=i;
			pwm2=i;
			pwm3=i;
			pwm4=i;
			pwm5=i;
			pwm6=i;
			if(i>10) _delay_ms(3);
			else _delay_ms(15);
	  		}
 
			//całkowite rozjaśnienie diod LED
                        OCR0=255;
 
		        pwm1=255;
			pwm2=255;
			pwm3=255;
			pwm4=255;
			pwm5=255;
			pwm6=255;
			_delay_ms(2000);
 
			//pętla stopniowo ściemniajaca diody LED
		      for(i=255;i;i--)
	  	    {
		    pwm1=i;
			pwm2=i;
			pwm3=i;
			pwm4=i;
			pwm5=i;
			pwm6=i;
			if(i>10) _delay_ms(3);
			else _delay_ms(15);
	  		}
 
			//całkowite wygaszenie diod LED przez 100ms
                       OCR0=0;
 
		        pwm1=0;
			pwm2=0;
			pwm3=0;
			pwm4=0;
			pwm5=0;
			pwm6=0;
			_delay_ms(2000);
 
 
     } 
 
  return 0;
 
}
 
ISR( TIMER2_COMP_vect )
{
static uint8_t cnt; ///definicja naszego licznika PWM
 
//bezpośrednie sterowanie wyjściami kanałow PWM
 
if(cnt>=pwm1)  PORTC |=  (1<<PC0); else PORTC &=  ~(1<<PC0);
if(cnt>=pwm2)  PORTC |=  (1<<PC1); else PORTC &=  ~(1<<PC1);
if(cnt>=pwm3)  PORTC |=  (1<<PC2); else PORTC &=  ~(1<<PC2);
if(cnt>=pwm4)  PORTD |=  (1<<PD7); else PORTD &=  ~(1<<PD7);
if(cnt>=pwm5)  PORTD |=  (1<<PD6); else PORTD &=  ~(1<<PD6);
if(cnt>=pwm6)  PORTD |=  (1<<PD2); else PORTD &=  ~(1<<PD2);
 
cnt++; //zwiększenie licznika o 1
}

keruseykaryu

Post autor: keruseykaryu » 04 sty 2012, 7:24

Proste. Przez czas od (0 - pwm) linia ma być w stanie 1 a przez czas ((pwm+1) - 255) ma być w stanie niskim. pwm się zmienia, zatem % czasu stanu niskiego do wysokiego w jednostce czasu (0 - 255) jest zmienny.

Awatar użytkownika
Dawid2379
Użytkownik
Posty: 318
Rejestracja: 17 lis 2010, 19:42
Lokalizacja: Kluczbork
Kontakt:

Post autor: Dawid2379 » 04 sty 2012, 18:49

aa.. jak mamy wypełnienie np 50% pwm=127 to jeśli cnt jest równe bądź większe będą ustawiane bity a jak inna wartość to zeruje co da nam efekt średniego świecenia diody, przy 25% tylko przez jedna czwarta czasu będą ustawiane bity

ODPOWIEDZ