Vizitator Bogdan Sig Postat Aprilie 22, 2016 Partajează Postat Aprilie 22, 2016 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
Mircea Postat Aprilie 22, 2016 Partajează Postat Aprilie 22, 2016 (editat) 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. 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 Aprilie 22, 2016 de thunderer Link spre comentariu
Liviu M Postat Aprilie 23, 2016 Partajează Postat Aprilie 23, 2016 (editat) 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 Aprilie 23, 2016 de Liviu M Link spre comentariu
Vizitator Bogdan Sig Postat Aprilie 24, 2016 Partajează Postat Aprilie 24, 2016 (editat) @ 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 Aprilie 24, 2016 de Bogdan Sig Link spre comentariu
Liviu M Postat Aprilie 24, 2016 Partajează Postat Aprilie 24, 2016 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
nico_2010 Postat Aprilie 25, 2016 Partajează Postat Aprilie 25, 2016 Cursorul potentiometrului trebuie conectat la unul din porturile PA0..7, iar pentru comanda efectiva a motorului cu semnal PWM vei folosi unul din porturile PD4 sau PD5 (daca folosesti OCR1A, respectiv OCR1B) In rest, ce a scris LiviuM este valabil. Link spre comentariu
one Postat Aprilie 28, 2016 Partajează Postat Aprilie 28, 2016 (editat) 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 Aprilie 28, 2016 de one Link spre comentariu
Postări Recomandate
Creează un cont sau autentifică-te pentru a adăuga comentariu
Trebuie să fi un membru pentru a putea lăsa un comentariu.
Creează un cont
Înregistrează-te pentru un nou cont în comunitatea nostră. Este simplu!
Înregistrează un nou contAutentificare
Ai deja un cont? Autentifică-te aici.
Autentifică-te acum