Sari la conținut
ELFORUM - Forumul electronistilor

Help, Comanda unui servomotor cu PWM (Atmega 32)


Vizitator Bogdan Sig

Postări Recomandate

Vizitator Bogdan Sig

Salut am si eu un proiect. Comandarea unui servomotor(Futaba s3000) prin PWM. Consta ca la rotirea unui potentiometru sa se roteasca si servomotorul de exemplu rotesc spre dreapta sa se roteasca de la 90 gr la 180 si spre stanga de la 90 gr la 0 ca in videoul acesta

. Putem folosii orice uC, eu am ales Atmel mega32. Am realizat si o schema in Proteus, problema ar fi codul. Am gasit un cod care face asta dar trebuie adaptat la schema care o am si asta nu inteleg cum intra comanda ce se intampla, conectarea la pini. Codul e folosit tot la Atmega 32.Ledul acela l-am pus cu intentia de a sta aprins pe tot parcursul functionarii. Schema facuta in Proteus : http://www.fast-files.com/getfile.aspx?file=112110 #include#include#includevolatile int servo_value;int delay( void );int main( void ){ADCSRA |= 1 << ADEN;ADCSRA |= 1 << ADIE;sei();ADCSRA |= 1 << ADPS2;ADMUX |= 1 << REFS0;TCCR1A |= 1 << COM1A1 | 1 << COM1A0 | 1 << WGM11;TCCR1B |= 1 << WGM13 | 1 << WGM12 | 1 << CS10;ICR1 = 19999;DDRD |= 1 << PIND5;servo_value = 18059;ADCSRA |= 1 << ADSC;while(1){OCR1A = servo_value;//delay();//OCR1A = 19519;//delay();}}int delay( void ){ _delay_ms( 100 );return 1;}ISR( ADC_vect ){servo_value = (-1.427175 * ADC + 19519);ADCSRA |= 1 << ADSC;} 
Link spre comentariu
  • Răspunsuri 6
  • Creat
  • Ultimul Răspuns

Top autori în acest subiect

Nu e corect spus PWM, caci ai de a face cu PPM. Semnalul pentru controlul servo este cu perioada de 20ms (50Hz) si ai pulsul care variaza intre 1 si 2ms. Cu un semnal PWM ar trebui sa variezi factorul de umplere de la 5 la 10% in pasi mici, practic imposibil cu solutia aleasa.

 

Posted Image

 

Dar schema ai la ce ai facut? Nu am sa descarc din linkul tau. E de evitat genul asta de postare de schema. Nu toti avem licente de Proteus ca sa deschidem schema ta.

 

Din pacate nu lucrez cu Atmega, dar poate gasim noi problema ta.

Editat de thunderer
Link spre comentariu

si asta nu inteleg cum intra comanda ce se intampla, conectarea la pini.

N-am proteus si nici n-am de gand sa-l cumpar, asa ca nu pot vedea schema, asa ca vorbesc "teorie". Cum nici cu atmelurile n-am facut nimic, teoria e cam abstracta, da'... In principiu, din cate m-am prins eu, codul postat foloseste o intrare ADC ca sa citeasca resistenta si un timer ca sa genereze pulsurile PPM in functie de ce citeste ADC-ul.

ADCSRA |= 1 << ADEN;ADCSRA |= 1 << ADIE;sei();ADCSRA |= 1 << ADPS2;ADMUX |= 1 << REFS0;

Bucata asta a folosit la configurarea ADC-ului. Urmeaza configurarea timerului: 

TCCR1A |= 1 << COM1A1 | 1 << COM1A0 | 1 << WGM11;TCCR1B |= 1 << WGM13 | 1 << WGM12 | 1 << CS10;ICR1 = 19999;DDRD |= 1 << PIND5;

Ca sa afli ce pini sa folosesti, iei binisor foaia de catalog a controllerului si citesti despre ADC si timere. Presupun cu iesirea PPM e pe pinul D5, da' e numai o presupunere. Te las pe tine s-o verifici.Urmeaza o initializare a valorii pentru servo; valoarea va fi actualizata permanent prin citirea valorii rezistentei cu ajutorul ADC-ului.

servo_value = 18059;
ADCSRA |= 1 << ADSC;

Habar n-am ce a facut comanda anterioara, da' presupun ca porneste achizitia ADC.Bucla urmatoare (infinita) se ocupa cu scrierea valorii curente (masurate de ADC) in timer.

while(1){OCR1A = servo_value;//delay();//OCR1A = 19519;//delay();}

De ADC si timer se ocupa modulele corespunzatoare din controller. Schimbul de date intre modulele astea si programul tau se poate face in programul principal, asa cum se intampla cu actualizarea timerului, sau se face "atunci cand e nevoie" coordonat de sistemul de intreruperi - cand a terminat ce avea de facut, modulul hardware activeaza intreruperea corespunzatoare si "intrerupe" controllerul din ce facea. Dupa "tratarea intreruperii" programul se reia de unde a fost intrerupt. Un astfel de sistem e folosit in cazul ADC-ului - functia urmatoare e functia de tratare a intreruperilor de la ADC. Cand achizitia ADC e terminata (achizitia nu e instantanee, are nevoie de ceva timp ca sa fie realizata), intreruperea e activata si programul "intra" in functia asta. In functia e citita valoarea achizitionata si e pornita o noua achizitie, dupa care programul principal se reia, urmand sa fie intrerupt din nou cand achizitia proaspat pornita se termina. 

 ISR( ADC_vect ){servo_value = (-1.427175 * ADC + 19519);ADCSRA |= 1 << ADSC;}

Spor!

Editat de Liviu M
Link spre comentariu
Vizitator Bogdan Sig

@ thunderer

Am atasat poza cu schema facuta de mine. @Liviu M

Acum m-am apucat de citit datele din catalog amanuntit, eu trebuie sa fac prin comanda PWM.

Am codul de la de la un proiect realizat anul trecut de cineva a folosit PIC12F675, insa nu ma pot duce tot cu acelasi :(. Am atasat schema si semnalul PWM de pe osciloscop.

 

 

#include <pic.h>

#define Semnal  GPIO2

 

// Declarare functii

void Init();

unsigned int AdcRead();

 

int tmr1ms = 0xF82F; //65535-2000=63535 (F82F)

int AdcValue;

int timerValue ;//val ce o depun in TMR1 H si L

 

void main()

{

  Init();

 

  while(1)

  {

 

  }

 

;}

void Init()

{

 

  ANSEL  = 0b0010001;    // Fosc/8 , ANS0

  ADCON0 = 0b00000001; // channel 00, right justified

  TRISIO = 0b11111011;   // GPI02 output

  GPIO  = 0x00;  //GPIO output

  INTCON = 0b01100000;     //GiE,PEIE

  T1CON = 0b00000101;    //prescaler 1:1

  OPTION = 0b11000111;    //prescaler 256

  TMR0 = 0xB3;   // 256-78+1=179

  T0IE = 1;   //enable interrupts timer0

  GIE = 1;   //general enable interrupts

  T0IF = 0; //flag timer0

  TMR1IF = 0;    //flag-ul timeri1

  ADCON0 |= 0x02;  

}

 

unsigned int AdcRead()

{

  int HIGH=0;

 

  GODONE  = 1;     // Enable Go/Done

 

 

 

  if (GODONE=1)

  {

 

  HIGH = ADRESH; //incarca continutul din ADRESH in HIGH

  HIGH = HIGH*4+24;  

 

  }

 

  return HIGH;

}

 

void interrupt Isr(void)

{

  if((T0IE&T0IF)==1)  //If Timer0 Interrupt

  {

  AdcRead();  

  AdcValue = AdcRead();

  timerValue = tmr1ms + AdcValue;    //valoarea de 2 ms + valorea potentiometrului

  TMR1IE=0;     //enable interrupts timer1

  TMR1H = timerValue>>8; //deplaseaza valoarea cu 8 biti la dreapta

  TMR1L = timerValue;   //incarca valoarea

 

  Semnal = 1; // semnal PWM

 

  TMR1IE=1; //enable interuupts timer1 

  T0IF = 0; //reset flag timer0

  TMR0 = 0xB3;

 

 

 

  }

 

  if((TMR1IE&TMR1IF)==1)  //If Timer1 Interrupt

  {

  Semnal = 0; //semnal PWM

  TMR1IF = 0;   // reset flag timer1

 

  }

 

}

Editat de Bogdan Sig
Link spre comentariu

Eu as zice sa te opresti la o schema + un cod si sa te stradui sa intelegi ce se intampla acolo.

Ti-am zis mai sus sa citesti foaia de catalog - in special modulele ADC si Timer - ca sa determini pe ce pini trebuie sa conectezi rezistenta si comanda servo-ului.

Dupa cum arata schema ta, inca nu le-ai aflat (de exemplu, m-as astepta sa fie un pin cu ADC in nume pentru rezistenta).

Link spre comentariu

Nu am avut rabdare sa analizez codul dar remarc unele ciudatenii.

 

Fac un singur exemplu:

TCCR1A |= 1 << COM1A1 | 1 << COM1A0 | 1 << WGM11;

de ce setezi COM1A0 ? nu cumva vrei sa fie PWM normal (neinversat?). Atunci ar trebui sa stergi OC1A la atingere prag.

(Clear OC1A/OC1B on compare match, set OC1A/OC1B at BOTTOM)
 
O alta observatie, dincolo de precedenta operatorilor, ar fi bine sa scrii ceva de genul:
TCCR1A |= (1<<COM1A1)|(1<<COM1A0)|(1<<WGM11);

De fapt,

TCCR1A |= (1<<COM1A1)|(1<<WGM11);

Apoi, nu stiu daca este atat de "urgent" sa generezi o intrerupere la sfarsitul fiecarei conversii, caci cred ca oricum aceasta apare mai repede decat semnalul tau PWM si nu prea vad sensul.

 

Apoi, valorile pentru impulsul minin si maxim ar trebui sa le definesti undeva si apoi sa lucrezi cu numele lor nu cu numere.

Exemplu:

servo_value = (-1.427175 * ADC + 19519);

ai putea sa definesti 

#define servo_minim 19519

si apoi ceva de genul:

servo_value = (coeficient* ADC + servo_minim);

Apoi orice ajustare va fi simpla, iar pentru cei care vor citi codul, va fi mai clar. Ar trebui ca cineva sa dedice 15 minute sa refaca tot calculul tau si eventual in timpul acesta putea scrie programul de la zero, daca era mai clar iti raspundea in 20 secunde.

Observ ca ai folosit un coeficient negativ (probabil compensezi PWM inversat). De ce ? Nu e mai simplu sa gandesti totul in pozitiv ? Comanzi unghiuri negative ?

 

Ma grabesc acum sa ies si nu am timp, dar maine cred ca iti prezint o solutie.

Editat de one
Link spre comentariu

Alătură-te conversației

Poți posta acum și să te înregistrezi mai târziu. Dacă ai un cont, autentifică-te acum pentru a posta cu contul tău.
Notă: Postarea ta va necesita aprobare moderator înainte de a fi vizibilă.

Vizitator
Unfortunately, your content contains terms that we do not allow. Please edit your content to remove the highlighted words below.
Răspunde la acest subiect...

×   Alipit ca text avansat.   Restituie formatare

  Doar 75 emoji sunt permise.

×   Linkul tău a fost încorporat automat.   Afișează ca link în schimb

×   Conținutul tău precedent a fost resetat.   Curăță editor

×   Nu poți lipi imagini direct. Încarcă sau inserează imagini din URL.




×
×
  • Creează nouă...

Informații Importante

Am plasat cookie-uri pe dispozitivul tău pentru a îmbunătății navigarea pe acest site. Poți modifica setările cookie, altfel considerăm că ești de acord să continui.Termeni de Utilizare si Ghidări