Skocz do zawartości

Problem z PWM i Atmega32


Marioslul

Pomocna odpowiedź

Witam, niedawno czytałem sobie EdW pożyczone od kumpla i natknąłem się na artykuł "robot dla każdego, czyli także dla ciebie". Po dokładnym przemysleniu sprawy (ok 30 sekund zastanawiania się) postanowiłem zamówić całosć z avt. Płytki już zlutowane, pisałem, a własciwie zmieniałem nieco programy dołączone do tego kursu(dotyczące zabawy z diodą led, która jest na płytce głównej robota). W międzyczasie udało mi się uwalić jedną atmegę i zmienić programator (starym musiałem wrzucać program nawet po 100 razy). Mam już nową atmegę, ale nie wiem czy reszta płytek nadal jest sprawna (mostek H L293D, moduł czujników). Nie mam jak tego sprawdzić ponieważ nawet nie wiem czy kod który wrzucam do pamięci procesora ma prawo uruchomić silniki. Zamieszczam kod, który odpowiada za sterowanie PWM silników:

#define F_CPU 8000000UL 
#include "stdio.h"
#include "stdlib.h"
#include <avr/io.h> 
#include <util\delay.h> 
#include <avr/interrupt.h>

#define cbi(add,bit) ((add) &= ~(1 << bit));
#define sbi(add,bit) ((add) |= (1 << bit));
#define  Led  PORTB 
#define silnikl PORTD

void init_PWM(void)
{
sbi(DDRD,4);
sbi(DDRD,5);
TCCR1A|=_BV(COM1A1);  
TCCR1A|=_BV(COM1B1);  
TCCR1A|=_BV(WGM10);
TCCR1B|=_BV(WGM12);
TCCR1B|=_BV(CS11);
OCR1AH=0x00;  
OCR1AL=225;
OCR1BH=0x00;  
OCR1BL=225;


}
void init_TIMER(void)
{
  TCCR0=0x03;
  TCNT0=0x00;
  TIMSK=0x01;
}

int main(void)
{ 
init_TIMER();
init_PWM();
}

Zamieszczam też schematy płytki mózgu i płytki z mostkiem H. Złącze 2 służy do łączenia tych płytek ze sobą. Prosiłbym o wskazówki - jak uruchomić silniki bądź o poprawienie kodu

(który pewnie jest bez sensu).

Schemat mózgu

Schemat mostka

Link do komentarza
Share on other sites

Co do samego uruchamiania silników, testuj je najpierw bez PWM, enable na sztywno jeden lub zero, bo widzę że nie ustawiasz sobie kierunku obrotów silnik, są to wejścia IN1 IN2 i IN3,IN4 ( na jednym musi być zero a na drugim jeden) żeby silnik się kręcił, zmiana obu stanów spowoduje zmianę kierunku obrotów.

Co do PWM wydaje mi się wszystko OK, nie wiem tylko po co "init_TIMER"

  • Pomogłeś! 1
Link do komentarza
Share on other sites

Witam ponownie i dzięki Ci Rico 😉 .

Poradziłem już sobie ze sterowaniem silnikiem. Problem w tym, że działa tylko jeden z nich. Na tym działąjącym mam napięcie 4,35 V, a na drugim ciągle 0. Chyba wszystkie kombinacje wypróbowałem w programie ale wciąż nic. Zamieszczam programik testowy silników. Jesli ktos by miał jakies sugestie co może być nie tak, to bardzo bym prosił o napisanie posta.

#define F_CPU 8000000UL
#include "stdio.h"
#include "stdlib.h"
#include <avr/io.h>
#include <util\delay.h>
#include <avr/interrupt.h>

#define cbi(add,bit) ((add) &= ~(1 << bit));
#define sbi(add,bit) ((add) |= (1 << bit));
#define  Led  PORTB


void init_PWM(void)
{
sbi(DDRD,4);
sbi(DDRD,5);
DDRD |= _BV(DDD5); 
DDRD |= _BV(DDD4);
TCCR1A|=_BV(COM1A1); 
TCCR1A|=_BV(COM1B1); 
TCCR1A|=_BV(WGM10);
TCCR1B|=_BV(WGM12);
TCCR1B|=_BV(CS11);
OCR1AH=0x00; 
OCR1AL=255; //lewy
OCR1BH=0x00; 
OCR1BL=255;
}

int main(void)
{

int zliczacz=0;
int a=0;
while(a==0)
{
if(bit_is_clear(PINB, 3))
  {
  a=a+1;
  }
}
while(a==1)
{
init_PWM();

  while(zliczacz%2==0)
  {

 sbi(DDRB,2);
 OCR1AL=255;
 OCR1BL=255;
 sbi(DDRD, 2);
    cbi(DDRD, 3);
    sbi(DDRD, 6);//lewy
    cbi(DDRD, 7);//lewy
    _delay_ms(10000);
 OCR1AL=0;
 OCR1BL=0;
 _delay_ms(1000);
 zliczacz=zliczacz+1;
    cbi(DDRB, 2);
}
  while(zliczacz%2==1)
  	{
  OCR1AL=255;
  OCR1BL=255;
  cbi(DDRD, 2);
  sbi(DDRD, 2);
  cbi(DDRD, 6);  //lewy
  sbi(DDRD, 7);  //lewy
  _delay_ms(10000);
     OCR1AL=0;
  OCR1BL=0;
  _delay_ms(1000);
  zliczacz=zliczacz+1;
  	} 
 }   
}

Edit: Już wszystko ok. Gapa ze mnie i nie widziałem, że jeden kabelek jest słabo przylutowany do silnika. 🙂

Link do komentarza
Share on other sites

Witam ponownie. Przez jakis czas robot leżał w kącie, ale postanowiłem w końcu do niego wrocić i pomajstrować. Podpiąłem czujnik, tzw. wąs. Aby sprawdzić czy wszystko jest ok napisałem prosty programik. Robot stoi w miejscu, a gdy wąs będzie wcisnięty to robot ma ruszyć do przodu. No i rusza, tyle że napięcie na silnikach wynosi niespełna 2 volty, przez co porusza się bardzo wolno. Czujnik jest podpięty pod port ADC, zamieszczam kod w nadziei, że znów ktos pomoże 🙄 .

sbi(ADCSRA,ADEN);     
sbi(ADCSRA,ADPS1);    
sbi(ADMUX,ADLAR);
  init_PWM();
  while(1)
  { 

    sbi(DDRB,2);
 OCR1AL=0;
 OCR1BL=0;
 sbi(DDRD, 2);
    cbi(DDRD, 3);
    sbi(DDRD, 6);//lewy
    cbi(DDRD, 7);//lewy
    if(bit_is_set(PINA, 5))
 {
   OCR1AL=255;
   OCR1BL=255;
    }
 }
Link do komentarza
Share on other sites

Zarejestruj się lub zaloguj, aby ukryć tę reklamę.
Zarejestruj się lub zaloguj, aby ukryć tę reklamę.

jlcpcb.jpg

jlcpcb.jpg

Produkcja i montaż PCB - wybierz sprawdzone PCBWay!
   • Darmowe płytki dla studentów i projektów non-profit
   • Tylko 5$ za 10 prototypów PCB w 24 godziny
   • Usługa projektowania PCB na zlecenie
   • Montaż PCB od 30$ + bezpłatna dostawa i szablony
   • Darmowe narzędzie do podglądu plików Gerber
Zobacz również » Film z fabryki PCBWay

1. Pozmieniaj cbi i sbi. Nie powinno się tego używać i mogą nie działać w nowym winavr.

2. Zmierz napięcie na pinach en. Powinno być ok 5v.

Link do komentarza
Share on other sites

Dlaczego działasz na rejestrze DDRx? On służy tylko do ustawienia czy dany pin jest wejściem czy wyjściem. Jeśli chcesz zmienić wartość wystawioną na wyjściu, zapisuj ją do rejestru PORTx.

Link do komentarza
Share on other sites

Witam, mam kolejny problem. Kupiłem serwo tower pro sg-5010 i chcę nim sterować za pomocą OC0 czyli PB3. Zastanawiam się jak ustawić ten dzielnik częstotliwosciowy, przy liczniku timer1 było to ICR1, a przy timer0 nie mam pojęcia co wpisać. Po wgraniu poniższego programu do procka serwo robi niewielki ruch w lewo i tak zostaje. Szukałem rozwiązania w przykładach, ale każdy do sterowania serwa używa OC1A lub OC1B. Z datasheeta atmela też nic nie wydedukowałem.

#define F_CPU 8000000UL
#include "stdio.h"
#include "stdlib.h"
#include <avr/io.h>
#include <util\delay.h>
#include <avr/interrupt.h>
#define cbi(add,bit) ((add) &= ~(1 << bit));
#define sbi(add,bit) ((add) |= (1 << bit));

void init_PWM(void)
{
 DDRB |=_BV(DDB3);
 TCCR0 |= _BV(WGM00);
 TCCR0 |= _BV(CS01);
 TCCR0 |= _BV(COM01);
 //??? IC0 = 10000; ???
 OCR0=750;
}
int main(void)
{
 sbi(PORTB, 3);
 init_PWM();
while(1)
{
 OCR0=750;
 _delay_ms(3000);
 OCR0=850;
 _delay_ms(3000);
}
}

Nie wiem jak ustawić wartosć tego rejestru w miejscu oznaczonym znakami zapytania. 😕 Proszę o pomoc.

Link do komentarza
Share on other sites

Marioslul wybrałeś jak tryb PWM, Phase Correct (PWM, korekcja fazy) zatem maksymalna wartość do której zlicza licznik to 255 (0xFF). Za pomocą rejestru OCR0 ustawiasz liczbę impulsów do zliczenia nie więcej niż 255. Jedynie w trybie CTC możesz sobie ustalić maksymalną wartość do której zlicza licznik.

Link do komentarza
Share on other sites

Dziękuję za pomoc hakroom. Wpadłem na pomysł, żeby do sterowania serwa wykorzystać przerwanie od timera0, jednak najpierw chciałem zrobić prosty programik testujący - zapalający i gaszący diodę. Przerwanie niestety nie działa, próbowałem używać gotowców i też nie działają. Co może być nie tak?

#define F_CPU 8000000UL
#include "stdio.h"
#include "stdlib.h"
#include <avr/io.h>
#include <util\delay.h>
#include <avr/interrupt.h>
#define cbi(add,bit) ((add) &= ~(1 << bit));
#define sbi(add,bit) ((add) |= (1 << bit));

void init_PWM(void)
{
 DDRB |=_BV(DDB2);  //pb2 jako wyjscie
 DDRB |=_BV(DDB3); //pb3 jako wyjscie
 TCCR0 |= _BV(WGM00);  //phase correct
 TCCR0 |= _BV(CS02) | _BV(CS00); //preskaler 1024
 TCCR0 |= _BV(COM01);  //clear OCx on compate match
 TCNT0=0x00; 
 TIMSK=0x01;  //overflow interrupt enabled
}

SIGNAL (SIG_OVERFLOW0)
{
  cli();   //wylaczenie przerwan na czas dzialania tego przerwania
  sbi(PORTB, 2); //dioda
  _delay_ms(50);
  cbi(PORTB, 2);
  _delay_ms(100);
  sei();  //zezwolenie na przerwania
}

int main(void)
{
 sbi(PORTB, 3);
 init_PWM();
 sei();
while(1)
{

} 
}

Edit: Zostawilem przerwania na jakis czas, udało mi się uruchomić serwo ale strasznie piszczy i bardzo wolno zmienia pozycję, czasami potrafi się zatrzymać na kilka sekund i rusza dalej. Zmienna x odpowiada za wychylenie serwa (bezpiecznie wartosci to zakres od 31 do 40). Wywalając asm ("nop") serwo zatrzymuje się na blokadzie i nie jestem w stanie znaleźć takiego x przy którym mógłbym zmieniać jego położenie. Ponownie proszę o pomoc 🙄 .

#define F_CPU 8000000UL
#include "stdio.h"
#include "stdlib.h"
#include <avr/io.h>
#include <util\delay.h>
#include <avr/interrupt.h>
#define cbi(add,bit) ((add) &= ~(1 << bit));
#define sbi(add,bit) ((add) |= (1 << bit));

int main(void)
{
  int x=32;
  DDRB |= (1<<3);  //wyjscie dla serwa
  while(1)
 {
  sbi(PORTB,3);              // serwo
  for (int z=0; z<x;z++)
  { 
  asm ("nop") ;  //funkcja nie robiaca nic
  }
  cbi(PORTB,3);
  }
  return 0; 
} 
Link do komentarza
Share on other sites

Bądź aktywny - zaloguj się lub utwórz konto!

Tylko zarejestrowani użytkownicy mogą komentować zawartość tej strony

Utwórz konto w ~20 sekund!

Zarejestruj nowe konto, to proste!

Zarejestruj się »

Zaloguj się

Posiadasz własne konto? Użyj go!

Zaloguj się »
×
×
  • Utwórz nowe...

Ważne informacje

Ta strona używa ciasteczek (cookies), dzięki którym może działać lepiej. Więcej na ten temat znajdziesz w Polityce Prywatności.